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,561 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Callable
3
+
4
+ import numpy
5
+ from amulet_nbt import (
6
+ NamedTag,
7
+ ByteTag,
8
+ ShortTag,
9
+ IntTag,
10
+ LongTag,
11
+ FloatTag,
12
+ DoubleTag,
13
+ StringTag,
14
+ CompoundTag,
15
+ ListTag,
16
+ ByteArrayTag,
17
+ IntArrayTag,
18
+ LongArrayTag,
19
+ )
20
+
21
+ from amulet.game import get_game_version
22
+ from amulet.game.java import Waterloggable
23
+ from amulet.block import Block, BlockStack, PropertyValueType
24
+ from amulet.biome import Biome
25
+ from amulet.block_entity import BlockEntity
26
+ from amulet.entity import Entity
27
+ from amulet.version import VersionNumber, VersionRange
28
+ from amulet.palette import BlockPalette
29
+ from amulet.chunk import ComponentDataMapping
30
+ from amulet.chunk.components.height_2d import Height2DComponent
31
+ from amulet.chunk.components.sub_chunk_array import SubChunkArrayContainer
32
+ from amulet.chunk.components.biome import (
33
+ Biome2DComponent,
34
+ Biome2DComponentData,
35
+ Biome3DComponent,
36
+ Biome3DComponentData,
37
+ )
38
+ from amulet.chunk.components.block import BlockComponent, BlockComponentData
39
+ from amulet.chunk.components.block_entity import (
40
+ BlockEntityComponent,
41
+ BlockEntityComponentData,
42
+ )
43
+ from amulet.chunk.components.entity import EntityComponent, EntityComponentData
44
+
45
+ from amulet.utils.world_utils import decode_long_array, from_nibble_array
46
+ from amulet.utils.numpy import unique_inverse
47
+
48
+ from amulet.level.java.anvil import RawChunkType
49
+ from amulet.level.java.chunk import (
50
+ JavaChunk,
51
+ JavaChunkNA,
52
+ JavaChunk0,
53
+ JavaChunk1444,
54
+ JavaChunk1466,
55
+ JavaChunk2203,
56
+ )
57
+
58
+ from amulet.level.java.chunk.components.raw_chunk import RawChunkComponent
59
+ from amulet.level.java.chunk.components.data_version import DataVersionComponent
60
+ from amulet.level.java.chunk.components.legacy_version import LegacyVersionComponent
61
+ from amulet.level.java.chunk.components.status import StatusComponent
62
+ from amulet.level.java.chunk.components.light_populated import LightPopulatedComponent
63
+ from amulet.level.java.chunk.components.terrain_populated import (
64
+ TerrainPopulatedComponent,
65
+ )
66
+ from amulet.level.java.chunk.components.named_height_2d import (
67
+ NamedHeight2DComponent,
68
+ NamedHeight2DData,
69
+ )
70
+ from amulet.level.java.chunk.components.last_update import LastUpdateComponent
71
+ from amulet.level.java.chunk.components.inhabited_time import InhabitedTimeComponent
72
+
73
+ if TYPE_CHECKING:
74
+ from ._level import JavaRawLevel
75
+ from ._dimension import JavaRawDimension
76
+
77
+
78
+ def raw_to_native(
79
+ raw_level: JavaRawLevel,
80
+ dimension: JavaRawDimension,
81
+ raw_chunk: RawChunkType,
82
+ cx: int,
83
+ cz: int,
84
+ ) -> JavaChunk:
85
+ floor_y = dimension.bounds().min_y
86
+ ceil_y = dimension.bounds().max_y
87
+ height_y = ceil_y - floor_y
88
+
89
+ # Init the chunk components
90
+ chunk_components: ComponentDataMapping = {} # type: ignore
91
+ # Raw chunk data
92
+ chunk_components[RawChunkComponent] = raw_chunk
93
+
94
+ # Get the region object
95
+ region = raw_chunk.get("region", NamedTag()).compound
96
+ # Get the level object. This may not exist.
97
+ level = region.get_compound("Level", CompoundTag())
98
+
99
+ # Pull out the data version
100
+ chunk_components[DataVersionComponent] = data_version = region.pop_int(
101
+ "DataVersion", IntTag(-1)
102
+ ).py_int
103
+ version = VersionNumber(data_version)
104
+ version_range = VersionRange("java", version, version)
105
+ game_version = get_game_version("java", version)
106
+
107
+ # Get the chunk class
108
+ chunk_class: type[JavaChunk]
109
+ if data_version >= 2203:
110
+ chunk_class = JavaChunk2203
111
+ elif data_version >= 1466:
112
+ chunk_class = JavaChunk1466
113
+ elif data_version >= 1444:
114
+ chunk_class = JavaChunk1444
115
+ elif data_version >= 0:
116
+ chunk_class = JavaChunk0
117
+ else:
118
+ chunk_class = JavaChunkNA
119
+
120
+ if data_version == -1:
121
+ chunk_components[LegacyVersionComponent] = level.pop_byte(
122
+ "V", ByteTag(1)
123
+ ).py_int
124
+
125
+ # Chunk x and y pos
126
+ if data_version >= 2844:
127
+ assert region.pop_int("xPos") == IntTag(cx)
128
+ floor_cy = region.pop_int("yPos", IntTag(0)).py_int << 4
129
+ assert region.pop_int("zPos") == IntTag(cz)
130
+ else:
131
+ assert level.pop_int("xPos") == IntTag(cx)
132
+ floor_cy = 0
133
+ assert level.pop_int("zPos") == IntTag(cz)
134
+
135
+ # LastUpdate and InhabitedTime
136
+ if data_version >= 2844:
137
+ chunk_components[LastUpdateComponent] = region.pop_long(
138
+ "LastUpdate", LongTag(0)
139
+ ).py_int
140
+ chunk_components[InhabitedTimeComponent] = region.pop_long(
141
+ "InhabitedTime", LongTag(0)
142
+ ).py_int
143
+ else:
144
+ chunk_components[LastUpdateComponent] = level.pop_long(
145
+ "LastUpdate", LongTag(0)
146
+ ).py_int
147
+ chunk_components[InhabitedTimeComponent] = level.pop_long(
148
+ "InhabitedTime", LongTag(0)
149
+ ).py_int
150
+
151
+ # Status
152
+ if data_version >= 1444:
153
+ if data_version >= 2844:
154
+ status = region.pop_string("Status")
155
+ else:
156
+ status = level.pop_string("Status")
157
+
158
+ if status is not None:
159
+ chunk_components[StatusComponent] = status.py_str
160
+ elif data_version >= 3454:
161
+ chunk_components[StatusComponent] = "minecraft:full"
162
+ elif data_version >= 1912:
163
+ chunk_components[StatusComponent] = "full"
164
+ else:
165
+ chunk_components[StatusComponent] = "postprocessed"
166
+ else:
167
+ chunk_components[TerrainPopulatedComponent] = bool(
168
+ level.pop_byte("TerrainPopulated", ByteTag(1))
169
+ )
170
+ chunk_components[LightPopulatedComponent] = bool(
171
+ level.pop_byte("LightPopulated", ByteTag(1))
172
+ )
173
+
174
+ # Height map
175
+ if data_version >= 1466:
176
+ # CompoundTag of named heightmaps
177
+ if data_version >= 2844:
178
+ heights = region.pop_compound("HeightMaps", CompoundTag())
179
+ else:
180
+ heights = level.pop_compound("HeightMaps", CompoundTag())
181
+ arrays: dict[str, numpy.ndarray] = {}
182
+ for key, value in heights.items():
183
+ if isinstance(key, str) and isinstance(value, LongArrayTag):
184
+ arrays[key] = decode_long_array(
185
+ value.np_array,
186
+ 256,
187
+ height_y.bit_length(),
188
+ dense=data_version <= 2529,
189
+ ).reshape((16, 16)) + (floor_cy << 4)
190
+ chunk_components[NamedHeight2DComponent] = NamedHeight2DData((16, 16), arrays)
191
+ else:
192
+ # Single heightmap
193
+ height = level.pop_int_array("HeightMap")
194
+ if isinstance(height, IntArrayTag) and len(height) == 256:
195
+ chunk_components[Height2DComponent] = height.np_array.astype(
196
+ numpy.int64
197
+ ).reshape((16, 16))
198
+ else:
199
+ chunk_components[Height2DComponent] = numpy.zeros((16, 16), numpy.int64)
200
+
201
+ if data_version >= 2844:
202
+ # region.sections[]
203
+ sections = region.get_list("sections", ListTag())
204
+ else:
205
+ # region.Level.sections[]
206
+ sections = level.get_list("sections", ListTag())
207
+ sections_map = {}
208
+ for section in sections:
209
+ assert isinstance(section, CompoundTag)
210
+ sections_map[section.get_byte("Y", ByteTag(0)).py_int] = section
211
+
212
+ # biomes
213
+ default_biome = dimension.default_biome()
214
+ if not version_range.contains(default_biome.platform, default_biome.version):
215
+ default_biome = get_game_version(
216
+ default_biome.platform, default_biome.version
217
+ ).biome.translate("java", version, default_biome)
218
+ if data_version >= 2836:
219
+ # if data_version >= 2844:
220
+ # # region.sections[].biomes
221
+ # else:
222
+ # # region.Level.sections[].biomes
223
+ chunk_components[Biome3DComponent] = biome_data_3d = Biome3DComponentData(
224
+ version_range, (4, 4, 4), default_biome
225
+ )
226
+ for cy, section in sections_map.items():
227
+ biomes_structure = section.get_compound("biomes")
228
+ if biomes_structure is None:
229
+ continue
230
+ palette_tag = biomes_structure.get_list("palette", raise_errors=True)
231
+ lut = []
232
+ for biome_name in palette_tag:
233
+ assert isinstance(biome_name, StringTag)
234
+ namespace, base_name = biome_name.py_str.split(":", 1)
235
+ lut.append(
236
+ biome_data_3d.palette.biome_to_index(
237
+ Biome("java", version, namespace, base_name)
238
+ )
239
+ )
240
+ data = biomes_structure.get_long_array("data")
241
+ if data is None:
242
+ biome_data_3d.sections[cy] = numpy.full((4, 4, 4), lut[0], numpy.uint32)
243
+ else:
244
+ biome_data_3d.sections[cy] = numpy.array(lut, numpy.uint32)[
245
+ numpy.transpose(
246
+ decode_long_array(
247
+ data.np_array,
248
+ 4**3,
249
+ max(1, (len(lut) - 1).bit_length()),
250
+ dense=data_version <= 2529,
251
+ )
252
+ .astype(numpy.uint32)
253
+ .reshape((4, 4, 4)),
254
+ (2, 0, 1),
255
+ )
256
+ ]
257
+ elif data_version >= 2203:
258
+ # region.Level.Biomes (4x64x4 IntArrayTag[1024])
259
+ biomes_3d = level.pop_int_array("Biomes")
260
+ chunk_components[Biome3DComponent] = biome_data_3d = Biome3DComponentData(
261
+ version_range, (4, 4, 4), default_biome
262
+ )
263
+ if biomes_3d is not None:
264
+ arr: numpy.ndarray = biomes_3d.np_array
265
+ assert len(arr) % 64 == 0
266
+ numerical_ids, arr = numpy.unique(arr, return_inverse=True)
267
+ arr = numpy.transpose(
268
+ arr.astype(numpy.uint32).reshape((-1, 4, 4)),
269
+ (2, 0, 1),
270
+ ) # YZX -> XYZ
271
+ lut = []
272
+ for numerical_id in numerical_ids:
273
+ try:
274
+ (
275
+ namespace,
276
+ base_name,
277
+ ) = raw_level.biome_id_override.numerical_id_to_namespace_id(
278
+ numerical_id
279
+ )
280
+ except KeyError:
281
+ namespace, base_name = (
282
+ game_version.biome.numerical_id_to_namespace_id(numerical_id)
283
+ )
284
+ biome = Biome("java", version, namespace, base_name)
285
+ runtime_id = biome_data_3d.palette.biome_to_index(biome)
286
+ lut.append(runtime_id)
287
+ arr = numpy.array(lut, dtype=numpy.uint32)[arr]
288
+ for sy, sub_arr in enumerate(
289
+ numpy.split(
290
+ arr,
291
+ arr.shape[1] // 4,
292
+ 1,
293
+ )
294
+ ):
295
+ biome_data_3d.sections[sy + floor_cy] = sub_arr
296
+ else:
297
+ biomes_2d: ByteArrayTag | IntArrayTag | None
298
+ if data_version >= 1467:
299
+ # region.Level.Biomes (16x16 IntArrayTag[256])
300
+ biomes_2d = level.pop_int_array("Biomes")
301
+ else:
302
+ # region.Level.Biomes (16x16 ByteArrayTag[256])
303
+ biomes_2d = level.pop_byte_array("Biomes")
304
+ chunk_components[Biome2DComponent] = biome_data_2d = Biome2DComponentData(
305
+ version_range, (16, 16), default_biome
306
+ )
307
+ if biomes_2d is not None and len(biomes_2d) == 256:
308
+ _decode_2d_biomes(
309
+ biome_data_2d,
310
+ version,
311
+ biomes_2d.np_array,
312
+ raw_level.biome_id_override.numerical_id_to_namespace_id,
313
+ game_version.biome.numerical_id_to_namespace_id,
314
+ )
315
+
316
+ # blocks
317
+ blocks: list[Block] = []
318
+ for block in dimension.default_block():
319
+ if version_range.contains(block.platform, block.version):
320
+ blocks.append(block)
321
+ else:
322
+ block_ = get_game_version(block.platform, block.version).block.translate(
323
+ "java", version, block
324
+ )[0]
325
+ if isinstance(block_, Block):
326
+ blocks.append(block_)
327
+ chunk_components[BlockComponent] = block_component_data = BlockComponentData(
328
+ version_range, (16, 16, 16), BlockStack(*blocks)
329
+ )
330
+ block_palette: BlockPalette = block_component_data.palette
331
+ block_sections: SubChunkArrayContainer = block_component_data.sections
332
+
333
+ if data_version >= 1444:
334
+ # if data_version >= 2844:
335
+ # # region.sections[].block_states.data
336
+ # # region.sections[].block_states.palette
337
+ # elif data_version >= 2836:
338
+ # # region.Level.Sections[].block_states.data
339
+ # # region.Level.Sections[].block_states.palette
340
+ # else:
341
+ # # region.Level.Sections[].BlockStates
342
+ # # region.Level.Sections[].Palette
343
+
344
+ _water_block: Block | None = None
345
+
346
+ def get_water() -> Block:
347
+ nonlocal _water_block
348
+ if _water_block is None:
349
+ _block, _, _ = get_game_version(
350
+ "java", VersionNumber(1, 20, 5)
351
+ ).block.translate(
352
+ "java",
353
+ version,
354
+ Block(
355
+ "java",
356
+ VersionNumber(1, 20, 5),
357
+ "minecraft",
358
+ "water",
359
+ {"level": StringTag("0")},
360
+ ),
361
+ )
362
+ if not isinstance(_block, Block):
363
+ raise RuntimeError
364
+ _water_block = _block
365
+ return _water_block
366
+
367
+ for cy, section in sections_map.items():
368
+ if data_version >= 2836:
369
+ block_states_tag = section.pop_compound("block_states", CompoundTag())
370
+ palette_tag = block_states_tag.pop_list("palette")
371
+ data_tag = block_states_tag.pop_long_array("data")
372
+ else:
373
+ palette_tag = section.pop_list("Palette")
374
+ data_tag = section.pop_long_array("BlockStates")
375
+ if palette_tag is None:
376
+ continue
377
+ lut = []
378
+ for block_tag in palette_tag:
379
+ assert isinstance(block_tag, CompoundTag)
380
+ namespace, base_name = block_tag.get_string(
381
+ "Name", raise_errors=True
382
+ ).py_str.split(":", 1)
383
+ properties = {
384
+ k: v
385
+ for k, v in block_tag.get_compound(
386
+ "Properties", CompoundTag({})
387
+ ).items()
388
+ if isinstance(k, str) and isinstance(v, PropertyValueType)
389
+ }
390
+ blocks = []
391
+ waterloggable = game_version.block.waterloggable(namespace, base_name)
392
+ if waterloggable == Waterloggable.Yes:
393
+ # waterlogged property
394
+ if properties.get("waterlogged") == StringTag("true"):
395
+ del properties["waterlogged"]
396
+ blocks.append(get_water())
397
+ elif waterloggable == Waterloggable.Always:
398
+ blocks.append(get_water())
399
+ blocks.insert(
400
+ 0, Block("java", version, namespace, base_name, properties)
401
+ )
402
+ lut.append(block_palette.block_stack_to_index(BlockStack(*blocks)))
403
+
404
+ if data_tag is None:
405
+ arr = numpy.zeros((16, 16, 16), numpy.uint32)
406
+ else:
407
+ decoded = decode_long_array(
408
+ data_tag.np_array,
409
+ 16**3,
410
+ max(4, (len(palette_tag) - 1).bit_length()),
411
+ dense=data_version <= 2529,
412
+ ).astype(numpy.uint32)
413
+ arr = numpy.transpose(decoded.reshape((16, 16, 16)), (2, 0, 1))
414
+ block_sections[cy] = numpy.array(lut, dtype=numpy.uint32)[arr]
415
+ else:
416
+ # region.Level.Sections[].Blocks
417
+ # region.Level.Sections[].Add
418
+ # region.Level.Sections[].Data
419
+ get_block_namespace_override = (
420
+ raw_level.biome_id_override.numerical_id_to_namespace_id
421
+ )
422
+ get_block_namespace_game = game_version.biome.numerical_id_to_namespace_id
423
+ for cy, section in sections_map.items():
424
+ block_tag = section.pop_byte_array("Blocks")
425
+ data_tag = section.pop_byte_array("Data")
426
+ if block_tag is None or data_tag is None:
427
+ continue
428
+ section_blocks = numpy.asarray(block_tag, dtype=numpy.uint16)
429
+ section_data = from_nibble_array(numpy.asarray(data_tag, dtype=numpy.uint8))
430
+
431
+ # add_tag = section.pop_byte_array("Add")
432
+ # if add_tag is not None:
433
+ # add_blocks = from_nibble_array(numpy.asarray(add_tag, dtype=numpy.uint8)).astype(numpy.uint16)
434
+ # section_blocks |= add_blocks << 8
435
+ # # TODO: fix this
436
+
437
+ section_palette, section_array = unique_inverse(
438
+ (section_blocks << 4) + section_data
439
+ )
440
+ section_array = numpy.transpose(
441
+ section_array.reshape((16, 16, 16)), (2, 0, 1)
442
+ ) # YZX -> XYZ
443
+ section_block_ids = section_palette >> 4
444
+ section_block_datas = section_palette & 15
445
+ lut = []
446
+ for block_id, block_data in zip(section_block_ids, section_block_datas):
447
+ try:
448
+ namespace, base_name = get_block_namespace_override(block_id)
449
+ except KeyError:
450
+ try:
451
+ namespace, base_name = get_block_namespace_game(block_id)
452
+ except KeyError:
453
+ namespace = "numerical"
454
+ base_name = str(block_id)
455
+ lut.append(
456
+ block_palette.block_stack_to_index(
457
+ BlockStack(
458
+ Block(
459
+ "java",
460
+ version,
461
+ namespace,
462
+ base_name,
463
+ {"block_data": IntTag(block_data)},
464
+ )
465
+ )
466
+ )
467
+ )
468
+ block_sections[cy] = numpy.array(lut, dtype=numpy.uint32)[section_array]
469
+
470
+ # block entities
471
+ if data_version >= 2844:
472
+ # region.block_entities
473
+ block_entities = region.pop_list("block_entities", ListTag())
474
+ else:
475
+ # region.Level.TileEntities
476
+ block_entities = level.pop_list("TileEntities", ListTag())
477
+ chunk_components[BlockEntityComponent] = block_entity_component = (
478
+ BlockEntityComponentData(version_range)
479
+ )
480
+ for tag in block_entities:
481
+ if not isinstance(tag, CompoundTag):
482
+ continue
483
+
484
+ entity_id = tag.pop_string("id", raise_errors=True)
485
+ namespace, base_name = entity_id.py_str.split(":", 1)
486
+ x_int = tag.pop_int("x", raise_errors=True).py_int
487
+ y_int = tag.pop_int("y", raise_errors=True).py_int
488
+ z_int = tag.pop_int("z", raise_errors=True).py_int
489
+
490
+ block_entity_component[(x_int, y_int, z_int)] = BlockEntity(
491
+ "java", version, namespace, base_name, NamedTag(tag)
492
+ )
493
+
494
+ # entities
495
+ entities = ListTag[CompoundTag]()
496
+ if data_version >= 2681:
497
+ # It seems like the inline version can exist at the same time as the external format.
498
+ # entities.Entities
499
+ entity_layer = raw_chunk.get("entities", NamedTag()).compound
500
+ assert (
501
+ entity_layer.get_int("DataVersion", IntTag(data_version)).py_int
502
+ == data_version
503
+ ), "data version mismatch."
504
+ entities.extend(entity_layer.pop_list("Entities", ListTag()))
505
+ if data_version >= 2844:
506
+ # region.entities
507
+ entities.extend(region.pop_list("entities", ListTag()))
508
+ else:
509
+ # region.Level.Entities
510
+ entities.extend(level.pop_list("Entities", ListTag()))
511
+ chunk_components[EntityComponent] = entity_component = EntityComponentData(
512
+ version_range
513
+ )
514
+ for tag in entities:
515
+ if not isinstance(tag, CompoundTag):
516
+ continue
517
+
518
+ entity_id = tag.pop_string("id", raise_errors=True)
519
+ namespace, base_name = entity_id.py_str.split(":", 1)
520
+ pos = tag.pop_list("Pos", raise_errors=True)
521
+ x_float = pos.get_double(0).py_float
522
+ y_float = pos.get_double(1).py_float
523
+ z_float = pos.get_double(2).py_float
524
+ entity_component.add(
525
+ Entity(
526
+ "java",
527
+ version,
528
+ namespace,
529
+ base_name,
530
+ x_float,
531
+ y_float,
532
+ z_float,
533
+ NamedTag(tag),
534
+ )
535
+ )
536
+
537
+ return chunk_class.from_component_data(chunk_components)
538
+
539
+
540
+ def _decode_2d_biomes(
541
+ biome_data_2d: Biome2DComponentData,
542
+ version: VersionNumber,
543
+ arr: numpy.ndarray,
544
+ numerical_id_to_namespace_id_override: Callable[[int], tuple[str, str]],
545
+ numerical_id_to_namespace_id: Callable[[int], tuple[str, str]],
546
+ ) -> None:
547
+ numerical_ids, arr = numpy.unique(arr, return_inverse=True)
548
+ arr = arr.reshape(16, 16).T.astype(numpy.uint32)
549
+ lut = []
550
+ for numerical_id in numerical_ids:
551
+ try:
552
+ (
553
+ namespace,
554
+ base_name,
555
+ ) = numerical_id_to_namespace_id_override(numerical_id)
556
+ except KeyError:
557
+ namespace, base_name = numerical_id_to_namespace_id(numerical_id)
558
+ biome = Biome("java", version, namespace, base_name)
559
+ runtime_id = biome_data_2d.palette.biome_to_index(biome)
560
+ lut.append(runtime_id)
561
+ biome_data_2d.array[:, :] = numpy.array(lut, dtype=numpy.uint32)[arr]