amulet-core 2.0a5__cp312-cp312-macosx_10_13_universal2.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of amulet-core might be problematic. Click here for more details.
- amulet/__init__.cpython-312-darwin.so +0 -0
- amulet/__init__.pyi +30 -0
- amulet/__pyinstaller/__init__.py +2 -0
- amulet/__pyinstaller/hook-amulet.py +4 -0
- amulet/_init.py +28 -0
- amulet/_version.py +21 -0
- amulet/biome.cpp +36 -0
- amulet/biome.hpp +43 -0
- amulet/biome.pyi +77 -0
- amulet/block.cpp +435 -0
- amulet/block.hpp +119 -0
- amulet/block.pyi +273 -0
- amulet/block_entity.cpp +12 -0
- amulet/block_entity.hpp +56 -0
- amulet/block_entity.pyi +80 -0
- amulet/chunk.cpp +16 -0
- amulet/chunk.hpp +99 -0
- amulet/chunk.pyi +30 -0
- amulet/chunk_/components/biome.py +155 -0
- amulet/chunk_/components/block_entity.py +117 -0
- amulet/chunk_/components/entity.py +64 -0
- amulet/chunk_/components/height_2d.py +16 -0
- amulet/chunk_components.pyi +95 -0
- amulet/collections.pyi +37 -0
- amulet/data_types.py +29 -0
- amulet/entity.py +180 -0
- amulet/errors.py +63 -0
- amulet/game/__init__.py +7 -0
- amulet/game/_game.py +152 -0
- amulet/game/_universal/__init__.py +1 -0
- amulet/game/_universal/_biome.py +17 -0
- amulet/game/_universal/_block.py +47 -0
- amulet/game/_universal/_version.py +68 -0
- amulet/game/abc/__init__.py +22 -0
- amulet/game/abc/_block_specification.py +150 -0
- amulet/game/abc/biome.py +213 -0
- amulet/game/abc/block.py +331 -0
- amulet/game/abc/game_version_container.py +25 -0
- amulet/game/abc/json_interface.py +27 -0
- amulet/game/abc/version.py +44 -0
- amulet/game/bedrock/__init__.py +1 -0
- amulet/game/bedrock/_biome.py +35 -0
- amulet/game/bedrock/_block.py +42 -0
- amulet/game/bedrock/_version.py +165 -0
- amulet/game/java/__init__.py +2 -0
- amulet/game/java/_biome.py +35 -0
- amulet/game/java/_block.py +60 -0
- amulet/game/java/_version.py +176 -0
- amulet/game/translate/__init__.py +12 -0
- amulet/game/translate/_functions/__init__.py +15 -0
- amulet/game/translate/_functions/_code_functions/__init__.py +0 -0
- amulet/game/translate/_functions/_code_functions/_text.py +553 -0
- amulet/game/translate/_functions/_code_functions/banner_pattern.py +67 -0
- amulet/game/translate/_functions/_code_functions/bedrock_chest_connection.py +152 -0
- amulet/game/translate/_functions/_code_functions/bedrock_moving_block_pos.py +88 -0
- amulet/game/translate/_functions/_code_functions/bedrock_sign.py +152 -0
- amulet/game/translate/_functions/_code_functions/bedrock_skull_rotation.py +16 -0
- amulet/game/translate/_functions/_code_functions/custom_name.py +146 -0
- amulet/game/translate/_functions/_frozen.py +66 -0
- amulet/game/translate/_functions/_state.py +54 -0
- amulet/game/translate/_functions/_typing.py +98 -0
- amulet/game/translate/_functions/abc.py +116 -0
- amulet/game/translate/_functions/carry_nbt.py +160 -0
- amulet/game/translate/_functions/carry_properties.py +80 -0
- amulet/game/translate/_functions/code.py +143 -0
- amulet/game/translate/_functions/map_block_name.py +66 -0
- amulet/game/translate/_functions/map_nbt.py +111 -0
- amulet/game/translate/_functions/map_properties.py +93 -0
- amulet/game/translate/_functions/multiblock.py +112 -0
- amulet/game/translate/_functions/new_block.py +42 -0
- amulet/game/translate/_functions/new_entity.py +43 -0
- amulet/game/translate/_functions/new_nbt.py +206 -0
- amulet/game/translate/_functions/new_properties.py +64 -0
- amulet/game/translate/_functions/sequence.py +51 -0
- amulet/game/translate/_functions/walk_input_nbt.py +331 -0
- amulet/game/translate/_translator.py +433 -0
- amulet/item.py +75 -0
- amulet/level/__init__.pyi +27 -0
- amulet/level/_load.py +100 -0
- amulet/level/abc/__init__.py +12 -0
- amulet/level/abc/_chunk_handle.py +335 -0
- amulet/level/abc/_dimension.py +86 -0
- amulet/level/abc/_history/__init__.py +1 -0
- amulet/level/abc/_history/_cache.py +224 -0
- amulet/level/abc/_history/_history_manager.py +291 -0
- amulet/level/abc/_level/__init__.py +5 -0
- amulet/level/abc/_level/_compactable_level.py +10 -0
- amulet/level/abc/_level/_creatable_level.py +29 -0
- amulet/level/abc/_level/_disk_level.py +17 -0
- amulet/level/abc/_level/_level.py +453 -0
- amulet/level/abc/_level/_loadable_level.py +42 -0
- amulet/level/abc/_player_storage.py +7 -0
- amulet/level/abc/_raw_level.py +187 -0
- amulet/level/abc/_registry.py +40 -0
- amulet/level/bedrock/__init__.py +2 -0
- amulet/level/bedrock/_chunk_handle.py +19 -0
- amulet/level/bedrock/_dimension.py +22 -0
- amulet/level/bedrock/_level.py +187 -0
- amulet/level/bedrock/_raw/__init__.py +5 -0
- amulet/level/bedrock/_raw/_actor_counter.py +53 -0
- amulet/level/bedrock/_raw/_chunk.py +54 -0
- amulet/level/bedrock/_raw/_chunk_decode.py +668 -0
- amulet/level/bedrock/_raw/_chunk_encode.py +602 -0
- amulet/level/bedrock/_raw/_constant.py +9 -0
- amulet/level/bedrock/_raw/_dimension.py +343 -0
- amulet/level/bedrock/_raw/_level.py +463 -0
- amulet/level/bedrock/_raw/_level_dat.py +90 -0
- amulet/level/bedrock/_raw/_typing.py +6 -0
- amulet/level/bedrock/_raw/leveldb_chunk_versions.py +83 -0
- amulet/level/bedrock/chunk/__init__.py +1 -0
- amulet/level/bedrock/chunk/_chunk.py +126 -0
- amulet/level/bedrock/chunk/components/__init__.py +0 -0
- amulet/level/bedrock/chunk/components/chunk_version.py +12 -0
- amulet/level/bedrock/chunk/components/finalised_state.py +13 -0
- amulet/level/bedrock/chunk/components/raw_chunk.py +15 -0
- amulet/level/construction/__init__.py +0 -0
- amulet/level/java/__init__.pyi +21 -0
- amulet/level/java/_chunk_handle.py +17 -0
- amulet/level/java/_chunk_handle.pyi +15 -0
- amulet/level/java/_dimension.py +20 -0
- amulet/level/java/_dimension.pyi +13 -0
- amulet/level/java/_level.py +184 -0
- amulet/level/java/_level.pyi +120 -0
- amulet/level/java/_raw/__init__.pyi +19 -0
- amulet/level/java/_raw/_chunk.pyi +23 -0
- amulet/level/java/_raw/_chunk_decode.py +561 -0
- amulet/level/java/_raw/_chunk_encode.py +463 -0
- amulet/level/java/_raw/_constant.py +9 -0
- amulet/level/java/_raw/_constant.pyi +20 -0
- amulet/level/java/_raw/_data_pack/__init__.py +2 -0
- amulet/level/java/_raw/_data_pack/__init__.pyi +8 -0
- amulet/level/java/_raw/_data_pack/data_pack.py +241 -0
- amulet/level/java/_raw/_data_pack/data_pack.pyi +197 -0
- amulet/level/java/_raw/_data_pack/data_pack_manager.py +77 -0
- amulet/level/java/_raw/_data_pack/data_pack_manager.pyi +75 -0
- amulet/level/java/_raw/_dimension.py +86 -0
- amulet/level/java/_raw/_dimension.pyi +72 -0
- amulet/level/java/_raw/_level.py +507 -0
- amulet/level/java/_raw/_level.pyi +238 -0
- amulet/level/java/_raw/_typing.py +3 -0
- amulet/level/java/_raw/_typing.pyi +5 -0
- amulet/level/java/anvil/__init__.py +2 -0
- amulet/level/java/anvil/__init__.pyi +11 -0
- amulet/level/java/anvil/_dimension.py +170 -0
- amulet/level/java/anvil/_dimension.pyi +109 -0
- amulet/level/java/anvil/_region.py +421 -0
- amulet/level/java/anvil/_region.pyi +197 -0
- amulet/level/java/anvil/_sector_manager.py +223 -0
- amulet/level/java/anvil/_sector_manager.pyi +142 -0
- amulet/level/java/chunk.pyi +81 -0
- amulet/level/java/chunk_/_chunk.py +260 -0
- amulet/level/java/chunk_/components/inhabited_time.py +12 -0
- amulet/level/java/chunk_/components/last_update.py +12 -0
- amulet/level/java/chunk_/components/legacy_version.py +12 -0
- amulet/level/java/chunk_/components/light_populated.py +12 -0
- amulet/level/java/chunk_/components/named_height_2d.py +37 -0
- amulet/level/java/chunk_/components/status.py +11 -0
- amulet/level/java/chunk_/components/terrain_populated.py +12 -0
- amulet/level/java/chunk_components.pyi +22 -0
- amulet/level/java/long_array.pyi +38 -0
- amulet/level/java_forge/__init__.py +0 -0
- amulet/level/mcstructure/__init__.py +0 -0
- amulet/level/nbt/__init__.py +0 -0
- amulet/level/schematic/__init__.py +0 -0
- amulet/level/sponge_schematic/__init__.py +0 -0
- amulet/level/temporary_level/__init__.py +1 -0
- amulet/level/temporary_level/_level.py +16 -0
- amulet/palette/__init__.pyi +8 -0
- amulet/palette/biome_palette.pyi +45 -0
- amulet/palette/block_palette.pyi +45 -0
- amulet/player.py +64 -0
- amulet/py.typed +0 -0
- amulet/selection/__init__.py +2 -0
- amulet/selection/abstract_selection.py +342 -0
- amulet/selection/box.py +852 -0
- amulet/selection/group.py +481 -0
- amulet/utils/__init__.pyi +28 -0
- amulet/utils/call_spec/__init__.py +24 -0
- amulet/utils/call_spec/__init__.pyi +53 -0
- amulet/utils/call_spec/_call_spec.py +262 -0
- amulet/utils/call_spec/_call_spec.pyi +272 -0
- amulet/utils/format_utils.py +41 -0
- amulet/utils/generator.py +18 -0
- amulet/utils/matrix.py +243 -0
- amulet/utils/matrix.pyi +177 -0
- amulet/utils/numpy.pyi +11 -0
- amulet/utils/numpy_helpers.py +19 -0
- amulet/utils/shareable_lock.py +335 -0
- amulet/utils/shareable_lock.pyi +190 -0
- amulet/utils/signal/__init__.py +10 -0
- amulet/utils/signal/__init__.pyi +25 -0
- amulet/utils/signal/_signal.py +228 -0
- amulet/utils/signal/_signal.pyi +84 -0
- amulet/utils/task_manager.py +235 -0
- amulet/utils/task_manager.pyi +168 -0
- amulet/utils/typed_property.py +111 -0
- amulet/utils/typing.py +4 -0
- amulet/utils/typing.pyi +6 -0
- amulet/utils/weakref.py +70 -0
- amulet/utils/weakref.pyi +50 -0
- amulet/utils/world_utils.py +102 -0
- amulet/utils/world_utils.pyi +109 -0
- amulet/version.cpp +136 -0
- amulet/version.hpp +142 -0
- amulet/version.pyi +94 -0
- amulet_core-2.0a5.dist-info/METADATA +103 -0
- amulet_core-2.0a5.dist-info/RECORD +210 -0
- amulet_core-2.0a5.dist-info/WHEEL +5 -0
- amulet_core-2.0a5.dist-info/entry_points.txt +2 -0
- amulet_core-2.0a5.dist-info/top_level.txt +1 -0
|
Binary file
|
amulet/__init__.pyi
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from . import (
|
|
4
|
+
biome,
|
|
5
|
+
block,
|
|
6
|
+
block_entity,
|
|
7
|
+
chunk,
|
|
8
|
+
chunk_components,
|
|
9
|
+
collections,
|
|
10
|
+
level,
|
|
11
|
+
palette,
|
|
12
|
+
utils,
|
|
13
|
+
version,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"IMG_DIRECTORY",
|
|
18
|
+
"biome",
|
|
19
|
+
"block",
|
|
20
|
+
"block_entity",
|
|
21
|
+
"chunk",
|
|
22
|
+
"chunk_components",
|
|
23
|
+
"collections",
|
|
24
|
+
"level",
|
|
25
|
+
"palette",
|
|
26
|
+
"utils",
|
|
27
|
+
"version",
|
|
28
|
+
]
|
|
29
|
+
IMG_DIRECTORY: str
|
|
30
|
+
__version__: str
|
amulet/_init.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def init(m: Any) -> None:
|
|
5
|
+
import os
|
|
6
|
+
import logging
|
|
7
|
+
import platformdirs
|
|
8
|
+
|
|
9
|
+
from ._version import get_versions
|
|
10
|
+
|
|
11
|
+
m.__version__ = get_versions()["version"]
|
|
12
|
+
|
|
13
|
+
# m.entity_support = False
|
|
14
|
+
|
|
15
|
+
m.IMG_DIRECTORY = os.path.join(os.path.dirname(__file__), "img")
|
|
16
|
+
|
|
17
|
+
# Initialise default paths. Applications should override these environment variables.
|
|
18
|
+
# os.environ.setdefault("DATA_DIR", platformdirs.user_data_dir("AmuletTeam", "AmuletTeam"))
|
|
19
|
+
# os.environ.setdefault("CONFIG_DIR", platformdirs.user_config_dir("AmuletTeam", "AmuletTeam"))
|
|
20
|
+
os.environ.setdefault(
|
|
21
|
+
"CACHE_DIR", platformdirs.user_cache_dir("AmuletTeam", "AmuletTeam")
|
|
22
|
+
)
|
|
23
|
+
os.environ.setdefault(
|
|
24
|
+
"LOG_DIR", platformdirs.user_log_dir("AmuletTeam", "AmuletTeam")
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# init a default logger
|
|
28
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s")
|
amulet/_version.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
# This file was generated by 'versioneer.py' (0.29) from
|
|
3
|
+
# revision-control system data, or from the parent directory name of an
|
|
4
|
+
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
|
5
|
+
# of this file.
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
version_json = '''
|
|
10
|
+
{
|
|
11
|
+
"date": "2024-09-17T14:48:15+0100",
|
|
12
|
+
"dirty": false,
|
|
13
|
+
"error": null,
|
|
14
|
+
"full-revisionid": "44627ded044dfa5a4f63fc941b36dd5e84be0a54",
|
|
15
|
+
"version": "2.0a5"
|
|
16
|
+
}
|
|
17
|
+
''' # END VERSION_JSON
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_versions():
|
|
21
|
+
return json.loads(version_json)
|
amulet/biome.cpp
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#include <map>
|
|
2
|
+
#include <variant>
|
|
3
|
+
#include <type_traits>
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <functional>
|
|
6
|
+
#include <stdexcept>
|
|
7
|
+
|
|
8
|
+
#include <amulet/biome.hpp>
|
|
9
|
+
#include <amulet_nbt/nbt_encoding/binary.hpp>
|
|
10
|
+
#include <amulet_nbt/nbt_encoding/string.hpp>
|
|
11
|
+
|
|
12
|
+
namespace Amulet {
|
|
13
|
+
void Biome::serialise(BinaryWriter& writer) const {
|
|
14
|
+
writer.writeNumeric<std::uint8_t>(1);
|
|
15
|
+
writer.writeSizeAndBytes(get_platform());
|
|
16
|
+
get_version()->serialise(writer);
|
|
17
|
+
writer.writeSizeAndBytes(namespace_);
|
|
18
|
+
writer.writeSizeAndBytes(base_name);
|
|
19
|
+
}
|
|
20
|
+
std::shared_ptr<Biome> Biome::deserialise(BinaryReader& reader){
|
|
21
|
+
auto version_number = reader.readNumeric<std::uint8_t>();
|
|
22
|
+
switch (version_number) {
|
|
23
|
+
case 1:
|
|
24
|
+
{
|
|
25
|
+
std::string platform = reader.readSizeAndBytes();
|
|
26
|
+
std::shared_ptr<VersionNumber> version = VersionNumber::deserialise(reader);
|
|
27
|
+
std::string namespace_ = reader.readSizeAndBytes();
|
|
28
|
+
std::string base_name = reader.readSizeAndBytes();
|
|
29
|
+
return std::make_shared<Biome>(platform, version, namespace_, base_name);
|
|
30
|
+
}
|
|
31
|
+
default:
|
|
32
|
+
throw std::invalid_argument("Unsupported version " + std::to_string(version_number));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
}
|
amulet/biome.hpp
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
|
|
5
|
+
#include <amulet/version.hpp>
|
|
6
|
+
#include <amulet/io/binary_reader.hpp>
|
|
7
|
+
#include <amulet/io/binary_writer.hpp>
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
namespace Amulet {
|
|
11
|
+
class Biome: public PlatformVersionContainer {
|
|
12
|
+
private:
|
|
13
|
+
std::string namespace_;
|
|
14
|
+
std::string base_name;
|
|
15
|
+
public:
|
|
16
|
+
const std::string& get_namespace() const { return namespace_; }
|
|
17
|
+
const std::string& get_base_name() const { return base_name; }
|
|
18
|
+
|
|
19
|
+
Biome(
|
|
20
|
+
const PlatformType& platform,
|
|
21
|
+
std::shared_ptr<VersionNumber> version,
|
|
22
|
+
const std::string& namespace_,
|
|
23
|
+
const std::string& base_name
|
|
24
|
+
):
|
|
25
|
+
PlatformVersionContainer(platform, version),
|
|
26
|
+
namespace_(namespace_),
|
|
27
|
+
base_name(base_name) {}
|
|
28
|
+
|
|
29
|
+
void serialise(BinaryWriter&) const;
|
|
30
|
+
static std::shared_ptr<Biome> deserialise(BinaryReader&);
|
|
31
|
+
|
|
32
|
+
auto operator<=>(const Biome& other) const {
|
|
33
|
+
auto cmp = PlatformVersionContainer::operator<=>(other);
|
|
34
|
+
if (cmp != 0) { return cmp; }
|
|
35
|
+
cmp = namespace_ <=> other.namespace_;
|
|
36
|
+
if (cmp != 0) { return cmp; }
|
|
37
|
+
return base_name <=> other.base_name;
|
|
38
|
+
}
|
|
39
|
+
bool operator==(const Biome& other) const {
|
|
40
|
+
return (*this <=> other) == 0;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
}
|
amulet/biome.pyi
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import types
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
import amulet.version
|
|
7
|
+
|
|
8
|
+
__all__ = ["Biome"]
|
|
9
|
+
|
|
10
|
+
class Biome(amulet.version.PlatformVersionContainer):
|
|
11
|
+
"""
|
|
12
|
+
A class to manage the state of a biome.
|
|
13
|
+
|
|
14
|
+
It is an immutable object that contains the platform, version, namespace and base name.
|
|
15
|
+
|
|
16
|
+
Here's a few examples on how create a Biome object:
|
|
17
|
+
|
|
18
|
+
>>> # Create a plains biome for Java 1.20.2
|
|
19
|
+
>>> plains = Biome("java", VersionNumber(3578), "minecraft", "plains")
|
|
20
|
+
>>> # The version number for Java is the Java data version
|
|
21
|
+
|
|
22
|
+
>>> # Create a plains biome for Bedrock
|
|
23
|
+
>>> plains = Biome("bedrock", VersionNumber(1, 21, 0, 3), "minecraft", "plains")
|
|
24
|
+
>>> # The biome version number is unused in Bedrock but it is here for completeness.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
@typing.overload
|
|
28
|
+
def __eq__(self, arg0: Biome) -> bool: ...
|
|
29
|
+
@typing.overload
|
|
30
|
+
def __eq__(self, arg0: typing.Any) -> bool | types.NotImplementedType: ...
|
|
31
|
+
def __ge__(self, arg0: Biome) -> bool: ...
|
|
32
|
+
def __getstate__(self) -> bytes: ...
|
|
33
|
+
def __gt__(self, arg0: Biome) -> bool: ...
|
|
34
|
+
def __hash__(self) -> int: ...
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
platform: str,
|
|
38
|
+
version: amulet.version.VersionNumber,
|
|
39
|
+
namespace: str,
|
|
40
|
+
base_name: str,
|
|
41
|
+
) -> None: ...
|
|
42
|
+
def __le__(self, arg0: Biome) -> bool: ...
|
|
43
|
+
def __lt__(self, arg0: Biome) -> bool: ...
|
|
44
|
+
def __repr__(self) -> str: ...
|
|
45
|
+
def __setstate__(self, arg0: bytes) -> None: ...
|
|
46
|
+
@property
|
|
47
|
+
def base_name(self) -> str:
|
|
48
|
+
"""
|
|
49
|
+
The base name of the :class:`Biome` object.
|
|
50
|
+
|
|
51
|
+
>>> biome: Biome
|
|
52
|
+
>>> biome.base_name
|
|
53
|
+
|
|
54
|
+
:return: The base name of the biome
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def namespace(self) -> str:
|
|
59
|
+
"""
|
|
60
|
+
The namespace of the :class:`Biome` object.
|
|
61
|
+
|
|
62
|
+
>>> biome: Biome
|
|
63
|
+
>>> water.namespace
|
|
64
|
+
|
|
65
|
+
:return: The namespace of the biome
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def namespaced_name(self) -> str:
|
|
70
|
+
"""
|
|
71
|
+
The namespaced id of the :class:`Biome` object.
|
|
72
|
+
|
|
73
|
+
>>> biome: Biome
|
|
74
|
+
>>> biome.namespaced_name
|
|
75
|
+
|
|
76
|
+
:return: The "namespace:base_name" of the biome
|
|
77
|
+
"""
|
amulet/block.cpp
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
#include <map>
|
|
2
|
+
#include <variant>
|
|
3
|
+
#include <type_traits>
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <functional>
|
|
6
|
+
#include <stdexcept>
|
|
7
|
+
|
|
8
|
+
#include <amulet/block.hpp>
|
|
9
|
+
#include <amulet_nbt/nbt_encoding/binary.hpp>
|
|
10
|
+
#include <amulet_nbt/nbt_encoding/string.hpp>
|
|
11
|
+
|
|
12
|
+
namespace Amulet {
|
|
13
|
+
void Block::serialise(BinaryWriter& writer) const {
|
|
14
|
+
writer.writeNumeric<std::uint8_t>(1);
|
|
15
|
+
writer.writeSizeAndBytes(get_platform());
|
|
16
|
+
get_version()->serialise(writer);
|
|
17
|
+
writer.writeSizeAndBytes(namespace_);
|
|
18
|
+
writer.writeSizeAndBytes(base_name);
|
|
19
|
+
|
|
20
|
+
writer.writeNumeric<std::uint64_t>(properties.size());
|
|
21
|
+
for (auto const& [key, val] : properties) {
|
|
22
|
+
writer.writeSizeAndBytes(key);
|
|
23
|
+
std::visit([&writer](auto&& tag) {
|
|
24
|
+
AmuletNBT::write_nbt(writer, "", tag);
|
|
25
|
+
}, val);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
std::shared_ptr<Block> Block::deserialise(BinaryReader& reader){
|
|
29
|
+
auto version_number = reader.readNumeric<std::uint8_t>();
|
|
30
|
+
switch (version_number) {
|
|
31
|
+
case 1:
|
|
32
|
+
{
|
|
33
|
+
std::string platform = reader.readSizeAndBytes();
|
|
34
|
+
std::shared_ptr<VersionNumber> version = VersionNumber::deserialise(reader);
|
|
35
|
+
std::string namespace_ = reader.readSizeAndBytes();
|
|
36
|
+
std::string base_name = reader.readSizeAndBytes();
|
|
37
|
+
std::uint64_t property_count;
|
|
38
|
+
BlockProperites properties;
|
|
39
|
+
reader.readNumericInto<std::uint64_t>(property_count);
|
|
40
|
+
for (std::uint64_t i = 0; i < property_count; i++) {
|
|
41
|
+
std::string name = reader.readSizeAndBytes();
|
|
42
|
+
AmuletNBT::NamedTag named_tag = AmuletNBT::read_nbt(reader);
|
|
43
|
+
properties[name] = std::visit([](auto&& tag) -> PropertyValueType {
|
|
44
|
+
using T = std::decay_t<decltype(tag)>;
|
|
45
|
+
if constexpr (
|
|
46
|
+
std::is_same_v<T, AmuletNBT::ByteTag> ||
|
|
47
|
+
std::is_same_v<T, AmuletNBT::ShortTag> ||
|
|
48
|
+
std::is_same_v<T, AmuletNBT::IntTag> ||
|
|
49
|
+
std::is_same_v<T, AmuletNBT::LongTag> ||
|
|
50
|
+
std::is_same_v<T, AmuletNBT::StringTag>
|
|
51
|
+
) {
|
|
52
|
+
return tag;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
throw std::invalid_argument("Property tag must be Byte, Short, Int, Long or String");
|
|
56
|
+
}
|
|
57
|
+
}, named_tag.tag_node);
|
|
58
|
+
}
|
|
59
|
+
return std::make_shared<Block>(platform, version, namespace_, base_name, properties);
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
throw std::invalid_argument("Unsupported Block version " + std::to_string(version_number));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
template <typename T>
|
|
67
|
+
inline std::vector<std::string> get_ordered_keys(const T& map) {
|
|
68
|
+
std::vector<std::string> keys;
|
|
69
|
+
keys.reserve(map.size());
|
|
70
|
+
for (const auto& [key, _] : map) {
|
|
71
|
+
keys.push_back(key);
|
|
72
|
+
}
|
|
73
|
+
std::sort(keys.begin(), keys.end());
|
|
74
|
+
return keys;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
std::string Block::java_blockstate() const {
|
|
78
|
+
std::string blockstate;
|
|
79
|
+
blockstate += get_namespace();
|
|
80
|
+
blockstate += ":";
|
|
81
|
+
blockstate += get_base_name();
|
|
82
|
+
const auto& properties = get_properties();
|
|
83
|
+
if (!properties.empty()) {
|
|
84
|
+
blockstate += "[";
|
|
85
|
+
auto keys = get_ordered_keys(properties);
|
|
86
|
+
bool is_first = true;
|
|
87
|
+
for (const std::string& key : keys) {
|
|
88
|
+
const auto& it = properties.find(key);
|
|
89
|
+
std::visit(
|
|
90
|
+
[&is_first, &blockstate, &key](auto&& tag) {
|
|
91
|
+
using T = std::decay_t<decltype(tag)>;
|
|
92
|
+
if constexpr (std::is_same_v<T, AmuletNBT::StringTag>) {
|
|
93
|
+
if (is_first) {
|
|
94
|
+
is_first = false;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
blockstate += ",";
|
|
98
|
+
}
|
|
99
|
+
blockstate += key;
|
|
100
|
+
blockstate += "=";
|
|
101
|
+
blockstate += tag;
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
it->second
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
blockstate += "]";
|
|
108
|
+
}
|
|
109
|
+
return blockstate;
|
|
110
|
+
}
|
|
111
|
+
std::string Block::bedrock_blockstate() const {
|
|
112
|
+
std::string blockstate;
|
|
113
|
+
blockstate += get_namespace();
|
|
114
|
+
blockstate += ":";
|
|
115
|
+
blockstate += get_base_name();
|
|
116
|
+
const auto& properties = get_properties();
|
|
117
|
+
if (!properties.empty()) {
|
|
118
|
+
blockstate += "[";
|
|
119
|
+
auto keys = get_ordered_keys(properties);
|
|
120
|
+
bool is_first = true;
|
|
121
|
+
for (const std::string& key : keys) {
|
|
122
|
+
const auto& it = properties.find(key);
|
|
123
|
+
std::visit(
|
|
124
|
+
[&is_first, &blockstate, &key](auto&& tag) {
|
|
125
|
+
if (is_first) {
|
|
126
|
+
is_first = false;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
blockstate += ",";
|
|
130
|
+
}
|
|
131
|
+
blockstate += "\"";
|
|
132
|
+
blockstate += key;
|
|
133
|
+
blockstate += "\"=";
|
|
134
|
+
using T = std::decay_t<decltype(tag)>;
|
|
135
|
+
if constexpr (std::is_same_v<T, AmuletNBT::ByteTag>) {
|
|
136
|
+
if (tag == 0) {
|
|
137
|
+
blockstate += "false";
|
|
138
|
+
} else if (tag == 1) {
|
|
139
|
+
blockstate += "true";
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
blockstate += AmuletNBT::write_snbt(tag);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else if constexpr (std::is_same_v<T, AmuletNBT::StringTag>) {
|
|
146
|
+
blockstate += "\"";
|
|
147
|
+
blockstate += tag;
|
|
148
|
+
blockstate += "\"";
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
blockstate += AmuletNBT::write_snbt(tag);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
it->second
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
blockstate += "]";
|
|
158
|
+
}
|
|
159
|
+
return blockstate;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
template <
|
|
163
|
+
void(*namespace_validator)(const size_t&, const std::string&),
|
|
164
|
+
void(*base_name_validator)(const size_t&, const std::string&),
|
|
165
|
+
std::string(*capture_key)(const std::string&, size_t&),
|
|
166
|
+
PropertyValueType(*capture_value)(const std::string&, size_t&)
|
|
167
|
+
>
|
|
168
|
+
std::shared_ptr<Block> parse_blockstate(
|
|
169
|
+
const PlatformType& platform,
|
|
170
|
+
std::shared_ptr<VersionNumber> version,
|
|
171
|
+
const std::string& blockstate
|
|
172
|
+
) {
|
|
173
|
+
// This is more lenient than the game parser.
|
|
174
|
+
// It may parse formats that the game parsers wouldn't parse but it should support everything they do parse.
|
|
175
|
+
|
|
176
|
+
// Find the start of the property section and the end of the resource identifier.
|
|
177
|
+
size_t property_start = blockstate.find("[");
|
|
178
|
+
if (property_start > blockstate.size()) {
|
|
179
|
+
property_start = blockstate.size();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
size_t colon_pos = blockstate.find(":");
|
|
183
|
+
std::string namespace_;
|
|
184
|
+
std::string base_name;
|
|
185
|
+
if (colon_pos < property_start) {
|
|
186
|
+
// namespaced name
|
|
187
|
+
if (colon_pos == 0) { throw std::invalid_argument("namespace is empty"); }
|
|
188
|
+
namespace_ = std::string(blockstate.begin(), blockstate.begin() + colon_pos);
|
|
189
|
+
if (colon_pos + 1 == property_start) { throw std::invalid_argument("base name is empty"); }
|
|
190
|
+
base_name = std::string(blockstate.begin() + colon_pos + 1, blockstate.begin() + property_start);
|
|
191
|
+
namespace_validator(0, namespace_);
|
|
192
|
+
base_name_validator(colon_pos + 1, base_name);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// only base name
|
|
196
|
+
namespace_ = "minecraft";
|
|
197
|
+
if (property_start == 0) { throw std::invalid_argument("base name is empty"); }
|
|
198
|
+
base_name = std::string(blockstate.begin(), blockstate.begin() + property_start);
|
|
199
|
+
base_name_validator(0, base_name);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (property_start < blockstate.size()) {
|
|
203
|
+
// has properties
|
|
204
|
+
BlockProperites properties;
|
|
205
|
+
size_t property_pos = property_start + 1;
|
|
206
|
+
if (property_pos < blockstate.size() && blockstate[property_pos] == ']') {
|
|
207
|
+
// []
|
|
208
|
+
property_pos++;
|
|
209
|
+
if (property_pos < blockstate.size()) {
|
|
210
|
+
throw std::invalid_argument("Extra data after ]");
|
|
211
|
+
}
|
|
212
|
+
return std::make_shared<Block>(platform, version, namespace_, base_name, properties);
|
|
213
|
+
}
|
|
214
|
+
for (;;) {
|
|
215
|
+
std::string key = capture_key(blockstate, property_pos);
|
|
216
|
+
|
|
217
|
+
if (property_pos >= blockstate.size() || blockstate[property_pos] != '=') {
|
|
218
|
+
throw std::invalid_argument("Expected = at position " + std::to_string(property_pos));
|
|
219
|
+
}
|
|
220
|
+
property_pos++;
|
|
221
|
+
|
|
222
|
+
properties[key] = capture_value(blockstate, property_pos);
|
|
223
|
+
|
|
224
|
+
if (property_pos >= blockstate.size()) {
|
|
225
|
+
throw std::invalid_argument("Expected , or ] at position " + std::to_string(property_pos));
|
|
226
|
+
}
|
|
227
|
+
switch (blockstate[property_pos]) {
|
|
228
|
+
case ',':
|
|
229
|
+
break;
|
|
230
|
+
case ']':
|
|
231
|
+
property_pos++;
|
|
232
|
+
if (property_pos < blockstate.size()) {
|
|
233
|
+
throw std::invalid_argument("Extra data after ]");
|
|
234
|
+
}
|
|
235
|
+
return std::make_shared<Block>(platform, version, namespace_, base_name, properties);
|
|
236
|
+
default:
|
|
237
|
+
throw std::invalid_argument("Expected , or ] at position " + std::to_string(property_pos));
|
|
238
|
+
}
|
|
239
|
+
property_pos++;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
// does not have properties
|
|
244
|
+
return std::make_shared<Block>(platform, version, namespace_, base_name);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
auto is_alnum = [](const char& chr) {
|
|
249
|
+
return (
|
|
250
|
+
('0' <= chr && chr <= '9') ||
|
|
251
|
+
('a' <= (chr | 32) && (chr | 32) <= 'z')
|
|
252
|
+
);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
inline void validate_java_namespace(const size_t& offset, const std::string& namespace_) {
|
|
256
|
+
for (size_t i = 0; i < namespace_.size(); i++) {
|
|
257
|
+
const auto& chr = namespace_[i];
|
|
258
|
+
if (!(is_alnum(chr) || chr == '_' || chr == '-' || chr == '.')){
|
|
259
|
+
throw std::invalid_argument("Invalid namespace character at position " + std::to_string(offset + i));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
inline void validate_java_base_name(const size_t& offset, const std::string& base_name) {
|
|
264
|
+
for (size_t i = 0; i < base_name.size(); i++) {
|
|
265
|
+
const auto& chr = base_name[i];
|
|
266
|
+
if (!(is_alnum(chr) || chr == '_' || chr == '-' || chr == '.' || chr == '/')) {
|
|
267
|
+
throw std::invalid_argument("Invalid base name character at position " + std::to_string(offset + i));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// key=str
|
|
272
|
+
inline std::string capture_java_blockstate_property_key(const std::string& blockstate, size_t& offset) {
|
|
273
|
+
size_t key_start = offset;
|
|
274
|
+
while (offset < blockstate.size()) {
|
|
275
|
+
const auto& chr = blockstate[offset];
|
|
276
|
+
if (!(is_alnum(chr) || chr == '_')) {
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
offset++;
|
|
280
|
+
}
|
|
281
|
+
if (key_start == offset) {
|
|
282
|
+
throw std::invalid_argument("Expected a key or ] at position " + std::to_string(offset));
|
|
283
|
+
}
|
|
284
|
+
return std::string(blockstate.begin() + key_start, blockstate.begin() + offset);
|
|
285
|
+
}
|
|
286
|
+
inline PropertyValueType capture_java_blockstate_property_value(const std::string& blockstate, size_t& offset) {
|
|
287
|
+
size_t value_start = offset;
|
|
288
|
+
while (offset < blockstate.size()) {
|
|
289
|
+
const auto& chr = blockstate[offset];
|
|
290
|
+
if (!(is_alnum(chr) || chr == '_')) {
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
offset++;
|
|
294
|
+
}
|
|
295
|
+
if (value_start == offset) {
|
|
296
|
+
throw std::invalid_argument("Expected a value at position " + std::to_string(offset));
|
|
297
|
+
}
|
|
298
|
+
return AmuletNBT::StringTag(blockstate.begin() + value_start, blockstate.begin() + offset);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// I think Bedrock resource identifiers are not limited to a-z0-9_-.
|
|
302
|
+
inline void validate_bedrock_namespace(const size_t& offset, const std::string& namespace_) {
|
|
303
|
+
for (size_t i = 0; i < namespace_.size(); i++) {
|
|
304
|
+
const auto& chr = namespace_[i];
|
|
305
|
+
if (!(is_alnum(chr) || chr == '_' || chr == '-' || chr == '.')) {
|
|
306
|
+
throw std::invalid_argument("Invalid namespace character at position " + std::to_string(offset + i));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
inline void validate_bedrock_base_name(const size_t& offset, const std::string& base_name) {
|
|
311
|
+
for (size_t i = 0; i < base_name.size(); i++) {
|
|
312
|
+
const auto& chr = base_name[i];
|
|
313
|
+
if (!(is_alnum(chr) || chr == '_' || chr == '-' || chr == '.')) {
|
|
314
|
+
throw std::invalid_argument("Invalid base name character at position " + std::to_string(offset + i));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// "key"=false
|
|
319
|
+
// "key"=true
|
|
320
|
+
// "key"=nbt
|
|
321
|
+
inline std::string capture_bedrock_blockstate_property_key(const std::string& blockstate, size_t& offset) {
|
|
322
|
+
// Opening "
|
|
323
|
+
if (offset >= blockstate.size() || blockstate[offset] != '"') {
|
|
324
|
+
throw std::invalid_argument("Expected \" at position " + std::to_string(offset));
|
|
325
|
+
}
|
|
326
|
+
offset++;
|
|
327
|
+
|
|
328
|
+
// Key
|
|
329
|
+
size_t key_start = offset;
|
|
330
|
+
while (offset < blockstate.size()) {
|
|
331
|
+
const auto& chr = blockstate[offset];
|
|
332
|
+
if (!(is_alnum(chr) || chr == '_')) {
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
offset++;
|
|
336
|
+
}
|
|
337
|
+
if (key_start == offset) {
|
|
338
|
+
throw std::invalid_argument("Expected a key or ] at position " + std::to_string(offset));
|
|
339
|
+
}
|
|
340
|
+
size_t key_end = offset;
|
|
341
|
+
|
|
342
|
+
// Closing "
|
|
343
|
+
if (offset >= blockstate.size() || blockstate[offset] != '"') {
|
|
344
|
+
throw std::invalid_argument("Expected \" at position " + std::to_string(offset));
|
|
345
|
+
}
|
|
346
|
+
offset++;
|
|
347
|
+
|
|
348
|
+
return std::string(blockstate.begin() + key_start, blockstate.begin() + key_end);
|
|
349
|
+
}
|
|
350
|
+
inline PropertyValueType capture_bedrock_blockstate_property_value(const std::string& blockstate, size_t& offset) {
|
|
351
|
+
size_t value_start = offset;
|
|
352
|
+
size_t value_end = std::min(
|
|
353
|
+
blockstate.find(",", value_start),
|
|
354
|
+
blockstate.find("]", value_start)
|
|
355
|
+
);
|
|
356
|
+
if (value_end >= blockstate.size()) {
|
|
357
|
+
throw std::invalid_argument("Expected , or ] after position " + std::to_string(offset));
|
|
358
|
+
}
|
|
359
|
+
offset = value_end;
|
|
360
|
+
AmuletNBT::TagNode node;
|
|
361
|
+
try {
|
|
362
|
+
node = AmuletNBT::read_snbt(std::string(blockstate.begin() + value_start, blockstate.begin() + value_end));
|
|
363
|
+
}
|
|
364
|
+
catch (const std::exception& e) {
|
|
365
|
+
throw std::invalid_argument("Failed parsing SNBT at position " + std::to_string(value_start) + ". " + e.what());
|
|
366
|
+
}
|
|
367
|
+
return std::visit(
|
|
368
|
+
[](auto&& tag) -> PropertyValueType {
|
|
369
|
+
using T = std::decay_t<decltype(tag)>;
|
|
370
|
+
if constexpr (
|
|
371
|
+
std::is_same_v<T, AmuletNBT::ByteTag> ||
|
|
372
|
+
std::is_same_v<T, AmuletNBT::ShortTag> ||
|
|
373
|
+
std::is_same_v<T, AmuletNBT::IntTag> ||
|
|
374
|
+
std::is_same_v<T, AmuletNBT::LongTag> ||
|
|
375
|
+
std::is_same_v<T, AmuletNBT::StringTag>
|
|
376
|
+
) {
|
|
377
|
+
return tag;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
throw std::invalid_argument("Values must be byte, short, int, long or string tags.");
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
node
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
std::shared_ptr<Block> Block::from_java_blockstate(const PlatformType& platform, std::shared_ptr<VersionNumber> version, const std::string& blockstate) {
|
|
388
|
+
return parse_blockstate<
|
|
389
|
+
validate_java_namespace,
|
|
390
|
+
validate_java_base_name,
|
|
391
|
+
capture_java_blockstate_property_key,
|
|
392
|
+
capture_java_blockstate_property_value
|
|
393
|
+
>(
|
|
394
|
+
platform,
|
|
395
|
+
version,
|
|
396
|
+
blockstate
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
std::shared_ptr<Block> Block::from_bedrock_blockstate(const PlatformType& platform, std::shared_ptr<VersionNumber> version, const std::string& blockstate) {
|
|
400
|
+
return parse_blockstate<
|
|
401
|
+
validate_bedrock_namespace,
|
|
402
|
+
validate_bedrock_base_name,
|
|
403
|
+
capture_bedrock_blockstate_property_key,
|
|
404
|
+
capture_bedrock_blockstate_property_value
|
|
405
|
+
>(
|
|
406
|
+
platform,
|
|
407
|
+
version,
|
|
408
|
+
blockstate
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
void BlockStack::serialise(BinaryWriter& writer) const {
|
|
413
|
+
writer.writeNumeric<std::uint8_t>(1);
|
|
414
|
+
writer.writeNumeric<std::uint64_t>(get_blocks().size());
|
|
415
|
+
for (const auto& block : get_blocks()) {
|
|
416
|
+
block->serialise(writer);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
std::shared_ptr<BlockStack> BlockStack::deserialise(BinaryReader& reader) {
|
|
420
|
+
auto version_number = reader.readNumeric<std::uint8_t>();
|
|
421
|
+
switch (version_number) {
|
|
422
|
+
case 1:
|
|
423
|
+
{
|
|
424
|
+
std::vector<std::shared_ptr<Block>> blocks;
|
|
425
|
+
auto count = reader.readNumeric<std::uint64_t>();
|
|
426
|
+
for (auto i = 0; i < count; i++) {
|
|
427
|
+
blocks.push_back(Block::deserialise(reader));
|
|
428
|
+
}
|
|
429
|
+
return std::make_shared<BlockStack>(blocks);
|
|
430
|
+
}
|
|
431
|
+
default:
|
|
432
|
+
throw std::invalid_argument("Unsupported BlockStack version " + std::to_string(version_number));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|