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
amulet/api/chunk/biomes.py
CHANGED
|
@@ -1,207 +1,207 @@
|
|
|
1
|
-
import numpy
|
|
2
|
-
from typing import Union, Optional, Dict, Tuple
|
|
3
|
-
from copy import deepcopy
|
|
4
|
-
from enum import IntEnum
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
from amulet.api.partial_3d_array import UnboundedPartial3DArray
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Biomes3D(UnboundedPartial3DArray):
|
|
11
|
-
"""
|
|
12
|
-
The Biomes3D class is designed to represent a 3D integer array but with no vertical height limit.
|
|
13
|
-
|
|
14
|
-
See :class:`UnboundedPartial3DArray` for more information on how this works.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
def __init__(
|
|
18
|
-
self,
|
|
19
|
-
input_array: Optional[Union[Dict[int, numpy.ndarray], "Biomes3D"]] = None,
|
|
20
|
-
):
|
|
21
|
-
"""
|
|
22
|
-
Construct a :class:`Biomes3D` class from the given data.
|
|
23
|
-
|
|
24
|
-
:param input_array: Either an instance of :class:`Biomes3D` or a dictionary converting sub-chunk id to a 4x4x4 numpy array.
|
|
25
|
-
"""
|
|
26
|
-
if input_array is None:
|
|
27
|
-
input_array = {}
|
|
28
|
-
if isinstance(input_array, Biomes3D):
|
|
29
|
-
input_array: dict = deepcopy(input_array._sections)
|
|
30
|
-
if not isinstance(input_array, dict):
|
|
31
|
-
raise Exception(f"Input array must be Biomes3D or dict, got {input_array}")
|
|
32
|
-
super().__init__(numpy.uint32, 0, (4, 4, 4), (0, 16), sections=input_array)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class BiomesShape(IntEnum):
|
|
36
|
-
"""
|
|
37
|
-
An enum of the different states the :class:`Biomes` class can be in.
|
|
38
|
-
|
|
39
|
-
>>> ShapeNull = 0 # The biome array does not exist
|
|
40
|
-
>>> Shape2D = 2 # The biome array is a 2D array
|
|
41
|
-
>>> Shape3D = 3 # The biome array is a 3D array
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
ShapeNull = 0 # doc: The biome array does not exist
|
|
45
|
-
Shape2D = 2 # doc: The biome array is a 2D array
|
|
46
|
-
Shape3D = 3 # doc: The biome array is a 3D array
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class Biomes:
|
|
50
|
-
"""
|
|
51
|
-
Biomes is a class used to store a 2D biome array and/or 3D biome array and facilitate switching between them.
|
|
52
|
-
|
|
53
|
-
There are three states biomes can be in.
|
|
54
|
-
|
|
55
|
-
The first is a blank state where no biomes are defined. This is used when a chunk is partially generated and the biomes array has not be created.
|
|
56
|
-
|
|
57
|
-
The second is a 2D array of size (16, 16) used for old Java worlds and Bedrock worlds.
|
|
58
|
-
|
|
59
|
-
The last is the 3D state used since Java 1.15. See :class:`Biomes3D` for more information.
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
__slots__ = ("_2d", "_3d", "_dimension")
|
|
63
|
-
_2d: Optional[numpy.ndarray]
|
|
64
|
-
_3d: Optional[Biomes3D]
|
|
65
|
-
_dimension: BiomesShape
|
|
66
|
-
|
|
67
|
-
def __init__(
|
|
68
|
-
self, array: Union[numpy.ndarray, Biomes3D, Dict[int, numpy.ndarray]] = None
|
|
69
|
-
):
|
|
70
|
-
"""
|
|
71
|
-
Construct a new instance of :class:`Biomes`
|
|
72
|
-
|
|
73
|
-
:param array: The array to initialise with. Can be None or not defined to have the empty state.
|
|
74
|
-
"""
|
|
75
|
-
self._2d: Optional[numpy.ndarray] = None
|
|
76
|
-
self._3d: Optional[Biomes3D] = None
|
|
77
|
-
if array is None:
|
|
78
|
-
self._dimension = BiomesShape.ShapeNull
|
|
79
|
-
elif isinstance(array, numpy.ndarray):
|
|
80
|
-
assert array.shape == (
|
|
81
|
-
16,
|
|
82
|
-
16,
|
|
83
|
-
), "If Biomes is given an ndarray it must be 16x16"
|
|
84
|
-
self._2d = array.copy()
|
|
85
|
-
self._dimension = BiomesShape.Shape2D
|
|
86
|
-
elif isinstance(array, (dict, Biomes3D)):
|
|
87
|
-
self._3d = Biomes3D(array)
|
|
88
|
-
self._dimension = BiomesShape.Shape3D
|
|
89
|
-
|
|
90
|
-
def to_raw(
|
|
91
|
-
self,
|
|
92
|
-
) -> Tuple[
|
|
93
|
-
BiomesShape, Optional[numpy.ndarray], Optional[Dict[int, numpy.ndarray]]
|
|
94
|
-
]:
|
|
95
|
-
"""Don't use this method. Use to pickle data."""
|
|
96
|
-
if self._3d is None:
|
|
97
|
-
sections = None
|
|
98
|
-
else:
|
|
99
|
-
sections = self._3d._sections
|
|
100
|
-
return self._dimension, self._2d, sections
|
|
101
|
-
|
|
102
|
-
@classmethod
|
|
103
|
-
def from_raw(
|
|
104
|
-
cls,
|
|
105
|
-
dimension: BiomesShape,
|
|
106
|
-
d2: Optional[numpy.ndarray],
|
|
107
|
-
d3: Optional[Dict[int, numpy.ndarray]],
|
|
108
|
-
) -> "Biomes":
|
|
109
|
-
"""Don't use this method. Use to unpickle data."""
|
|
110
|
-
biomes = cls()
|
|
111
|
-
biomes._dimension = dimension
|
|
112
|
-
biomes._2d = d2
|
|
113
|
-
if d3 is not None:
|
|
114
|
-
biomes._3d = Biomes3D(d3)
|
|
115
|
-
return biomes
|
|
116
|
-
|
|
117
|
-
@property
|
|
118
|
-
def dimension(self) -> BiomesShape:
|
|
119
|
-
"""
|
|
120
|
-
The number of dimensions the data has
|
|
121
|
-
|
|
122
|
-
:attr:`BiomesShape.ShapeNull` when there is no data.
|
|
123
|
-
Will error if you try accessing data from it without converting to one of the other formats.
|
|
124
|
-
|
|
125
|
-
:attr:`BiomesShape.Shape2D` when the data is a 2D (16, 16) numpy array.
|
|
126
|
-
|
|
127
|
-
:attr:`BiomesShape.Shape3D` when the data is a 3D (4, inf, 4) :class:`Biome3D` array made of sections of size (4, 4, 4).
|
|
128
|
-
"""
|
|
129
|
-
return self._dimension
|
|
130
|
-
|
|
131
|
-
def convert_to_2d(self):
|
|
132
|
-
"""
|
|
133
|
-
Convert the data to the 2D 16x16 format from whatever format it was in.
|
|
134
|
-
|
|
135
|
-
If it was in the Null state it will be initialised with the first entry in the :obj:`~amulet.api.registry.biome_manager.BiomeManager`.
|
|
136
|
-
|
|
137
|
-
In this mode this class will behave like a numpy array.
|
|
138
|
-
"""
|
|
139
|
-
if self._2d is None:
|
|
140
|
-
self._2d = numpy.zeros((16, 16), numpy.uint32)
|
|
141
|
-
if self._dimension is BiomesShape.Shape3D and self._3d is not None:
|
|
142
|
-
# convert from 3D
|
|
143
|
-
self._2d[:, :] = numpy.kron(
|
|
144
|
-
numpy.reshape(self._3d[:, 0, :], (4, 4)), numpy.ones((4, 4))
|
|
145
|
-
)
|
|
146
|
-
self._dimension = BiomesShape.Shape2D
|
|
147
|
-
|
|
148
|
-
def convert_to_3d(self):
|
|
149
|
-
"""
|
|
150
|
-
Convert the data to the 3D (4, inf, 4) format from whatever format it was in.
|
|
151
|
-
|
|
152
|
-
If it was in the Null state it will be initialised with the first entry in the :class:`~amulet.api.registry.biome_manager.BiomeManager`.
|
|
153
|
-
|
|
154
|
-
In this mode this class will behave like the :class:`Biome3D` class.
|
|
155
|
-
"""
|
|
156
|
-
if self._3d is None:
|
|
157
|
-
self._3d = Biomes3D()
|
|
158
|
-
if self._dimension is BiomesShape.Shape2D and self._2d is not None:
|
|
159
|
-
# convert from 2D
|
|
160
|
-
self._3d[:, :, :] = numpy.repeat(
|
|
161
|
-
self._2d[::4, ::4].reshape(4, 1, 4), 64, axis=1
|
|
162
|
-
)
|
|
163
|
-
self._dimension = BiomesShape.Shape3D
|
|
164
|
-
|
|
165
|
-
def _get_active(self) -> Union[numpy.ndarray, Biomes3D]:
|
|
166
|
-
if self._dimension is BiomesShape.ShapeNull:
|
|
167
|
-
raise Exception(
|
|
168
|
-
"You are trying to use Biomes but have not picked a format. Use one of the convert methods to specify the format."
|
|
169
|
-
)
|
|
170
|
-
elif self._dimension is BiomesShape.Shape2D:
|
|
171
|
-
self.convert_to_2d()
|
|
172
|
-
return self._2d
|
|
173
|
-
elif self._dimension is BiomesShape.Shape3D:
|
|
174
|
-
self.convert_to_3d()
|
|
175
|
-
return self._3d
|
|
176
|
-
else:
|
|
177
|
-
raise Exception("Dimension is invalid. This shouldn't happen")
|
|
178
|
-
|
|
179
|
-
def copy(self):
|
|
180
|
-
return self.__copy__()
|
|
181
|
-
|
|
182
|
-
def __copy__(self):
|
|
183
|
-
cls = self.__class__
|
|
184
|
-
result = cls.__new__(cls)
|
|
185
|
-
for k in self.__slots__:
|
|
186
|
-
setattr(result, k, getattr(self, k))
|
|
187
|
-
return result
|
|
188
|
-
|
|
189
|
-
def __deepcopy__(self, memodict=None):
|
|
190
|
-
cls = self.__class__
|
|
191
|
-
result = cls.__new__(cls)
|
|
192
|
-
memodict[id(self)] = result
|
|
193
|
-
for k in self.__slots__:
|
|
194
|
-
setattr(result, k, deepcopy(getattr(self, k), memodict))
|
|
195
|
-
return result
|
|
196
|
-
|
|
197
|
-
def __getattr__(self, item):
|
|
198
|
-
return getattr(self._get_active(), item)
|
|
199
|
-
|
|
200
|
-
def __contains__(self, item):
|
|
201
|
-
return item in self._get_active()
|
|
202
|
-
|
|
203
|
-
def __getitem__(self, item):
|
|
204
|
-
return self._get_active()[item]
|
|
205
|
-
|
|
206
|
-
def __setitem__(self, key, value):
|
|
207
|
-
self._get_active()[key] = value
|
|
1
|
+
import numpy
|
|
2
|
+
from typing import Union, Optional, Dict, Tuple
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
from enum import IntEnum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from amulet.api.partial_3d_array import UnboundedPartial3DArray
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Biomes3D(UnboundedPartial3DArray):
|
|
11
|
+
"""
|
|
12
|
+
The Biomes3D class is designed to represent a 3D integer array but with no vertical height limit.
|
|
13
|
+
|
|
14
|
+
See :class:`UnboundedPartial3DArray` for more information on how this works.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
input_array: Optional[Union[Dict[int, numpy.ndarray], "Biomes3D"]] = None,
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
Construct a :class:`Biomes3D` class from the given data.
|
|
23
|
+
|
|
24
|
+
:param input_array: Either an instance of :class:`Biomes3D` or a dictionary converting sub-chunk id to a 4x4x4 numpy array.
|
|
25
|
+
"""
|
|
26
|
+
if input_array is None:
|
|
27
|
+
input_array = {}
|
|
28
|
+
if isinstance(input_array, Biomes3D):
|
|
29
|
+
input_array: dict = deepcopy(input_array._sections)
|
|
30
|
+
if not isinstance(input_array, dict):
|
|
31
|
+
raise Exception(f"Input array must be Biomes3D or dict, got {input_array}")
|
|
32
|
+
super().__init__(numpy.uint32, 0, (4, 4, 4), (0, 16), sections=input_array)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BiomesShape(IntEnum):
|
|
36
|
+
"""
|
|
37
|
+
An enum of the different states the :class:`Biomes` class can be in.
|
|
38
|
+
|
|
39
|
+
>>> ShapeNull = 0 # The biome array does not exist
|
|
40
|
+
>>> Shape2D = 2 # The biome array is a 2D array
|
|
41
|
+
>>> Shape3D = 3 # The biome array is a 3D array
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
ShapeNull = 0 # doc: The biome array does not exist
|
|
45
|
+
Shape2D = 2 # doc: The biome array is a 2D array
|
|
46
|
+
Shape3D = 3 # doc: The biome array is a 3D array
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Biomes:
|
|
50
|
+
"""
|
|
51
|
+
Biomes is a class used to store a 2D biome array and/or 3D biome array and facilitate switching between them.
|
|
52
|
+
|
|
53
|
+
There are three states biomes can be in.
|
|
54
|
+
|
|
55
|
+
The first is a blank state where no biomes are defined. This is used when a chunk is partially generated and the biomes array has not be created.
|
|
56
|
+
|
|
57
|
+
The second is a 2D array of size (16, 16) used for old Java worlds and Bedrock worlds.
|
|
58
|
+
|
|
59
|
+
The last is the 3D state used since Java 1.15. See :class:`Biomes3D` for more information.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
__slots__ = ("_2d", "_3d", "_dimension")
|
|
63
|
+
_2d: Optional[numpy.ndarray]
|
|
64
|
+
_3d: Optional[Biomes3D]
|
|
65
|
+
_dimension: BiomesShape
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self, array: Union[numpy.ndarray, Biomes3D, Dict[int, numpy.ndarray]] = None
|
|
69
|
+
):
|
|
70
|
+
"""
|
|
71
|
+
Construct a new instance of :class:`Biomes`
|
|
72
|
+
|
|
73
|
+
:param array: The array to initialise with. Can be None or not defined to have the empty state.
|
|
74
|
+
"""
|
|
75
|
+
self._2d: Optional[numpy.ndarray] = None
|
|
76
|
+
self._3d: Optional[Biomes3D] = None
|
|
77
|
+
if array is None:
|
|
78
|
+
self._dimension = BiomesShape.ShapeNull
|
|
79
|
+
elif isinstance(array, numpy.ndarray):
|
|
80
|
+
assert array.shape == (
|
|
81
|
+
16,
|
|
82
|
+
16,
|
|
83
|
+
), "If Biomes is given an ndarray it must be 16x16"
|
|
84
|
+
self._2d = array.copy()
|
|
85
|
+
self._dimension = BiomesShape.Shape2D
|
|
86
|
+
elif isinstance(array, (dict, Biomes3D)):
|
|
87
|
+
self._3d = Biomes3D(array)
|
|
88
|
+
self._dimension = BiomesShape.Shape3D
|
|
89
|
+
|
|
90
|
+
def to_raw(
|
|
91
|
+
self,
|
|
92
|
+
) -> Tuple[
|
|
93
|
+
BiomesShape, Optional[numpy.ndarray], Optional[Dict[int, numpy.ndarray]]
|
|
94
|
+
]:
|
|
95
|
+
"""Don't use this method. Use to pickle data."""
|
|
96
|
+
if self._3d is None:
|
|
97
|
+
sections = None
|
|
98
|
+
else:
|
|
99
|
+
sections = self._3d._sections
|
|
100
|
+
return self._dimension, self._2d, sections
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def from_raw(
|
|
104
|
+
cls,
|
|
105
|
+
dimension: BiomesShape,
|
|
106
|
+
d2: Optional[numpy.ndarray],
|
|
107
|
+
d3: Optional[Dict[int, numpy.ndarray]],
|
|
108
|
+
) -> "Biomes":
|
|
109
|
+
"""Don't use this method. Use to unpickle data."""
|
|
110
|
+
biomes = cls()
|
|
111
|
+
biomes._dimension = dimension
|
|
112
|
+
biomes._2d = d2
|
|
113
|
+
if d3 is not None:
|
|
114
|
+
biomes._3d = Biomes3D(d3)
|
|
115
|
+
return biomes
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def dimension(self) -> BiomesShape:
|
|
119
|
+
"""
|
|
120
|
+
The number of dimensions the data has
|
|
121
|
+
|
|
122
|
+
:attr:`BiomesShape.ShapeNull` when there is no data.
|
|
123
|
+
Will error if you try accessing data from it without converting to one of the other formats.
|
|
124
|
+
|
|
125
|
+
:attr:`BiomesShape.Shape2D` when the data is a 2D (16, 16) numpy array.
|
|
126
|
+
|
|
127
|
+
:attr:`BiomesShape.Shape3D` when the data is a 3D (4, inf, 4) :class:`Biome3D` array made of sections of size (4, 4, 4).
|
|
128
|
+
"""
|
|
129
|
+
return self._dimension
|
|
130
|
+
|
|
131
|
+
def convert_to_2d(self):
|
|
132
|
+
"""
|
|
133
|
+
Convert the data to the 2D 16x16 format from whatever format it was in.
|
|
134
|
+
|
|
135
|
+
If it was in the Null state it will be initialised with the first entry in the :obj:`~amulet.api.registry.biome_manager.BiomeManager`.
|
|
136
|
+
|
|
137
|
+
In this mode this class will behave like a numpy array.
|
|
138
|
+
"""
|
|
139
|
+
if self._2d is None:
|
|
140
|
+
self._2d = numpy.zeros((16, 16), numpy.uint32)
|
|
141
|
+
if self._dimension is BiomesShape.Shape3D and self._3d is not None:
|
|
142
|
+
# convert from 3D
|
|
143
|
+
self._2d[:, :] = numpy.kron(
|
|
144
|
+
numpy.reshape(self._3d[:, 0, :], (4, 4)), numpy.ones((4, 4))
|
|
145
|
+
)
|
|
146
|
+
self._dimension = BiomesShape.Shape2D
|
|
147
|
+
|
|
148
|
+
def convert_to_3d(self):
|
|
149
|
+
"""
|
|
150
|
+
Convert the data to the 3D (4, inf, 4) format from whatever format it was in.
|
|
151
|
+
|
|
152
|
+
If it was in the Null state it will be initialised with the first entry in the :class:`~amulet.api.registry.biome_manager.BiomeManager`.
|
|
153
|
+
|
|
154
|
+
In this mode this class will behave like the :class:`Biome3D` class.
|
|
155
|
+
"""
|
|
156
|
+
if self._3d is None:
|
|
157
|
+
self._3d = Biomes3D()
|
|
158
|
+
if self._dimension is BiomesShape.Shape2D and self._2d is not None:
|
|
159
|
+
# convert from 2D
|
|
160
|
+
self._3d[:, :, :] = numpy.repeat(
|
|
161
|
+
self._2d[::4, ::4].reshape(4, 1, 4), 64, axis=1
|
|
162
|
+
)
|
|
163
|
+
self._dimension = BiomesShape.Shape3D
|
|
164
|
+
|
|
165
|
+
def _get_active(self) -> Union[numpy.ndarray, Biomes3D]:
|
|
166
|
+
if self._dimension is BiomesShape.ShapeNull:
|
|
167
|
+
raise Exception(
|
|
168
|
+
"You are trying to use Biomes but have not picked a format. Use one of the convert methods to specify the format."
|
|
169
|
+
)
|
|
170
|
+
elif self._dimension is BiomesShape.Shape2D:
|
|
171
|
+
self.convert_to_2d()
|
|
172
|
+
return self._2d
|
|
173
|
+
elif self._dimension is BiomesShape.Shape3D:
|
|
174
|
+
self.convert_to_3d()
|
|
175
|
+
return self._3d
|
|
176
|
+
else:
|
|
177
|
+
raise Exception("Dimension is invalid. This shouldn't happen")
|
|
178
|
+
|
|
179
|
+
def copy(self):
|
|
180
|
+
return self.__copy__()
|
|
181
|
+
|
|
182
|
+
def __copy__(self):
|
|
183
|
+
cls = self.__class__
|
|
184
|
+
result = cls.__new__(cls)
|
|
185
|
+
for k in self.__slots__:
|
|
186
|
+
setattr(result, k, getattr(self, k))
|
|
187
|
+
return result
|
|
188
|
+
|
|
189
|
+
def __deepcopy__(self, memodict=None):
|
|
190
|
+
cls = self.__class__
|
|
191
|
+
result = cls.__new__(cls)
|
|
192
|
+
memodict[id(self)] = result
|
|
193
|
+
for k in self.__slots__:
|
|
194
|
+
setattr(result, k, deepcopy(getattr(self, k), memodict))
|
|
195
|
+
return result
|
|
196
|
+
|
|
197
|
+
def __getattr__(self, item):
|
|
198
|
+
return getattr(self._get_active(), item)
|
|
199
|
+
|
|
200
|
+
def __contains__(self, item):
|
|
201
|
+
return item in self._get_active()
|
|
202
|
+
|
|
203
|
+
def __getitem__(self, item):
|
|
204
|
+
return self._get_active()[item]
|
|
205
|
+
|
|
206
|
+
def __setitem__(self, key, value):
|
|
207
|
+
self._get_active()[key] = value
|