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,567 +1,567 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Tuple, Optional, TYPE_CHECKING
|
|
4
|
-
import copy
|
|
5
|
-
import math
|
|
6
|
-
import logging
|
|
7
|
-
|
|
8
|
-
import numpy
|
|
9
|
-
|
|
10
|
-
from amulet import entity_support
|
|
11
|
-
from amulet.api.registry import BlockManager, BiomeManager
|
|
12
|
-
from amulet.api.block import Block
|
|
13
|
-
from amulet.api.block_entity import BlockEntity
|
|
14
|
-
from amulet.api.entity import Entity
|
|
15
|
-
from amulet.api.chunk import Chunk, BiomesShape
|
|
16
|
-
from amulet.api.data_types import (
|
|
17
|
-
AnyNDArray,
|
|
18
|
-
BlockNDArray,
|
|
19
|
-
BlockCoordinates,
|
|
20
|
-
GetChunkCallback,
|
|
21
|
-
TranslateBlockCallback,
|
|
22
|
-
TranslateEntityCallback,
|
|
23
|
-
GetBlockCallback,
|
|
24
|
-
TranslateBlockCallbackReturn,
|
|
25
|
-
TranslateEntityCallbackReturn,
|
|
26
|
-
VersionNumberAny,
|
|
27
|
-
VersionIdentifierType,
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
log = logging.getLogger(__name__)
|
|
31
|
-
|
|
32
|
-
if TYPE_CHECKING:
|
|
33
|
-
from PyMCTranslate import Version, TranslationManager
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class Translator:
|
|
37
|
-
def translator_key(self, version_number: VersionNumberAny) -> VersionIdentifierType:
|
|
38
|
-
return self._translator_key(version_number)
|
|
39
|
-
|
|
40
|
-
def _translator_key(
|
|
41
|
-
self, version_number: VersionNumberAny
|
|
42
|
-
) -> VersionIdentifierType:
|
|
43
|
-
"""
|
|
44
|
-
Return the version key for PyMCTranslate
|
|
45
|
-
|
|
46
|
-
:return: The tuple version key for PyMCTranslate
|
|
47
|
-
"""
|
|
48
|
-
raise NotImplementedError
|
|
49
|
-
|
|
50
|
-
@staticmethod
|
|
51
|
-
def is_valid(key: Tuple) -> bool:
|
|
52
|
-
"""
|
|
53
|
-
Returns whether this translator is able to translate the chunk type with a given identifier key,
|
|
54
|
-
generated by the decoder.
|
|
55
|
-
|
|
56
|
-
:param key: The key who's decodability needs to be checked.
|
|
57
|
-
:return: True if this translator is able to translate the chunk type associated with the key, False otherwise.
|
|
58
|
-
"""
|
|
59
|
-
raise NotImplementedError
|
|
60
|
-
|
|
61
|
-
@staticmethod
|
|
62
|
-
def _translate(
|
|
63
|
-
chunk: Chunk,
|
|
64
|
-
get_chunk_callback: Optional[GetChunkCallback],
|
|
65
|
-
translate_block: TranslateBlockCallback,
|
|
66
|
-
translate_entity: TranslateEntityCallback,
|
|
67
|
-
full_translate: bool,
|
|
68
|
-
):
|
|
69
|
-
if full_translate:
|
|
70
|
-
todo = []
|
|
71
|
-
output_block_entities = []
|
|
72
|
-
output_entities = []
|
|
73
|
-
finished = BlockManager()
|
|
74
|
-
palette_mappings = {}
|
|
75
|
-
|
|
76
|
-
# translate each block without using the callback
|
|
77
|
-
for i, input_block in enumerate(chunk.block_palette):
|
|
78
|
-
input_block: Block
|
|
79
|
-
(
|
|
80
|
-
output_block,
|
|
81
|
-
output_block_entity,
|
|
82
|
-
output_entity,
|
|
83
|
-
extra,
|
|
84
|
-
) = translate_block(input_block, None, (0, 0, 0))
|
|
85
|
-
if extra and get_chunk_callback:
|
|
86
|
-
todo.append(i)
|
|
87
|
-
elif output_block is not None:
|
|
88
|
-
palette_mappings[i] = finished.get_add_block(output_block)
|
|
89
|
-
if output_block_entity is not None:
|
|
90
|
-
for cy in chunk.blocks.sub_chunks:
|
|
91
|
-
for x, y, z in zip(
|
|
92
|
-
*numpy.where(chunk.blocks.get_sub_chunk(cy) == i)
|
|
93
|
-
):
|
|
94
|
-
output_block_entities.append(
|
|
95
|
-
output_block_entity.new_at_location(
|
|
96
|
-
x + chunk.cx * 16,
|
|
97
|
-
y + cy * 16,
|
|
98
|
-
z + chunk.cz * 16,
|
|
99
|
-
)
|
|
100
|
-
)
|
|
101
|
-
else:
|
|
102
|
-
# TODO: this should only happen if the object is an entity, set the block to air
|
|
103
|
-
pass
|
|
104
|
-
|
|
105
|
-
if output_entity and entity_support:
|
|
106
|
-
for cy in chunk.blocks.sub_chunks:
|
|
107
|
-
for x, y, z in zip(
|
|
108
|
-
*numpy.where(chunk.blocks.get_sub_chunk(cy) == i)
|
|
109
|
-
):
|
|
110
|
-
x += chunk.cx * 16
|
|
111
|
-
y += cy * 16
|
|
112
|
-
z += chunk.cz * 16
|
|
113
|
-
for entity in output_entity:
|
|
114
|
-
e = copy.deepcopy(entity)
|
|
115
|
-
e.location += (x, y, z)
|
|
116
|
-
output_entities.append(e)
|
|
117
|
-
|
|
118
|
-
# re-translate the blocks that require extra information
|
|
119
|
-
block_mappings = {}
|
|
120
|
-
for index in todo:
|
|
121
|
-
for cy in chunk.blocks.sub_chunks:
|
|
122
|
-
for x, y, z in zip(
|
|
123
|
-
*numpy.where(chunk.blocks.get_sub_chunk(cy) == index)
|
|
124
|
-
):
|
|
125
|
-
y += cy * 16
|
|
126
|
-
|
|
127
|
-
def get_block_at(
|
|
128
|
-
pos: BlockCoordinates,
|
|
129
|
-
) -> Tuple[Block, Optional[BlockEntity]]:
|
|
130
|
-
"""Get a block at a location relative to the current block"""
|
|
131
|
-
nonlocal x, y, z, chunk, cy
|
|
132
|
-
|
|
133
|
-
# calculate position relative to chunk base
|
|
134
|
-
dx, dy, dz = pos
|
|
135
|
-
dx += x
|
|
136
|
-
dy += y
|
|
137
|
-
dz += z
|
|
138
|
-
|
|
139
|
-
abs_x = dx + chunk.cx * 16
|
|
140
|
-
abs_y = dy
|
|
141
|
-
abs_z = dz + chunk.cz * 16
|
|
142
|
-
|
|
143
|
-
# calculate relative chunk position
|
|
144
|
-
cx = dx // 16
|
|
145
|
-
cz = dz // 16
|
|
146
|
-
if cx == 0 and cz == 0:
|
|
147
|
-
# if it is the current chunk
|
|
148
|
-
block = chunk.block_palette[chunk.blocks[dx, dy, dz]]
|
|
149
|
-
return (
|
|
150
|
-
block,
|
|
151
|
-
chunk.block_entities.get((abs_x, abs_y, abs_z)),
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
# if it is in a different chunk
|
|
155
|
-
local_chunk = get_chunk_callback(cx, cz)
|
|
156
|
-
block = local_chunk.block_palette[
|
|
157
|
-
local_chunk.blocks[dx % 16, dy, dz % 16]
|
|
158
|
-
]
|
|
159
|
-
return (
|
|
160
|
-
block,
|
|
161
|
-
local_chunk.block_entities.get((abs_x, abs_y, abs_z)),
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
input_block = chunk.block_palette[chunk.blocks[x, y, z]]
|
|
165
|
-
(
|
|
166
|
-
output_block,
|
|
167
|
-
output_block_entity,
|
|
168
|
-
output_entity,
|
|
169
|
-
_,
|
|
170
|
-
) = translate_block(
|
|
171
|
-
input_block,
|
|
172
|
-
get_block_at,
|
|
173
|
-
(x + chunk.cx * 16, y, z + chunk.cz * 16),
|
|
174
|
-
)
|
|
175
|
-
if output_block is not None:
|
|
176
|
-
block_mappings[(x, y, z)] = finished.get_add_block(
|
|
177
|
-
output_block
|
|
178
|
-
)
|
|
179
|
-
if output_block_entity is not None:
|
|
180
|
-
output_block_entities.append(
|
|
181
|
-
output_block_entity.new_at_location(
|
|
182
|
-
x + chunk.cx * 16, y, z + chunk.cz * 16
|
|
183
|
-
)
|
|
184
|
-
)
|
|
185
|
-
else:
|
|
186
|
-
# TODO: set the block to air
|
|
187
|
-
pass
|
|
188
|
-
|
|
189
|
-
if output_entity and entity_support:
|
|
190
|
-
for entity in output_entity:
|
|
191
|
-
e = copy.deepcopy(entity)
|
|
192
|
-
e.location += (x, y, z)
|
|
193
|
-
output_entities.append(e)
|
|
194
|
-
|
|
195
|
-
if entity_support:
|
|
196
|
-
for entity in chunk.entities:
|
|
197
|
-
output_block, output_block_entity, output_entity = translate_entity(
|
|
198
|
-
entity
|
|
199
|
-
)
|
|
200
|
-
if output_block is not None:
|
|
201
|
-
block_location = (
|
|
202
|
-
int(math.floor(entity.x)),
|
|
203
|
-
int(math.floor(entity.y)),
|
|
204
|
-
int(math.floor(entity.z)),
|
|
205
|
-
)
|
|
206
|
-
block_mappings[block_location] = output_block
|
|
207
|
-
if output_block_entity:
|
|
208
|
-
output_block_entities.append(
|
|
209
|
-
output_block_entity.new_at_location(*block_location)
|
|
210
|
-
)
|
|
211
|
-
if output_entity:
|
|
212
|
-
for e in output_entity:
|
|
213
|
-
e.location = entity.location
|
|
214
|
-
output_entities.append(e)
|
|
215
|
-
|
|
216
|
-
for cy in chunk.blocks.sub_chunks:
|
|
217
|
-
old_blocks = chunk.blocks.get_sub_chunk(cy)
|
|
218
|
-
new_blocks = numpy.zeros(old_blocks.shape, dtype=old_blocks.dtype)
|
|
219
|
-
for old, new in palette_mappings.items():
|
|
220
|
-
new_blocks[old_blocks == old] = new
|
|
221
|
-
chunk.blocks.add_sub_chunk(cy, new_blocks)
|
|
222
|
-
for (x, y, z), new in block_mappings.items():
|
|
223
|
-
chunk.blocks[x, y, z] = new
|
|
224
|
-
chunk.block_entities = output_block_entities
|
|
225
|
-
chunk.entities = output_entities
|
|
226
|
-
chunk._block_palette = finished
|
|
227
|
-
|
|
228
|
-
def to_universal(
|
|
229
|
-
self,
|
|
230
|
-
chunk_version: VersionNumberAny,
|
|
231
|
-
translation_manager: "TranslationManager",
|
|
232
|
-
chunk: Chunk,
|
|
233
|
-
get_chunk_callback: Optional[GetChunkCallback],
|
|
234
|
-
full_translate: bool,
|
|
235
|
-
) -> Chunk:
|
|
236
|
-
"""
|
|
237
|
-
Translate an interface-specific chunk into the universal format.
|
|
238
|
-
|
|
239
|
-
:param chunk_version: The version number (int or tuple) of the input chunk
|
|
240
|
-
:param translation_manager: TranslationManager used for the translation
|
|
241
|
-
:param chunk: The chunk to translate.
|
|
242
|
-
:param get_chunk_callback: function callback to get a chunk's data
|
|
243
|
-
:param full_translate: if true do a full translate. If false just unpack the block_palette (used in callback)
|
|
244
|
-
:return: Chunk object in the universal format.
|
|
245
|
-
"""
|
|
246
|
-
version = translation_manager.get_version(*self._translator_key(chunk_version))
|
|
247
|
-
self._biomes_to_universal(version, chunk)
|
|
248
|
-
self._blocks_entities_to_universal(
|
|
249
|
-
chunk_version,
|
|
250
|
-
translation_manager,
|
|
251
|
-
chunk,
|
|
252
|
-
get_chunk_callback,
|
|
253
|
-
full_translate,
|
|
254
|
-
)
|
|
255
|
-
return chunk
|
|
256
|
-
|
|
257
|
-
def _blocks_entities_to_universal(
|
|
258
|
-
self,
|
|
259
|
-
chunk_version: VersionNumberAny,
|
|
260
|
-
translation_manager: "TranslationManager",
|
|
261
|
-
chunk: Chunk,
|
|
262
|
-
get_chunk_callback: Optional[GetChunkCallback],
|
|
263
|
-
full_translate: bool,
|
|
264
|
-
):
|
|
265
|
-
version = translation_manager.get_version(*self._translator_key(chunk_version))
|
|
266
|
-
|
|
267
|
-
def translate_block(
|
|
268
|
-
input_object: Block,
|
|
269
|
-
get_block_callback: Optional[GetBlockCallback],
|
|
270
|
-
block_location: BlockCoordinates,
|
|
271
|
-
) -> TranslateBlockCallbackReturn:
|
|
272
|
-
final_block = None
|
|
273
|
-
final_block_entity = None
|
|
274
|
-
final_entities = []
|
|
275
|
-
final_extra = False
|
|
276
|
-
|
|
277
|
-
for depth, block in enumerate(input_object.block_tuple):
|
|
278
|
-
(
|
|
279
|
-
output_object,
|
|
280
|
-
output_block_entity,
|
|
281
|
-
extra,
|
|
282
|
-
) = version.block.to_universal(
|
|
283
|
-
block,
|
|
284
|
-
get_block_callback=get_block_callback,
|
|
285
|
-
block_location=block_location,
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
if isinstance(output_object, Block):
|
|
289
|
-
if not output_object.namespace.startswith("universal"):
|
|
290
|
-
log.debug(
|
|
291
|
-
f"Error translating {input_object.full_blockstate} to universal. Got {output_object.full_blockstate}"
|
|
292
|
-
)
|
|
293
|
-
if final_block is None:
|
|
294
|
-
final_block = output_object
|
|
295
|
-
else:
|
|
296
|
-
final_block += output_object
|
|
297
|
-
if depth == 0:
|
|
298
|
-
final_block_entity = output_block_entity
|
|
299
|
-
|
|
300
|
-
elif isinstance(output_object, Entity):
|
|
301
|
-
final_entities.append(output_object)
|
|
302
|
-
# TODO: offset entity coords
|
|
303
|
-
|
|
304
|
-
final_extra |= extra
|
|
305
|
-
|
|
306
|
-
return final_block, final_block_entity, final_entities, final_extra
|
|
307
|
-
|
|
308
|
-
def translate_entity(input_object: Entity) -> TranslateEntityCallbackReturn:
|
|
309
|
-
final_block = None
|
|
310
|
-
final_block_entity = None
|
|
311
|
-
final_entities = []
|
|
312
|
-
# TODO
|
|
313
|
-
return final_block, final_block_entity, final_entities
|
|
314
|
-
|
|
315
|
-
self._translate(
|
|
316
|
-
chunk,
|
|
317
|
-
get_chunk_callback,
|
|
318
|
-
translate_block,
|
|
319
|
-
translate_entity,
|
|
320
|
-
full_translate,
|
|
321
|
-
)
|
|
322
|
-
|
|
323
|
-
@staticmethod
|
|
324
|
-
def _biomes_to_universal(translator_version: "Version", chunk: Chunk):
|
|
325
|
-
chunk._biome_palette = BiomeManager(
|
|
326
|
-
[
|
|
327
|
-
translator_version.biome.to_universal(biome)
|
|
328
|
-
for biome in chunk.biome_palette
|
|
329
|
-
]
|
|
330
|
-
)
|
|
331
|
-
|
|
332
|
-
def from_universal(
|
|
333
|
-
self,
|
|
334
|
-
max_world_version_number: VersionNumberAny,
|
|
335
|
-
translation_manager: "TranslationManager",
|
|
336
|
-
chunk: Chunk,
|
|
337
|
-
get_chunk_callback: Optional[GetChunkCallback],
|
|
338
|
-
full_translate: bool,
|
|
339
|
-
) -> Chunk:
|
|
340
|
-
"""
|
|
341
|
-
Translate a universal chunk into the interface-specific format.
|
|
342
|
-
|
|
343
|
-
:param max_world_version_number: The version number (int or tuple) of the max world version
|
|
344
|
-
:param translation_manager: TranslationManager used for the translation
|
|
345
|
-
:param chunk: The chunk to translate.
|
|
346
|
-
:param get_chunk_callback: function callback to get a chunk's data
|
|
347
|
-
:param full_translate: if true do a full translate. If false just pack the block_palette (used in callback)
|
|
348
|
-
:return: Chunk object in the interface-specific format and block_palette.
|
|
349
|
-
"""
|
|
350
|
-
version = translation_manager.get_version(
|
|
351
|
-
*self._translator_key(max_world_version_number)
|
|
352
|
-
)
|
|
353
|
-
self._blocks_entities_from_universal(
|
|
354
|
-
max_world_version_number,
|
|
355
|
-
translation_manager,
|
|
356
|
-
chunk,
|
|
357
|
-
get_chunk_callback,
|
|
358
|
-
full_translate,
|
|
359
|
-
)
|
|
360
|
-
self._biomes_from_universal(version, chunk)
|
|
361
|
-
return chunk
|
|
362
|
-
|
|
363
|
-
def _blocks_entities_from_universal(
|
|
364
|
-
self,
|
|
365
|
-
max_world_version_number: VersionNumberAny,
|
|
366
|
-
translation_manager: "TranslationManager",
|
|
367
|
-
chunk: Chunk,
|
|
368
|
-
get_chunk_callback: Optional[GetChunkCallback],
|
|
369
|
-
full_translate: bool,
|
|
370
|
-
):
|
|
371
|
-
version = translation_manager.get_version(
|
|
372
|
-
*self._translator_key(max_world_version_number)
|
|
373
|
-
)
|
|
374
|
-
|
|
375
|
-
# TODO: perhaps find a way so this code isn't duplicated in three places
|
|
376
|
-
def translate_block(
|
|
377
|
-
input_object: Block,
|
|
378
|
-
get_block_callback: Optional[GetBlockCallback],
|
|
379
|
-
block_location: BlockCoordinates,
|
|
380
|
-
) -> TranslateBlockCallbackReturn:
|
|
381
|
-
final_block = None
|
|
382
|
-
final_block_entity = None
|
|
383
|
-
final_entities = []
|
|
384
|
-
final_extra = False
|
|
385
|
-
|
|
386
|
-
for depth, block in enumerate(input_object.block_tuple):
|
|
387
|
-
(
|
|
388
|
-
output_object,
|
|
389
|
-
output_block_entity,
|
|
390
|
-
extra,
|
|
391
|
-
) = version.block.from_universal(
|
|
392
|
-
block,
|
|
393
|
-
get_block_callback=get_block_callback,
|
|
394
|
-
block_location=block_location,
|
|
395
|
-
)
|
|
396
|
-
|
|
397
|
-
if isinstance(output_object, Block):
|
|
398
|
-
if __debug__ and output_object.namespace.startswith("universal"):
|
|
399
|
-
log.debug(
|
|
400
|
-
f"Error translating {input_object.blockstate} from universal. Got {output_object.blockstate}"
|
|
401
|
-
)
|
|
402
|
-
if final_block is None:
|
|
403
|
-
final_block = output_object
|
|
404
|
-
else:
|
|
405
|
-
final_block += output_object
|
|
406
|
-
if depth == 0:
|
|
407
|
-
final_block_entity = output_block_entity
|
|
408
|
-
|
|
409
|
-
elif isinstance(output_object, Entity):
|
|
410
|
-
final_entities.append(output_object)
|
|
411
|
-
# TODO: offset entity coords
|
|
412
|
-
|
|
413
|
-
final_extra |= extra
|
|
414
|
-
|
|
415
|
-
return final_block, final_block_entity, final_entities, final_extra
|
|
416
|
-
|
|
417
|
-
def translate_entity(input_object: Entity) -> TranslateEntityCallbackReturn:
|
|
418
|
-
final_block = None
|
|
419
|
-
final_block_entity = None
|
|
420
|
-
final_entities = []
|
|
421
|
-
# TODO
|
|
422
|
-
return final_block, final_block_entity, final_entities
|
|
423
|
-
|
|
424
|
-
self._translate(
|
|
425
|
-
chunk,
|
|
426
|
-
get_chunk_callback,
|
|
427
|
-
translate_block,
|
|
428
|
-
translate_entity,
|
|
429
|
-
full_translate,
|
|
430
|
-
)
|
|
431
|
-
|
|
432
|
-
@staticmethod
|
|
433
|
-
def _biomes_from_universal(translator_version: "Version", chunk: Chunk):
|
|
434
|
-
chunk._biome_palette = BiomeManager(
|
|
435
|
-
[
|
|
436
|
-
translator_version.biome.from_universal(biome)
|
|
437
|
-
for biome in chunk.biome_palette
|
|
438
|
-
]
|
|
439
|
-
)
|
|
440
|
-
|
|
441
|
-
def unpack(
|
|
442
|
-
self,
|
|
443
|
-
chunk_version: VersionNumberAny,
|
|
444
|
-
translation_manager: "TranslationManager",
|
|
445
|
-
chunk: Chunk,
|
|
446
|
-
palette: AnyNDArray,
|
|
447
|
-
) -> Chunk:
|
|
448
|
-
"""
|
|
449
|
-
Unpack the version-specific block_palette into the stringified version where needed.
|
|
450
|
-
|
|
451
|
-
:return: The block_palette converted to block objects.
|
|
452
|
-
"""
|
|
453
|
-
version_identifier = self._translator_key(chunk_version)
|
|
454
|
-
self._unpack_blocks(translation_manager, version_identifier, chunk, palette)
|
|
455
|
-
self._unpack_biomes(translation_manager, version_identifier, chunk)
|
|
456
|
-
return chunk
|
|
457
|
-
|
|
458
|
-
@staticmethod
|
|
459
|
-
def _unpack_blocks(
|
|
460
|
-
translation_manager: "TranslationManager",
|
|
461
|
-
version_identifier: VersionIdentifierType,
|
|
462
|
-
chunk: Chunk,
|
|
463
|
-
block_palette: AnyNDArray,
|
|
464
|
-
):
|
|
465
|
-
"""
|
|
466
|
-
Unpack the version-specific block_palette into the stringified version where needed.
|
|
467
|
-
:return: The block_palette converted to block objects.
|
|
468
|
-
"""
|
|
469
|
-
chunk._block_palette = BlockManager(block_palette)
|
|
470
|
-
|
|
471
|
-
@staticmethod
|
|
472
|
-
def _unpack_biomes(
|
|
473
|
-
translation_manager: "TranslationManager",
|
|
474
|
-
version_identifier: VersionIdentifierType,
|
|
475
|
-
chunk: Chunk,
|
|
476
|
-
):
|
|
477
|
-
"""
|
|
478
|
-
Unpack the version-specific biome_palette into the stringified version where needed.
|
|
479
|
-
:return: The biome_palette converted to biome objects.
|
|
480
|
-
"""
|
|
481
|
-
version = translation_manager.get_version(*version_identifier)
|
|
482
|
-
|
|
483
|
-
if chunk.biomes.dimension == BiomesShape.Shape2D:
|
|
484
|
-
biome_int_palette, biome_array = numpy.unique(
|
|
485
|
-
chunk.biomes, return_inverse=True
|
|
486
|
-
)
|
|
487
|
-
chunk.biomes = biome_array.reshape(chunk.biomes.shape)
|
|
488
|
-
chunk._biome_palette = BiomeManager(
|
|
489
|
-
[version.biome.unpack(biome) for biome in biome_int_palette]
|
|
490
|
-
)
|
|
491
|
-
elif chunk.biomes.dimension == BiomesShape.Shape3D:
|
|
492
|
-
biomes = {}
|
|
493
|
-
palette = []
|
|
494
|
-
palette_length = 0
|
|
495
|
-
for sy in chunk.biomes.sections:
|
|
496
|
-
biome_int_palette, biome_array = numpy.unique(
|
|
497
|
-
chunk.biomes.get_section(sy), return_inverse=True
|
|
498
|
-
)
|
|
499
|
-
biomes[sy] = (
|
|
500
|
-
biome_array.reshape(chunk.biomes.section_shape) + palette_length
|
|
501
|
-
)
|
|
502
|
-
palette_length += len(biome_int_palette)
|
|
503
|
-
palette.append(biome_int_palette)
|
|
504
|
-
|
|
505
|
-
if palette:
|
|
506
|
-
chunk_palette, lut = numpy.unique(
|
|
507
|
-
numpy.concatenate(palette), return_inverse=True
|
|
508
|
-
)
|
|
509
|
-
lut = lut.astype(numpy.uint32)
|
|
510
|
-
for sy in biomes:
|
|
511
|
-
biomes[sy] = lut[biomes[sy]]
|
|
512
|
-
|
|
513
|
-
chunk.biomes = biomes
|
|
514
|
-
chunk._biome_palette = BiomeManager(
|
|
515
|
-
numpy.vectorize(version.biome.unpack)(chunk_palette)
|
|
516
|
-
)
|
|
517
|
-
|
|
518
|
-
def pack(
|
|
519
|
-
self,
|
|
520
|
-
max_world_version_number: VersionNumberAny,
|
|
521
|
-
translation_manager: "TranslationManager",
|
|
522
|
-
chunk: Chunk,
|
|
523
|
-
) -> Tuple[Chunk, AnyNDArray]:
|
|
524
|
-
"""
|
|
525
|
-
Translate the list of block objects into a version-specific block_palette.
|
|
526
|
-
:return: The block_palette converted into version-specific blocks (ie id, data tuples for 1.12)
|
|
527
|
-
"""
|
|
528
|
-
version_identifier = self._translator_key(max_world_version_number)
|
|
529
|
-
version = translation_manager.get_version(*version_identifier)
|
|
530
|
-
self._pack_biomes(translation_manager, version_identifier, chunk)
|
|
531
|
-
return (
|
|
532
|
-
chunk,
|
|
533
|
-
self._pack_block_palette(version, numpy.array(chunk.block_palette.blocks)),
|
|
534
|
-
)
|
|
535
|
-
|
|
536
|
-
def _pack_block_palette(
|
|
537
|
-
self, version: "Version", palette: BlockNDArray
|
|
538
|
-
) -> AnyNDArray:
|
|
539
|
-
"""
|
|
540
|
-
Pack the list of block objects into a version-specific block_palette.
|
|
541
|
-
:return: The block_palette converted into version-specific blocks (ie id, data tuples for 1.12)
|
|
542
|
-
"""
|
|
543
|
-
return palette
|
|
544
|
-
|
|
545
|
-
@staticmethod
|
|
546
|
-
def _pack_biomes(
|
|
547
|
-
translation_manager: "TranslationManager",
|
|
548
|
-
version_identifier: VersionIdentifierType,
|
|
549
|
-
chunk: Chunk,
|
|
550
|
-
):
|
|
551
|
-
"""
|
|
552
|
-
Unpack the version-specific biome_palette into the stringified version where needed.
|
|
553
|
-
:return: The biome_palette converted to biome objects.
|
|
554
|
-
"""
|
|
555
|
-
version = translation_manager.get_version(*version_identifier)
|
|
556
|
-
|
|
557
|
-
biome_palette = numpy.array(
|
|
558
|
-
[version.biome.pack(biome) for biome in chunk.biome_palette], numpy.uint32
|
|
559
|
-
)
|
|
560
|
-
if chunk.biomes.dimension == BiomesShape.Shape2D:
|
|
561
|
-
chunk.biomes = biome_palette[chunk.biomes]
|
|
562
|
-
elif chunk.biomes.dimension == BiomesShape.Shape3D:
|
|
563
|
-
chunk.biomes = {
|
|
564
|
-
sy: biome_palette[chunk.biomes.get_section(sy)]
|
|
565
|
-
for sy in chunk.biomes.sections
|
|
566
|
-
}
|
|
567
|
-
chunk._biome_palette = BiomeManager()
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Tuple, Optional, TYPE_CHECKING
|
|
4
|
+
import copy
|
|
5
|
+
import math
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
import numpy
|
|
9
|
+
|
|
10
|
+
from amulet import entity_support
|
|
11
|
+
from amulet.api.registry import BlockManager, BiomeManager
|
|
12
|
+
from amulet.api.block import Block
|
|
13
|
+
from amulet.api.block_entity import BlockEntity
|
|
14
|
+
from amulet.api.entity import Entity
|
|
15
|
+
from amulet.api.chunk import Chunk, BiomesShape
|
|
16
|
+
from amulet.api.data_types import (
|
|
17
|
+
AnyNDArray,
|
|
18
|
+
BlockNDArray,
|
|
19
|
+
BlockCoordinates,
|
|
20
|
+
GetChunkCallback,
|
|
21
|
+
TranslateBlockCallback,
|
|
22
|
+
TranslateEntityCallback,
|
|
23
|
+
GetBlockCallback,
|
|
24
|
+
TranslateBlockCallbackReturn,
|
|
25
|
+
TranslateEntityCallbackReturn,
|
|
26
|
+
VersionNumberAny,
|
|
27
|
+
VersionIdentifierType,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
log = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from PyMCTranslate import Version, TranslationManager
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Translator:
|
|
37
|
+
def translator_key(self, version_number: VersionNumberAny) -> VersionIdentifierType:
|
|
38
|
+
return self._translator_key(version_number)
|
|
39
|
+
|
|
40
|
+
def _translator_key(
|
|
41
|
+
self, version_number: VersionNumberAny
|
|
42
|
+
) -> VersionIdentifierType:
|
|
43
|
+
"""
|
|
44
|
+
Return the version key for PyMCTranslate
|
|
45
|
+
|
|
46
|
+
:return: The tuple version key for PyMCTranslate
|
|
47
|
+
"""
|
|
48
|
+
raise NotImplementedError
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def is_valid(key: Tuple) -> bool:
|
|
52
|
+
"""
|
|
53
|
+
Returns whether this translator is able to translate the chunk type with a given identifier key,
|
|
54
|
+
generated by the decoder.
|
|
55
|
+
|
|
56
|
+
:param key: The key who's decodability needs to be checked.
|
|
57
|
+
:return: True if this translator is able to translate the chunk type associated with the key, False otherwise.
|
|
58
|
+
"""
|
|
59
|
+
raise NotImplementedError
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def _translate(
|
|
63
|
+
chunk: Chunk,
|
|
64
|
+
get_chunk_callback: Optional[GetChunkCallback],
|
|
65
|
+
translate_block: TranslateBlockCallback,
|
|
66
|
+
translate_entity: TranslateEntityCallback,
|
|
67
|
+
full_translate: bool,
|
|
68
|
+
):
|
|
69
|
+
if full_translate:
|
|
70
|
+
todo = []
|
|
71
|
+
output_block_entities = []
|
|
72
|
+
output_entities = []
|
|
73
|
+
finished = BlockManager()
|
|
74
|
+
palette_mappings = {}
|
|
75
|
+
|
|
76
|
+
# translate each block without using the callback
|
|
77
|
+
for i, input_block in enumerate(chunk.block_palette):
|
|
78
|
+
input_block: Block
|
|
79
|
+
(
|
|
80
|
+
output_block,
|
|
81
|
+
output_block_entity,
|
|
82
|
+
output_entity,
|
|
83
|
+
extra,
|
|
84
|
+
) = translate_block(input_block, None, (0, 0, 0))
|
|
85
|
+
if extra and get_chunk_callback:
|
|
86
|
+
todo.append(i)
|
|
87
|
+
elif output_block is not None:
|
|
88
|
+
palette_mappings[i] = finished.get_add_block(output_block)
|
|
89
|
+
if output_block_entity is not None:
|
|
90
|
+
for cy in chunk.blocks.sub_chunks:
|
|
91
|
+
for x, y, z in zip(
|
|
92
|
+
*numpy.where(chunk.blocks.get_sub_chunk(cy) == i)
|
|
93
|
+
):
|
|
94
|
+
output_block_entities.append(
|
|
95
|
+
output_block_entity.new_at_location(
|
|
96
|
+
x + chunk.cx * 16,
|
|
97
|
+
y + cy * 16,
|
|
98
|
+
z + chunk.cz * 16,
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
# TODO: this should only happen if the object is an entity, set the block to air
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
if output_entity and entity_support:
|
|
106
|
+
for cy in chunk.blocks.sub_chunks:
|
|
107
|
+
for x, y, z in zip(
|
|
108
|
+
*numpy.where(chunk.blocks.get_sub_chunk(cy) == i)
|
|
109
|
+
):
|
|
110
|
+
x += chunk.cx * 16
|
|
111
|
+
y += cy * 16
|
|
112
|
+
z += chunk.cz * 16
|
|
113
|
+
for entity in output_entity:
|
|
114
|
+
e = copy.deepcopy(entity)
|
|
115
|
+
e.location += (x, y, z)
|
|
116
|
+
output_entities.append(e)
|
|
117
|
+
|
|
118
|
+
# re-translate the blocks that require extra information
|
|
119
|
+
block_mappings = {}
|
|
120
|
+
for index in todo:
|
|
121
|
+
for cy in chunk.blocks.sub_chunks:
|
|
122
|
+
for x, y, z in zip(
|
|
123
|
+
*numpy.where(chunk.blocks.get_sub_chunk(cy) == index)
|
|
124
|
+
):
|
|
125
|
+
y += cy * 16
|
|
126
|
+
|
|
127
|
+
def get_block_at(
|
|
128
|
+
pos: BlockCoordinates,
|
|
129
|
+
) -> Tuple[Block, Optional[BlockEntity]]:
|
|
130
|
+
"""Get a block at a location relative to the current block"""
|
|
131
|
+
nonlocal x, y, z, chunk, cy
|
|
132
|
+
|
|
133
|
+
# calculate position relative to chunk base
|
|
134
|
+
dx, dy, dz = pos
|
|
135
|
+
dx += x
|
|
136
|
+
dy += y
|
|
137
|
+
dz += z
|
|
138
|
+
|
|
139
|
+
abs_x = dx + chunk.cx * 16
|
|
140
|
+
abs_y = dy
|
|
141
|
+
abs_z = dz + chunk.cz * 16
|
|
142
|
+
|
|
143
|
+
# calculate relative chunk position
|
|
144
|
+
cx = dx // 16
|
|
145
|
+
cz = dz // 16
|
|
146
|
+
if cx == 0 and cz == 0:
|
|
147
|
+
# if it is the current chunk
|
|
148
|
+
block = chunk.block_palette[chunk.blocks[dx, dy, dz]]
|
|
149
|
+
return (
|
|
150
|
+
block,
|
|
151
|
+
chunk.block_entities.get((abs_x, abs_y, abs_z)),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# if it is in a different chunk
|
|
155
|
+
local_chunk = get_chunk_callback(cx, cz)
|
|
156
|
+
block = local_chunk.block_palette[
|
|
157
|
+
local_chunk.blocks[dx % 16, dy, dz % 16]
|
|
158
|
+
]
|
|
159
|
+
return (
|
|
160
|
+
block,
|
|
161
|
+
local_chunk.block_entities.get((abs_x, abs_y, abs_z)),
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
input_block = chunk.block_palette[chunk.blocks[x, y, z]]
|
|
165
|
+
(
|
|
166
|
+
output_block,
|
|
167
|
+
output_block_entity,
|
|
168
|
+
output_entity,
|
|
169
|
+
_,
|
|
170
|
+
) = translate_block(
|
|
171
|
+
input_block,
|
|
172
|
+
get_block_at,
|
|
173
|
+
(x + chunk.cx * 16, y, z + chunk.cz * 16),
|
|
174
|
+
)
|
|
175
|
+
if output_block is not None:
|
|
176
|
+
block_mappings[(x, y, z)] = finished.get_add_block(
|
|
177
|
+
output_block
|
|
178
|
+
)
|
|
179
|
+
if output_block_entity is not None:
|
|
180
|
+
output_block_entities.append(
|
|
181
|
+
output_block_entity.new_at_location(
|
|
182
|
+
x + chunk.cx * 16, y, z + chunk.cz * 16
|
|
183
|
+
)
|
|
184
|
+
)
|
|
185
|
+
else:
|
|
186
|
+
# TODO: set the block to air
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
if output_entity and entity_support:
|
|
190
|
+
for entity in output_entity:
|
|
191
|
+
e = copy.deepcopy(entity)
|
|
192
|
+
e.location += (x, y, z)
|
|
193
|
+
output_entities.append(e)
|
|
194
|
+
|
|
195
|
+
if entity_support:
|
|
196
|
+
for entity in chunk.entities:
|
|
197
|
+
output_block, output_block_entity, output_entity = translate_entity(
|
|
198
|
+
entity
|
|
199
|
+
)
|
|
200
|
+
if output_block is not None:
|
|
201
|
+
block_location = (
|
|
202
|
+
int(math.floor(entity.x)),
|
|
203
|
+
int(math.floor(entity.y)),
|
|
204
|
+
int(math.floor(entity.z)),
|
|
205
|
+
)
|
|
206
|
+
block_mappings[block_location] = output_block
|
|
207
|
+
if output_block_entity:
|
|
208
|
+
output_block_entities.append(
|
|
209
|
+
output_block_entity.new_at_location(*block_location)
|
|
210
|
+
)
|
|
211
|
+
if output_entity:
|
|
212
|
+
for e in output_entity:
|
|
213
|
+
e.location = entity.location
|
|
214
|
+
output_entities.append(e)
|
|
215
|
+
|
|
216
|
+
for cy in chunk.blocks.sub_chunks:
|
|
217
|
+
old_blocks = chunk.blocks.get_sub_chunk(cy)
|
|
218
|
+
new_blocks = numpy.zeros(old_blocks.shape, dtype=old_blocks.dtype)
|
|
219
|
+
for old, new in palette_mappings.items():
|
|
220
|
+
new_blocks[old_blocks == old] = new
|
|
221
|
+
chunk.blocks.add_sub_chunk(cy, new_blocks)
|
|
222
|
+
for (x, y, z), new in block_mappings.items():
|
|
223
|
+
chunk.blocks[x, y, z] = new
|
|
224
|
+
chunk.block_entities = output_block_entities
|
|
225
|
+
chunk.entities = output_entities
|
|
226
|
+
chunk._block_palette = finished
|
|
227
|
+
|
|
228
|
+
def to_universal(
|
|
229
|
+
self,
|
|
230
|
+
chunk_version: VersionNumberAny,
|
|
231
|
+
translation_manager: "TranslationManager",
|
|
232
|
+
chunk: Chunk,
|
|
233
|
+
get_chunk_callback: Optional[GetChunkCallback],
|
|
234
|
+
full_translate: bool,
|
|
235
|
+
) -> Chunk:
|
|
236
|
+
"""
|
|
237
|
+
Translate an interface-specific chunk into the universal format.
|
|
238
|
+
|
|
239
|
+
:param chunk_version: The version number (int or tuple) of the input chunk
|
|
240
|
+
:param translation_manager: TranslationManager used for the translation
|
|
241
|
+
:param chunk: The chunk to translate.
|
|
242
|
+
:param get_chunk_callback: function callback to get a chunk's data
|
|
243
|
+
:param full_translate: if true do a full translate. If false just unpack the block_palette (used in callback)
|
|
244
|
+
:return: Chunk object in the universal format.
|
|
245
|
+
"""
|
|
246
|
+
version = translation_manager.get_version(*self._translator_key(chunk_version))
|
|
247
|
+
self._biomes_to_universal(version, chunk)
|
|
248
|
+
self._blocks_entities_to_universal(
|
|
249
|
+
chunk_version,
|
|
250
|
+
translation_manager,
|
|
251
|
+
chunk,
|
|
252
|
+
get_chunk_callback,
|
|
253
|
+
full_translate,
|
|
254
|
+
)
|
|
255
|
+
return chunk
|
|
256
|
+
|
|
257
|
+
def _blocks_entities_to_universal(
|
|
258
|
+
self,
|
|
259
|
+
chunk_version: VersionNumberAny,
|
|
260
|
+
translation_manager: "TranslationManager",
|
|
261
|
+
chunk: Chunk,
|
|
262
|
+
get_chunk_callback: Optional[GetChunkCallback],
|
|
263
|
+
full_translate: bool,
|
|
264
|
+
):
|
|
265
|
+
version = translation_manager.get_version(*self._translator_key(chunk_version))
|
|
266
|
+
|
|
267
|
+
def translate_block(
|
|
268
|
+
input_object: Block,
|
|
269
|
+
get_block_callback: Optional[GetBlockCallback],
|
|
270
|
+
block_location: BlockCoordinates,
|
|
271
|
+
) -> TranslateBlockCallbackReturn:
|
|
272
|
+
final_block = None
|
|
273
|
+
final_block_entity = None
|
|
274
|
+
final_entities = []
|
|
275
|
+
final_extra = False
|
|
276
|
+
|
|
277
|
+
for depth, block in enumerate(input_object.block_tuple):
|
|
278
|
+
(
|
|
279
|
+
output_object,
|
|
280
|
+
output_block_entity,
|
|
281
|
+
extra,
|
|
282
|
+
) = version.block.to_universal(
|
|
283
|
+
block,
|
|
284
|
+
get_block_callback=get_block_callback,
|
|
285
|
+
block_location=block_location,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if isinstance(output_object, Block):
|
|
289
|
+
if not output_object.namespace.startswith("universal"):
|
|
290
|
+
log.debug(
|
|
291
|
+
f"Error translating {input_object.full_blockstate} to universal. Got {output_object.full_blockstate}"
|
|
292
|
+
)
|
|
293
|
+
if final_block is None:
|
|
294
|
+
final_block = output_object
|
|
295
|
+
else:
|
|
296
|
+
final_block += output_object
|
|
297
|
+
if depth == 0:
|
|
298
|
+
final_block_entity = output_block_entity
|
|
299
|
+
|
|
300
|
+
elif isinstance(output_object, Entity):
|
|
301
|
+
final_entities.append(output_object)
|
|
302
|
+
# TODO: offset entity coords
|
|
303
|
+
|
|
304
|
+
final_extra |= extra
|
|
305
|
+
|
|
306
|
+
return final_block, final_block_entity, final_entities, final_extra
|
|
307
|
+
|
|
308
|
+
def translate_entity(input_object: Entity) -> TranslateEntityCallbackReturn:
|
|
309
|
+
final_block = None
|
|
310
|
+
final_block_entity = None
|
|
311
|
+
final_entities = []
|
|
312
|
+
# TODO
|
|
313
|
+
return final_block, final_block_entity, final_entities
|
|
314
|
+
|
|
315
|
+
self._translate(
|
|
316
|
+
chunk,
|
|
317
|
+
get_chunk_callback,
|
|
318
|
+
translate_block,
|
|
319
|
+
translate_entity,
|
|
320
|
+
full_translate,
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
@staticmethod
|
|
324
|
+
def _biomes_to_universal(translator_version: "Version", chunk: Chunk):
|
|
325
|
+
chunk._biome_palette = BiomeManager(
|
|
326
|
+
[
|
|
327
|
+
translator_version.biome.to_universal(biome)
|
|
328
|
+
for biome in chunk.biome_palette
|
|
329
|
+
]
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
def from_universal(
|
|
333
|
+
self,
|
|
334
|
+
max_world_version_number: VersionNumberAny,
|
|
335
|
+
translation_manager: "TranslationManager",
|
|
336
|
+
chunk: Chunk,
|
|
337
|
+
get_chunk_callback: Optional[GetChunkCallback],
|
|
338
|
+
full_translate: bool,
|
|
339
|
+
) -> Chunk:
|
|
340
|
+
"""
|
|
341
|
+
Translate a universal chunk into the interface-specific format.
|
|
342
|
+
|
|
343
|
+
:param max_world_version_number: The version number (int or tuple) of the max world version
|
|
344
|
+
:param translation_manager: TranslationManager used for the translation
|
|
345
|
+
:param chunk: The chunk to translate.
|
|
346
|
+
:param get_chunk_callback: function callback to get a chunk's data
|
|
347
|
+
:param full_translate: if true do a full translate. If false just pack the block_palette (used in callback)
|
|
348
|
+
:return: Chunk object in the interface-specific format and block_palette.
|
|
349
|
+
"""
|
|
350
|
+
version = translation_manager.get_version(
|
|
351
|
+
*self._translator_key(max_world_version_number)
|
|
352
|
+
)
|
|
353
|
+
self._blocks_entities_from_universal(
|
|
354
|
+
max_world_version_number,
|
|
355
|
+
translation_manager,
|
|
356
|
+
chunk,
|
|
357
|
+
get_chunk_callback,
|
|
358
|
+
full_translate,
|
|
359
|
+
)
|
|
360
|
+
self._biomes_from_universal(version, chunk)
|
|
361
|
+
return chunk
|
|
362
|
+
|
|
363
|
+
def _blocks_entities_from_universal(
|
|
364
|
+
self,
|
|
365
|
+
max_world_version_number: VersionNumberAny,
|
|
366
|
+
translation_manager: "TranslationManager",
|
|
367
|
+
chunk: Chunk,
|
|
368
|
+
get_chunk_callback: Optional[GetChunkCallback],
|
|
369
|
+
full_translate: bool,
|
|
370
|
+
):
|
|
371
|
+
version = translation_manager.get_version(
|
|
372
|
+
*self._translator_key(max_world_version_number)
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
# TODO: perhaps find a way so this code isn't duplicated in three places
|
|
376
|
+
def translate_block(
|
|
377
|
+
input_object: Block,
|
|
378
|
+
get_block_callback: Optional[GetBlockCallback],
|
|
379
|
+
block_location: BlockCoordinates,
|
|
380
|
+
) -> TranslateBlockCallbackReturn:
|
|
381
|
+
final_block = None
|
|
382
|
+
final_block_entity = None
|
|
383
|
+
final_entities = []
|
|
384
|
+
final_extra = False
|
|
385
|
+
|
|
386
|
+
for depth, block in enumerate(input_object.block_tuple):
|
|
387
|
+
(
|
|
388
|
+
output_object,
|
|
389
|
+
output_block_entity,
|
|
390
|
+
extra,
|
|
391
|
+
) = version.block.from_universal(
|
|
392
|
+
block,
|
|
393
|
+
get_block_callback=get_block_callback,
|
|
394
|
+
block_location=block_location,
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
if isinstance(output_object, Block):
|
|
398
|
+
if __debug__ and output_object.namespace.startswith("universal"):
|
|
399
|
+
log.debug(
|
|
400
|
+
f"Error translating {input_object.blockstate} from universal. Got {output_object.blockstate}"
|
|
401
|
+
)
|
|
402
|
+
if final_block is None:
|
|
403
|
+
final_block = output_object
|
|
404
|
+
else:
|
|
405
|
+
final_block += output_object
|
|
406
|
+
if depth == 0:
|
|
407
|
+
final_block_entity = output_block_entity
|
|
408
|
+
|
|
409
|
+
elif isinstance(output_object, Entity):
|
|
410
|
+
final_entities.append(output_object)
|
|
411
|
+
# TODO: offset entity coords
|
|
412
|
+
|
|
413
|
+
final_extra |= extra
|
|
414
|
+
|
|
415
|
+
return final_block, final_block_entity, final_entities, final_extra
|
|
416
|
+
|
|
417
|
+
def translate_entity(input_object: Entity) -> TranslateEntityCallbackReturn:
|
|
418
|
+
final_block = None
|
|
419
|
+
final_block_entity = None
|
|
420
|
+
final_entities = []
|
|
421
|
+
# TODO
|
|
422
|
+
return final_block, final_block_entity, final_entities
|
|
423
|
+
|
|
424
|
+
self._translate(
|
|
425
|
+
chunk,
|
|
426
|
+
get_chunk_callback,
|
|
427
|
+
translate_block,
|
|
428
|
+
translate_entity,
|
|
429
|
+
full_translate,
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
@staticmethod
|
|
433
|
+
def _biomes_from_universal(translator_version: "Version", chunk: Chunk):
|
|
434
|
+
chunk._biome_palette = BiomeManager(
|
|
435
|
+
[
|
|
436
|
+
translator_version.biome.from_universal(biome)
|
|
437
|
+
for biome in chunk.biome_palette
|
|
438
|
+
]
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
def unpack(
|
|
442
|
+
self,
|
|
443
|
+
chunk_version: VersionNumberAny,
|
|
444
|
+
translation_manager: "TranslationManager",
|
|
445
|
+
chunk: Chunk,
|
|
446
|
+
palette: AnyNDArray,
|
|
447
|
+
) -> Chunk:
|
|
448
|
+
"""
|
|
449
|
+
Unpack the version-specific block_palette into the stringified version where needed.
|
|
450
|
+
|
|
451
|
+
:return: The block_palette converted to block objects.
|
|
452
|
+
"""
|
|
453
|
+
version_identifier = self._translator_key(chunk_version)
|
|
454
|
+
self._unpack_blocks(translation_manager, version_identifier, chunk, palette)
|
|
455
|
+
self._unpack_biomes(translation_manager, version_identifier, chunk)
|
|
456
|
+
return chunk
|
|
457
|
+
|
|
458
|
+
@staticmethod
|
|
459
|
+
def _unpack_blocks(
|
|
460
|
+
translation_manager: "TranslationManager",
|
|
461
|
+
version_identifier: VersionIdentifierType,
|
|
462
|
+
chunk: Chunk,
|
|
463
|
+
block_palette: AnyNDArray,
|
|
464
|
+
):
|
|
465
|
+
"""
|
|
466
|
+
Unpack the version-specific block_palette into the stringified version where needed.
|
|
467
|
+
:return: The block_palette converted to block objects.
|
|
468
|
+
"""
|
|
469
|
+
chunk._block_palette = BlockManager(block_palette)
|
|
470
|
+
|
|
471
|
+
@staticmethod
|
|
472
|
+
def _unpack_biomes(
|
|
473
|
+
translation_manager: "TranslationManager",
|
|
474
|
+
version_identifier: VersionIdentifierType,
|
|
475
|
+
chunk: Chunk,
|
|
476
|
+
):
|
|
477
|
+
"""
|
|
478
|
+
Unpack the version-specific biome_palette into the stringified version where needed.
|
|
479
|
+
:return: The biome_palette converted to biome objects.
|
|
480
|
+
"""
|
|
481
|
+
version = translation_manager.get_version(*version_identifier)
|
|
482
|
+
|
|
483
|
+
if chunk.biomes.dimension == BiomesShape.Shape2D:
|
|
484
|
+
biome_int_palette, biome_array = numpy.unique(
|
|
485
|
+
chunk.biomes, return_inverse=True
|
|
486
|
+
)
|
|
487
|
+
chunk.biomes = biome_array.reshape(chunk.biomes.shape)
|
|
488
|
+
chunk._biome_palette = BiomeManager(
|
|
489
|
+
[version.biome.unpack(biome) for biome in biome_int_palette]
|
|
490
|
+
)
|
|
491
|
+
elif chunk.biomes.dimension == BiomesShape.Shape3D:
|
|
492
|
+
biomes = {}
|
|
493
|
+
palette = []
|
|
494
|
+
palette_length = 0
|
|
495
|
+
for sy in chunk.biomes.sections:
|
|
496
|
+
biome_int_palette, biome_array = numpy.unique(
|
|
497
|
+
chunk.biomes.get_section(sy), return_inverse=True
|
|
498
|
+
)
|
|
499
|
+
biomes[sy] = (
|
|
500
|
+
biome_array.reshape(chunk.biomes.section_shape) + palette_length
|
|
501
|
+
)
|
|
502
|
+
palette_length += len(biome_int_palette)
|
|
503
|
+
palette.append(biome_int_palette)
|
|
504
|
+
|
|
505
|
+
if palette:
|
|
506
|
+
chunk_palette, lut = numpy.unique(
|
|
507
|
+
numpy.concatenate(palette), return_inverse=True
|
|
508
|
+
)
|
|
509
|
+
lut = lut.astype(numpy.uint32)
|
|
510
|
+
for sy in biomes:
|
|
511
|
+
biomes[sy] = lut[biomes[sy]]
|
|
512
|
+
|
|
513
|
+
chunk.biomes = biomes
|
|
514
|
+
chunk._biome_palette = BiomeManager(
|
|
515
|
+
numpy.vectorize(version.biome.unpack)(chunk_palette)
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
def pack(
|
|
519
|
+
self,
|
|
520
|
+
max_world_version_number: VersionNumberAny,
|
|
521
|
+
translation_manager: "TranslationManager",
|
|
522
|
+
chunk: Chunk,
|
|
523
|
+
) -> Tuple[Chunk, AnyNDArray]:
|
|
524
|
+
"""
|
|
525
|
+
Translate the list of block objects into a version-specific block_palette.
|
|
526
|
+
:return: The block_palette converted into version-specific blocks (ie id, data tuples for 1.12)
|
|
527
|
+
"""
|
|
528
|
+
version_identifier = self._translator_key(max_world_version_number)
|
|
529
|
+
version = translation_manager.get_version(*version_identifier)
|
|
530
|
+
self._pack_biomes(translation_manager, version_identifier, chunk)
|
|
531
|
+
return (
|
|
532
|
+
chunk,
|
|
533
|
+
self._pack_block_palette(version, numpy.array(chunk.block_palette.blocks)),
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
def _pack_block_palette(
|
|
537
|
+
self, version: "Version", palette: BlockNDArray
|
|
538
|
+
) -> AnyNDArray:
|
|
539
|
+
"""
|
|
540
|
+
Pack the list of block objects into a version-specific block_palette.
|
|
541
|
+
:return: The block_palette converted into version-specific blocks (ie id, data tuples for 1.12)
|
|
542
|
+
"""
|
|
543
|
+
return palette
|
|
544
|
+
|
|
545
|
+
@staticmethod
|
|
546
|
+
def _pack_biomes(
|
|
547
|
+
translation_manager: "TranslationManager",
|
|
548
|
+
version_identifier: VersionIdentifierType,
|
|
549
|
+
chunk: Chunk,
|
|
550
|
+
):
|
|
551
|
+
"""
|
|
552
|
+
Unpack the version-specific biome_palette into the stringified version where needed.
|
|
553
|
+
:return: The biome_palette converted to biome objects.
|
|
554
|
+
"""
|
|
555
|
+
version = translation_manager.get_version(*version_identifier)
|
|
556
|
+
|
|
557
|
+
biome_palette = numpy.array(
|
|
558
|
+
[version.biome.pack(biome) for biome in chunk.biome_palette], numpy.uint32
|
|
559
|
+
)
|
|
560
|
+
if chunk.biomes.dimension == BiomesShape.Shape2D:
|
|
561
|
+
chunk.biomes = biome_palette[chunk.biomes]
|
|
562
|
+
elif chunk.biomes.dimension == BiomesShape.Shape3D:
|
|
563
|
+
chunk.biomes = {
|
|
564
|
+
sy: biome_palette[chunk.biomes.get_section(sy)]
|
|
565
|
+
for sy in chunk.biomes.sections
|
|
566
|
+
}
|
|
567
|
+
chunk._biome_palette = BiomeManager()
|