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.

Files changed (210) hide show
  1. amulet/__init__.cpython-312-darwin.so +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.0a5.dist-info/METADATA +103 -0
  207. amulet_core-2.0a5.dist-info/RECORD +210 -0
  208. amulet_core-2.0a5.dist-info/WHEEL +5 -0
  209. amulet_core-2.0a5.dist-info/entry_points.txt +2 -0
  210. amulet_core-2.0a5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,433 @@
1
+ from __future__ import annotations
2
+ from typing import Callable, Union, Sequence, TypeVar, Type, Any, TYPE_CHECKING
3
+ import json
4
+ import glob
5
+ import os
6
+ from concurrent.futures import ThreadPoolExecutor
7
+
8
+ from amulet_nbt import (
9
+ read_nbt,
10
+ read_snbt,
11
+ NamedTag,
12
+ ListTag,
13
+ CompoundTag,
14
+ AnyNBT,
15
+ )
16
+
17
+ from amulet.block import Block
18
+ from amulet.block_entity import BlockEntity
19
+ from amulet.entity import Entity
20
+ from amulet.data_types import BlockCoordinates
21
+ from amulet.version import VersionNumber
22
+
23
+ from ._functions import (
24
+ AbstractBaseTranslationFunction,
25
+ SrcData,
26
+ SrcDataExtra,
27
+ StateData,
28
+ DstData,
29
+ )
30
+ from ._functions.abc import translation_function_from_json
31
+ from ._functions._typing import NBTPath
32
+
33
+ if TYPE_CHECKING:
34
+ from amulet.game.abc import GameVersion, BlockSpec
35
+
36
+
37
+ # These classes exist to do some pre-translation and post-translation processing.
38
+ # They also store the constant data so that it doesn't need to be passed in each time.
39
+ # They don't do any caching
40
+
41
+
42
+ def create_nbt(
43
+ outer_name: str,
44
+ outer_type: type[ListTag] | type[CompoundTag],
45
+ nbt_list: Sequence[
46
+ tuple[
47
+ str,
48
+ type[ListTag] | type[CompoundTag],
49
+ NBTPath,
50
+ Union[str, int],
51
+ AnyNBT,
52
+ ]
53
+ ],
54
+ default_template: str | None = None,
55
+ ) -> NamedTag:
56
+ nbt_object: AnyNBT
57
+ if default_template is None:
58
+ nbt_object = outer_type()
59
+ else:
60
+ nbt_object = read_snbt(default_template)
61
+
62
+ for nbt_entry in nbt_list:
63
+ (
64
+ element_outer_name,
65
+ element_outer_type,
66
+ element_nbt_path,
67
+ element_data_path,
68
+ element_data,
69
+ ) = nbt_entry
70
+ if outer_name == element_outer_name and issubclass(
71
+ outer_type, element_outer_type
72
+ ):
73
+ nbt_temp: AnyNBT = nbt_object
74
+ for path, nbt_type in element_nbt_path:
75
+ # if the nested NBT object does not exist then create it
76
+ if isinstance(nbt_temp, CompoundTag):
77
+ assert isinstance(path, str)
78
+ if path not in nbt_temp or not isinstance(nbt_temp[path], nbt_type):
79
+ nbt_temp[path] = nbt_type()
80
+ nbt_temp = nbt_temp[path]
81
+ elif isinstance(nbt_temp, ListTag):
82
+ assert isinstance(path, int)
83
+ # if the list is a different type to nbt_type replace it with nbt_type
84
+ if len(nbt_temp) > 0 and not isinstance(nbt_temp[0], nbt_type):
85
+ raise RuntimeError("ListTag elements are the wrong type")
86
+
87
+ for _ in range(path + 1 - len(nbt_temp)):
88
+ # pad out the list to the length of the index
89
+ nbt_temp.append(nbt_type())
90
+ # we now should have a ListTag of the same type as nbt_type and length as path
91
+ nbt_temp = nbt_temp[path]
92
+ else:
93
+ raise RuntimeError
94
+
95
+ if isinstance(nbt_temp, CompoundTag):
96
+ assert isinstance(element_data_path, str)
97
+ nbt_temp[element_data_path] = element_data
98
+
99
+ elif isinstance(nbt_temp, ListTag):
100
+ assert isinstance(element_data_path, int)
101
+ # if the list is a different type to data replace it with type(data)
102
+ if (
103
+ len(nbt_temp) > 0
104
+ and nbt_temp[0].list_data_type != element_data.tag_id
105
+ ):
106
+ raise RuntimeError("ListTag elements are the wrong type")
107
+
108
+ for _ in range(element_data_path + 1 - len(nbt_temp)):
109
+ # pad out the list to the length of the index
110
+ nbt_temp.append(element_data.__class__())
111
+ # we now should have a ListTag of the same type as nbt_type and length as data_path
112
+ nbt_temp[element_data_path] = element_data
113
+
114
+ # TODO:
115
+ # elif isinstance(nbt_temp, ByteArrayTag) and isinstance(data, ByteTag):
116
+ # # pad to the length of data_path if less than the current length
117
+ # # nbt_temp[data_path] = data.value
118
+ # elif isinstance(nbt_temp, IntArrayTag) and isinstance(data, IntTag):
119
+ # elif isinstance(nbt_temp, LongArrayTag) and isinstance(data, LongTag):
120
+
121
+ return NamedTag(nbt_object, outer_name)
122
+
123
+
124
+ class BlockToUniversalTranslator:
125
+ # Class variables
126
+ _instances: dict[BlockToUniversalTranslator, BlockToUniversalTranslator] = {}
127
+
128
+ # Instance variables
129
+ _src_spec: BlockSpec
130
+ _translation: AbstractBaseTranslationFunction
131
+ _universal_version: GameVersion
132
+ _hash: int | None
133
+
134
+ def __new__(
135
+ cls,
136
+ src_spec: BlockSpec,
137
+ translation: AbstractBaseTranslationFunction,
138
+ universal_version: GameVersion,
139
+ ) -> BlockToUniversalTranslator:
140
+ self = super().__new__(cls)
141
+ self._src_spec = src_spec
142
+ self._translation = translation
143
+ self._universal_version = universal_version
144
+ self._hash = None
145
+ return cls._instances.setdefault(self, self)
146
+
147
+ def __reduce__(self) -> Any:
148
+ return BlockToUniversalTranslator, (
149
+ self._src_spec,
150
+ self._translation,
151
+ self._universal_version,
152
+ )
153
+
154
+ def __hash__(self) -> int:
155
+ if self._hash is None:
156
+ self._hash = hash(
157
+ (self._src_spec, self._translation, self._universal_version)
158
+ )
159
+ return self._hash
160
+
161
+ def run(
162
+ self,
163
+ block: Block,
164
+ block_entity: BlockEntity | None,
165
+ extra: (
166
+ tuple[
167
+ BlockCoordinates,
168
+ Callable[[BlockCoordinates], tuple[Block, BlockEntity | None]],
169
+ ]
170
+ | None
171
+ ),
172
+ ) -> tuple[Block, BlockEntity | None, bool, bool]:
173
+ if extra is None:
174
+ src_extra = None
175
+ else:
176
+ coords, get_block = extra
177
+ src_extra = SrcDataExtra(coords, get_block)
178
+
179
+ block_entity_nbt = None if block_entity is None else block_entity.nbt
180
+
181
+ if self._src_spec.nbt is not None and block_entity_nbt is None:
182
+ # There should be a block entity
183
+ if src_extra is not None:
184
+ # Load it from the level
185
+ block_entity = src_extra.get_block_callback((0, 0, 0))[1]
186
+ if block_entity is not None:
187
+ block_entity_nbt = block_entity.nbt
188
+ if block_entity_nbt is None:
189
+ # If it is still None then load it from the specification
190
+ block_entity_nbt = read_nbt(self._src_spec.nbt.snbt)
191
+
192
+ src = SrcData(block, block_entity_nbt, src_extra)
193
+ state = StateData()
194
+ dst = DstData()
195
+ self._translation.run(src, state, dst)
196
+
197
+ assert dst.cls is Block
198
+ assert dst.resource_id is not None
199
+ namespace, base_name = dst.resource_id
200
+
201
+ dst_spec = self._universal_version.block.get_specification(namespace, base_name)
202
+ properties = {k: v.default for k, v in dst_spec.properties.items()}
203
+ properties.update(dst.properties)
204
+
205
+ dst_block = Block(
206
+ "universal", VersionNumber(1), namespace, base_name, properties
207
+ )
208
+
209
+ if dst_spec.nbt is None:
210
+ dst_block_entity = None
211
+ else:
212
+ dst_block_entity = BlockEntity(
213
+ "universal",
214
+ VersionNumber(1),
215
+ dst_spec.nbt.namespace,
216
+ dst_spec.nbt.base_name,
217
+ create_nbt(
218
+ "",
219
+ CompoundTag,
220
+ dst.nbt,
221
+ dst_spec.nbt.snbt,
222
+ ),
223
+ )
224
+
225
+ return dst_block, dst_block_entity, dst.extra_needed, dst.cacheable
226
+
227
+
228
+ class BlockFromUniversalTranslator:
229
+ # Class variables
230
+ _instances: dict[BlockFromUniversalTranslator, BlockFromUniversalTranslator] = {}
231
+
232
+ # Instance variables
233
+ _src_spec: BlockSpec
234
+ _translation: AbstractBaseTranslationFunction
235
+ _target_version: GameVersion
236
+ _hash: int | None
237
+
238
+ def __new__(
239
+ cls,
240
+ src_spec: BlockSpec,
241
+ translation: AbstractBaseTranslationFunction,
242
+ target_version: GameVersion,
243
+ ) -> BlockFromUniversalTranslator:
244
+ self = super().__new__(cls)
245
+ self._src_spec = src_spec
246
+ self._translation = translation
247
+ self._target_version = target_version
248
+ self._hash = None
249
+ return cls._instances.setdefault(self, self)
250
+
251
+ def __reduce__(self) -> Any:
252
+ return BlockFromUniversalTranslator, (
253
+ self._src_spec,
254
+ self._translation,
255
+ self._target_version,
256
+ )
257
+
258
+ def __hash__(self) -> int:
259
+ if self._hash is None:
260
+ self._hash = hash((self._src_spec, self._translation, self._target_version))
261
+ return self._hash
262
+
263
+ def run(
264
+ self,
265
+ target_platform: str,
266
+ target_version: VersionNumber,
267
+ block: Block,
268
+ block_entity: BlockEntity | None,
269
+ extra: (
270
+ tuple[
271
+ BlockCoordinates,
272
+ Callable[[BlockCoordinates], tuple[Block, BlockEntity | None]],
273
+ ]
274
+ | None
275
+ ),
276
+ ) -> tuple[Block, BlockEntity | None, bool, bool] | tuple[Entity, None, bool, bool]:
277
+ if extra is None:
278
+ src_extra = None
279
+ else:
280
+ coords, get_block = extra
281
+ src_extra = SrcDataExtra(coords, get_block)
282
+
283
+ block_entity_nbt = None if block_entity is None else block_entity.nbt
284
+
285
+ if self._src_spec.nbt is not None and block_entity_nbt is None:
286
+ # There should be a block entity
287
+ if src_extra is not None:
288
+ # Load it from the level
289
+ block_entity = src_extra.get_block_callback((0, 0, 0))[1]
290
+ if block_entity is not None:
291
+ block_entity_nbt = block_entity.nbt
292
+ if block_entity_nbt is None:
293
+ # If it is still None then load it from the specification
294
+ block_entity_nbt = read_nbt(self._src_spec.nbt.snbt)
295
+
296
+ src = SrcData(block, block_entity_nbt, src_extra)
297
+ state = StateData()
298
+ dst = DstData()
299
+ self._translation.run(src, state, dst)
300
+
301
+ if dst.cls is Block:
302
+ assert dst.resource_id is not None
303
+ namespace, base_name = dst.resource_id
304
+
305
+ dst_spec = self._target_version.block.get_specification(
306
+ namespace, base_name
307
+ )
308
+ properties = {k: v.default for k, v in dst_spec.properties.items()}
309
+ properties.update(dst.properties)
310
+
311
+ dst_block = Block(
312
+ target_platform, target_version, namespace, base_name, properties
313
+ )
314
+
315
+ if dst_spec.nbt is None:
316
+ dst_block_entity = None
317
+ else:
318
+ dst_block_entity = BlockEntity(
319
+ target_platform,
320
+ target_version,
321
+ dst_spec.nbt.namespace,
322
+ dst_spec.nbt.base_name,
323
+ create_nbt(
324
+ "",
325
+ CompoundTag,
326
+ dst.nbt,
327
+ dst_spec.nbt.snbt,
328
+ ),
329
+ )
330
+
331
+ return dst_block, dst_block_entity, dst.extra_needed, dst.cacheable
332
+
333
+ elif dst.cls is Entity:
334
+ assert dst.resource_id is not None
335
+ namespace, base_name = dst.resource_id
336
+
337
+ # dst_spec = self._target_version.block.get_specification(
338
+ # namespace, base_name
339
+ # )
340
+
341
+ dst_entity = Entity(
342
+ target_platform,
343
+ target_version,
344
+ namespace,
345
+ base_name,
346
+ 0.0,
347
+ 0.0,
348
+ 0.0,
349
+ create_nbt(
350
+ "",
351
+ CompoundTag,
352
+ dst.nbt,
353
+ # dst_spec.nbt.snbt,
354
+ ),
355
+ )
356
+
357
+ return dst_entity, None, dst.extra_needed, dst.cacheable
358
+
359
+ else:
360
+ raise RuntimeError
361
+
362
+
363
+ TranslationClsT = TypeVar(
364
+ "TranslationClsT", BlockToUniversalTranslator, BlockFromUniversalTranslator
365
+ )
366
+
367
+
368
+ def _read_file(path: str) -> str:
369
+ with open(path) as f:
370
+ return f.read()
371
+
372
+
373
+ def load_json_block_translations(
374
+ version_path: str,
375
+ block_format: str,
376
+ direction: str,
377
+ translation_cls: Type[TranslationClsT],
378
+ get_src_spec: Callable[[str, str], BlockSpec],
379
+ target_version: GameVersion,
380
+ ) -> dict[tuple[str, str], TranslationClsT]:
381
+ translations = dict[tuple[str, str], TranslationClsT]()
382
+ paths = glob.glob(
383
+ os.path.join(
384
+ glob.escape(version_path),
385
+ "block",
386
+ block_format,
387
+ direction,
388
+ "*",
389
+ "*",
390
+ "*.json",
391
+ )
392
+ )
393
+ with ThreadPoolExecutor() as e:
394
+ for file_path, data in zip(paths, e.map(_read_file, paths)):
395
+ *_, namespace, _, base_name = os.path.splitext(os.path.normpath(file_path))[
396
+ 0
397
+ ].split(os.sep)
398
+ translations[(namespace, base_name)] = translation_cls(
399
+ get_src_spec(namespace, base_name),
400
+ translation_function_from_json(json.loads(data)),
401
+ target_version,
402
+ )
403
+ return translations
404
+
405
+
406
+ class EntityToUniversalTranslator:
407
+ def run(
408
+ self,
409
+ entity: Entity,
410
+ extra: (
411
+ tuple[
412
+ BlockCoordinates,
413
+ Callable[[BlockCoordinates], tuple[Block, BlockEntity | None]],
414
+ ]
415
+ | None
416
+ ),
417
+ ) -> tuple[Block, BlockEntity | None, bool, bool]:
418
+ raise NotImplementedError
419
+
420
+
421
+ class EntityFromUniversalTranslator:
422
+ def run(
423
+ self,
424
+ entity: Entity | None,
425
+ extra: (
426
+ tuple[
427
+ BlockCoordinates,
428
+ Callable[[BlockCoordinates], tuple[Block, BlockEntity | None]],
429
+ ]
430
+ | None
431
+ ),
432
+ ) -> tuple[Block, BlockEntity | None, bool] | tuple[Entity, None, bool]:
433
+ raise NotImplementedError
amulet/item.py ADDED
@@ -0,0 +1,75 @@
1
+ # from amulet_nbt import CompoundTag, StringTag
2
+ #
3
+ #
4
+ # class Item(CompoundTag):
5
+ # """
6
+ # {
7
+ # "namespace": StringTag,
8
+ # "base_name": StringTag,
9
+ # "metadata": CompoundTag
10
+ # }
11
+ # """
12
+ #
13
+ # def __init__(self, namespace: str, base_name: str, metadata: dict = None) -> None:
14
+ # super().__init__(
15
+ # {
16
+ # "namespace": StringTag(namespace),
17
+ # "base_name": StringTag(base_name),
18
+ # "metadata": CompoundTag(metadata or {}),
19
+ # }
20
+ # )
21
+ #
22
+ # @property
23
+ # def namespace(self) -> str:
24
+ # return self.get_string("namespace").py_str
25
+ #
26
+ # @property
27
+ # def base_name(self) -> str:
28
+ # return self.get_string("base_name").py_str
29
+ #
30
+ # @property
31
+ # def metadata(self) -> CompoundTag:
32
+ # return self.get_compound("metadata")
33
+ #
34
+ #
35
+ # class BlockItem(CompoundTag):
36
+ # """
37
+ # {
38
+ # "namespace": StringTag,
39
+ # "base_name": StringTag,
40
+ # "properties": CompoundTag
41
+ # "metadata": CompoundTag
42
+ # }
43
+ # """
44
+ #
45
+ # def __init__(
46
+ # self,
47
+ # namespace: str,
48
+ # base_name: str,
49
+ # properties: dict = None,
50
+ # metadata: dict = None,
51
+ # ):
52
+ # super().__init__(
53
+ # {
54
+ # "namespace": StringTag(namespace),
55
+ # "base_name": StringTag(base_name),
56
+ # "properties": CompoundTag(properties or {}),
57
+ # "metadata": CompoundTag(metadata or {}),
58
+ # }
59
+ # )
60
+ #
61
+ # @property
62
+ # def namespace(self) -> str:
63
+ # return self.get_string("namespace").py_str
64
+ #
65
+ # @property
66
+ # def base_name(self) -> str:
67
+ # return self.get_string("base_name").py_str
68
+ #
69
+ # @property
70
+ # def properties(self) -> CompoundTag:
71
+ # return self.get_compound("properties")
72
+ #
73
+ # @property
74
+ # def metadata(self) -> CompoundTag:
75
+ # return self.get_compound("metadata")
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+
5
+ from amulet.level._load import (
6
+ NoValidLevel,
7
+ get_level,
8
+ register_level_class,
9
+ unregister_level_class,
10
+ )
11
+ from amulet.level.abc._level._level import Level
12
+ from amulet.level.java._level import JavaLevel
13
+
14
+ from . import java
15
+
16
+ __all__ = [
17
+ "JavaLevel",
18
+ "Level",
19
+ "NoValidLevel",
20
+ "get_level",
21
+ "java",
22
+ "register_level_class",
23
+ "unregister_level_class",
24
+ ]
25
+
26
+ def __dir__() -> typing.Any: ...
27
+ def __getattr__(arg0: typing.Any) -> typing.Any: ...
amulet/level/_load.py ADDED
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Type, Any
4
+ import logging
5
+ from inspect import isclass
6
+ from threading import Lock
7
+ from weakref import WeakValueDictionary
8
+
9
+ from amulet.level.abc import LoadableLevel
10
+
11
+
12
+ log = logging.getLogger(__name__)
13
+
14
+
15
+ _level_classes = set[Type[LoadableLevel]]()
16
+ _levels = WeakValueDictionary[Any, LoadableLevel]()
17
+ _lock = Lock()
18
+
19
+
20
+ def _check_loadable_level(cls: Any) -> None:
21
+ if not (isclass(cls) and issubclass(cls, LoadableLevel)):
22
+ raise TypeError(
23
+ "cls must be a subclass of amulet.level.abc.Level and amulet.level.abc.LoadableLevel"
24
+ )
25
+
26
+
27
+ def register_level_class(cls: Type[LoadableLevel]) -> None:
28
+ """Add a level class to be considered when getting a level.
29
+
30
+ :param cls: The Level subclass to register.
31
+ :return:
32
+ """
33
+ _check_loadable_level(cls)
34
+ with _lock:
35
+ _level_classes.add(cls)
36
+
37
+
38
+ def unregister_level_class(cls: Type[LoadableLevel]) -> None:
39
+ """Remove a level class from consideration when getting a level.
40
+
41
+ Note that any instances of the class will remain.
42
+
43
+ :param cls: The Level subclass to unregister.
44
+ """
45
+ _check_loadable_level(cls)
46
+ with _lock:
47
+ _level_classes.discard(cls)
48
+
49
+
50
+ class NoValidLevel(Exception):
51
+ """An error thrown if no level could load the token."""
52
+
53
+ pass
54
+
55
+
56
+ def get_level(token: Any) -> LoadableLevel:
57
+ """Get the level for the given token.
58
+
59
+ If a level object already exists for this token then that will be returned.
60
+ This will return a subclass of Level specialised for that level type.
61
+ Note that the returned level may or may not be open.
62
+ The level will automatically close itself when the last reference is lost so you must hold a strong reference to it.
63
+
64
+ :param token: The token to load. This may be a file/directory path or some other token.
65
+ :return: The level instance.
66
+ :raises:
67
+ NoValidLevel: If no level could load the token.
68
+
69
+ Exception: Other errors.
70
+ """
71
+ level: None | LoadableLevel
72
+ with _lock:
73
+ # Find the level to load the token
74
+ cls = next((cls for cls in _level_classes if cls.can_load(token)), None)
75
+
76
+ if cls is None:
77
+ # If no level could load the token then raise
78
+ raise NoValidLevel(f"Could not load {token}")
79
+
80
+ try:
81
+ # Try and get a cached instance of the level
82
+ level = _levels.get(token)
83
+ if level is not None:
84
+ # If there is a cached instance then return it
85
+ return level
86
+ except TypeError:
87
+ # If the token is not hashable
88
+ pass
89
+
90
+ # Load the level
91
+ level = cls.load(token)
92
+
93
+ try:
94
+ # Cache the level
95
+ _levels[token] = level
96
+ except TypeError:
97
+ # Token may not be hashable
98
+ pass
99
+
100
+ return level
@@ -0,0 +1,12 @@
1
+ from ._level import *
2
+ from ._chunk_handle import ChunkHandle
3
+ from ._player_storage import PlayerStorage
4
+ from ._raw_level import (
5
+ RawLevel,
6
+ RawLevelFriend,
7
+ RawLevelPlayerComponent,
8
+ RawLevelBufferedComponent,
9
+ RawDimension,
10
+ )
11
+ from ._dimension import Dimension
12
+ from ._registry import IdRegistry