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.
- amulet/__init__.py +27 -27
- amulet/__pyinstaller/__init__.py +2 -2
- amulet/__pyinstaller/hook-amulet.py +4 -4
- amulet/_version.py +21 -21
- amulet/api/__init__.py +2 -2
- amulet/api/abstract_base_entity.py +128 -128
- amulet/api/block.py +630 -630
- amulet/api/block_entity.py +71 -71
- amulet/api/cache.py +107 -107
- amulet/api/chunk/__init__.py +6 -6
- amulet/api/chunk/biomes.py +207 -207
- amulet/api/chunk/block_entity_dict.py +175 -175
- amulet/api/chunk/blocks.py +46 -46
- amulet/api/chunk/chunk.py +389 -389
- amulet/api/chunk/entity_list.py +75 -75
- amulet/api/chunk/status.py +167 -167
- amulet/api/data_types/__init__.py +4 -4
- amulet/api/data_types/generic_types.py +4 -4
- amulet/api/data_types/operation_types.py +16 -16
- amulet/api/data_types/world_types.py +49 -49
- amulet/api/data_types/wrapper_types.py +71 -71
- amulet/api/entity.py +74 -74
- amulet/api/errors.py +119 -119
- amulet/api/history/__init__.py +36 -36
- amulet/api/history/base/__init__.py +3 -3
- amulet/api/history/base/base_history.py +26 -26
- amulet/api/history/base/history_manager.py +63 -63
- amulet/api/history/base/revision_manager.py +73 -73
- amulet/api/history/changeable.py +15 -15
- amulet/api/history/data_types.py +7 -7
- amulet/api/history/history_manager/__init__.py +3 -3
- amulet/api/history/history_manager/container.py +102 -102
- amulet/api/history/history_manager/database.py +279 -279
- amulet/api/history/history_manager/meta.py +93 -93
- amulet/api/history/history_manager/object.py +116 -116
- amulet/api/history/revision_manager/__init__.py +2 -2
- amulet/api/history/revision_manager/disk.py +33 -33
- amulet/api/history/revision_manager/ram.py +12 -12
- amulet/api/item.py +75 -75
- amulet/api/level/__init__.py +4 -4
- amulet/api/level/base_level/__init__.py +1 -1
- amulet/api/level/base_level/base_level.py +1035 -1026
- amulet/api/level/base_level/chunk_manager.py +227 -227
- amulet/api/level/base_level/clone.py +389 -389
- amulet/api/level/base_level/player_manager.py +101 -101
- amulet/api/level/immutable_structure/__init__.py +1 -1
- amulet/api/level/immutable_structure/immutable_structure.py +94 -94
- amulet/api/level/immutable_structure/void_format_wrapper.py +117 -117
- amulet/api/level/structure.py +22 -22
- amulet/api/level/world.py +19 -19
- amulet/api/partial_3d_array/__init__.py +2 -2
- amulet/api/partial_3d_array/base_partial_3d_array.py +263 -263
- amulet/api/partial_3d_array/bounded_partial_3d_array.py +528 -528
- amulet/api/partial_3d_array/data_types.py +15 -15
- amulet/api/partial_3d_array/unbounded_partial_3d_array.py +229 -229
- amulet/api/partial_3d_array/util.py +152 -152
- amulet/api/player.py +65 -65
- amulet/api/registry/__init__.py +2 -2
- amulet/api/registry/base_registry.py +34 -34
- amulet/api/registry/biome_manager.py +153 -153
- amulet/api/registry/block_manager.py +156 -156
- amulet/api/selection/__init__.py +2 -2
- amulet/api/selection/abstract_selection.py +315 -315
- amulet/api/selection/box.py +805 -805
- amulet/api/selection/group.py +488 -488
- amulet/api/structure.py +37 -37
- amulet/api/wrapper/__init__.py +8 -8
- amulet/api/wrapper/chunk/interface.py +441 -441
- amulet/api/wrapper/chunk/translator.py +567 -567
- amulet/api/wrapper/format_wrapper.py +772 -772
- amulet/api/wrapper/structure_format_wrapper.py +116 -116
- amulet/api/wrapper/world_format_wrapper.py +63 -63
- amulet/level/__init__.py +1 -1
- amulet/level/formats/anvil_forge_world.py +40 -40
- amulet/level/formats/anvil_world/__init__.py +3 -3
- amulet/level/formats/anvil_world/_sector_manager.py +291 -384
- amulet/level/formats/anvil_world/data_pack/__init__.py +2 -2
- amulet/level/formats/anvil_world/data_pack/data_pack.py +224 -224
- amulet/level/formats/anvil_world/data_pack/data_pack_manager.py +77 -77
- amulet/level/formats/anvil_world/dimension.py +177 -177
- amulet/level/formats/anvil_world/format.py +769 -769
- amulet/level/formats/anvil_world/region.py +384 -384
- amulet/level/formats/construction/__init__.py +3 -3
- amulet/level/formats/construction/format_wrapper.py +515 -515
- amulet/level/formats/construction/interface.py +134 -134
- amulet/level/formats/construction/section.py +60 -60
- amulet/level/formats/construction/util.py +165 -165
- amulet/level/formats/leveldb_world/__init__.py +3 -3
- amulet/level/formats/leveldb_world/chunk.py +33 -33
- amulet/level/formats/leveldb_world/dimension.py +385 -419
- amulet/level/formats/leveldb_world/format.py +659 -641
- amulet/level/formats/leveldb_world/interface/chunk/__init__.py +36 -36
- amulet/level/formats/leveldb_world/interface/chunk/base_leveldb_interface.py +836 -836
- amulet/level/formats/leveldb_world/interface/chunk/generate_interface.py +31 -31
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_0.py +30 -30
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_1.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_10.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_11.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_12.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_13.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_14.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_15.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_16.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_17.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_18.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_19.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_2.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_20.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_21.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_22.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_23.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_24.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_25.py +24 -24
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_26.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_27.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_28.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_29.py +33 -33
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_3.py +57 -57
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_30.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_31.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_32.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_33.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_34.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_35.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_36.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_37.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_38.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_39.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_4.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_40.py +16 -16
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_5.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_6.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_7.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_8.py +180 -180
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_9.py +18 -18
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_chunk_versions.py +79 -79
- amulet/level/formats/mcstructure/__init__.py +3 -3
- amulet/level/formats/mcstructure/chunk.py +50 -50
- amulet/level/formats/mcstructure/format_wrapper.py +408 -408
- amulet/level/formats/mcstructure/interface.py +175 -175
- amulet/level/formats/schematic/__init__.py +3 -3
- amulet/level/formats/schematic/chunk.py +55 -55
- amulet/level/formats/schematic/data_types.py +4 -4
- amulet/level/formats/schematic/format_wrapper.py +373 -373
- amulet/level/formats/schematic/interface.py +142 -142
- amulet/level/formats/sponge_schem/__init__.py +4 -4
- amulet/level/formats/sponge_schem/chunk.py +62 -62
- amulet/level/formats/sponge_schem/format_wrapper.py +463 -463
- amulet/level/formats/sponge_schem/interface.py +118 -118
- amulet/level/formats/sponge_schem/varint/__init__.py +1 -1
- amulet/level/formats/sponge_schem/varint/varint.py +87 -87
- amulet/level/interfaces/chunk/anvil/anvil_0.py +72 -72
- amulet/level/interfaces/chunk/anvil/anvil_1444.py +336 -336
- amulet/level/interfaces/chunk/anvil/anvil_1466.py +94 -94
- amulet/level/interfaces/chunk/anvil/anvil_1467.py +37 -37
- amulet/level/interfaces/chunk/anvil/anvil_1484.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1503.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1519.py +34 -34
- amulet/level/interfaces/chunk/anvil/anvil_1901.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1908.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1912.py +21 -21
- amulet/level/interfaces/chunk/anvil/anvil_1934.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_2203.py +69 -69
- amulet/level/interfaces/chunk/anvil/anvil_2529.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_2681.py +76 -76
- amulet/level/interfaces/chunk/anvil/anvil_2709.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_2844.py +267 -267
- amulet/level/interfaces/chunk/anvil/anvil_3463.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_na.py +607 -607
- amulet/level/interfaces/chunk/anvil/base_anvil_interface.py +326 -326
- amulet/level/load.py +59 -59
- amulet/level/loader.py +95 -95
- amulet/level/translators/chunk/bedrock/__init__.py +267 -267
- amulet/level/translators/chunk/bedrock/bedrock_nbt_blockstate_translator.py +46 -46
- amulet/level/translators/chunk/bedrock/bedrock_numerical_translator.py +39 -39
- amulet/level/translators/chunk/bedrock/bedrock_psudo_numerical_translator.py +37 -37
- amulet/level/translators/chunk/java/java_1_18_translator.py +40 -40
- amulet/level/translators/chunk/java/java_blockstate_translator.py +94 -94
- amulet/level/translators/chunk/java/java_numerical_translator.py +62 -62
- amulet/libs/leveldb/__init__.py +7 -7
- amulet/operations/__init__.py +5 -5
- amulet/operations/clone.py +18 -18
- amulet/operations/delete_chunk.py +32 -32
- amulet/operations/fill.py +30 -30
- amulet/operations/paste.py +65 -65
- amulet/operations/replace.py +58 -58
- amulet/utils/__init__.py +14 -14
- amulet/utils/format_utils.py +41 -41
- amulet/utils/generator.py +15 -15
- amulet/utils/matrix.py +243 -243
- amulet/utils/numpy_helpers.py +46 -46
- amulet/utils/world_utils.py +349 -349
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/METADATA +97 -97
- amulet_core-1.9.20.dist-info/RECORD +208 -0
- amulet_core-1.9.19.dist-info/RECORD +0 -208
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/WHEEL +0 -0
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/entry_points.txt +0 -0
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/top_level.txt +0 -0
|
@@ -1,267 +1,267 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
from typing import Tuple, Dict, Optional
|
|
3
|
-
import numpy
|
|
4
|
-
|
|
5
|
-
from amulet_nbt import (
|
|
6
|
-
CompoundTag,
|
|
7
|
-
ListTag,
|
|
8
|
-
ByteTag,
|
|
9
|
-
IntTag,
|
|
10
|
-
LongTag,
|
|
11
|
-
LongArrayTag,
|
|
12
|
-
StringTag,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
from amulet.api.chunk import Chunk
|
|
16
|
-
from amulet.api.registry import BiomeManager
|
|
17
|
-
from amulet.api.data_types import AnyNDArray, BiomeType
|
|
18
|
-
from amulet.utils.world_utils import (
|
|
19
|
-
decode_long_array,
|
|
20
|
-
encode_long_array,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
from .base_anvil_interface import (
|
|
24
|
-
ChunkDataType,
|
|
25
|
-
ChunkPathType,
|
|
26
|
-
)
|
|
27
|
-
from .anvil_2709 import (
|
|
28
|
-
Anvil2709Interface as ParentInterface,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class Anvil2844Interface(ParentInterface):
|
|
33
|
-
"""
|
|
34
|
-
Note that some of these changes happened in earlier snapshots
|
|
35
|
-
Chunk restructuring
|
|
36
|
-
Contents of Level tag moved into root
|
|
37
|
-
Some tags renamed from PascalCase to snake_case
|
|
38
|
-
2844
|
|
39
|
-
Level.Entities -> entities.
|
|
40
|
-
Level.TileEntities -> block_entities.
|
|
41
|
-
Level.TileTicks and Level.ToBeTicked have moved to block_ticks.
|
|
42
|
-
Level.LiquidTicks and Level.LiquidsToBeTicked have moved to fluid_ticks.
|
|
43
|
-
Level.Sections -> sections.
|
|
44
|
-
Level.Structures -> structures.
|
|
45
|
-
Level.Structures.Starts -> structures.starts.
|
|
46
|
-
Level.Sections[].block_states -> sections[].block_states.
|
|
47
|
-
Level.Sections[].biomes -> sections[].biomes
|
|
48
|
-
Added yPos the minimum section y position in the chunk.
|
|
49
|
-
Added below_zero_retrogen containing data to support below zero generation.
|
|
50
|
-
Added blending_data containing data to support blending new world generation with existing chunks.
|
|
51
|
-
2836
|
|
52
|
-
Level.Sections[].BlockStates & Level.Sections[].Palette -> Level.Sections[].block_states.
|
|
53
|
-
Level.Biomes -> Level.Sections[].biomes.
|
|
54
|
-
Level.CarvingMasks[] is now long[] instead of byte[].
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
OldLevel: ChunkPathType = ("region", [("Level", CompoundTag)], CompoundTag)
|
|
58
|
-
Level: ChunkPathType = ("region", [], CompoundTag)
|
|
59
|
-
Sections: ChunkPathType = ("region", [("sections", ListTag)], ListTag)
|
|
60
|
-
|
|
61
|
-
Entities: ChunkPathType = ("region", [("entities", ListTag)], ListTag)
|
|
62
|
-
BlockEntities: ChunkPathType = ("region", [("block_entities", ListTag)], ListTag)
|
|
63
|
-
BlockTicks: ChunkPathType = ("region", [("block_ticks", ListTag)], ListTag)
|
|
64
|
-
ToBeTicked = None
|
|
65
|
-
LiquidTicks: ChunkPathType = ("region", [("fluid_ticks", ListTag)], ListTag)
|
|
66
|
-
LiquidsToBeTicked = None
|
|
67
|
-
Structures: ChunkPathType = ("region", [("structures", CompoundTag)], CompoundTag)
|
|
68
|
-
yPos: ChunkPathType = ("region", [("yPos", IntTag)], IntTag)
|
|
69
|
-
Biomes = None
|
|
70
|
-
|
|
71
|
-
# Changed attributes not listed on the wiki
|
|
72
|
-
xPos: ChunkPathType = ("region", [("xPos", IntTag)], IntTag)
|
|
73
|
-
zPos: ChunkPathType = ("region", [("zPos", IntTag)], IntTag)
|
|
74
|
-
LastUpdate: ChunkPathType = ("region", [("LastUpdate", LongTag)], LongTag)
|
|
75
|
-
InhabitedTime: ChunkPathType = ("region", [("InhabitedTime", LongTag)], LongTag)
|
|
76
|
-
Status: ChunkPathType = ("region", [("Status", StringTag)], StringTag("full"))
|
|
77
|
-
PostProcessing: ChunkPathType = ("region", [("PostProcessing", ListTag)], ListTag)
|
|
78
|
-
Heightmaps: ChunkPathType = ("region", [("Heightmaps", CompoundTag)], CompoundTag)
|
|
79
|
-
|
|
80
|
-
def __init__(self):
|
|
81
|
-
super().__init__()
|
|
82
|
-
self._register_post_encoder(self._post_encode_remove_old_level)
|
|
83
|
-
|
|
84
|
-
@staticmethod
|
|
85
|
-
def minor_is_valid(key: int):
|
|
86
|
-
return 2844 <= key <= 3337
|
|
87
|
-
|
|
88
|
-
def _get_floor_cy(self, data: ChunkDataType):
|
|
89
|
-
return self.get_layer_obj(data, self.yPos, pop_last=True).py_int
|
|
90
|
-
|
|
91
|
-
def _decode_block_section(
|
|
92
|
-
self, section: CompoundTag
|
|
93
|
-
) -> Optional[Tuple[numpy.ndarray, list]]:
|
|
94
|
-
block_states = self.get_obj(section, "block_states", CompoundTag)
|
|
95
|
-
if (
|
|
96
|
-
isinstance(block_states, CompoundTag) and "palette" in block_states
|
|
97
|
-
): # 1.14 makes block_palette/blocks optional.
|
|
98
|
-
section_palette = self._decode_block_palette(block_states.pop("palette"))
|
|
99
|
-
data = block_states.pop("data", None)
|
|
100
|
-
if data is None:
|
|
101
|
-
arr = numpy.zeros((16, 16, 16), numpy.uint32)
|
|
102
|
-
else:
|
|
103
|
-
decoded = decode_long_array(
|
|
104
|
-
data.np_array,
|
|
105
|
-
16**3,
|
|
106
|
-
max(4, (len(section_palette) - 1).bit_length()),
|
|
107
|
-
dense=self.LongArrayDense,
|
|
108
|
-
).astype(numpy.uint32)
|
|
109
|
-
arr = numpy.transpose(decoded.reshape((16, 16, 16)), (2, 0, 1))
|
|
110
|
-
return arr, section_palette
|
|
111
|
-
else:
|
|
112
|
-
return None
|
|
113
|
-
|
|
114
|
-
@staticmethod
|
|
115
|
-
def _decode_biome_palette(palette: ListTag) -> list[BiomeType]:
|
|
116
|
-
return [entry.py_data for entry in palette]
|
|
117
|
-
|
|
118
|
-
def _decode_biome_section(
|
|
119
|
-
self, section: CompoundTag
|
|
120
|
-
) -> Optional[Tuple[numpy.ndarray, list]]:
|
|
121
|
-
biomes = self.get_obj(section, "biomes", CompoundTag)
|
|
122
|
-
if isinstance(biomes, CompoundTag) and "palette" in biomes:
|
|
123
|
-
section_palette = self._decode_biome_palette(biomes.pop("palette"))
|
|
124
|
-
assert section_palette, "Biome palette cannot be empty"
|
|
125
|
-
data = biomes.pop("data", None)
|
|
126
|
-
if data is None:
|
|
127
|
-
# case 1: palette contains one value and data does not exist (undefined zero array)
|
|
128
|
-
# TODO: in the new biome system just leave this as the number
|
|
129
|
-
arr = numpy.zeros((4, 4, 4), numpy.uint32)
|
|
130
|
-
else:
|
|
131
|
-
# case 2: palette contains values and data is an index array
|
|
132
|
-
arr = numpy.transpose(
|
|
133
|
-
decode_long_array(
|
|
134
|
-
data.np_array,
|
|
135
|
-
4**3,
|
|
136
|
-
max(1, (len(section_palette) - 1).bit_length()),
|
|
137
|
-
dense=self.LongArrayDense,
|
|
138
|
-
)
|
|
139
|
-
.astype(numpy.uint32)
|
|
140
|
-
.reshape((4, 4, 4)),
|
|
141
|
-
(2, 0, 1),
|
|
142
|
-
)
|
|
143
|
-
return arr, section_palette
|
|
144
|
-
else:
|
|
145
|
-
return None
|
|
146
|
-
|
|
147
|
-
def _decode_biomes(
|
|
148
|
-
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
149
|
-
):
|
|
150
|
-
biomes: Dict[int, numpy.ndarray] = {}
|
|
151
|
-
palette = BiomeManager()
|
|
152
|
-
|
|
153
|
-
for cy, section in self._iter_sections(data):
|
|
154
|
-
data = self._decode_biome_section(section)
|
|
155
|
-
if data is not None:
|
|
156
|
-
arr, section_palette = data
|
|
157
|
-
lut = numpy.array(
|
|
158
|
-
[palette.get_add_biome(biome) for biome in section_palette]
|
|
159
|
-
)
|
|
160
|
-
biomes[cy] = lut[arr].astype(numpy.uint32)
|
|
161
|
-
|
|
162
|
-
chunk.biomes = biomes
|
|
163
|
-
chunk.biome_palette = palette
|
|
164
|
-
|
|
165
|
-
def _decode_block_ticks(
|
|
166
|
-
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
167
|
-
):
|
|
168
|
-
chunk.misc.setdefault("block_ticks", {}).update(
|
|
169
|
-
self._decode_ticks(self.get_layer_obj(data, self.BlockTicks, pop_last=True))
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
def _decode_fluid_ticks(
|
|
173
|
-
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
174
|
-
):
|
|
175
|
-
chunk.misc.setdefault("fluid_ticks", {}).update(
|
|
176
|
-
self._decode_ticks(
|
|
177
|
-
self.get_layer_obj(data, self.LiquidTicks, pop_last=True)
|
|
178
|
-
)
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
def _encode_coords(
|
|
182
|
-
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
183
|
-
):
|
|
184
|
-
super()._encode_coords(chunk, data, floor_cy, height_cy)
|
|
185
|
-
self.set_layer_obj(data, self.yPos, IntTag(floor_cy))
|
|
186
|
-
|
|
187
|
-
def _encode_block_section(
|
|
188
|
-
self,
|
|
189
|
-
chunk: Chunk,
|
|
190
|
-
sections: Dict[int, CompoundTag],
|
|
191
|
-
palette: AnyNDArray,
|
|
192
|
-
cy: int,
|
|
193
|
-
):
|
|
194
|
-
block_sub_array = numpy.transpose(
|
|
195
|
-
chunk.blocks.get_sub_chunk(cy), (1, 2, 0)
|
|
196
|
-
).ravel()
|
|
197
|
-
|
|
198
|
-
sub_palette_, block_sub_array = numpy.unique(
|
|
199
|
-
block_sub_array, return_inverse=True
|
|
200
|
-
)
|
|
201
|
-
sub_palette = self._encode_block_palette(palette[sub_palette_])
|
|
202
|
-
section = sections.setdefault(cy, CompoundTag())
|
|
203
|
-
block_states = section["block_states"] = CompoundTag({"palette": sub_palette})
|
|
204
|
-
if len(sub_palette) != 1:
|
|
205
|
-
block_states["data"] = LongArrayTag(
|
|
206
|
-
encode_long_array(
|
|
207
|
-
block_sub_array, dense=self.LongArrayDense, min_bits_per_entry=4
|
|
208
|
-
)
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
@staticmethod
|
|
212
|
-
def _encode_biome_palette(palette: list[BiomeType]) -> ListTag:
|
|
213
|
-
return ListTag([StringTag(entry) for entry in palette])
|
|
214
|
-
|
|
215
|
-
def _encode_biome_section(
|
|
216
|
-
self,
|
|
217
|
-
chunk: Chunk,
|
|
218
|
-
sections: Dict[int, CompoundTag],
|
|
219
|
-
cy: int,
|
|
220
|
-
):
|
|
221
|
-
biome_sub_array = numpy.transpose(
|
|
222
|
-
chunk.biomes.get_section(cy), (1, 2, 0)
|
|
223
|
-
).ravel()
|
|
224
|
-
|
|
225
|
-
sub_palette_, biome_sub_array = numpy.unique(
|
|
226
|
-
biome_sub_array, return_inverse=True
|
|
227
|
-
)
|
|
228
|
-
sub_palette = self._encode_biome_palette(chunk.biome_palette[sub_palette_])
|
|
229
|
-
biomes = sections[cy]["biomes"] = CompoundTag({"palette": sub_palette})
|
|
230
|
-
if len(sub_palette) != 1:
|
|
231
|
-
biomes["data"] = LongArrayTag(
|
|
232
|
-
encode_long_array(biome_sub_array, dense=self.LongArrayDense)
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
def _encode_biomes(
|
|
236
|
-
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
237
|
-
):
|
|
238
|
-
sections = self._get_encode_sections(data, floor_cy, height_cy)
|
|
239
|
-
ceil_cy = floor_cy + height_cy
|
|
240
|
-
chunk.biomes.convert_to_3d()
|
|
241
|
-
for cy in chunk.biomes.sections:
|
|
242
|
-
if floor_cy <= cy < ceil_cy:
|
|
243
|
-
self._encode_biome_section(chunk, sections, cy)
|
|
244
|
-
|
|
245
|
-
def _encode_block_ticks(
|
|
246
|
-
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
247
|
-
):
|
|
248
|
-
self.set_layer_obj(
|
|
249
|
-
data, self.BlockTicks, self._encode_ticks(chunk.misc.get("block_ticks", {}))
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
def _encode_fluid_ticks(
|
|
253
|
-
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
254
|
-
):
|
|
255
|
-
self.set_layer_obj(
|
|
256
|
-
data,
|
|
257
|
-
self.LiquidTicks,
|
|
258
|
-
self._encode_ticks(chunk.misc.get("fluid_ticks", {})),
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
def _post_encode_remove_old_level(
|
|
262
|
-
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
263
|
-
):
|
|
264
|
-
self.get_layer_obj(data, self.OldLevel, pop_last=True)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
export = Anvil2844Interface
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Tuple, Dict, Optional
|
|
3
|
+
import numpy
|
|
4
|
+
|
|
5
|
+
from amulet_nbt import (
|
|
6
|
+
CompoundTag,
|
|
7
|
+
ListTag,
|
|
8
|
+
ByteTag,
|
|
9
|
+
IntTag,
|
|
10
|
+
LongTag,
|
|
11
|
+
LongArrayTag,
|
|
12
|
+
StringTag,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from amulet.api.chunk import Chunk
|
|
16
|
+
from amulet.api.registry import BiomeManager
|
|
17
|
+
from amulet.api.data_types import AnyNDArray, BiomeType
|
|
18
|
+
from amulet.utils.world_utils import (
|
|
19
|
+
decode_long_array,
|
|
20
|
+
encode_long_array,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from .base_anvil_interface import (
|
|
24
|
+
ChunkDataType,
|
|
25
|
+
ChunkPathType,
|
|
26
|
+
)
|
|
27
|
+
from .anvil_2709 import (
|
|
28
|
+
Anvil2709Interface as ParentInterface,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Anvil2844Interface(ParentInterface):
|
|
33
|
+
"""
|
|
34
|
+
Note that some of these changes happened in earlier snapshots
|
|
35
|
+
Chunk restructuring
|
|
36
|
+
Contents of Level tag moved into root
|
|
37
|
+
Some tags renamed from PascalCase to snake_case
|
|
38
|
+
2844
|
|
39
|
+
Level.Entities -> entities.
|
|
40
|
+
Level.TileEntities -> block_entities.
|
|
41
|
+
Level.TileTicks and Level.ToBeTicked have moved to block_ticks.
|
|
42
|
+
Level.LiquidTicks and Level.LiquidsToBeTicked have moved to fluid_ticks.
|
|
43
|
+
Level.Sections -> sections.
|
|
44
|
+
Level.Structures -> structures.
|
|
45
|
+
Level.Structures.Starts -> structures.starts.
|
|
46
|
+
Level.Sections[].block_states -> sections[].block_states.
|
|
47
|
+
Level.Sections[].biomes -> sections[].biomes
|
|
48
|
+
Added yPos the minimum section y position in the chunk.
|
|
49
|
+
Added below_zero_retrogen containing data to support below zero generation.
|
|
50
|
+
Added blending_data containing data to support blending new world generation with existing chunks.
|
|
51
|
+
2836
|
|
52
|
+
Level.Sections[].BlockStates & Level.Sections[].Palette -> Level.Sections[].block_states.
|
|
53
|
+
Level.Biomes -> Level.Sections[].biomes.
|
|
54
|
+
Level.CarvingMasks[] is now long[] instead of byte[].
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
OldLevel: ChunkPathType = ("region", [("Level", CompoundTag)], CompoundTag)
|
|
58
|
+
Level: ChunkPathType = ("region", [], CompoundTag)
|
|
59
|
+
Sections: ChunkPathType = ("region", [("sections", ListTag)], ListTag)
|
|
60
|
+
|
|
61
|
+
Entities: ChunkPathType = ("region", [("entities", ListTag)], ListTag)
|
|
62
|
+
BlockEntities: ChunkPathType = ("region", [("block_entities", ListTag)], ListTag)
|
|
63
|
+
BlockTicks: ChunkPathType = ("region", [("block_ticks", ListTag)], ListTag)
|
|
64
|
+
ToBeTicked = None
|
|
65
|
+
LiquidTicks: ChunkPathType = ("region", [("fluid_ticks", ListTag)], ListTag)
|
|
66
|
+
LiquidsToBeTicked = None
|
|
67
|
+
Structures: ChunkPathType = ("region", [("structures", CompoundTag)], CompoundTag)
|
|
68
|
+
yPos: ChunkPathType = ("region", [("yPos", IntTag)], IntTag)
|
|
69
|
+
Biomes = None
|
|
70
|
+
|
|
71
|
+
# Changed attributes not listed on the wiki
|
|
72
|
+
xPos: ChunkPathType = ("region", [("xPos", IntTag)], IntTag)
|
|
73
|
+
zPos: ChunkPathType = ("region", [("zPos", IntTag)], IntTag)
|
|
74
|
+
LastUpdate: ChunkPathType = ("region", [("LastUpdate", LongTag)], LongTag)
|
|
75
|
+
InhabitedTime: ChunkPathType = ("region", [("InhabitedTime", LongTag)], LongTag)
|
|
76
|
+
Status: ChunkPathType = ("region", [("Status", StringTag)], StringTag("full"))
|
|
77
|
+
PostProcessing: ChunkPathType = ("region", [("PostProcessing", ListTag)], ListTag)
|
|
78
|
+
Heightmaps: ChunkPathType = ("region", [("Heightmaps", CompoundTag)], CompoundTag)
|
|
79
|
+
|
|
80
|
+
def __init__(self):
|
|
81
|
+
super().__init__()
|
|
82
|
+
self._register_post_encoder(self._post_encode_remove_old_level)
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def minor_is_valid(key: int):
|
|
86
|
+
return 2844 <= key <= 3337
|
|
87
|
+
|
|
88
|
+
def _get_floor_cy(self, data: ChunkDataType):
|
|
89
|
+
return self.get_layer_obj(data, self.yPos, pop_last=True).py_int
|
|
90
|
+
|
|
91
|
+
def _decode_block_section(
|
|
92
|
+
self, section: CompoundTag
|
|
93
|
+
) -> Optional[Tuple[numpy.ndarray, list]]:
|
|
94
|
+
block_states = self.get_obj(section, "block_states", CompoundTag)
|
|
95
|
+
if (
|
|
96
|
+
isinstance(block_states, CompoundTag) and "palette" in block_states
|
|
97
|
+
): # 1.14 makes block_palette/blocks optional.
|
|
98
|
+
section_palette = self._decode_block_palette(block_states.pop("palette"))
|
|
99
|
+
data = block_states.pop("data", None)
|
|
100
|
+
if data is None:
|
|
101
|
+
arr = numpy.zeros((16, 16, 16), numpy.uint32)
|
|
102
|
+
else:
|
|
103
|
+
decoded = decode_long_array(
|
|
104
|
+
data.np_array,
|
|
105
|
+
16**3,
|
|
106
|
+
max(4, (len(section_palette) - 1).bit_length()),
|
|
107
|
+
dense=self.LongArrayDense,
|
|
108
|
+
).astype(numpy.uint32)
|
|
109
|
+
arr = numpy.transpose(decoded.reshape((16, 16, 16)), (2, 0, 1))
|
|
110
|
+
return arr, section_palette
|
|
111
|
+
else:
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def _decode_biome_palette(palette: ListTag) -> list[BiomeType]:
|
|
116
|
+
return [entry.py_data for entry in palette]
|
|
117
|
+
|
|
118
|
+
def _decode_biome_section(
|
|
119
|
+
self, section: CompoundTag
|
|
120
|
+
) -> Optional[Tuple[numpy.ndarray, list]]:
|
|
121
|
+
biomes = self.get_obj(section, "biomes", CompoundTag)
|
|
122
|
+
if isinstance(biomes, CompoundTag) and "palette" in biomes:
|
|
123
|
+
section_palette = self._decode_biome_palette(biomes.pop("palette"))
|
|
124
|
+
assert section_palette, "Biome palette cannot be empty"
|
|
125
|
+
data = biomes.pop("data", None)
|
|
126
|
+
if data is None:
|
|
127
|
+
# case 1: palette contains one value and data does not exist (undefined zero array)
|
|
128
|
+
# TODO: in the new biome system just leave this as the number
|
|
129
|
+
arr = numpy.zeros((4, 4, 4), numpy.uint32)
|
|
130
|
+
else:
|
|
131
|
+
# case 2: palette contains values and data is an index array
|
|
132
|
+
arr = numpy.transpose(
|
|
133
|
+
decode_long_array(
|
|
134
|
+
data.np_array,
|
|
135
|
+
4**3,
|
|
136
|
+
max(1, (len(section_palette) - 1).bit_length()),
|
|
137
|
+
dense=self.LongArrayDense,
|
|
138
|
+
)
|
|
139
|
+
.astype(numpy.uint32)
|
|
140
|
+
.reshape((4, 4, 4)),
|
|
141
|
+
(2, 0, 1),
|
|
142
|
+
)
|
|
143
|
+
return arr, section_palette
|
|
144
|
+
else:
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
def _decode_biomes(
|
|
148
|
+
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
149
|
+
):
|
|
150
|
+
biomes: Dict[int, numpy.ndarray] = {}
|
|
151
|
+
palette = BiomeManager()
|
|
152
|
+
|
|
153
|
+
for cy, section in self._iter_sections(data):
|
|
154
|
+
data = self._decode_biome_section(section)
|
|
155
|
+
if data is not None:
|
|
156
|
+
arr, section_palette = data
|
|
157
|
+
lut = numpy.array(
|
|
158
|
+
[palette.get_add_biome(biome) for biome in section_palette]
|
|
159
|
+
)
|
|
160
|
+
biomes[cy] = lut[arr].astype(numpy.uint32)
|
|
161
|
+
|
|
162
|
+
chunk.biomes = biomes
|
|
163
|
+
chunk.biome_palette = palette
|
|
164
|
+
|
|
165
|
+
def _decode_block_ticks(
|
|
166
|
+
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
167
|
+
):
|
|
168
|
+
chunk.misc.setdefault("block_ticks", {}).update(
|
|
169
|
+
self._decode_ticks(self.get_layer_obj(data, self.BlockTicks, pop_last=True))
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def _decode_fluid_ticks(
|
|
173
|
+
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
174
|
+
):
|
|
175
|
+
chunk.misc.setdefault("fluid_ticks", {}).update(
|
|
176
|
+
self._decode_ticks(
|
|
177
|
+
self.get_layer_obj(data, self.LiquidTicks, pop_last=True)
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
def _encode_coords(
|
|
182
|
+
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
183
|
+
):
|
|
184
|
+
super()._encode_coords(chunk, data, floor_cy, height_cy)
|
|
185
|
+
self.set_layer_obj(data, self.yPos, IntTag(floor_cy))
|
|
186
|
+
|
|
187
|
+
def _encode_block_section(
|
|
188
|
+
self,
|
|
189
|
+
chunk: Chunk,
|
|
190
|
+
sections: Dict[int, CompoundTag],
|
|
191
|
+
palette: AnyNDArray,
|
|
192
|
+
cy: int,
|
|
193
|
+
):
|
|
194
|
+
block_sub_array = numpy.transpose(
|
|
195
|
+
chunk.blocks.get_sub_chunk(cy), (1, 2, 0)
|
|
196
|
+
).ravel()
|
|
197
|
+
|
|
198
|
+
sub_palette_, block_sub_array = numpy.unique(
|
|
199
|
+
block_sub_array, return_inverse=True
|
|
200
|
+
)
|
|
201
|
+
sub_palette = self._encode_block_palette(palette[sub_palette_])
|
|
202
|
+
section = sections.setdefault(cy, CompoundTag())
|
|
203
|
+
block_states = section["block_states"] = CompoundTag({"palette": sub_palette})
|
|
204
|
+
if len(sub_palette) != 1:
|
|
205
|
+
block_states["data"] = LongArrayTag(
|
|
206
|
+
encode_long_array(
|
|
207
|
+
block_sub_array, dense=self.LongArrayDense, min_bits_per_entry=4
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
@staticmethod
|
|
212
|
+
def _encode_biome_palette(palette: list[BiomeType]) -> ListTag:
|
|
213
|
+
return ListTag([StringTag(entry) for entry in palette])
|
|
214
|
+
|
|
215
|
+
def _encode_biome_section(
|
|
216
|
+
self,
|
|
217
|
+
chunk: Chunk,
|
|
218
|
+
sections: Dict[int, CompoundTag],
|
|
219
|
+
cy: int,
|
|
220
|
+
):
|
|
221
|
+
biome_sub_array = numpy.transpose(
|
|
222
|
+
chunk.biomes.get_section(cy), (1, 2, 0)
|
|
223
|
+
).ravel()
|
|
224
|
+
|
|
225
|
+
sub_palette_, biome_sub_array = numpy.unique(
|
|
226
|
+
biome_sub_array, return_inverse=True
|
|
227
|
+
)
|
|
228
|
+
sub_palette = self._encode_biome_palette(chunk.biome_palette[sub_palette_])
|
|
229
|
+
biomes = sections[cy]["biomes"] = CompoundTag({"palette": sub_palette})
|
|
230
|
+
if len(sub_palette) != 1:
|
|
231
|
+
biomes["data"] = LongArrayTag(
|
|
232
|
+
encode_long_array(biome_sub_array, dense=self.LongArrayDense)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def _encode_biomes(
|
|
236
|
+
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
237
|
+
):
|
|
238
|
+
sections = self._get_encode_sections(data, floor_cy, height_cy)
|
|
239
|
+
ceil_cy = floor_cy + height_cy
|
|
240
|
+
chunk.biomes.convert_to_3d()
|
|
241
|
+
for cy in chunk.biomes.sections:
|
|
242
|
+
if floor_cy <= cy < ceil_cy:
|
|
243
|
+
self._encode_biome_section(chunk, sections, cy)
|
|
244
|
+
|
|
245
|
+
def _encode_block_ticks(
|
|
246
|
+
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
247
|
+
):
|
|
248
|
+
self.set_layer_obj(
|
|
249
|
+
data, self.BlockTicks, self._encode_ticks(chunk.misc.get("block_ticks", {}))
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def _encode_fluid_ticks(
|
|
253
|
+
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
254
|
+
):
|
|
255
|
+
self.set_layer_obj(
|
|
256
|
+
data,
|
|
257
|
+
self.LiquidTicks,
|
|
258
|
+
self._encode_ticks(chunk.misc.get("fluid_ticks", {})),
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
def _post_encode_remove_old_level(
|
|
262
|
+
self, chunk: Chunk, data: ChunkDataType, floor_cy: int, height_cy: int
|
|
263
|
+
):
|
|
264
|
+
self.get_layer_obj(data, self.OldLevel, pop_last=True)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
export = Anvil2844Interface
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from .anvil_2844 import (
|
|
4
|
-
Anvil2844Interface as ParentInterface,
|
|
5
|
-
)
|
|
6
|
-
from amulet.api.chunk import StatusFormats
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Anvil3463Interface(ParentInterface):
|
|
10
|
-
def __init__(self):
|
|
11
|
-
super().__init__()
|
|
12
|
-
self._set_feature("status", StatusFormats.Java_20)
|
|
13
|
-
|
|
14
|
-
@staticmethod
|
|
15
|
-
def minor_is_valid(key: int):
|
|
16
|
-
return 3454 <= key < 3580
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export = Anvil3463Interface
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from .anvil_2844 import (
|
|
4
|
+
Anvil2844Interface as ParentInterface,
|
|
5
|
+
)
|
|
6
|
+
from amulet.api.chunk import StatusFormats
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Anvil3463Interface(ParentInterface):
|
|
10
|
+
def __init__(self):
|
|
11
|
+
super().__init__()
|
|
12
|
+
self._set_feature("status", StatusFormats.Java_20)
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def minor_is_valid(key: int):
|
|
16
|
+
return 3454 <= key < 3580
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export = Anvil3463Interface
|