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,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
|