amulet-core 1.9.19__py3-none-any.whl → 1.9.20__py3-none-any.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 (198) hide show
  1. amulet/__init__.py +27 -27
  2. amulet/__pyinstaller/__init__.py +2 -2
  3. amulet/__pyinstaller/hook-amulet.py +4 -4
  4. amulet/_version.py +21 -21
  5. amulet/api/__init__.py +2 -2
  6. amulet/api/abstract_base_entity.py +128 -128
  7. amulet/api/block.py +630 -630
  8. amulet/api/block_entity.py +71 -71
  9. amulet/api/cache.py +107 -107
  10. amulet/api/chunk/__init__.py +6 -6
  11. amulet/api/chunk/biomes.py +207 -207
  12. amulet/api/chunk/block_entity_dict.py +175 -175
  13. amulet/api/chunk/blocks.py +46 -46
  14. amulet/api/chunk/chunk.py +389 -389
  15. amulet/api/chunk/entity_list.py +75 -75
  16. amulet/api/chunk/status.py +167 -167
  17. amulet/api/data_types/__init__.py +4 -4
  18. amulet/api/data_types/generic_types.py +4 -4
  19. amulet/api/data_types/operation_types.py +16 -16
  20. amulet/api/data_types/world_types.py +49 -49
  21. amulet/api/data_types/wrapper_types.py +71 -71
  22. amulet/api/entity.py +74 -74
  23. amulet/api/errors.py +119 -119
  24. amulet/api/history/__init__.py +36 -36
  25. amulet/api/history/base/__init__.py +3 -3
  26. amulet/api/history/base/base_history.py +26 -26
  27. amulet/api/history/base/history_manager.py +63 -63
  28. amulet/api/history/base/revision_manager.py +73 -73
  29. amulet/api/history/changeable.py +15 -15
  30. amulet/api/history/data_types.py +7 -7
  31. amulet/api/history/history_manager/__init__.py +3 -3
  32. amulet/api/history/history_manager/container.py +102 -102
  33. amulet/api/history/history_manager/database.py +279 -279
  34. amulet/api/history/history_manager/meta.py +93 -93
  35. amulet/api/history/history_manager/object.py +116 -116
  36. amulet/api/history/revision_manager/__init__.py +2 -2
  37. amulet/api/history/revision_manager/disk.py +33 -33
  38. amulet/api/history/revision_manager/ram.py +12 -12
  39. amulet/api/item.py +75 -75
  40. amulet/api/level/__init__.py +4 -4
  41. amulet/api/level/base_level/__init__.py +1 -1
  42. amulet/api/level/base_level/base_level.py +1035 -1026
  43. amulet/api/level/base_level/chunk_manager.py +227 -227
  44. amulet/api/level/base_level/clone.py +389 -389
  45. amulet/api/level/base_level/player_manager.py +101 -101
  46. amulet/api/level/immutable_structure/__init__.py +1 -1
  47. amulet/api/level/immutable_structure/immutable_structure.py +94 -94
  48. amulet/api/level/immutable_structure/void_format_wrapper.py +117 -117
  49. amulet/api/level/structure.py +22 -22
  50. amulet/api/level/world.py +19 -19
  51. amulet/api/partial_3d_array/__init__.py +2 -2
  52. amulet/api/partial_3d_array/base_partial_3d_array.py +263 -263
  53. amulet/api/partial_3d_array/bounded_partial_3d_array.py +528 -528
  54. amulet/api/partial_3d_array/data_types.py +15 -15
  55. amulet/api/partial_3d_array/unbounded_partial_3d_array.py +229 -229
  56. amulet/api/partial_3d_array/util.py +152 -152
  57. amulet/api/player.py +65 -65
  58. amulet/api/registry/__init__.py +2 -2
  59. amulet/api/registry/base_registry.py +34 -34
  60. amulet/api/registry/biome_manager.py +153 -153
  61. amulet/api/registry/block_manager.py +156 -156
  62. amulet/api/selection/__init__.py +2 -2
  63. amulet/api/selection/abstract_selection.py +315 -315
  64. amulet/api/selection/box.py +805 -805
  65. amulet/api/selection/group.py +488 -488
  66. amulet/api/structure.py +37 -37
  67. amulet/api/wrapper/__init__.py +8 -8
  68. amulet/api/wrapper/chunk/interface.py +441 -441
  69. amulet/api/wrapper/chunk/translator.py +567 -567
  70. amulet/api/wrapper/format_wrapper.py +772 -772
  71. amulet/api/wrapper/structure_format_wrapper.py +116 -116
  72. amulet/api/wrapper/world_format_wrapper.py +63 -63
  73. amulet/level/__init__.py +1 -1
  74. amulet/level/formats/anvil_forge_world.py +40 -40
  75. amulet/level/formats/anvil_world/__init__.py +3 -3
  76. amulet/level/formats/anvil_world/_sector_manager.py +291 -384
  77. amulet/level/formats/anvil_world/data_pack/__init__.py +2 -2
  78. amulet/level/formats/anvil_world/data_pack/data_pack.py +224 -224
  79. amulet/level/formats/anvil_world/data_pack/data_pack_manager.py +77 -77
  80. amulet/level/formats/anvil_world/dimension.py +177 -177
  81. amulet/level/formats/anvil_world/format.py +769 -769
  82. amulet/level/formats/anvil_world/region.py +384 -384
  83. amulet/level/formats/construction/__init__.py +3 -3
  84. amulet/level/formats/construction/format_wrapper.py +515 -515
  85. amulet/level/formats/construction/interface.py +134 -134
  86. amulet/level/formats/construction/section.py +60 -60
  87. amulet/level/formats/construction/util.py +165 -165
  88. amulet/level/formats/leveldb_world/__init__.py +3 -3
  89. amulet/level/formats/leveldb_world/chunk.py +33 -33
  90. amulet/level/formats/leveldb_world/dimension.py +385 -419
  91. amulet/level/formats/leveldb_world/format.py +659 -641
  92. amulet/level/formats/leveldb_world/interface/chunk/__init__.py +36 -36
  93. amulet/level/formats/leveldb_world/interface/chunk/base_leveldb_interface.py +836 -836
  94. amulet/level/formats/leveldb_world/interface/chunk/generate_interface.py +31 -31
  95. amulet/level/formats/leveldb_world/interface/chunk/leveldb_0.py +30 -30
  96. amulet/level/formats/leveldb_world/interface/chunk/leveldb_1.py +12 -12
  97. amulet/level/formats/leveldb_world/interface/chunk/leveldb_10.py +12 -12
  98. amulet/level/formats/leveldb_world/interface/chunk/leveldb_11.py +12 -12
  99. amulet/level/formats/leveldb_world/interface/chunk/leveldb_12.py +12 -12
  100. amulet/level/formats/leveldb_world/interface/chunk/leveldb_13.py +12 -12
  101. amulet/level/formats/leveldb_world/interface/chunk/leveldb_14.py +12 -12
  102. amulet/level/formats/leveldb_world/interface/chunk/leveldb_15.py +12 -12
  103. amulet/level/formats/leveldb_world/interface/chunk/leveldb_16.py +12 -12
  104. amulet/level/formats/leveldb_world/interface/chunk/leveldb_17.py +12 -12
  105. amulet/level/formats/leveldb_world/interface/chunk/leveldb_18.py +12 -12
  106. amulet/level/formats/leveldb_world/interface/chunk/leveldb_19.py +12 -12
  107. amulet/level/formats/leveldb_world/interface/chunk/leveldb_2.py +12 -12
  108. amulet/level/formats/leveldb_world/interface/chunk/leveldb_20.py +12 -12
  109. amulet/level/formats/leveldb_world/interface/chunk/leveldb_21.py +12 -12
  110. amulet/level/formats/leveldb_world/interface/chunk/leveldb_22.py +12 -12
  111. amulet/level/formats/leveldb_world/interface/chunk/leveldb_23.py +10 -10
  112. amulet/level/formats/leveldb_world/interface/chunk/leveldb_24.py +10 -10
  113. amulet/level/formats/leveldb_world/interface/chunk/leveldb_25.py +24 -24
  114. amulet/level/formats/leveldb_world/interface/chunk/leveldb_26.py +10 -10
  115. amulet/level/formats/leveldb_world/interface/chunk/leveldb_27.py +10 -10
  116. amulet/level/formats/leveldb_world/interface/chunk/leveldb_28.py +10 -10
  117. amulet/level/formats/leveldb_world/interface/chunk/leveldb_29.py +33 -33
  118. amulet/level/formats/leveldb_world/interface/chunk/leveldb_3.py +57 -57
  119. amulet/level/formats/leveldb_world/interface/chunk/leveldb_30.py +10 -10
  120. amulet/level/formats/leveldb_world/interface/chunk/leveldb_31.py +10 -10
  121. amulet/level/formats/leveldb_world/interface/chunk/leveldb_32.py +10 -10
  122. amulet/level/formats/leveldb_world/interface/chunk/leveldb_33.py +10 -10
  123. amulet/level/formats/leveldb_world/interface/chunk/leveldb_34.py +10 -10
  124. amulet/level/formats/leveldb_world/interface/chunk/leveldb_35.py +10 -10
  125. amulet/level/formats/leveldb_world/interface/chunk/leveldb_36.py +10 -10
  126. amulet/level/formats/leveldb_world/interface/chunk/leveldb_37.py +10 -10
  127. amulet/level/formats/leveldb_world/interface/chunk/leveldb_38.py +10 -10
  128. amulet/level/formats/leveldb_world/interface/chunk/leveldb_39.py +12 -12
  129. amulet/level/formats/leveldb_world/interface/chunk/leveldb_4.py +12 -12
  130. amulet/level/formats/leveldb_world/interface/chunk/leveldb_40.py +16 -16
  131. amulet/level/formats/leveldb_world/interface/chunk/leveldb_5.py +12 -12
  132. amulet/level/formats/leveldb_world/interface/chunk/leveldb_6.py +12 -12
  133. amulet/level/formats/leveldb_world/interface/chunk/leveldb_7.py +12 -12
  134. amulet/level/formats/leveldb_world/interface/chunk/leveldb_8.py +180 -180
  135. amulet/level/formats/leveldb_world/interface/chunk/leveldb_9.py +18 -18
  136. amulet/level/formats/leveldb_world/interface/chunk/leveldb_chunk_versions.py +79 -79
  137. amulet/level/formats/mcstructure/__init__.py +3 -3
  138. amulet/level/formats/mcstructure/chunk.py +50 -50
  139. amulet/level/formats/mcstructure/format_wrapper.py +408 -408
  140. amulet/level/formats/mcstructure/interface.py +175 -175
  141. amulet/level/formats/schematic/__init__.py +3 -3
  142. amulet/level/formats/schematic/chunk.py +55 -55
  143. amulet/level/formats/schematic/data_types.py +4 -4
  144. amulet/level/formats/schematic/format_wrapper.py +373 -373
  145. amulet/level/formats/schematic/interface.py +142 -142
  146. amulet/level/formats/sponge_schem/__init__.py +4 -4
  147. amulet/level/formats/sponge_schem/chunk.py +62 -62
  148. amulet/level/formats/sponge_schem/format_wrapper.py +463 -463
  149. amulet/level/formats/sponge_schem/interface.py +118 -118
  150. amulet/level/formats/sponge_schem/varint/__init__.py +1 -1
  151. amulet/level/formats/sponge_schem/varint/varint.py +87 -87
  152. amulet/level/interfaces/chunk/anvil/anvil_0.py +72 -72
  153. amulet/level/interfaces/chunk/anvil/anvil_1444.py +336 -336
  154. amulet/level/interfaces/chunk/anvil/anvil_1466.py +94 -94
  155. amulet/level/interfaces/chunk/anvil/anvil_1467.py +37 -37
  156. amulet/level/interfaces/chunk/anvil/anvil_1484.py +20 -20
  157. amulet/level/interfaces/chunk/anvil/anvil_1503.py +20 -20
  158. amulet/level/interfaces/chunk/anvil/anvil_1519.py +34 -34
  159. amulet/level/interfaces/chunk/anvil/anvil_1901.py +20 -20
  160. amulet/level/interfaces/chunk/anvil/anvil_1908.py +20 -20
  161. amulet/level/interfaces/chunk/anvil/anvil_1912.py +21 -21
  162. amulet/level/interfaces/chunk/anvil/anvil_1934.py +20 -20
  163. amulet/level/interfaces/chunk/anvil/anvil_2203.py +69 -69
  164. amulet/level/interfaces/chunk/anvil/anvil_2529.py +19 -19
  165. amulet/level/interfaces/chunk/anvil/anvil_2681.py +76 -76
  166. amulet/level/interfaces/chunk/anvil/anvil_2709.py +19 -19
  167. amulet/level/interfaces/chunk/anvil/anvil_2844.py +267 -267
  168. amulet/level/interfaces/chunk/anvil/anvil_3463.py +19 -19
  169. amulet/level/interfaces/chunk/anvil/anvil_na.py +607 -607
  170. amulet/level/interfaces/chunk/anvil/base_anvil_interface.py +326 -326
  171. amulet/level/load.py +59 -59
  172. amulet/level/loader.py +95 -95
  173. amulet/level/translators/chunk/bedrock/__init__.py +267 -267
  174. amulet/level/translators/chunk/bedrock/bedrock_nbt_blockstate_translator.py +46 -46
  175. amulet/level/translators/chunk/bedrock/bedrock_numerical_translator.py +39 -39
  176. amulet/level/translators/chunk/bedrock/bedrock_psudo_numerical_translator.py +37 -37
  177. amulet/level/translators/chunk/java/java_1_18_translator.py +40 -40
  178. amulet/level/translators/chunk/java/java_blockstate_translator.py +94 -94
  179. amulet/level/translators/chunk/java/java_numerical_translator.py +62 -62
  180. amulet/libs/leveldb/__init__.py +7 -7
  181. amulet/operations/__init__.py +5 -5
  182. amulet/operations/clone.py +18 -18
  183. amulet/operations/delete_chunk.py +32 -32
  184. amulet/operations/fill.py +30 -30
  185. amulet/operations/paste.py +65 -65
  186. amulet/operations/replace.py +58 -58
  187. amulet/utils/__init__.py +14 -14
  188. amulet/utils/format_utils.py +41 -41
  189. amulet/utils/generator.py +15 -15
  190. amulet/utils/matrix.py +243 -243
  191. amulet/utils/numpy_helpers.py +46 -46
  192. amulet/utils/world_utils.py +349 -349
  193. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/METADATA +97 -97
  194. amulet_core-1.9.20.dist-info/RECORD +208 -0
  195. amulet_core-1.9.19.dist-info/RECORD +0 -208
  196. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/WHEEL +0 -0
  197. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/entry_points.txt +0 -0
  198. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/top_level.txt +0 -0
