amulet-core 2.0a3__cp311-cp311-win_amd64.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.

Files changed (210) hide show
  1. amulet/__init__.cp311-win_amd64.pyd +0 -0
  2. amulet/__init__.pyi +30 -0
  3. amulet/__pyinstaller/__init__.py +2 -0
  4. amulet/__pyinstaller/hook-amulet.py +4 -0
  5. amulet/_init.py +28 -0
  6. amulet/_version.py +21 -0
  7. amulet/biome.cpp +36 -0
  8. amulet/biome.hpp +43 -0
  9. amulet/biome.pyi +77 -0
  10. amulet/block.cpp +435 -0
  11. amulet/block.hpp +119 -0
  12. amulet/block.pyi +273 -0
  13. amulet/block_entity.cpp +12 -0
  14. amulet/block_entity.hpp +56 -0
  15. amulet/block_entity.pyi +80 -0
  16. amulet/chunk.cpp +16 -0
  17. amulet/chunk.hpp +99 -0
  18. amulet/chunk.pyi +30 -0
  19. amulet/chunk_/components/biome.py +155 -0
  20. amulet/chunk_/components/block_entity.py +117 -0
  21. amulet/chunk_/components/entity.py +64 -0
  22. amulet/chunk_/components/height_2d.py +16 -0
  23. amulet/chunk_components.pyi +95 -0
  24. amulet/collections.pyi +37 -0
  25. amulet/data_types.py +29 -0
  26. amulet/entity.py +180 -0
  27. amulet/errors.py +63 -0
  28. amulet/game/__init__.py +7 -0
  29. amulet/game/_game.py +152 -0
  30. amulet/game/_universal/__init__.py +1 -0
  31. amulet/game/_universal/_biome.py +17 -0
  32. amulet/game/_universal/_block.py +47 -0
  33. amulet/game/_universal/_version.py +68 -0
  34. amulet/game/abc/__init__.py +22 -0
  35. amulet/game/abc/_block_specification.py +150 -0
  36. amulet/game/abc/biome.py +213 -0
  37. amulet/game/abc/block.py +331 -0
  38. amulet/game/abc/game_version_container.py +25 -0
  39. amulet/game/abc/json_interface.py +27 -0
  40. amulet/game/abc/version.py +44 -0
  41. amulet/game/bedrock/__init__.py +1 -0
  42. amulet/game/bedrock/_biome.py +35 -0
  43. amulet/game/bedrock/_block.py +42 -0
  44. amulet/game/bedrock/_version.py +165 -0
  45. amulet/game/java/__init__.py +2 -0
  46. amulet/game/java/_biome.py +35 -0
  47. amulet/game/java/_block.py +60 -0
  48. amulet/game/java/_version.py +176 -0
  49. amulet/game/translate/__init__.py +12 -0
  50. amulet/game/translate/_functions/__init__.py +15 -0
  51. amulet/game/translate/_functions/_code_functions/__init__.py +0 -0
  52. amulet/game/translate/_functions/_code_functions/_text.py +553 -0
  53. amulet/game/translate/_functions/_code_functions/banner_pattern.py +67 -0
  54. amulet/game/translate/_functions/_code_functions/bedrock_chest_connection.py +152 -0
  55. amulet/game/translate/_functions/_code_functions/bedrock_moving_block_pos.py +88 -0
  56. amulet/game/translate/_functions/_code_functions/bedrock_sign.py +152 -0
  57. amulet/game/translate/_functions/_code_functions/bedrock_skull_rotation.py +16 -0
  58. amulet/game/translate/_functions/_code_functions/custom_name.py +146 -0
  59. amulet/game/translate/_functions/_frozen.py +66 -0
  60. amulet/game/translate/_functions/_state.py +54 -0
  61. amulet/game/translate/_functions/_typing.py +98 -0
  62. amulet/game/translate/_functions/abc.py +116 -0
  63. amulet/game/translate/_functions/carry_nbt.py +160 -0
  64. amulet/game/translate/_functions/carry_properties.py +80 -0
  65. amulet/game/translate/_functions/code.py +143 -0
  66. amulet/game/translate/_functions/map_block_name.py +66 -0
  67. amulet/game/translate/_functions/map_nbt.py +111 -0
  68. amulet/game/translate/_functions/map_properties.py +93 -0
  69. amulet/game/translate/_functions/multiblock.py +112 -0
  70. amulet/game/translate/_functions/new_block.py +42 -0
  71. amulet/game/translate/_functions/new_entity.py +43 -0
  72. amulet/game/translate/_functions/new_nbt.py +206 -0
  73. amulet/game/translate/_functions/new_properties.py +64 -0
  74. amulet/game/translate/_functions/sequence.py +51 -0
  75. amulet/game/translate/_functions/walk_input_nbt.py +331 -0
  76. amulet/game/translate/_translator.py +433 -0
  77. amulet/item.py +75 -0
  78. amulet/level/__init__.pyi +27 -0
  79. amulet/level/_load.py +100 -0
  80. amulet/level/abc/__init__.py +12 -0
  81. amulet/level/abc/_chunk_handle.py +335 -0
  82. amulet/level/abc/_dimension.py +86 -0
  83. amulet/level/abc/_history/__init__.py +1 -0
  84. amulet/level/abc/_history/_cache.py +224 -0
  85. amulet/level/abc/_history/_history_manager.py +291 -0
  86. amulet/level/abc/_level/__init__.py +5 -0
  87. amulet/level/abc/_level/_compactable_level.py +10 -0
  88. amulet/level/abc/_level/_creatable_level.py +29 -0
  89. amulet/level/abc/_level/_disk_level.py +17 -0
  90. amulet/level/abc/_level/_level.py +453 -0
  91. amulet/level/abc/_level/_loadable_level.py +42 -0
  92. amulet/level/abc/_player_storage.py +7 -0
  93. amulet/level/abc/_raw_level.py +187 -0
  94. amulet/level/abc/_registry.py +40 -0
  95. amulet/level/bedrock/__init__.py +2 -0
  96. amulet/level/bedrock/_chunk_handle.py +19 -0
  97. amulet/level/bedrock/_dimension.py +22 -0
  98. amulet/level/bedrock/_level.py +187 -0
  99. amulet/level/bedrock/_raw/__init__.py +5 -0
  100. amulet/level/bedrock/_raw/_actor_counter.py +53 -0
  101. amulet/level/bedrock/_raw/_chunk.py +54 -0
  102. amulet/level/bedrock/_raw/_chunk_decode.py +668 -0
  103. amulet/level/bedrock/_raw/_chunk_encode.py +602 -0
  104. amulet/level/bedrock/_raw/_constant.py +9 -0
  105. amulet/level/bedrock/_raw/_dimension.py +343 -0
  106. amulet/level/bedrock/_raw/_level.py +463 -0
  107. amulet/level/bedrock/_raw/_level_dat.py +90 -0
  108. amulet/level/bedrock/_raw/_typing.py +6 -0
  109. amulet/level/bedrock/_raw/leveldb_chunk_versions.py +83 -0
  110. amulet/level/bedrock/chunk/__init__.py +1 -0
  111. amulet/level/bedrock/chunk/_chunk.py +126 -0
  112. amulet/level/bedrock/chunk/components/__init__.py +0 -0
  113. amulet/level/bedrock/chunk/components/chunk_version.py +12 -0
  114. amulet/level/bedrock/chunk/components/finalised_state.py +13 -0
  115. amulet/level/bedrock/chunk/components/raw_chunk.py +15 -0
  116. amulet/level/construction/__init__.py +0 -0
  117. amulet/level/java/__init__.pyi +21 -0
  118. amulet/level/java/_chunk_handle.py +17 -0
  119. amulet/level/java/_chunk_handle.pyi +15 -0
  120. amulet/level/java/_dimension.py +20 -0
  121. amulet/level/java/_dimension.pyi +13 -0
  122. amulet/level/java/_level.py +184 -0
  123. amulet/level/java/_level.pyi +120 -0
  124. amulet/level/java/_raw/__init__.pyi +19 -0
  125. amulet/level/java/_raw/_chunk.pyi +23 -0
  126. amulet/level/java/_raw/_chunk_decode.py +561 -0
  127. amulet/level/java/_raw/_chunk_encode.py +463 -0
  128. amulet/level/java/_raw/_constant.py +9 -0
  129. amulet/level/java/_raw/_constant.pyi +20 -0
  130. amulet/level/java/_raw/_data_pack/__init__.py +2 -0
  131. amulet/level/java/_raw/_data_pack/__init__.pyi +8 -0
  132. amulet/level/java/_raw/_data_pack/data_pack.py +241 -0
  133. amulet/level/java/_raw/_data_pack/data_pack.pyi +197 -0
  134. amulet/level/java/_raw/_data_pack/data_pack_manager.py +77 -0
  135. amulet/level/java/_raw/_data_pack/data_pack_manager.pyi +75 -0
  136. amulet/level/java/_raw/_dimension.py +86 -0
  137. amulet/level/java/_raw/_dimension.pyi +72 -0
  138. amulet/level/java/_raw/_level.py +507 -0
  139. amulet/level/java/_raw/_level.pyi +238 -0
  140. amulet/level/java/_raw/_typing.py +3 -0
  141. amulet/level/java/_raw/_typing.pyi +5 -0
  142. amulet/level/java/anvil/__init__.py +2 -0
  143. amulet/level/java/anvil/__init__.pyi +11 -0
  144. amulet/level/java/anvil/_dimension.py +170 -0
  145. amulet/level/java/anvil/_dimension.pyi +109 -0
  146. amulet/level/java/anvil/_region.py +421 -0
  147. amulet/level/java/anvil/_region.pyi +197 -0
  148. amulet/level/java/anvil/_sector_manager.py +223 -0
  149. amulet/level/java/anvil/_sector_manager.pyi +142 -0
  150. amulet/level/java/chunk.pyi +81 -0
  151. amulet/level/java/chunk_/_chunk.py +260 -0
  152. amulet/level/java/chunk_/components/inhabited_time.py +12 -0
  153. amulet/level/java/chunk_/components/last_update.py +12 -0
  154. amulet/level/java/chunk_/components/legacy_version.py +12 -0
  155. amulet/level/java/chunk_/components/light_populated.py +12 -0
  156. amulet/level/java/chunk_/components/named_height_2d.py +37 -0
  157. amulet/level/java/chunk_/components/status.py +11 -0
  158. amulet/level/java/chunk_/components/terrain_populated.py +12 -0
  159. amulet/level/java/chunk_components.pyi +22 -0
  160. amulet/level/java/long_array.pyi +38 -0
  161. amulet/level/java_forge/__init__.py +0 -0
  162. amulet/level/mcstructure/__init__.py +0 -0
  163. amulet/level/nbt/__init__.py +0 -0
  164. amulet/level/schematic/__init__.py +0 -0
  165. amulet/level/sponge_schematic/__init__.py +0 -0
  166. amulet/level/temporary_level/__init__.py +1 -0
  167. amulet/level/temporary_level/_level.py +16 -0
  168. amulet/palette/__init__.pyi +8 -0
  169. amulet/palette/biome_palette.pyi +45 -0
  170. amulet/palette/block_palette.pyi +45 -0
  171. amulet/player.py +64 -0
  172. amulet/py.typed +0 -0
  173. amulet/selection/__init__.py +2 -0
  174. amulet/selection/abstract_selection.py +342 -0
  175. amulet/selection/box.py +852 -0
  176. amulet/selection/group.py +481 -0
  177. amulet/utils/__init__.pyi +28 -0
  178. amulet/utils/call_spec/__init__.py +24 -0
  179. amulet/utils/call_spec/__init__.pyi +53 -0
  180. amulet/utils/call_spec/_call_spec.py +262 -0
  181. amulet/utils/call_spec/_call_spec.pyi +272 -0
  182. amulet/utils/format_utils.py +41 -0
  183. amulet/utils/generator.py +18 -0
  184. amulet/utils/matrix.py +243 -0
  185. amulet/utils/matrix.pyi +177 -0
  186. amulet/utils/numpy.pyi +11 -0
  187. amulet/utils/numpy_helpers.py +19 -0
  188. amulet/utils/shareable_lock.py +335 -0
  189. amulet/utils/shareable_lock.pyi +190 -0
  190. amulet/utils/signal/__init__.py +10 -0
  191. amulet/utils/signal/__init__.pyi +25 -0
  192. amulet/utils/signal/_signal.py +228 -0
  193. amulet/utils/signal/_signal.pyi +84 -0
  194. amulet/utils/task_manager.py +235 -0
  195. amulet/utils/task_manager.pyi +168 -0
  196. amulet/utils/typed_property.py +111 -0
  197. amulet/utils/typing.py +4 -0
  198. amulet/utils/typing.pyi +6 -0
  199. amulet/utils/weakref.py +70 -0
  200. amulet/utils/weakref.pyi +50 -0
  201. amulet/utils/world_utils.py +102 -0
  202. amulet/utils/world_utils.pyi +109 -0
  203. amulet/version.cpp +136 -0
  204. amulet/version.hpp +142 -0
  205. amulet/version.pyi +94 -0
  206. amulet_core-2.0a3.dist-info/METADATA +103 -0
  207. amulet_core-2.0a3.dist-info/RECORD +210 -0
  208. amulet_core-2.0a3.dist-info/WHEEL +5 -0
  209. amulet_core-2.0a3.dist-info/entry_points.txt +2 -0
  210. amulet_core-2.0a3.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
@@ -0,0 +1,2 @@
1
+ def get_hook_dirs() -> list[str]:
2
+ return __path__
@@ -0,0 +1,4 @@
1
+ from PyInstaller.utils.hooks import collect_data_files, collect_submodules
2
+
3
+ hiddenimports = collect_submodules("amulet")
4
+ datas = collect_data_files("amulet")
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-17T11:48:57+0100",
12
+ "dirty": false,
13
+ "error": null,
14
+ "full-revisionid": "c74042d82cf944a7ef539dba6a51abb17b5c5d2a",
15
+ "version": "2.0a3"
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
+ }