amulet-core 1.9.18__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/_version.py +3 -3
- amulet/api/level/base_level/base_level.py +19 -10
- amulet/level/formats/anvil_world/_sector_manager.py +5 -98
- amulet/level/formats/anvil_world/format.py +98 -83
- amulet/level/formats/leveldb_world/dimension.py +31 -65
- amulet/level/formats/leveldb_world/format.py +62 -44
- amulet/level/interfaces/chunk/anvil/anvil_3463.py +1 -1
- {amulet_core-1.9.18.dist-info → amulet_core-1.9.20.dist-info}/METADATA +2 -2
- {amulet_core-1.9.18.dist-info → amulet_core-1.9.20.dist-info}/RECORD +12 -12
- {amulet_core-1.9.18.dist-info → amulet_core-1.9.20.dist-info}/WHEEL +0 -0
- {amulet_core-1.9.18.dist-info → amulet_core-1.9.20.dist-info}/entry_points.txt +0 -0
- {amulet_core-1.9.18.dist-info → amulet_core-1.9.20.dist-info}/top_level.txt +0 -0
amulet/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2023-
|
|
11
|
+
"date": "2023-09-29T11:29:40+0100",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "1.9.
|
|
14
|
+
"full-revisionid": "b673f749bf1c348e31bf0594e71ffa30f6ea8519",
|
|
15
|
+
"version": "1.9.20"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -770,11 +770,19 @@ class BaseLevel:
|
|
|
770
770
|
chunk = self.get_chunk(cx, cz, dimension)
|
|
771
771
|
offset_x, offset_z = x - 16 * cx, z - 16 * cz
|
|
772
772
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
).
|
|
776
|
-
|
|
773
|
+
translator = self.translation_manager.get_version(*version).block
|
|
774
|
+
|
|
775
|
+
src_blocks = chunk.get_block(offset_x, y, offset_z).block_tuple
|
|
776
|
+
src_block_entity = chunk.block_entities.get((x, y, z))
|
|
777
|
+
|
|
778
|
+
output, extra_output, _ = translator.from_universal(
|
|
779
|
+
src_blocks[0], src_block_entity
|
|
777
780
|
)
|
|
781
|
+
if isinstance(output, Block):
|
|
782
|
+
for src_block in src_blocks[1:]:
|
|
783
|
+
converted_sub_block = translator.from_universal(src_block)[0]
|
|
784
|
+
if isinstance(converted_sub_block, Block):
|
|
785
|
+
output += converted_sub_block
|
|
778
786
|
return output, extra_output
|
|
779
787
|
|
|
780
788
|
def set_version_block(
|
|
@@ -812,13 +820,14 @@ class BaseLevel:
|
|
|
812
820
|
chunk = self.create_chunk(cx, cz, dimension)
|
|
813
821
|
offset_x, offset_z = x - 16 * cx, z - 16 * cz
|
|
814
822
|
|
|
815
|
-
(
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
block, block_entity
|
|
823
|
+
translator = self.translation_manager.get_version(*version).block
|
|
824
|
+
src_blocks = block.block_tuple
|
|
825
|
+
|
|
826
|
+
universal_block, universal_block_entity, _ = translator.to_universal(
|
|
827
|
+
src_blocks[0], block_entity
|
|
821
828
|
)
|
|
829
|
+
for src_block in src_blocks[1:]:
|
|
830
|
+
universal_block += translator.to_universal(src_block)[0]
|
|
822
831
|
chunk.set_block(offset_x, y, offset_z, universal_block),
|
|
823
832
|
if isinstance(universal_block_entity, BlockEntity):
|
|
824
833
|
chunk.block_entities[(x, y, z)] = universal_block_entity
|
|
@@ -141,9 +141,9 @@ class SectorManager:
|
|
|
141
141
|
|
|
142
142
|
@property
|
|
143
143
|
def sectors(self) -> List[Sector]:
|
|
144
|
-
"""A list of reserved sectors"""
|
|
144
|
+
"""A list of reserved sectors. Ordered by their start location."""
|
|
145
145
|
with self._lock:
|
|
146
|
-
return list(self._reserved)
|
|
146
|
+
return list(sorted(self._reserved, key=lambda i: i.start))
|
|
147
147
|
|
|
148
148
|
def reserve_space(self, length: int) -> Sector:
|
|
149
149
|
"""
|
|
@@ -170,6 +170,7 @@ class SectorManager:
|
|
|
170
170
|
self._free_start[start_index] = free_sector
|
|
171
171
|
else:
|
|
172
172
|
del self._free_start[start_index]
|
|
173
|
+
self._reserved.add(sector)
|
|
173
174
|
return sector
|
|
174
175
|
elif self._resizable:
|
|
175
176
|
sector = Sector(self._stop, self._stop + length)
|
|
@@ -261,6 +262,8 @@ class SectorManager:
|
|
|
261
262
|
:param sector: The sector to free
|
|
262
263
|
"""
|
|
263
264
|
with self._lock:
|
|
265
|
+
if sector not in self._reserved:
|
|
266
|
+
raise ValueError("Sector was not reserved")
|
|
264
267
|
# remove the sector from the reserved storage
|
|
265
268
|
self._reserved.remove(sector)
|
|
266
269
|
|
|
@@ -286,99 +289,3 @@ class SectorManager:
|
|
|
286
289
|
|
|
287
290
|
self._free_start.insert(index, sector)
|
|
288
291
|
self._add_size_sector(sector)
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
def validate(m):
|
|
292
|
-
assert set(m._free_start) == set(m._free_size)
|
|
293
|
-
free = sorted(list(m._free_start) + list(m._reserved), key=lambda k: k.start)
|
|
294
|
-
if free:
|
|
295
|
-
for i in range(len(free) - 1):
|
|
296
|
-
assert free[i].stop == free[i + 1].start
|
|
297
|
-
assert free[-1].stop == m._stop
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
def test1():
|
|
301
|
-
m = SectorManager(2, 3)
|
|
302
|
-
validate(m)
|
|
303
|
-
m.reserve(Sector(2, 3))
|
|
304
|
-
validate(m)
|
|
305
|
-
m.reserve(Sector(3, 4))
|
|
306
|
-
validate(m)
|
|
307
|
-
print(m.sectors)
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
def test2():
|
|
311
|
-
m = SectorManager(2, 102)
|
|
312
|
-
|
|
313
|
-
m.reserve(Sector(5, 6))
|
|
314
|
-
validate(m)
|
|
315
|
-
m.reserve(Sector(6, 7))
|
|
316
|
-
validate(m)
|
|
317
|
-
# m.reserve(Sector(7, 8))
|
|
318
|
-
m.reserve(Sector(8, 9))
|
|
319
|
-
validate(m)
|
|
320
|
-
|
|
321
|
-
try:
|
|
322
|
-
m.reserve(Sector(6, 8))
|
|
323
|
-
except NoValidSector:
|
|
324
|
-
pass
|
|
325
|
-
else:
|
|
326
|
-
raise Exception
|
|
327
|
-
|
|
328
|
-
validate(m)
|
|
329
|
-
|
|
330
|
-
try:
|
|
331
|
-
m.reserve(Sector(7, 9))
|
|
332
|
-
except NoValidSector:
|
|
333
|
-
pass
|
|
334
|
-
else:
|
|
335
|
-
raise Exception
|
|
336
|
-
|
|
337
|
-
validate(m)
|
|
338
|
-
m.free(Sector(5, 6))
|
|
339
|
-
validate(m)
|
|
340
|
-
m.free(Sector(6, 7))
|
|
341
|
-
validate(m)
|
|
342
|
-
m.free(Sector(8, 9))
|
|
343
|
-
validate(m)
|
|
344
|
-
|
|
345
|
-
m.reserve(Sector(6, 8))
|
|
346
|
-
validate(m)
|
|
347
|
-
m.free(Sector(6, 8))
|
|
348
|
-
validate(m)
|
|
349
|
-
|
|
350
|
-
m.reserve(Sector(7, 9))
|
|
351
|
-
validate(m)
|
|
352
|
-
m.free(Sector(7, 9))
|
|
353
|
-
|
|
354
|
-
validate(m)
|
|
355
|
-
|
|
356
|
-
assert len(m._free_start) == 1
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
# def test3():
|
|
360
|
-
# reserve a number of single length units
|
|
361
|
-
# for _ in range(20):
|
|
362
|
-
# i = free_indexes.pop(random.randrange(len(free_indexes)))
|
|
363
|
-
# m.reserve(Sector(i, i+1))
|
|
364
|
-
# validate(m)
|
|
365
|
-
# reserved_indexes.append(i)
|
|
366
|
-
#
|
|
367
|
-
# for _ in range(20):
|
|
368
|
-
# index = random.randrange(len(free_indexes))
|
|
369
|
-
# di = 1
|
|
370
|
-
# i = free_indexes.pop(index)
|
|
371
|
-
#
|
|
372
|
-
# for _ in range(10_000):
|
|
373
|
-
# m.reserve(Sector(i, i+1))
|
|
374
|
-
# validate(m)
|
|
375
|
-
# print(m.sectors)
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
def test():
|
|
379
|
-
test1()
|
|
380
|
-
test2()
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if __name__ == "__main__":
|
|
384
|
-
test()
|
|
@@ -231,93 +231,108 @@ class AnvilFormat(WorldFormatWrapper[VersionNumberInt]):
|
|
|
231
231
|
layers=("region",) + ("entities",) * (self.version >= 2681),
|
|
232
232
|
)
|
|
233
233
|
self._dimension_name_map[dimension_name] = relative_dimension_path
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
234
|
+
self._bounds[dimension_name] = self._get_dimenion_bounds(dimension_name)
|
|
235
|
+
|
|
236
|
+
def _get_dimenion_bounds(self, dimension_type_str: Dimension) -> SelectionGroup:
|
|
237
|
+
if self.version >= 2709: # This number might be smaller
|
|
238
|
+
# If in a version that supports custom height data packs
|
|
239
|
+
dimension_settings = (
|
|
240
|
+
self.root_tag.compound.get_compound("Data", CompoundTag())
|
|
241
|
+
.get_compound("WorldGenSettings", CompoundTag())
|
|
242
|
+
.get_compound("dimensions", CompoundTag())
|
|
243
|
+
.get_compound(dimension_type_str, CompoundTag())
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# "type" can be a reference (string) or inline (compound) dimension-type data.
|
|
247
|
+
dimension_type = dimension_settings.get("type")
|
|
248
|
+
|
|
249
|
+
if isinstance(dimension_type, StringTag):
|
|
250
|
+
# Reference type. Load the dimension data
|
|
251
|
+
dimension_type_str = dimension_type.py_str
|
|
252
|
+
if ":" in dimension_type_str:
|
|
253
|
+
namespace, base_name = dimension_type_str.split(":", 1)
|
|
254
|
+
else:
|
|
255
|
+
namespace = "minecraft"
|
|
256
|
+
base_name = dimension_type_str
|
|
257
|
+
name_tuple = namespace, base_name
|
|
258
|
+
|
|
259
|
+
# First try and load the reference from the data pack and then from defaults
|
|
260
|
+
dimension_path = f"data/{namespace}/dimension_type/{base_name}.json"
|
|
261
|
+
if self.data_pack.has_file(dimension_path):
|
|
262
|
+
with self.data_pack.open(dimension_path) as d:
|
|
263
|
+
try:
|
|
264
|
+
dimension_settings_json = json.load(d)
|
|
265
|
+
except json.JSONDecodeError:
|
|
266
|
+
pass
|
|
267
|
+
else:
|
|
268
|
+
if "min_y" in dimension_settings_json and isinstance(
|
|
269
|
+
dimension_settings_json["min_y"], int
|
|
270
|
+
):
|
|
271
|
+
min_y = dimension_settings_json["min_y"]
|
|
272
|
+
if min_y % 16:
|
|
273
|
+
min_y = 16 * (min_y // 16)
|
|
274
|
+
else:
|
|
275
|
+
min_y = 0
|
|
276
|
+
if "height" in dimension_settings_json and isinstance(
|
|
277
|
+
dimension_settings_json["height"], int
|
|
278
|
+
):
|
|
279
|
+
height = dimension_settings_json["height"]
|
|
280
|
+
if height % 16:
|
|
281
|
+
height = -16 * (-height // 16)
|
|
282
|
+
else:
|
|
283
|
+
height = 256
|
|
284
|
+
|
|
285
|
+
return SelectionGroup(
|
|
254
286
|
SelectionBox(
|
|
255
|
-
(-30_000_000,
|
|
256
|
-
(30_000_000,
|
|
287
|
+
(-30_000_000, min_y, -30_000_000),
|
|
288
|
+
(30_000_000, min_y + height, 30_000_000),
|
|
257
289
|
)
|
|
258
290
|
)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
and isinstance(
|
|
272
|
-
dimension_settings_json["min_y"], int
|
|
273
|
-
)
|
|
274
|
-
):
|
|
275
|
-
min_y = dimension_settings_json["min_y"]
|
|
276
|
-
if min_y % 16:
|
|
277
|
-
min_y = 16 * (min_y // 16)
|
|
278
|
-
else:
|
|
279
|
-
min_y = 0
|
|
280
|
-
if (
|
|
281
|
-
"height" in dimension_settings_json
|
|
282
|
-
and isinstance(
|
|
283
|
-
dimension_settings_json["height"], int
|
|
284
|
-
)
|
|
285
|
-
):
|
|
286
|
-
height = dimension_settings_json["height"]
|
|
287
|
-
if height % 16:
|
|
288
|
-
height = -16 * (-height // 16)
|
|
289
|
-
else:
|
|
290
|
-
height = 256
|
|
291
|
-
|
|
292
|
-
bounds = SelectionGroup(
|
|
293
|
-
SelectionBox(
|
|
294
|
-
(-30_000_000, min_y, -30_000_000),
|
|
295
|
-
(30_000_000, min_y + height, 30_000_000),
|
|
296
|
-
)
|
|
297
|
-
)
|
|
298
|
-
|
|
299
|
-
elif isinstance(dimension_tag, CompoundTag):
|
|
300
|
-
# the settings are here
|
|
301
|
-
dimension_compound_tag = dimension_tag
|
|
302
|
-
min_y = (
|
|
303
|
-
dimension_compound_tag.get_int("min_y", IntTag()).py_int // 16
|
|
304
|
-
) * 16
|
|
305
|
-
height = (
|
|
306
|
-
-dimension_compound_tag.get_int("height", IntTag(256)).py_int
|
|
307
|
-
// 16
|
|
308
|
-
) * -16
|
|
309
|
-
bounds = SelectionGroup(
|
|
310
|
-
SelectionBox(
|
|
311
|
-
(-30_000_000, min_y, -30_000_000),
|
|
312
|
-
(30_000_000, min_y + height, 30_000_000),
|
|
291
|
+
|
|
292
|
+
elif name_tuple in {
|
|
293
|
+
("minecraft", "overworld"),
|
|
294
|
+
("minecraft", "overworld_caves"),
|
|
295
|
+
}:
|
|
296
|
+
if self.version >= 2825:
|
|
297
|
+
# If newer than the height change version
|
|
298
|
+
return SelectionGroup(
|
|
299
|
+
SelectionBox(
|
|
300
|
+
(-30_000_000, -64, -30_000_000),
|
|
301
|
+
(30_000_000, 320, 30_000_000),
|
|
302
|
+
)
|
|
313
303
|
)
|
|
314
|
-
|
|
304
|
+
else:
|
|
305
|
+
return DefaultSelection
|
|
306
|
+
elif name_tuple in {
|
|
307
|
+
("minecraft", "the_nether"),
|
|
308
|
+
("minecraft", "the_end"),
|
|
309
|
+
}:
|
|
310
|
+
return DefaultSelection
|
|
315
311
|
else:
|
|
316
|
-
log.error(
|
|
317
|
-
|
|
312
|
+
log.error(f"Could not find dimension_type {':'.join(name_tuple)}")
|
|
313
|
+
|
|
314
|
+
elif isinstance(dimension_type, CompoundTag):
|
|
315
|
+
# Inline type
|
|
316
|
+
dimension_type_compound = dimension_type
|
|
317
|
+
min_y = (
|
|
318
|
+
dimension_type_compound.get_int("min_y", IntTag()).py_int // 16
|
|
319
|
+
) * 16
|
|
320
|
+
height = (
|
|
321
|
+
-dimension_type_compound.get_int("height", IntTag(256)).py_int // 16
|
|
322
|
+
) * -16
|
|
323
|
+
return SelectionGroup(
|
|
324
|
+
SelectionBox(
|
|
325
|
+
(-30_000_000, min_y, -30_000_000),
|
|
326
|
+
(30_000_000, min_y + height, 30_000_000),
|
|
318
327
|
)
|
|
328
|
+
)
|
|
329
|
+
else:
|
|
330
|
+
log.error(
|
|
331
|
+
f'level_dat["Data"]["WorldGenSettings"]["dimensions"]["{dimension_type_str}"]["type"] was not a StringTag or CompoundTag.'
|
|
332
|
+
)
|
|
319
333
|
|
|
320
|
-
|
|
334
|
+
# Return the default if nothing else returned
|
|
335
|
+
return DefaultSelection
|
|
321
336
|
|
|
322
337
|
def _get_interface(self, raw_chunk_data: Optional[Any] = None) -> "Interface":
|
|
323
338
|
from amulet.level.loader import Interfaces
|
|
@@ -405,9 +420,9 @@ class AnvilFormat(WorldFormatWrapper[VersionNumberInt]):
|
|
|
405
420
|
self._register_dimension("DIM-1", THE_NETHER)
|
|
406
421
|
self._register_dimension("DIM1", THE_END)
|
|
407
422
|
|
|
408
|
-
for
|
|
409
|
-
|
|
410
|
-
|
|
423
|
+
for level_path in glob.glob(os.path.join(glob.escape(self.path), "DIM*")):
|
|
424
|
+
if os.path.isdir(level_path):
|
|
425
|
+
dir_name = os.path.basename(level_path)
|
|
411
426
|
if AnvilDimensionManager.level_regex.fullmatch(dir_name) is None:
|
|
412
427
|
continue
|
|
413
428
|
self._register_dimension(dir_name)
|
|
@@ -8,7 +8,6 @@ from typing import (
|
|
|
8
8
|
List,
|
|
9
9
|
TYPE_CHECKING,
|
|
10
10
|
Tuple,
|
|
11
|
-
Union,
|
|
12
11
|
)
|
|
13
12
|
from threading import RLock
|
|
14
13
|
import logging
|
|
@@ -25,21 +24,17 @@ from amulet_nbt import (
|
|
|
25
24
|
utf8_escape_encoder,
|
|
26
25
|
)
|
|
27
26
|
|
|
28
|
-
from amulet.api.errors import ChunkDoesNotExist
|
|
27
|
+
from amulet.api.errors import ChunkDoesNotExist
|
|
29
28
|
from amulet.api.data_types import ChunkCoordinates
|
|
30
29
|
from leveldb import LevelDB
|
|
31
30
|
from .chunk import ChunkData
|
|
32
31
|
|
|
33
32
|
if TYPE_CHECKING:
|
|
34
|
-
from amulet.api.data_types import Dimension
|
|
35
33
|
from .format import LevelDBFormat
|
|
36
34
|
|
|
37
35
|
log = logging.getLogger(__name__)
|
|
38
36
|
|
|
39
37
|
InternalDimension = Optional[int]
|
|
40
|
-
OVERWORLD = "minecraft:overworld"
|
|
41
|
-
THE_NETHER = "minecraft:the_nether"
|
|
42
|
-
THE_END = "minecraft:the_end"
|
|
43
38
|
|
|
44
39
|
|
|
45
40
|
class ActorCounter:
|
|
@@ -102,12 +97,11 @@ class LevelDBDimensionManager:
|
|
|
102
97
|
self._actor_counter = ActorCounter.from_level(level)
|
|
103
98
|
# self._levels format Dict[level, Dict[Tuple[cx, cz], List[Tuple[full_key, key_extension]]]]
|
|
104
99
|
self._levels: Dict[InternalDimension, Set[ChunkCoordinates]] = {}
|
|
105
|
-
self._dimension_name_map: Dict["Dimension", InternalDimension] = {}
|
|
106
100
|
self._lock = RLock()
|
|
107
101
|
|
|
108
|
-
self.register_dimension(None
|
|
109
|
-
self.register_dimension(1
|
|
110
|
-
self.register_dimension(2
|
|
102
|
+
self.register_dimension(None) # overworld
|
|
103
|
+
self.register_dimension(1) # the nether
|
|
104
|
+
self.register_dimension(2) # the end
|
|
111
105
|
|
|
112
106
|
for key in self._db.keys():
|
|
113
107
|
if 9 <= len(key) <= 10 and key[8] in [44, 118]: # "," "v"
|
|
@@ -117,63 +111,36 @@ class LevelDBDimensionManager:
|
|
|
117
111
|
self._add_chunk(key, has_level=True)
|
|
118
112
|
|
|
119
113
|
@property
|
|
120
|
-
def dimensions(self) -> List[
|
|
114
|
+
def dimensions(self) -> List[InternalDimension]:
|
|
121
115
|
"""A list of all the levels contained in the world"""
|
|
122
|
-
return list(self.
|
|
116
|
+
return list(self._levels)
|
|
123
117
|
|
|
124
|
-
def register_dimension(
|
|
125
|
-
self,
|
|
126
|
-
dimension_internal: InternalDimension,
|
|
127
|
-
dimension_name: Optional["Dimension"] = None,
|
|
128
|
-
):
|
|
118
|
+
def register_dimension(self, dimension: InternalDimension):
|
|
129
119
|
"""
|
|
130
120
|
Register a new dimension.
|
|
131
121
|
|
|
132
|
-
:param
|
|
133
|
-
:param dimension_name: The name of the dimension shown to the user
|
|
122
|
+
:param dimension: The internal representation of the dimension
|
|
134
123
|
:return:
|
|
135
124
|
"""
|
|
136
|
-
if dimension_name is None:
|
|
137
|
-
dimension_name: "Dimension" = f"DIM{dimension_internal}"
|
|
138
|
-
|
|
139
125
|
with self._lock:
|
|
140
|
-
if
|
|
141
|
-
|
|
142
|
-
and dimension_name not in self._dimension_name_map
|
|
143
|
-
):
|
|
144
|
-
self._levels[dimension_internal] = set()
|
|
145
|
-
self._dimension_name_map[dimension_name] = dimension_internal
|
|
146
|
-
|
|
147
|
-
def _get_internal_dimension(self, dimension: "Dimension") -> InternalDimension:
|
|
148
|
-
if dimension in self._dimension_name_map:
|
|
149
|
-
return self._dimension_name_map[dimension]
|
|
150
|
-
else:
|
|
151
|
-
raise DimensionDoesNotExist(dimension)
|
|
126
|
+
if dimension not in self._levels:
|
|
127
|
+
self._levels[dimension] = set()
|
|
152
128
|
|
|
153
|
-
def all_chunk_coords(self, dimension:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return self._levels[internal_dimension]
|
|
129
|
+
def all_chunk_coords(self, dimension: InternalDimension) -> Set[ChunkCoordinates]:
|
|
130
|
+
if dimension in self._levels:
|
|
131
|
+
return self._levels[dimension]
|
|
157
132
|
else:
|
|
158
133
|
return set()
|
|
159
134
|
|
|
160
135
|
@staticmethod
|
|
161
|
-
def _get_key(cx: int, cz: int,
|
|
162
|
-
if
|
|
136
|
+
def _get_key(cx: int, cz: int, dimension: InternalDimension) -> bytes:
|
|
137
|
+
if dimension is None:
|
|
163
138
|
return struct.pack("<ii", cx, cz)
|
|
164
139
|
else:
|
|
165
|
-
return struct.pack("<iii", cx, cz,
|
|
166
|
-
|
|
167
|
-
def _has_chunk(
|
|
168
|
-
self, cx: int, cz: int, internal_dimension: InternalDimension
|
|
169
|
-
) -> bool:
|
|
170
|
-
return (
|
|
171
|
-
internal_dimension in self._levels
|
|
172
|
-
and (cx, cz) in self._levels[internal_dimension]
|
|
173
|
-
)
|
|
140
|
+
return struct.pack("<iii", cx, cz, dimension)
|
|
174
141
|
|
|
175
|
-
def has_chunk(self, cx: int, cz: int, dimension:
|
|
176
|
-
return self.
|
|
142
|
+
def has_chunk(self, cx: int, cz: int, dimension: InternalDimension) -> bool:
|
|
143
|
+
return dimension in self._levels and (cx, cz) in self._levels[dimension]
|
|
177
144
|
|
|
178
145
|
def _add_chunk(self, key_: bytes, has_level: bool = False):
|
|
179
146
|
if has_level:
|
|
@@ -185,14 +152,15 @@ class LevelDBDimensionManager:
|
|
|
185
152
|
self.register_dimension(level)
|
|
186
153
|
self._levels[level].add((cx, cz))
|
|
187
154
|
|
|
188
|
-
def get_chunk_data(
|
|
155
|
+
def get_chunk_data(
|
|
156
|
+
self, cx: int, cz: int, dimension: InternalDimension
|
|
157
|
+
) -> ChunkData:
|
|
189
158
|
"""Get a dictionary of chunk key extension in bytes to the raw data in the key.
|
|
190
159
|
chunk key extension are the character(s) after <cx><cz>[level] in the key
|
|
191
160
|
Will raise ChunkDoesNotExist if the chunk does not exist
|
|
192
161
|
"""
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
prefix = self._get_key(cx, cz, internal_dimension)
|
|
162
|
+
if self.has_chunk(cx, cz, dimension):
|
|
163
|
+
prefix = self._get_key(cx, cz, dimension)
|
|
196
164
|
prefix_len = len(prefix)
|
|
197
165
|
iter_end = prefix + b"\xff\xff\xff\xff"
|
|
198
166
|
|
|
@@ -288,13 +256,12 @@ class LevelDBDimensionManager:
|
|
|
288
256
|
cx: int,
|
|
289
257
|
cz: int,
|
|
290
258
|
chunk_data: ChunkData,
|
|
291
|
-
dimension:
|
|
259
|
+
dimension: InternalDimension,
|
|
292
260
|
):
|
|
293
261
|
"""pass data to the region file class"""
|
|
294
262
|
# get the region key
|
|
295
|
-
|
|
296
|
-
self.
|
|
297
|
-
key_prefix = self._get_key(cx, cz, internal_dimension)
|
|
263
|
+
self._levels[dimension].add((cx, cz))
|
|
264
|
+
key_prefix = self._get_key(cx, cz, dimension)
|
|
298
265
|
|
|
299
266
|
batch = {}
|
|
300
267
|
|
|
@@ -388,15 +355,14 @@ class LevelDBDimensionManager:
|
|
|
388
355
|
if batch:
|
|
389
356
|
self._db.putBatch(batch)
|
|
390
357
|
|
|
391
|
-
def delete_chunk(self, cx: int, cz: int, dimension:
|
|
392
|
-
if dimension not in self.
|
|
358
|
+
def delete_chunk(self, cx: int, cz: int, dimension: InternalDimension):
|
|
359
|
+
if dimension not in self._levels:
|
|
393
360
|
return # dimension does not exists so chunk cannot
|
|
394
361
|
|
|
395
|
-
|
|
396
|
-
if not self._has_chunk(cx, cz, internal_dimension):
|
|
362
|
+
if not self.has_chunk(cx, cz, dimension):
|
|
397
363
|
return # chunk does not exists
|
|
398
364
|
|
|
399
|
-
prefix = self._get_key(cx, cz,
|
|
365
|
+
prefix = self._get_key(cx, cz, dimension)
|
|
400
366
|
prefix_len = len(prefix)
|
|
401
367
|
iter_end = prefix + b"\xff\xff\xff\xff"
|
|
402
368
|
keys = []
|
|
@@ -414,6 +380,6 @@ class LevelDBDimensionManager:
|
|
|
414
380
|
actor_key = b"actorprefix" + digp[i : i + 8]
|
|
415
381
|
self._db.delete(actor_key)
|
|
416
382
|
|
|
417
|
-
self._levels[
|
|
383
|
+
self._levels[dimension].remove((cx, cz))
|
|
418
384
|
for key in keys:
|
|
419
385
|
self._db.delete(key)
|
|
@@ -38,22 +38,23 @@ from amulet.api.data_types import (
|
|
|
38
38
|
Dimension,
|
|
39
39
|
AnyNDArray,
|
|
40
40
|
)
|
|
41
|
-
from amulet.api.wrapper import WorldFormatWrapper
|
|
42
|
-
from amulet.api.errors import
|
|
41
|
+
from amulet.api.wrapper import WorldFormatWrapper, DefaultSelection
|
|
42
|
+
from amulet.api.errors import (
|
|
43
|
+
ObjectWriteError,
|
|
44
|
+
ObjectReadError,
|
|
45
|
+
PlayerDoesNotExist,
|
|
46
|
+
ChunkDoesNotExist,
|
|
47
|
+
)
|
|
43
48
|
|
|
44
49
|
from .interface.chunk.leveldb_chunk_versions import (
|
|
45
50
|
game_to_chunk_version,
|
|
46
51
|
)
|
|
47
|
-
from .dimension import
|
|
48
|
-
LevelDBDimensionManager,
|
|
49
|
-
ChunkData,
|
|
50
|
-
OVERWORLD,
|
|
51
|
-
THE_NETHER,
|
|
52
|
-
THE_END,
|
|
53
|
-
)
|
|
52
|
+
from .dimension import LevelDBDimensionManager, ChunkData, InternalDimension
|
|
54
53
|
from .interface.chunk import BaseLevelDBInterface, get_interface
|
|
55
54
|
|
|
56
|
-
|
|
55
|
+
OVERWORLD = "minecraft:overworld"
|
|
56
|
+
THE_NETHER = "minecraft:the_nether"
|
|
57
|
+
THE_END = "minecraft:the_end"
|
|
57
58
|
|
|
58
59
|
|
|
59
60
|
class BedrockLevelDAT(NamedTag):
|
|
@@ -177,6 +178,7 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
177
178
|
self._root_tag = BedrockLevelDAT(path=dat_path, level_dat_version=9)
|
|
178
179
|
self._db = None
|
|
179
180
|
self._dimension_manager = None
|
|
181
|
+
self._dimension_to_internal: dict[Dimension, InternalDimension] = {}
|
|
180
182
|
self._shallow_load()
|
|
181
183
|
|
|
182
184
|
def _shallow_load(self):
|
|
@@ -260,12 +262,12 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
260
262
|
return f"Bedrock Unknown Version"
|
|
261
263
|
|
|
262
264
|
@property
|
|
263
|
-
def dimensions(self) -> List[
|
|
265
|
+
def dimensions(self) -> List[Dimension]:
|
|
264
266
|
self._verify_has_lock()
|
|
265
|
-
return self.
|
|
267
|
+
return list(self._dimension_to_internal)
|
|
266
268
|
|
|
267
269
|
# def register_dimension(
|
|
268
|
-
# self, dimension_internal: int, dimension_name: Optional[
|
|
270
|
+
# self, dimension_internal: int, dimension_name: Optional[Dimension] = None
|
|
269
271
|
# ):
|
|
270
272
|
# """
|
|
271
273
|
# Register a new dimension.
|
|
@@ -348,6 +350,12 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
348
350
|
self._dimension_manager = LevelDBDimensionManager(self)
|
|
349
351
|
self._is_open = True
|
|
350
352
|
self._has_lock = True
|
|
353
|
+
|
|
354
|
+
self._dimension_to_internal.clear()
|
|
355
|
+
self._dimension_to_internal[OVERWORLD] = None
|
|
356
|
+
self._dimension_to_internal[THE_NETHER] = 1
|
|
357
|
+
self._dimension_to_internal[THE_END] = 2
|
|
358
|
+
|
|
351
359
|
experiments = self.root_tag.compound.get_compound(
|
|
352
360
|
"experiments", CompoundTag()
|
|
353
361
|
)
|
|
@@ -362,21 +370,14 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
362
370
|
)
|
|
363
371
|
)
|
|
364
372
|
else:
|
|
365
|
-
self._bounds[OVERWORLD] =
|
|
366
|
-
SelectionBox(
|
|
367
|
-
(-30_000_000, 0, -30_000_000), (30_000_000, 256, 30_000_000)
|
|
368
|
-
)
|
|
369
|
-
)
|
|
373
|
+
self._bounds[OVERWORLD] = DefaultSelection
|
|
370
374
|
self._bounds[THE_NETHER] = SelectionGroup(
|
|
371
375
|
SelectionBox(
|
|
372
376
|
(-30_000_000, 0, -30_000_000), (30_000_000, 128, 30_000_000)
|
|
373
377
|
)
|
|
374
378
|
)
|
|
375
|
-
self._bounds[THE_END] =
|
|
376
|
-
|
|
377
|
-
(-30_000_000, 0, -30_000_000), (30_000_000, 256, 30_000_000)
|
|
378
|
-
)
|
|
379
|
-
)
|
|
379
|
+
self._bounds[THE_END] = DefaultSelection
|
|
380
|
+
|
|
380
381
|
if b"LevelChunkMetaDataDictionary" in self.level_db:
|
|
381
382
|
data = self.level_db[b"LevelChunkMetaDataDictionary"]
|
|
382
383
|
count, data = struct.unpack("<I", data[:4])[0], data[4:]
|
|
@@ -396,9 +397,9 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
396
397
|
dimension_name = value.get_string("DimensionName").py_str
|
|
397
398
|
# The dimension names are stored differently TODO: split local and global names
|
|
398
399
|
dimension_name = {
|
|
399
|
-
"Overworld":
|
|
400
|
-
"Nether":
|
|
401
|
-
"TheEnd":
|
|
400
|
+
"Overworld": OVERWORLD,
|
|
401
|
+
"Nether": THE_NETHER,
|
|
402
|
+
"TheEnd": THE_END,
|
|
402
403
|
}.get(dimension_name, dimension_name)
|
|
403
404
|
|
|
404
405
|
except KeyError:
|
|
@@ -407,13 +408,7 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
407
408
|
pass
|
|
408
409
|
else:
|
|
409
410
|
previous_bounds = self._bounds.get(
|
|
410
|
-
dimension_name,
|
|
411
|
-
SelectionGroup(
|
|
412
|
-
SelectionBox(
|
|
413
|
-
(-30_000_000, 0, -30_000_000),
|
|
414
|
-
(30_000_000, 256, 30_000_000),
|
|
415
|
-
)
|
|
416
|
-
),
|
|
411
|
+
dimension_name, DefaultSelection
|
|
417
412
|
)
|
|
418
413
|
min_y = min(
|
|
419
414
|
value.get_compound(
|
|
@@ -447,6 +442,15 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
447
442
|
(previous_bounds.max_x, max_y, previous_bounds.max_z),
|
|
448
443
|
)
|
|
449
444
|
)
|
|
445
|
+
|
|
446
|
+
# Give all other dimensions found an entry
|
|
447
|
+
known_dimensions = set(self._dimension_to_internal.values())
|
|
448
|
+
for internal_dimension in self._dimension_manager.dimensions:
|
|
449
|
+
if internal_dimension not in known_dimensions:
|
|
450
|
+
dimension_name = f"DIM{internal_dimension}"
|
|
451
|
+
self._dimension_to_internal[dimension_name] = internal_dimension
|
|
452
|
+
self._bounds[dimension_name] = DefaultSelection
|
|
453
|
+
|
|
450
454
|
except LevelDBEncrypted as e:
|
|
451
455
|
self._is_open = self._has_lock = False
|
|
452
456
|
raise LevelDBException(
|
|
@@ -525,24 +529,34 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
525
529
|
def unload(self):
|
|
526
530
|
pass
|
|
527
531
|
|
|
528
|
-
def all_chunk_coords(self, dimension:
|
|
532
|
+
def all_chunk_coords(self, dimension: Dimension) -> Iterable[ChunkCoordinates]:
|
|
529
533
|
self._verify_has_lock()
|
|
530
|
-
|
|
534
|
+
if dimension in self._dimension_to_internal:
|
|
535
|
+
yield from self._dimension_manager.all_chunk_coords(
|
|
536
|
+
self._dimension_to_internal[dimension]
|
|
537
|
+
)
|
|
531
538
|
|
|
532
539
|
def has_chunk(self, cx: int, cz: int, dimension: Dimension) -> bool:
|
|
533
|
-
|
|
540
|
+
if dimension in self._dimension_to_internal:
|
|
541
|
+
return self._dimension_manager.has_chunk(
|
|
542
|
+
cx, cz, self._dimension_to_internal[dimension]
|
|
543
|
+
)
|
|
544
|
+
return False
|
|
534
545
|
|
|
535
|
-
def _delete_chunk(self, cx: int, cz: int, dimension:
|
|
536
|
-
self.
|
|
546
|
+
def _delete_chunk(self, cx: int, cz: int, dimension: Dimension):
|
|
547
|
+
if dimension in self._dimension_to_internal:
|
|
548
|
+
self._dimension_manager.delete_chunk(
|
|
549
|
+
cx, cz, self._dimension_to_internal[dimension]
|
|
550
|
+
)
|
|
537
551
|
|
|
538
552
|
def _put_raw_chunk_data(
|
|
539
|
-
self, cx: int, cz: int, data: ChunkData, dimension:
|
|
553
|
+
self, cx: int, cz: int, data: ChunkData, dimension: Dimension
|
|
540
554
|
):
|
|
541
|
-
|
|
555
|
+
self._dimension_manager.put_chunk_data(
|
|
556
|
+
cx, cz, data, self._dimension_to_internal[dimension]
|
|
557
|
+
)
|
|
542
558
|
|
|
543
|
-
def _get_raw_chunk_data(
|
|
544
|
-
self, cx: int, cz: int, dimension: "Dimension"
|
|
545
|
-
) -> ChunkData:
|
|
559
|
+
def _get_raw_chunk_data(self, cx: int, cz: int, dimension: Dimension) -> ChunkData:
|
|
546
560
|
"""
|
|
547
561
|
Return the raw data as loaded from disk.
|
|
548
562
|
|
|
@@ -551,7 +565,11 @@ class LevelDBFormat(WorldFormatWrapper[VersionNumberTuple]):
|
|
|
551
565
|
:param dimension: The dimension to load the data from.
|
|
552
566
|
:return: The raw chunk data.
|
|
553
567
|
"""
|
|
554
|
-
|
|
568
|
+
if dimension not in self._dimension_to_internal:
|
|
569
|
+
raise ChunkDoesNotExist
|
|
570
|
+
return self._dimension_manager.get_chunk_data(
|
|
571
|
+
cx, cz, self._dimension_to_internal[dimension]
|
|
572
|
+
)
|
|
555
573
|
|
|
556
574
|
def all_player_ids(self) -> Iterable[str]:
|
|
557
575
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: amulet-core
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.20
|
|
4
4
|
Summary: A Python library for reading/writing Minecraft's various save formats.
|
|
5
5
|
Home-page: https://www.amuletmc.com
|
|
6
6
|
Author: James Clare, Ben Gothard et al.
|
|
@@ -8,7 +8,7 @@ Author-email: amuleteditor@gmail.com
|
|
|
8
8
|
Platform: any
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
Requires-Dist: numpy ~=1.17
|
|
14
14
|
Requires-Dist: amulet-nbt ~=2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
amulet/__init__.py,sha256=sWKAqhofjzTINMJB22nXeBTITznt4H9rM3ZaaAn2SB4,866
|
|
2
|
-
amulet/_version.py,sha256=
|
|
2
|
+
amulet/_version.py,sha256=gUdgVfmYy5twLboNe4_FGwrJzp6s23bhMPNOnXdLQJQ,498
|
|
3
3
|
amulet/__pyinstaller/__init__.py,sha256=JJOm9J0BoU_vwoYyoHgd8vwSdiO5SGlHHWH6EQK6sc4,41
|
|
4
4
|
amulet/__pyinstaller/hook-amulet.py,sha256=5s6LZxxd47zNsrsJi-PORR7Q6QC079D7pcTkSn1uzCs,158
|
|
5
5
|
amulet/api/__init__.py,sha256=HJ88KU13JNYES9sptkz0la0OsoRvBGUavuOanaZ_RyM,46
|
|
@@ -43,7 +43,7 @@ amulet/api/level/__init__.py,sha256=w-tIez-d-wurUHaxYijjeIPXF3MaV6d5IHEZQo0z5Gg,
|
|
|
43
43
|
amulet/api/level/structure.py,sha256=jbcCaaZOoY8cwUxbSKu8R9Zq2HYdPLgiFSYBzoD2OSM,619
|
|
44
44
|
amulet/api/level/world.py,sha256=HpKe4uvV5Ar2RaNf59wuP5tsxJmComMMNHpnjYAT7_Y,613
|
|
45
45
|
amulet/api/level/base_level/__init__.py,sha256=Gix697NJxsR4zuYf-Q5Rj2IgrWWMpKvqQTfSc4TVuEY,34
|
|
46
|
-
amulet/api/level/base_level/base_level.py,sha256=
|
|
46
|
+
amulet/api/level/base_level/base_level.py,sha256=Sfd0Qgu-xGasJO9aLpMFmf68DjMSt6J3w6nmTIsOcSU,43619
|
|
47
47
|
amulet/api/level/base_level/chunk_manager.py,sha256=Dru933TSAmH3bklVulVvwxyp4VGFa2CHZvjmkDzmLZM,8921
|
|
48
48
|
amulet/api/level/base_level/clone.py,sha256=1CxmXha7i6Vlz7QOUY4K3q3zbd6l0SqF-ppvB12VHvc,19543
|
|
49
49
|
amulet/api/level/base_level/player_manager.py,sha256=ecx4AXAWGxuVG5zaQ_lS2Mr-O0VQu685n3KneTkV4nA,3226
|
|
@@ -78,9 +78,9 @@ amulet/level/loader.py,sha256=WF8LrPY8S9qAUIEse4FMkb7EDc0DzqNGs1graykj0-c,2869
|
|
|
78
78
|
amulet/level/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
79
|
amulet/level/formats/anvil_forge_world.py,sha256=oktfFzj7YYzCdpHJeRKPp-XAR6EzGIp9nHeaQSvUHGo,1187
|
|
80
80
|
amulet/level/formats/anvil_world/__init__.py,sha256=QlLF_96Ub9ceibhR8J1CVfkSaAqXl8dUQWWxFjDJkW0,54
|
|
81
|
-
amulet/level/formats/anvil_world/_sector_manager.py,sha256=
|
|
81
|
+
amulet/level/formats/anvil_world/_sector_manager.py,sha256=QK-M9C4j_QfcpBxd_GwmUeQbwpnTgc6TC6egqtB4ZP8,11080
|
|
82
82
|
amulet/level/formats/anvil_world/dimension.py,sha256=Ft38XWSjJ7mRjHqF-XjEIR7uJFTB_oBaWQIPNaMrsgQ,6069
|
|
83
|
-
amulet/level/formats/anvil_world/format.py,sha256=
|
|
83
|
+
amulet/level/formats/anvil_world/format.py,sha256=FYcBhiKw_kRb5yKLtFkTD-kqlYDsZTXN72snBgjmstI,27502
|
|
84
84
|
amulet/level/formats/anvil_world/region.py,sha256=-_Ru3na9SJsUWQhzRGOb1uTLoIbg2mdpVUNIa2-TM14,14095
|
|
85
85
|
amulet/level/formats/anvil_world/data_pack/__init__.py,sha256=L-He67mqDNWp0boI1VDyIz92BfBZqSKLnBcR0bYxQUA,79
|
|
86
86
|
amulet/level/formats/anvil_world/data_pack/data_pack.py,sha256=N7WwzdQuqmIsjInIqhk-I0UGV67wCFc_ysQMYh0UXYU,6161
|
|
@@ -92,8 +92,8 @@ amulet/level/formats/construction/section.py,sha256=_LdEQTLpaWnFhFCsmrzEFKRvXl7k
|
|
|
92
92
|
amulet/level/formats/construction/util.py,sha256=dBBITNfxUocxxzVnUpRUetr0KuLtMVGjk0-o6iAUKBs,4930
|
|
93
93
|
amulet/level/formats/leveldb_world/__init__.py,sha256=dXo6jIok-_suB3KSrhb5NZS7CicGQj-HCLiGpD76QDY,58
|
|
94
94
|
amulet/level/formats/leveldb_world/chunk.py,sha256=iNMwNs09Kyj9fUo3dFZxdtLyW_uh11aXgDUqe_MKoQo,1202
|
|
95
|
-
amulet/level/formats/leveldb_world/dimension.py,sha256=
|
|
96
|
-
amulet/level/formats/leveldb_world/format.py,sha256=
|
|
95
|
+
amulet/level/formats/leveldb_world/dimension.py,sha256=MDnPlQd5LYEJyd9Z9B_-bsbfCkOqQsoTZfEfrxVwupA,14726
|
|
96
|
+
amulet/level/formats/leveldb_world/format.py,sha256=PsnpNE778q83wKw_6bbH06V9Q1avIpyh3U8pj0iTMlw,23401
|
|
97
97
|
amulet/level/formats/leveldb_world/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
98
98
|
amulet/level/formats/leveldb_world/interface/chunk/__init__.py,sha256=S606IgGmRqdQfv223yciHil3qqna8r5DiW8gsrNHyf0,1180
|
|
99
99
|
amulet/level/formats/leveldb_world/interface/chunk/base_leveldb_interface.py,sha256=3SvaZX_2Umi3ibfD9zVo6pn6vnnJ34NQOJ51oDB8JRs,32470
|
|
@@ -174,7 +174,7 @@ amulet/level/interfaces/chunk/anvil/anvil_2529.py,sha256=UTtQkxcM3jUdSWpy02gehEh
|
|
|
174
174
|
amulet/level/interfaces/chunk/anvil/anvil_2681.py,sha256=w9lz9014E3yNFdsLUFvF4UP1IE_OzdwFp8lZ0Zl5tCg,2319
|
|
175
175
|
amulet/level/interfaces/chunk/anvil/anvil_2709.py,sha256=qRvOb67bjyh-HcSEUiqlf1YKMqPfZjeW98Aid92YQy8,417
|
|
176
176
|
amulet/level/interfaces/chunk/anvil/anvil_2844.py,sha256=0jqoRhw5kRgDUfmm6dF18lxpIsDvm0eSL2rckVFhCCY,10216
|
|
177
|
-
amulet/level/interfaces/chunk/anvil/anvil_3463.py,sha256=
|
|
177
|
+
amulet/level/interfaces/chunk/anvil/anvil_3463.py,sha256=vin45VuAiRsLhM03n6Sl527-O28fiiwIiTBwE3gklx4,422
|
|
178
178
|
amulet/level/interfaces/chunk/anvil/anvil_na.py,sha256=9E9Jd9sQQqG_osfYmIg50hbMpZ0c9Dhi1N1ZDurC2VI,22007
|
|
179
179
|
amulet/level/interfaces/chunk/anvil/base_anvil_interface.py,sha256=fG3nEkRxY9O-yvlBPFJW1abTb8Vw6Lhh7rjMJf7c1SA,11979
|
|
180
180
|
amulet/level/translators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -201,8 +201,8 @@ amulet/utils/generator.py,sha256=2pKToghl8irYozX5hBJYtjTQVzhljznPCi42hQKRGDQ,364
|
|
|
201
201
|
amulet/utils/matrix.py,sha256=KSqluO0H6oHUfe0pU4Esv67pOmHFurK2BDOrZAeNxg8,7665
|
|
202
202
|
amulet/utils/numpy_helpers.py,sha256=fM0rjZxbUqoTMTrFooZEVVhHfsqv0j_7KPGsjVq4ReM,1232
|
|
203
203
|
amulet/utils/world_utils.py,sha256=xb6JPrrbwDF0_y4ZYjTJ1ieydL3COzzLosTgcxDDyRc,12559
|
|
204
|
-
amulet_core-1.9.
|
|
205
|
-
amulet_core-1.9.
|
|
206
|
-
amulet_core-1.9.
|
|
207
|
-
amulet_core-1.9.
|
|
208
|
-
amulet_core-1.9.
|
|
204
|
+
amulet_core-1.9.20.dist-info/METADATA,sha256=SYeHecDnCp-awuJ5JkzMoHmIWRQMVm5RhR81LTzCfo0,4262
|
|
205
|
+
amulet_core-1.9.20.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
206
|
+
amulet_core-1.9.20.dist-info/entry_points.txt,sha256=53zFNThTPzI8f9ertsyU2DoUpxdWU8rjOA_Cu4YH5Vk,63
|
|
207
|
+
amulet_core-1.9.20.dist-info/top_level.txt,sha256=3ZqHzNDiIb9kV8TwSeeXxK_9haSrsu631Qe4ndDo0rc,7
|
|
208
|
+
amulet_core-1.9.20.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|