@@ -1,180 +1,180 @@
1
- from __future__ import annotations
2
-
3
- from .leveldb_7 import (
4
- LevelDB7Interface,
5
- )
6
-
7
- from typing import Tuple, Dict, Optional, TYPE_CHECKING, List
8
-
9
- import struct
10
- import numpy
11
- from numpy.typing import NDArray
12
- from amulet_nbt import NamedTag, CompoundTag, StringTag, IntTag, ShortTag
13
-
14
- from amulet.api.block import Block, PropertyDataTypes
15
-
16
- from amulet.utils.numpy_helpers import brute_sort_objects_no_hash
17
- from amulet.api.data_types import (
18
- AnyNDArray,
19
- VersionIdentifierTuple,
20
- )
21
-
22
- if TYPE_CHECKING:
23
- from amulet.api.chunk.blocks import Blocks
24
-
25
-
26
- PackedBlockT = Tuple[Tuple[Optional[int], Block], ...]
27
-
28
-
29
- class LevelDB8Interface(LevelDB7Interface):
30
- chunk_version = 8
31
-
32
- def __init__(self):
33
- super().__init__()
34
- self._set_feature("terrain", "2fnpalette")
35
-
36
- def _encode_subchunks(
37
- self,
38
- blocks: "Blocks",
39
- palette: AnyNDArray,
40
- bounds: Tuple[int, int],
41
- max_world_version: VersionIdentifierTuple,
42
- ) -> Dict[int, Optional[bytes]]:
43
- # Encode sub-chunk block format 8
44
- # TODO: untangle this mess. The lack of typing in numpy is just making this harder.
45
- palette_list: List[PackedBlockT] = list(palette)
46
- min_y = bounds[0] // 16
47
- max_y = bounds[1] // 16
48
- if palette_list:
49
- if palette_list[0][0][0] is None:
50
- air = NamedTag(
51
- CompoundTag(
52
- {
53
- "name": StringTag("minecraft:air"),
54
- "val": ShortTag(0),
55
- }
56
- )
57
- )
58
- else:
59
- air = NamedTag(
60
- CompoundTag(
61
- {
62
- "name": StringTag("minecraft:air"),
63
- "states": CompoundTag({}),
64
- "version": IntTag(17_629_184), # 1, 13, 0, 0
65
- }
66
- )
67
- )
68
-
69
- packed_palette: List[Tuple[NamedTag, ...]] = []
70
- for index, block in enumerate(palette_list):
71
- full_block: List[NamedTag] = []
72
- for sub_block_version, sub_block in block:
73
- properties = sub_block.properties
74
- if sub_block_version is None:
75
- block_data = properties.get("block_data", IntTag(0))
76
- if isinstance(block_data, IntTag):
77
- block_data = block_data.py_int
78
- # if block_data >= 16:
79
- # block_data = 0
80
- else:
81
- block_data = 0
82
- sub_block_ = NamedTag(
83
- CompoundTag(
84
- {
85
- "name": StringTag(sub_block.namespaced_name),
86
- "val": ShortTag(block_data),
87
- }
88
- )
89
- )
90
- else:
91
- sub_block_ = NamedTag(
92
- CompoundTag(
93
- {
94
- "name": StringTag(sub_block.namespaced_name),
95
- "states": CompoundTag(
96
- {
97
- key: val
98
- for key, val in properties.items()
99
- if isinstance(val, PropertyDataTypes)
100
- }
101
- ),
102
- "version": IntTag(sub_block_version),
103
- }
104
- )
105
- )
106
-
107
- full_block.append(sub_block_)
108
- packed_palette.append(tuple(full_block))
109
-
110
- chunk = {}
111
- palette_depth = numpy.array([len(block) for block in packed_palette])
112
- for cy in range(min_y, max_y):
113
- if cy in blocks:
114
- palette_index, sub_chunk = numpy.unique(
115
- blocks.get_sub_chunk(cy), return_inverse=True
116
- )
117
- sub_chunk_palette: List[Tuple[NamedTag, ...]] = [
118
- packed_palette[i] for i in palette_index
119
- ]
120
- sub_chunk_depth = palette_depth[palette_index].max()
121
-
122
- if (
123
- sub_chunk_depth == 1
124
- and len(sub_chunk_palette) == 1
125
- and sub_chunk_palette[0][0].compound.get_string("name").py_str
126
- == "minecraft:air"
127
- ):
128
- chunk[cy] = None
129
- else:
130
- # pad block_palette with air in the extra layers
131
- sub_chunk_palette_full: NDArray[NamedTag] = numpy.empty(
132
- (len(sub_chunk_palette), sub_chunk_depth), dtype=object
133
- )
134
- sub_chunk_palette_full.fill(air)
135
-
136
- for index, block_tuple in enumerate(sub_chunk_palette):
137
- for sub_index, block in enumerate(block_tuple):
138
- sub_chunk_palette_full[index, sub_index] = block
139
- # should now be a 2D array with an NamedTag in each element
140
-
141
- if max_world_version[1] >= (
142
- 1,
143
- 17,
144
- 30,
145
- ): # Why do I need to check against game version and not chunk version
146
- sub_chunk_bytes = [
147
- b"\x09",
148
- bytes([sub_chunk_depth]),
149
- struct.pack("b", cy),
150
- ]
151
- else:
152
- sub_chunk_bytes = [b"\x08", bytes([sub_chunk_depth])]
153
- for sub_chunk_layer_index in range(sub_chunk_depth):
154
- # TODO: sort out a way to do this quicker without brute forcing it.
155
- (
156
- sub_chunk_layer_palette,
157
- sub_chunk_remap,
158
- ) = brute_sort_objects_no_hash(
159
- sub_chunk_palette_full[:, sub_chunk_layer_index]
160
- )
161
- sub_chunk_layer = sub_chunk_remap[sub_chunk.ravel()]
162
-
163
- # sub_chunk_layer, sub_chunk_layer_palette = sub_chunk, sub_chunk_palette_full[:, sub_chunk_layer_index]
164
- sub_chunk_bytes.append(
165
- self._save_palette_subchunk(
166
- sub_chunk_layer.reshape(16, 16, 16),
167
- list(sub_chunk_layer_palette.ravel()),
168
- )
169
- )
170
-
171
- chunk[cy] = b"".join(sub_chunk_bytes)
172
- else:
173
- chunk[cy] = None
174
- else:
175
- chunk = {i: None for i in range(min_y, max_y)}
176
-
177
- return chunk
178
-
179
-
180
- export = LevelDB8Interface
1
+ from __future__ import annotations
2
+
3
+ from .leveldb_7 import (
4
+ LevelDB7Interface,
5
+ )
6
+
7
+ from typing import Tuple, Dict, Optional, TYPE_CHECKING, List
8
+
9
+ import struct
10
+ import numpy
11
+ from numpy.typing import NDArray
12
+ from amulet_nbt import NamedTag, CompoundTag, StringTag, IntTag, ShortTag
13
+
14
+ from amulet.api.block import Block, PropertyDataTypes
15
+
16
+ from amulet.utils.numpy_helpers import brute_sort_objects_no_hash
17
+ from amulet.api.data_types import (
18
+ AnyNDArray,
19
+ VersionIdentifierTuple,
20
+ )
21
+
22
+ if TYPE_CHECKING:
23
+ from amulet.api.chunk.blocks import Blocks
24
+
25
+
26
+ PackedBlockT = Tuple[Tuple[Optional[int], Block], ...]
27
+
28
+
29
+ class LevelDB8Interface(LevelDB7Interface):
30
+ chunk_version = 8
31
+
32
+ def __init__(self):
33
+ super().__init__()
34
+ self._set_feature("terrain", "2fnpalette")
35
+
36
+ def _encode_subchunks(
37
+ self,
38
+ blocks: "Blocks",
39
+ palette: AnyNDArray,
40
+ bounds: Tuple[int, int],
41
+ max_world_version: VersionIdentifierTuple,
42
+ ) -> Dict[int, Optional[bytes]]:
43
+ # Encode sub-chunk block format 8
44
+ # TODO: untangle this mess. The lack of typing in numpy is just making this harder.
45
+ palette_list: List[PackedBlockT] = list(palette)
46
+ min_y = bounds[0] // 16
47
+ max_y = bounds[1] // 16
48
+ if palette_list:
49
+ if palette_list[0][0][0] is None:
50
+ air = NamedTag(
51
+ CompoundTag(
52
+ {
53
+ "name": StringTag("minecraft:air"),
54
+ "val": ShortTag(0),
55
+ }
56
+ )
57
+ )
58
+ else:
59
+ air = NamedTag(
60
+ CompoundTag(
61
+ {
62
+ "name": StringTag("minecraft:air"),
63
+ "states": CompoundTag({}),
64
+ "version": IntTag(17_629_184), # 1, 13, 0, 0
65
+ }
66
+ )
67
+ )
68
+
69
+ packed_palette: List[Tuple[NamedTag, ...]] = []
70
+ for index, block in enumerate(palette_list):
71
+ full_block: List[NamedTag] = []
72
+ for sub_block_version, sub_block in block:
73
+ properties = sub_block.properties
74
+ if sub_block_version is None:
75
+ block_data = properties.get("block_data", IntTag(0))
76
+ if isinstance(block_data, IntTag):
77
+ block_data = block_data.py_int
78
+ # if block_data >= 16:
79
+ # block_data = 0
80
+ else:
81
+ block_data = 0
82
+ sub_block_ = NamedTag(
83
+ CompoundTag(
84
+ {
85
+ "name": StringTag(sub_block.namespaced_name),
86
+ "val": ShortTag(block_data),
87
+ }
88
+ )
89
+ )
90
+ else:
91
+ sub_block_ = NamedTag(
92
+ CompoundTag(
93
+ {
94
+ "name": StringTag(sub_block.namespaced_name),
95
+ "states": CompoundTag(
96
+ {
97
+ key: val
98
+ for key, val in properties.items()
99
+ if isinstance(val, PropertyDataTypes)
100
+ }
101
+ ),
102
+ "version": IntTag(sub_block_version),
103
+ }
104
+ )
105
+ )
106
+
107
+ full_block.append(sub_block_)
108
+ packed_palette.append(tuple(full_block))
109
+
110
+ chunk = {}
111
+ palette_depth = numpy.array([len(block) for block in packed_palette])
112
+ for cy in range(min_y, max_y):
113
+ if cy in blocks:
114
+ palette_index, sub_chunk = numpy.unique(
115
+ blocks.get_sub_chunk(cy), return_inverse=True
116
+ )
117
+ sub_chunk_palette: List[Tuple[NamedTag, ...]] = [
118
+ packed_palette[i] for i in palette_index
119
+ ]
120
+ sub_chunk_depth = palette_depth[palette_index].max()
121
+
122
+ if (
123
+ sub_chunk_depth == 1
124
+ and len(sub_chunk_palette) == 1
125
+ and sub_chunk_palette[0][0].compound.get_string("name").py_str
126
+ == "minecraft:air"
127
+ ):
128
+ chunk[cy] = None
129
+ else:
130
+ # pad block_palette with air in the extra layers
131
+ sub_chunk_palette_full: NDArray[NamedTag] = numpy.empty(
132
+ (len(sub_chunk_palette), sub_chunk_depth), dtype=object
133
+ )
134
+ sub_chunk_palette_full.fill(air)
135
+
136
+ for index, block_tuple in enumerate(sub_chunk_palette):
137
+ for sub_index, block in enumerate(block_tuple):
138
+ sub_chunk_palette_full[index, sub_index] = block
139
+ # should now be a 2D array with an NamedTag in each element
140
+
141
+ if max_world_version[1] >= (
142
+ 1,
143
+ 17,
144
+ 30,
145
+ ): # Why do I need to check against game version and not chunk version
146
+ sub_chunk_bytes = [
147
+ b"\x09",
148
+ bytes([sub_chunk_depth]),
149
+ struct.pack("b", cy),
150
+ ]
151
+ else:
152
+ sub_chunk_bytes = [b"\x08", bytes([sub_chunk_depth])]
153
+ for sub_chunk_layer_index in range(sub_chunk_depth):
154
+ # TODO: sort out a way to do this quicker without brute forcing it.
155
+ (
156
+ sub_chunk_layer_palette,
157
+ sub_chunk_remap,
158
+ ) = brute_sort_objects_no_hash(
159
+ sub_chunk_palette_full[:, sub_chunk_layer_index]
160
+ )
161
+ sub_chunk_layer = sub_chunk_remap[sub_chunk.ravel()]
162
+
163
+ # sub_chunk_layer, sub_chunk_layer_palette = sub_chunk, sub_chunk_palette_full[:, sub_chunk_layer_index]
164
+ sub_chunk_bytes.append(
165
+ self._save_palette_subchunk(
166
+ sub_chunk_layer.reshape(16, 16, 16),
167
+ list(sub_chunk_layer_palette.ravel()),
168
+ )
169
+ )
170
+
171
+ chunk[cy] = b"".join(sub_chunk_bytes)
172
+ else:
173
+ chunk[cy] = None
174
+ else:
175
+ chunk = {i: None for i in range(min_y, max_y)}
176
+
177
+ return chunk
178
+
179
+
180
+ export = LevelDB8Interface
@@ -1,18 +1,18 @@
1
- from __future__ import annotations
2
-
3
- from amulet.api.wrapper import EntityIDType
4
- from .leveldb_8 import (
5
- LevelDB8Interface,
6
- )
7
-
8
-
9
- class LevelDB9Interface(LevelDB8Interface):
10
- chunk_version = 9
11
-
12
- def __init__(self):
13
- super().__init__()
14
- # EntityIDType.int_id is present until at least v7. Not sure which was present for v8
15
- self._set_feature("entity_format", EntityIDType.namespace_str_identifier)
16
-
17
-
18
- export = LevelDB9Interface
1
+ from __future__ import annotations
2
+
3
+ from amulet.api.wrapper import EntityIDType
4
+ from .leveldb_8 import (
5
+ LevelDB8Interface,
6
+ )
7
+
8
+
9
+ class LevelDB9Interface(LevelDB8Interface):
10
+ chunk_version = 9
11
+
12
+ def __init__(self):
13
+ super().__init__()
14
+ # EntityIDType.int_id is present until at least v7. Not sure which was present for v8
15
+ self._set_feature("entity_format", EntityIDType.namespace_str_identifier)
16
+
17
+
18
+ export = LevelDB9Interface
@@ -1,79 +1,79 @@
1
- from typing import Dict, Tuple
2
- from amulet.api.data_types import VersionNumberTuple
3
-
4
- # This is a dictionary of the first and last times each chunk version was written by a game version
5
- # It is used to convert the chunk version to the game version that could have saved that chunk.
6
- # It is also used to convert back to the chunk version when saving based on the game version.
7
- chunk_version_to_max_version: Dict[
8
- int, Tuple[VersionNumberTuple, VersionNumberTuple]
9
- ] = {
10
- 0: ((0, 9, 0, 0), (0, 9, 1, 9999)),
11
- 1: ((0, 9, 2, 0), (0, 9, 4, 9999)),
12
- 2: ((0, 9, 5, 0), (0, 16, 999, 9999)),
13
- 3: ((0, 17, 0, 0), (0, 17, 999, 9999)),
14
- 4: ((0, 18, 0, 0), (0, 18, 0, 0)),
15
- 5: ((0, 18, 0, 0), (1, 1, 999, 9999)),
16
- 6: ((1, 2, 0, 0), (1, 2, 0, 0)),
17
- 7: ((1, 2, 0, 0), (1, 2, 999, 9999)),
18
- 8: ((1, 3, 0, 0), (1, 7, 999, 9999)),
19
- 9: ((1, 8, 0, 0), (1, 8, 999, 9999)),
20
- 10: ((1, 9, 0, 0), (1, 9, 999, 9999)),
21
- 11: ((1, 10, 0, 0), (1, 10, 999, 9999)),
22
- 12: ((1, 11, 0, 0), (1, 11, 0, 9999)),
23
- 13: ((1, 11, 1, 0), (1, 11, 1, 9999)),
24
- 14: ((1, 11, 2, 0), (1, 11, 999, 999)),
25
- 15: ((1, 12, 0, 0), (1, 15, 999, 9999)),
26
- 16: ((1, 15, 999, 9999), (1, 15, 999, 9999)),
27
- 17: ((1, 15, 999, 9999), (1, 15, 999, 9999)),
28
- 18: ((1, 16, 0, 0), (1, 16, 0, 0)),
29
- 19: ((1, 16, 0, 0), (1, 16, 100, 55)),
30
- 20: ((1, 16, 100, 56), (1, 16, 100, 57)),
31
- 21: ((1, 16, 100, 58), (1, 16, 210, 0)),
32
- 22: ((1, 16, 210, 0), (1, 17, 999, 999)), # caves and cliffs disabled
33
- # used with experimental features
34
- 23: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
35
- 24: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
36
- 25: ((1, 17, 0, 0), (1, 17, 20, 999)), # 1.17.0-20 caves and cliffs enabled
37
- 26: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
38
- 27: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
39
- 28: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
40
- 29: ((1, 17, 30, 0), (1, 17, 30, 999)), # 1.17.30 caves and cliffs enabled
41
- 30: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
42
- 31: ((1, 17, 40, 0), (1, 17, 999, 999)), # 1.17.40 caves and cliffs enabled
43
- 32: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
44
- 33: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
45
- 34: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
46
- 35: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
47
- 36: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
48
- 37: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
49
- 38: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
50
- # continue without experimental gameplay
51
- 39: ((1, 18, 0, 0), (1, 18, 29, 999)),
52
- 40: ((1, 18, 30, 0), (999, 999, 999, 999)),
53
- } # TODO: fill this list with the actual last game version number each chunk version was last used in
54
-
55
-
56
- def chunk_to_game_version(
57
- max_game_version: VersionNumberTuple, chunk_version: int
58
- ) -> VersionNumberTuple:
59
- """Find the game version to use based on the chunk version."""
60
- return min(chunk_version_to_max_version[chunk_version][1], max_game_version)
61
-
62
-
63
- def game_to_chunk_version(max_game_version: VersionNumberTuple, cnc=False) -> int:
64
- """Get the chunk version that should be used for the given game version number."""
65
- # The comparison can fail if they are no the same length
66
- max_game_version = (max_game_version + (0,) * (4 - len(max_game_version)))[:4]
67
- cnc = cnc or max_game_version >= (1, 18, 0)
68
- for chunk_version, (first, last) in chunk_version_to_max_version.items():
69
- if (
70
- first <= max_game_version <= last # if the version is in the range
71
- and cnc
72
- == (
73
- chunk_version > 22
74
- ) # and it is in the correct range (caves and cliffs or not)
75
- ):
76
- return chunk_version
77
-
78
- # If all else fails return the minimum we support
79
- return 6
1
+ from typing import Dict, Tuple
2
+ from amulet.api.data_types import VersionNumberTuple
3
+
4
+ # This is a dictionary of the first and last times each chunk version was written by a game version
5
+ # It is used to convert the chunk version to the game version that could have saved that chunk.
6
+ # It is also used to convert back to the chunk version when saving based on the game version.
7
+ chunk_version_to_max_version: Dict[
8
+ int, Tuple[VersionNumberTuple, VersionNumberTuple]
9
+ ] = {
10
+ 0: ((0, 9, 0, 0), (0, 9, 1, 9999)),
11
+ 1: ((0, 9, 2, 0), (0, 9, 4, 9999)),
12
+ 2: ((0, 9, 5, 0), (0, 16, 999, 9999)),
13
+ 3: ((0, 17, 0, 0), (0, 17, 999, 9999)),
14
+ 4: ((0, 18, 0, 0), (0, 18, 0, 0)),
15
+ 5: ((0, 18, 0, 0), (1, 1, 999, 9999)),
16
+ 6: ((1, 2, 0, 0), (1, 2, 0, 0)),
17
+ 7: ((1, 2, 0, 0), (1, 2, 999, 9999)),
18
+ 8: ((1, 3, 0, 0), (1, 7, 999, 9999)),
19
+ 9: ((1, 8, 0, 0), (1, 8, 999, 9999)),
20
+ 10: ((1, 9, 0, 0), (1, 9, 999, 9999)),
21
+ 11: ((1, 10, 0, 0), (1, 10, 999, 9999)),
22
+ 12: ((1, 11, 0, 0), (1, 11, 0, 9999)),
23
+ 13: ((1, 11, 1, 0), (1, 11, 1, 9999)),
24
+ 14: ((1, 11, 2, 0), (1, 11, 999, 999)),
25
+ 15: ((1, 12, 0, 0), (1, 15, 999, 9999)),
26
+ 16: ((1, 15, 999, 9999), (1, 15, 999, 9999)),
27
+ 17: ((1, 15, 999, 9999), (1, 15, 999, 9999)),
28
+ 18: ((1, 16, 0, 0), (1, 16, 0, 0)),
29
+ 19: ((1, 16, 0, 0), (1, 16, 100, 55)),
30
+ 20: ((1, 16, 100, 56), (1, 16, 100, 57)),
31
+ 21: ((1, 16, 100, 58), (1, 16, 210, 0)),
32
+ 22: ((1, 16, 210, 0), (1, 17, 999, 999)), # caves and cliffs disabled
33
+ # used with experimental features
34
+ 23: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
35
+ 24: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
36
+ 25: ((1, 17, 0, 0), (1, 17, 20, 999)), # 1.17.0-20 caves and cliffs enabled
37
+ 26: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
38
+ 27: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
39
+ 28: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
40
+ 29: ((1, 17, 30, 0), (1, 17, 30, 999)), # 1.17.30 caves and cliffs enabled
41
+ 30: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
42
+ 31: ((1, 17, 40, 0), (1, 17, 999, 999)), # 1.17.40 caves and cliffs enabled
43
+ 32: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
44
+ 33: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
45
+ 34: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
46
+ 35: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
47
+ 36: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
48
+ 37: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
49
+ 38: ((1, 17, 0, 0), (1, 17, 0, 0)), # ?
50
+ # continue without experimental gameplay
51
+ 39: ((1, 18, 0, 0), (1, 18, 29, 999)),
52
+ 40: ((1, 18, 30, 0), (999, 999, 999, 999)),
53
+ } # TODO: fill this list with the actual last game version number each chunk version was last used in
54
+
55
+
56
+ def chunk_to_game_version(
57
+ max_game_version: VersionNumberTuple, chunk_version: int
58
+ ) -> VersionNumberTuple:
59
+ """Find the game version to use based on the chunk version."""
60
+ return min(chunk_version_to_max_version[chunk_version][1], max_game_version)
61
+
62
+
63
+ def game_to_chunk_version(max_game_version: VersionNumberTuple, cnc=False) -> int:
64
+ """Get the chunk version that should be used for the given game version number."""
65
+ # The comparison can fail if they are no the same length
66
+ max_game_version = (max_game_version + (0,) * (4 - len(max_game_version)))[:4]
67
+ cnc = cnc or max_game_version >= (1, 18, 0)
68
+ for chunk_version, (first, last) in chunk_version_to_max_version.items():
69
+ if (
70
+ first <= max_game_version <= last # if the version is in the range
71
+ and cnc
72
+ == (
73
+ chunk_version > 22
74
+ ) # and it is in the correct range (caves and cliffs or not)
75
+ ):
76
+ return chunk_version
77
+
78
+ # If all else fails return the minimum we support
79
+ return 6
@@ -1,3 +1,3 @@
1
- from .format_wrapper import MCStructureFormatWrapper
2
-
3
- export = MCStructureFormatWrapper
1
+ from .format_wrapper import MCStructureFormatWrapper
2
+
3
+ export = MCStructureFormatWrapper