amulet-core 2.0a8__cp312-cp312-win_amd64.whl → 2.0.1a3.post250529101330__cp312-cp312-win_amd64.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/core/__init__.py +36 -0
- amulet/core/__pyinstaller/hook-amulet.core.py +4 -0
- amulet/core/_amulet_core.cp312-win_amd64.pyd +0 -0
- amulet/core/_amulet_core.pyi +7 -0
- amulet/{_version.py → core/_version.py} +3 -3
- amulet/core/amulet_core.dll +0 -0
- amulet/core/amulet_core.lib +0 -0
- amulet/core/amulet_coreConfig.cmake +18 -0
- amulet/{biome.pyi → core/biome/__init__.pyi} +3 -3
- amulet/core/biome/biome.hpp +53 -0
- amulet/{block.pyi → core/block/__init__.pyi} +25 -26
- amulet/core/block/block.hpp +156 -0
- amulet/{block_entity.pyi → core/block_entity/__init__.pyi} +7 -7
- amulet/core/block_entity/block_entity.hpp +84 -0
- amulet/{errors.py → core/chunk/__init__.pyi} +37 -33
- amulet/core/chunk/chunk.hpp +126 -0
- amulet/core/chunk/component/__init__.pyi +18 -0
- amulet/core/chunk/component/biome_3d_component.hpp +96 -0
- amulet/core/chunk/component/block_component.hpp +101 -0
- amulet/core/chunk/component/block_component.pyi +28 -0
- amulet/core/chunk/component/block_entity_component.hpp +119 -0
- amulet/core/chunk/component/section_array_map.hpp +129 -0
- amulet/{chunk_components.pyi → core/chunk/component/section_array_map.pyi} +4 -24
- amulet/core/dll.hpp +21 -0
- amulet/core/entity/__init__.pyi +105 -0
- amulet/core/entity/entity.hpp +100 -0
- amulet/{palette → core/palette}/__init__.pyi +2 -2
- amulet/core/palette/biome_palette.hpp +65 -0
- amulet/{palette → core/palette}/biome_palette.pyi +8 -8
- amulet/core/palette/block_palette.hpp +71 -0
- amulet/{palette → core/palette}/block_palette.pyi +12 -10
- amulet/core/selection/__init__.pyi +8 -0
- amulet/core/selection/box.hpp +86 -0
- amulet/core/selection/box.pyi +215 -0
- amulet/core/selection/group.hpp +80 -0
- amulet/core/selection/group.pyi +213 -0
- amulet/{version.pyi → core/version/__init__.pyi} +58 -10
- amulet/core/version/version.hpp +204 -0
- {amulet_core-2.0a8.dist-info → amulet_core-2.0.1a3.post250529101330.dist-info}/METADATA +25 -20
- amulet_core-2.0.1a3.post250529101330.dist-info/RECORD +45 -0
- {amulet_core-2.0a8.dist-info → amulet_core-2.0.1a3.post250529101330.dist-info}/WHEEL +1 -1
- amulet_core-2.0.1a3.post250529101330.dist-info/entry_points.txt +2 -0
- amulet/__init__.cp312-win_amd64.pyd +0 -0
- amulet/__init__.py.cpp +0 -45
- amulet/__init__.pyi +0 -30
- amulet/__pyinstaller/hook-amulet.py +0 -4
- amulet/_init.py +0 -26
- amulet/biome.cpp +0 -36
- amulet/biome.hpp +0 -43
- amulet/biome.py.cpp +0 -122
- amulet/block.cpp +0 -435
- amulet/block.hpp +0 -119
- amulet/block.py.cpp +0 -377
- amulet/block_entity.cpp +0 -12
- amulet/block_entity.hpp +0 -56
- amulet/block_entity.py.cpp +0 -115
- amulet/chunk.cpp +0 -16
- amulet/chunk.hpp +0 -100
- amulet/chunk.py.cpp +0 -80
- amulet/chunk.pyi +0 -28
- amulet/chunk_components/biome_3d_component.cpp +0 -5
- amulet/chunk_components/biome_3d_component.hpp +0 -79
- amulet/chunk_components/block_component.cpp +0 -41
- amulet/chunk_components/block_component.hpp +0 -88
- amulet/chunk_components/block_entity_component.cpp +0 -5
- amulet/chunk_components/block_entity_component.hpp +0 -147
- amulet/chunk_components/section_array_map.cpp +0 -129
- amulet/chunk_components/section_array_map.hpp +0 -147
- amulet/collections/eq.py.hpp +0 -37
- amulet/collections/hash.py.hpp +0 -27
- amulet/collections/holder.py.hpp +0 -37
- amulet/collections/iterator.py.hpp +0 -80
- amulet/collections/mapping.py.hpp +0 -199
- amulet/collections/mutable_mapping.py.hpp +0 -226
- amulet/collections/sequence.py.hpp +0 -163
- amulet/collections.pyi +0 -40
- amulet/data_types.py +0 -29
- amulet/entity.py +0 -182
- amulet/game/__init__.py +0 -7
- amulet/game/_game.py +0 -152
- amulet/game/_universal/__init__.py +0 -1
- amulet/game/_universal/_biome.py +0 -17
- amulet/game/_universal/_block.py +0 -47
- amulet/game/_universal/_version.py +0 -68
- amulet/game/abc/__init__.py +0 -22
- amulet/game/abc/_block_specification.py +0 -150
- amulet/game/abc/biome.py +0 -213
- amulet/game/abc/block.py +0 -331
- amulet/game/abc/game_version_container.py +0 -25
- amulet/game/abc/json_interface.py +0 -27
- amulet/game/abc/version.py +0 -44
- amulet/game/bedrock/__init__.py +0 -1
- amulet/game/bedrock/_biome.py +0 -35
- amulet/game/bedrock/_block.py +0 -42
- amulet/game/bedrock/_version.py +0 -165
- amulet/game/java/__init__.py +0 -2
- amulet/game/java/_biome.py +0 -35
- amulet/game/java/_block.py +0 -60
- amulet/game/java/_version.py +0 -176
- amulet/game/translate/__init__.py +0 -12
- amulet/game/translate/_functions/__init__.py +0 -15
- amulet/game/translate/_functions/_code_functions/__init__.py +0 -0
- amulet/game/translate/_functions/_code_functions/_text.py +0 -553
- amulet/game/translate/_functions/_code_functions/banner_pattern.py +0 -67
- amulet/game/translate/_functions/_code_functions/bedrock_chest_connection.py +0 -152
- amulet/game/translate/_functions/_code_functions/bedrock_moving_block_pos.py +0 -88
- amulet/game/translate/_functions/_code_functions/bedrock_sign.py +0 -152
- amulet/game/translate/_functions/_code_functions/bedrock_skull_rotation.py +0 -16
- amulet/game/translate/_functions/_code_functions/custom_name.py +0 -146
- amulet/game/translate/_functions/_frozen.py +0 -66
- amulet/game/translate/_functions/_state.py +0 -54
- amulet/game/translate/_functions/_typing.py +0 -98
- amulet/game/translate/_functions/abc.py +0 -123
- amulet/game/translate/_functions/carry_nbt.py +0 -160
- amulet/game/translate/_functions/carry_properties.py +0 -80
- amulet/game/translate/_functions/code.py +0 -143
- amulet/game/translate/_functions/map_block_name.py +0 -66
- amulet/game/translate/_functions/map_nbt.py +0 -111
- amulet/game/translate/_functions/map_properties.py +0 -93
- amulet/game/translate/_functions/multiblock.py +0 -112
- amulet/game/translate/_functions/new_block.py +0 -42
- amulet/game/translate/_functions/new_entity.py +0 -43
- amulet/game/translate/_functions/new_nbt.py +0 -206
- amulet/game/translate/_functions/new_properties.py +0 -64
- amulet/game/translate/_functions/sequence.py +0 -51
- amulet/game/translate/_functions/walk_input_nbt.py +0 -331
- amulet/game/translate/_translator.py +0 -433
- amulet/img/__init__.py +0 -10
- amulet/img/missing_no.png +0 -0
- amulet/img/missing_pack.png +0 -0
- amulet/img/missing_world.png +0 -0
- amulet/io/binary_reader.hpp +0 -45
- amulet/io/binary_writer.hpp +0 -30
- amulet/item.py +0 -75
- amulet/level/__init__.pyi +0 -23
- amulet/level/_load.py +0 -100
- amulet/level/abc/__init__.py +0 -12
- amulet/level/abc/_chunk_handle.py +0 -358
- amulet/level/abc/_dimension.py +0 -86
- amulet/level/abc/_history/__init__.py +0 -1
- amulet/level/abc/_history/_cache.py +0 -224
- amulet/level/abc/_history/_history_manager.py +0 -291
- amulet/level/abc/_level/__init__.py +0 -5
- amulet/level/abc/_level/_compactable_level.py +0 -10
- amulet/level/abc/_level/_creatable_level.py +0 -28
- amulet/level/abc/_level/_disk_level.py +0 -17
- amulet/level/abc/_level/_level.py +0 -449
- amulet/level/abc/_level/_loadable_level.py +0 -42
- amulet/level/abc/_player_storage.py +0 -7
- amulet/level/abc/_raw_level.py +0 -187
- amulet/level/abc/_registry.py +0 -40
- amulet/level/java/__init__.pyi +0 -16
- amulet/level/java/_chunk_handle.py +0 -17
- amulet/level/java/_dimension.py +0 -20
- amulet/level/java/_level.py +0 -184
- amulet/level/java/_raw/__init__.pyi +0 -15
- amulet/level/java/_raw/_chunk.pyi +0 -23
- amulet/level/java/_raw/_constant.py +0 -9
- amulet/level/java/_raw/_data_pack/__init__.py +0 -2
- amulet/level/java/_raw/_data_pack/data_pack.py +0 -241
- amulet/level/java/_raw/_data_pack/data_pack_manager.py +0 -77
- amulet/level/java/_raw/_dimension.py +0 -86
- amulet/level/java/_raw/_level.py +0 -507
- amulet/level/java/_raw/_typing.py +0 -3
- amulet/level/java/_raw/java_chunk_decode.cpp +0 -531
- amulet/level/java/_raw/java_chunk_decode.hpp +0 -23
- amulet/level/java/_raw/java_chunk_encode.cpp +0 -25
- amulet/level/java/_raw/java_chunk_encode.hpp +0 -23
- amulet/level/java/anvil/__init__.py +0 -2
- amulet/level/java/anvil/_dimension.py +0 -170
- amulet/level/java/anvil/_region.py +0 -421
- amulet/level/java/anvil/_sector_manager.py +0 -223
- amulet/level/java/chunk.pyi +0 -81
- amulet/level/java/chunk_/_chunk.py +0 -260
- amulet/level/java/chunk_/components/inhabited_time.py +0 -12
- amulet/level/java/chunk_/components/last_update.py +0 -12
- amulet/level/java/chunk_/components/legacy_version.py +0 -12
- amulet/level/java/chunk_/components/light_populated.py +0 -12
- amulet/level/java/chunk_/components/named_height_2d.py +0 -37
- amulet/level/java/chunk_/components/status.py +0 -11
- amulet/level/java/chunk_/components/terrain_populated.py +0 -12
- amulet/level/java/chunk_components/data_version_component.cpp +0 -32
- amulet/level/java/chunk_components/data_version_component.hpp +0 -31
- amulet/level/java/chunk_components/java_raw_chunk_component.cpp +0 -56
- amulet/level/java/chunk_components/java_raw_chunk_component.hpp +0 -45
- amulet/level/java/chunk_components.pyi +0 -22
- amulet/level/java/java_chunk.cpp +0 -170
- amulet/level/java/java_chunk.hpp +0 -141
- amulet/level/java/long_array.hpp +0 -175
- amulet/level/java/long_array.pyi +0 -39
- amulet/level/temporary_level/__init__.py +0 -1
- amulet/level/temporary_level/_level.py +0 -16
- amulet/mesh/__init__.py +0 -0
- amulet/mesh/block/__init__.pyi +0 -301
- amulet/mesh/block/_cube.py +0 -198
- amulet/mesh/block/_missing_block.py +0 -20
- amulet/mesh/block/block_mesh.cpp +0 -107
- amulet/mesh/block/block_mesh.hpp +0 -207
- amulet/mesh/util.py +0 -17
- amulet/palette/biome_palette.hpp +0 -85
- amulet/palette/block_palette.cpp +0 -32
- amulet/palette/block_palette.hpp +0 -93
- amulet/player.py +0 -62
- amulet/pybind11/collections.hpp +0 -118
- amulet/pybind11/numpy.hpp +0 -26
- amulet/pybind11/py_module.hpp +0 -34
- amulet/pybind11/type_hints.hpp +0 -51
- amulet/pybind11/types.hpp +0 -25
- amulet/pybind11/typing.hpp +0 -7
- amulet/resource_pack/__init__.py +0 -63
- amulet/resource_pack/abc/__init__.py +0 -2
- amulet/resource_pack/abc/resource_pack.py +0 -38
- amulet/resource_pack/abc/resource_pack_manager.py +0 -85
- amulet/resource_pack/java/__init__.py +0 -2
- amulet/resource_pack/java/download_resources.py +0 -212
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_black.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_blue.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_brown.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_cyan.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_gray.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_green.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_light_blue.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_light_gray.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_lime.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_magenta.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_orange.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_pink.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_purple.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_red.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_white.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_yellow.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/barrier.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/end_portal.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/grass.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/lava.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/structure_void.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/water.png +0 -0
- amulet/resource_pack/java/java_vanilla_fix/pack.png +0 -0
- amulet/resource_pack/java/resource_pack.py +0 -44
- amulet/resource_pack/java/resource_pack_manager.py +0 -563
- amulet/resource_pack/unknown_resource_pack.py +0 -10
- amulet/selection/__init__.py +0 -2
- amulet/selection/abstract_selection.py +0 -342
- amulet/selection/box.py +0 -852
- amulet/selection/group.py +0 -481
- amulet/utils/__init__.pyi +0 -23
- amulet/utils/call_spec/__init__.py +0 -24
- amulet/utils/call_spec/_call_spec.py +0 -257
- amulet/utils/cast.py +0 -10
- amulet/utils/comment_json.py +0 -188
- amulet/utils/format_utils.py +0 -41
- amulet/utils/generator.py +0 -18
- amulet/utils/matrix.py +0 -243
- amulet/utils/numpy.hpp +0 -36
- amulet/utils/numpy.pyi +0 -11
- amulet/utils/numpy_helpers.py +0 -19
- amulet/utils/shareable_lock.py +0 -335
- amulet/utils/signal/__init__.py +0 -10
- amulet/utils/signal/_signal.py +0 -228
- amulet/utils/task_manager.py +0 -235
- amulet/utils/typed_property.py +0 -111
- amulet/utils/weakref.py +0 -70
- amulet/utils/world_utils.py +0 -102
- amulet/version.cpp +0 -136
- amulet/version.hpp +0 -142
- amulet/version.py.cpp +0 -281
- amulet_core-2.0a8.dist-info/RECORD +0 -241
- amulet_core-2.0a8.dist-info/entry_points.txt +0 -2
- /amulet/{__pyinstaller → core/__pyinstaller}/__init__.py +0 -0
- /amulet/{py.typed → core/py.typed} +0 -0
- {amulet_core-2.0a8.dist-info → amulet_core-2.0.1a3.post250529101330.dist-info}/top_level.txt +0 -0
|
@@ -1,563 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import json
|
|
3
|
-
from typing import Union, Iterable, Iterator, Optional
|
|
4
|
-
from PIL import Image
|
|
5
|
-
import numpy
|
|
6
|
-
import glob
|
|
7
|
-
import itertools
|
|
8
|
-
import logging
|
|
9
|
-
import re
|
|
10
|
-
|
|
11
|
-
from amulet_nbt import StringTag
|
|
12
|
-
|
|
13
|
-
from amulet.utils.cast import dynamic_cast
|
|
14
|
-
from amulet.block import Block, PropertyValueType
|
|
15
|
-
from amulet.resource_pack import BaseResourcePackManager
|
|
16
|
-
from amulet.resource_pack.java import JavaResourcePack
|
|
17
|
-
from amulet.mesh.block import (
|
|
18
|
-
BlockMesh,
|
|
19
|
-
BlockMeshPart,
|
|
20
|
-
Triangle,
|
|
21
|
-
Vertex,
|
|
22
|
-
FloatVec3,
|
|
23
|
-
FloatVec2,
|
|
24
|
-
BlockMeshTransparency,
|
|
25
|
-
BlockMeshCullDirection,
|
|
26
|
-
merge_block_meshes,
|
|
27
|
-
FACE_KEYS,
|
|
28
|
-
CUBE_FACE_LUT,
|
|
29
|
-
UV_ROTATION_LUT,
|
|
30
|
-
TRI_FACE,
|
|
31
|
-
)
|
|
32
|
-
from amulet.mesh.util import rotate_3d
|
|
33
|
-
|
|
34
|
-
log = logging.getLogger(__name__)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
UselessImageGroups = {
|
|
38
|
-
"colormap",
|
|
39
|
-
"effect",
|
|
40
|
-
"environment",
|
|
41
|
-
"font",
|
|
42
|
-
"gui",
|
|
43
|
-
"map",
|
|
44
|
-
"mob_effect",
|
|
45
|
-
"particle",
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
_PropertiesPattern = re.compile(r"(?P<name>[a-zA-Z0-9_]+)=(?P<value>[a-zA-Z0-9_]+),?")
|
|
49
|
-
|
|
50
|
-
CULL_DIRECTIONS = {
|
|
51
|
-
None: BlockMeshCullDirection.CullNone,
|
|
52
|
-
"down": BlockMeshCullDirection.CullDown,
|
|
53
|
-
"up": BlockMeshCullDirection.CullUp,
|
|
54
|
-
"north": BlockMeshCullDirection.CullNorth,
|
|
55
|
-
"east": BlockMeshCullDirection.CullEast,
|
|
56
|
-
"south": BlockMeshCullDirection.CullSouth,
|
|
57
|
-
"west": BlockMeshCullDirection.CullWest,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def get_py_data(obj: PropertyValueType) -> str | bytes | int:
|
|
62
|
-
if isinstance(obj, StringTag):
|
|
63
|
-
return obj.py_str_or_bytes
|
|
64
|
-
else:
|
|
65
|
-
return obj.py_int
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class JavaResourcePackManager(BaseResourcePackManager[JavaResourcePack]):
|
|
69
|
-
"""A class to load and handle the data from the packs.
|
|
70
|
-
Packs are given as a list with the later packs overwriting the earlier ones."""
|
|
71
|
-
|
|
72
|
-
def __init__(
|
|
73
|
-
self,
|
|
74
|
-
resource_packs: Union[JavaResourcePack, Iterable[JavaResourcePack]],
|
|
75
|
-
load: bool = True,
|
|
76
|
-
) -> None:
|
|
77
|
-
super().__init__()
|
|
78
|
-
self._blockstate_files: dict[tuple[str, str], dict] = {}
|
|
79
|
-
self._textures: dict[tuple[str, str], str] = {}
|
|
80
|
-
self._texture_is_transparent: dict[str, tuple[float, bool]] = {}
|
|
81
|
-
self._model_files: dict[tuple[str, str], dict] = {}
|
|
82
|
-
if isinstance(resource_packs, Iterable):
|
|
83
|
-
self._packs = list(resource_packs)
|
|
84
|
-
elif isinstance(resource_packs, JavaResourcePack):
|
|
85
|
-
self._packs = [resource_packs]
|
|
86
|
-
else:
|
|
87
|
-
raise Exception(f"Invalid format {resource_packs}")
|
|
88
|
-
if load:
|
|
89
|
-
for _ in self.reload():
|
|
90
|
-
pass
|
|
91
|
-
|
|
92
|
-
def _unload(self) -> None:
|
|
93
|
-
"""Clear all loaded resources."""
|
|
94
|
-
super()._unload()
|
|
95
|
-
self._blockstate_files.clear()
|
|
96
|
-
self._textures.clear()
|
|
97
|
-
self._texture_is_transparent.clear()
|
|
98
|
-
self._model_files.clear()
|
|
99
|
-
|
|
100
|
-
def _load_iter(self) -> Iterator[float]:
|
|
101
|
-
blockstate_file_paths: dict[tuple[str, str], str] = {}
|
|
102
|
-
model_file_paths: dict[tuple[str, str], str] = {}
|
|
103
|
-
|
|
104
|
-
transparency_cache_path = os.path.join(
|
|
105
|
-
os.environ["CACHE_DIR"], "resource_packs", "java", "transparency_cache.json"
|
|
106
|
-
)
|
|
107
|
-
self._load_transparency_cache(transparency_cache_path)
|
|
108
|
-
|
|
109
|
-
self._textures[("minecraft", "missing_no")] = self.missing_no
|
|
110
|
-
|
|
111
|
-
pack_count = len(self._packs)
|
|
112
|
-
|
|
113
|
-
for pack_index, pack in enumerate(self._packs):
|
|
114
|
-
# pack_format=2 textures/blocks, textures/items - case sensitive
|
|
115
|
-
# pack_format=3 textures/blocks, textures/items - lower case
|
|
116
|
-
# pack_format=4 textures/block, textures/item
|
|
117
|
-
# pack_format=5 model paths and texture paths are now optionally namespaced
|
|
118
|
-
|
|
119
|
-
pack_progress = pack_index / pack_count
|
|
120
|
-
yield pack_progress
|
|
121
|
-
|
|
122
|
-
if pack.valid_pack and pack.pack_format >= 2:
|
|
123
|
-
image_paths = glob.glob(
|
|
124
|
-
os.path.join(
|
|
125
|
-
glob.escape(pack.root_dir),
|
|
126
|
-
"assets",
|
|
127
|
-
"*", # namespace
|
|
128
|
-
"textures",
|
|
129
|
-
"**",
|
|
130
|
-
"*.png",
|
|
131
|
-
),
|
|
132
|
-
recursive=True,
|
|
133
|
-
)
|
|
134
|
-
image_count = len(image_paths)
|
|
135
|
-
sub_progress = pack_progress
|
|
136
|
-
for image_index, texture_path in enumerate(image_paths):
|
|
137
|
-
_, namespace, _, *rel_path_list = os.path.normpath(
|
|
138
|
-
os.path.relpath(texture_path, pack.root_dir)
|
|
139
|
-
).split(os.sep)
|
|
140
|
-
if rel_path_list[0] not in UselessImageGroups:
|
|
141
|
-
rel_path = "/".join(rel_path_list)[:-4]
|
|
142
|
-
self._textures[(namespace, rel_path)] = texture_path
|
|
143
|
-
if (
|
|
144
|
-
os.stat(texture_path).st_mtime
|
|
145
|
-
!= self._texture_is_transparent.get(texture_path, [0])[0]
|
|
146
|
-
):
|
|
147
|
-
im: Image.Image = Image.open(texture_path)
|
|
148
|
-
if im.mode == "RGBA":
|
|
149
|
-
alpha = numpy.array(im.getchannel("A").getdata())
|
|
150
|
-
texture_is_transparent = bool(numpy.any(alpha != 255))
|
|
151
|
-
else:
|
|
152
|
-
texture_is_transparent = False
|
|
153
|
-
|
|
154
|
-
self._texture_is_transparent[texture_path] = (
|
|
155
|
-
os.stat(texture_path).st_mtime,
|
|
156
|
-
texture_is_transparent,
|
|
157
|
-
)
|
|
158
|
-
yield sub_progress + image_index / (image_count * pack_count * 3)
|
|
159
|
-
|
|
160
|
-
blockstate_paths = glob.glob(
|
|
161
|
-
os.path.join(
|
|
162
|
-
glob.escape(pack.root_dir),
|
|
163
|
-
"assets",
|
|
164
|
-
"*", # namespace
|
|
165
|
-
"blockstates",
|
|
166
|
-
"*.json",
|
|
167
|
-
)
|
|
168
|
-
)
|
|
169
|
-
blockstate_count = len(blockstate_paths)
|
|
170
|
-
sub_progress = pack_progress + 1 / (pack_count * 3)
|
|
171
|
-
for blockstate_index, blockstate_path in enumerate(blockstate_paths):
|
|
172
|
-
_, namespace, _, blockstate_file = os.path.normpath(
|
|
173
|
-
os.path.relpath(blockstate_path, pack.root_dir)
|
|
174
|
-
).split(os.sep)
|
|
175
|
-
blockstate_file_paths[(namespace, blockstate_file[:-5])] = (
|
|
176
|
-
blockstate_path
|
|
177
|
-
)
|
|
178
|
-
yield sub_progress + (blockstate_index) / (
|
|
179
|
-
blockstate_count * pack_count * 3
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
model_paths = glob.glob(
|
|
183
|
-
os.path.join(
|
|
184
|
-
glob.escape(pack.root_dir),
|
|
185
|
-
"assets",
|
|
186
|
-
"*", # namespace
|
|
187
|
-
"models",
|
|
188
|
-
"**",
|
|
189
|
-
"*.json",
|
|
190
|
-
),
|
|
191
|
-
recursive=True,
|
|
192
|
-
)
|
|
193
|
-
model_count = len(model_paths)
|
|
194
|
-
sub_progress = pack_progress + 2 / (pack_count * 3)
|
|
195
|
-
for model_index, model_path in enumerate(model_paths):
|
|
196
|
-
_, namespace, _, *rel_path_list = os.path.normpath(
|
|
197
|
-
os.path.relpath(model_path, pack.root_dir)
|
|
198
|
-
).split(os.sep)
|
|
199
|
-
rel_path = "/".join(rel_path_list)[:-5]
|
|
200
|
-
model_file_paths[(namespace, rel_path.replace(os.sep, "/"))] = (
|
|
201
|
-
model_path
|
|
202
|
-
)
|
|
203
|
-
yield sub_progress + (model_index) / (model_count * pack_count * 3)
|
|
204
|
-
|
|
205
|
-
os.makedirs(os.path.dirname(transparency_cache_path), exist_ok=True)
|
|
206
|
-
with open(transparency_cache_path, "w") as f:
|
|
207
|
-
json.dump(self._texture_is_transparent, f)
|
|
208
|
-
|
|
209
|
-
for key, path in blockstate_file_paths.items():
|
|
210
|
-
with open(path) as fi:
|
|
211
|
-
try:
|
|
212
|
-
self._blockstate_files[key] = json.load(fi)
|
|
213
|
-
except json.JSONDecodeError:
|
|
214
|
-
log.error(f"Failed to parse blockstate file {path}")
|
|
215
|
-
|
|
216
|
-
for key, path in model_file_paths.items():
|
|
217
|
-
with open(path) as fi:
|
|
218
|
-
try:
|
|
219
|
-
self._model_files[key] = json.load(fi)
|
|
220
|
-
except json.JSONDecodeError:
|
|
221
|
-
log.error(f"Failed to parse model file file {path}")
|
|
222
|
-
|
|
223
|
-
@property
|
|
224
|
-
def textures(self) -> tuple[str, ...]:
|
|
225
|
-
"""Returns a tuple of all the texture paths in the resource pack."""
|
|
226
|
-
return tuple(self._textures.values())
|
|
227
|
-
|
|
228
|
-
def get_texture_path(self, namespace: Optional[str], relative_path: str) -> str:
|
|
229
|
-
"""Get the absolute texture path from the namespace and relative path pair"""
|
|
230
|
-
if namespace is None:
|
|
231
|
-
return self.missing_no
|
|
232
|
-
key = (namespace, relative_path)
|
|
233
|
-
if key in self._textures:
|
|
234
|
-
return self._textures[key]
|
|
235
|
-
else:
|
|
236
|
-
return self.missing_no
|
|
237
|
-
|
|
238
|
-
@staticmethod
|
|
239
|
-
def parse_state_val(val: Union[str, bool]) -> list:
|
|
240
|
-
"""Convert the json block state format into a consistent format."""
|
|
241
|
-
if isinstance(val, str):
|
|
242
|
-
return [StringTag(v) for v in val.split("|")]
|
|
243
|
-
elif isinstance(val, bool):
|
|
244
|
-
return [StringTag("true") if val else StringTag("false")]
|
|
245
|
-
else:
|
|
246
|
-
raise Exception(f"Could not parse state val {val}")
|
|
247
|
-
|
|
248
|
-
def _get_model(self, block: Block) -> BlockMesh:
|
|
249
|
-
"""Find the model paths for a given block state and load them."""
|
|
250
|
-
if (block.namespace, block.base_name) in self._blockstate_files:
|
|
251
|
-
blockstate: dict = self._blockstate_files[
|
|
252
|
-
(block.namespace, block.base_name)
|
|
253
|
-
]
|
|
254
|
-
if "variants" in blockstate:
|
|
255
|
-
for variant in blockstate["variants"]:
|
|
256
|
-
if variant == "":
|
|
257
|
-
try:
|
|
258
|
-
return self._load_blockstate_model(
|
|
259
|
-
blockstate["variants"][variant]
|
|
260
|
-
)
|
|
261
|
-
except Exception as e:
|
|
262
|
-
log.exception(
|
|
263
|
-
f"Failed to load block model {blockstate['variants'][variant]}\n{e}"
|
|
264
|
-
)
|
|
265
|
-
else:
|
|
266
|
-
properties_match = _PropertiesPattern.finditer(f",{variant}")
|
|
267
|
-
if all(
|
|
268
|
-
get_py_data(
|
|
269
|
-
block.properties.get(
|
|
270
|
-
match.group("name"),
|
|
271
|
-
StringTag(match.group("value")),
|
|
272
|
-
)
|
|
273
|
-
)
|
|
274
|
-
== match.group("value")
|
|
275
|
-
for match in properties_match
|
|
276
|
-
):
|
|
277
|
-
try:
|
|
278
|
-
return self._load_blockstate_model(
|
|
279
|
-
blockstate["variants"][variant]
|
|
280
|
-
)
|
|
281
|
-
except Exception as e:
|
|
282
|
-
log.exception(
|
|
283
|
-
f"Failed to load block model {blockstate['variants'][variant]}\n{e}"
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
elif "multipart" in blockstate:
|
|
287
|
-
models = []
|
|
288
|
-
|
|
289
|
-
for case in blockstate["multipart"]:
|
|
290
|
-
try:
|
|
291
|
-
if "when" in case:
|
|
292
|
-
if "OR" in case["when"]:
|
|
293
|
-
if not any(
|
|
294
|
-
all(
|
|
295
|
-
block.properties.get(prop, None)
|
|
296
|
-
in self.parse_state_val(val)
|
|
297
|
-
for prop, val in prop_match.items()
|
|
298
|
-
)
|
|
299
|
-
for prop_match in case["when"]["OR"]
|
|
300
|
-
):
|
|
301
|
-
continue
|
|
302
|
-
elif "AND" in case["when"]:
|
|
303
|
-
if not all(
|
|
304
|
-
all(
|
|
305
|
-
block.properties.get(prop, None)
|
|
306
|
-
in self.parse_state_val(val)
|
|
307
|
-
for prop, val in prop_match.items()
|
|
308
|
-
)
|
|
309
|
-
for prop_match in case["when"]["AND"]
|
|
310
|
-
):
|
|
311
|
-
continue
|
|
312
|
-
elif not all(
|
|
313
|
-
block.properties.get(prop, None)
|
|
314
|
-
in self.parse_state_val(val)
|
|
315
|
-
for prop, val in case["when"].items()
|
|
316
|
-
):
|
|
317
|
-
continue
|
|
318
|
-
|
|
319
|
-
if "apply" in case:
|
|
320
|
-
try:
|
|
321
|
-
models.append(
|
|
322
|
-
self._load_blockstate_model(case["apply"])
|
|
323
|
-
)
|
|
324
|
-
|
|
325
|
-
except Exception as e:
|
|
326
|
-
log.exception(
|
|
327
|
-
f"Failed to load block model {case['apply']}\n{e}"
|
|
328
|
-
)
|
|
329
|
-
except Exception as e:
|
|
330
|
-
log.exception(f"Failed to parse block state for {block}\n{e}")
|
|
331
|
-
|
|
332
|
-
return merge_block_meshes(models)
|
|
333
|
-
|
|
334
|
-
return self.missing_block
|
|
335
|
-
|
|
336
|
-
def _load_blockstate_model(
|
|
337
|
-
self, blockstate_value: Union[dict, list[dict]]
|
|
338
|
-
) -> BlockMesh:
|
|
339
|
-
"""Load the model(s) associated with a block state and apply rotations if needed."""
|
|
340
|
-
if isinstance(blockstate_value, list):
|
|
341
|
-
blockstate_value = blockstate_value[0]
|
|
342
|
-
if "model" not in blockstate_value:
|
|
343
|
-
return self.missing_block
|
|
344
|
-
model_path = blockstate_value["model"]
|
|
345
|
-
rotx = int(blockstate_value.get("x", 0) // 90)
|
|
346
|
-
roty = int(blockstate_value.get("y", 0) // 90)
|
|
347
|
-
uvlock = blockstate_value.get("uvlock", False)
|
|
348
|
-
|
|
349
|
-
model = self._load_block_model(model_path)
|
|
350
|
-
|
|
351
|
-
# TODO: rotate model based on uv_lock
|
|
352
|
-
return model.rotate(rotx, roty)
|
|
353
|
-
|
|
354
|
-
def _load_block_model(self, model_path: str) -> BlockMesh:
|
|
355
|
-
"""Load the model file associated with the Block and convert to a BlockMesh."""
|
|
356
|
-
# recursively load model files into one dictionary
|
|
357
|
-
java_model = self._recursive_load_block_model(model_path)
|
|
358
|
-
|
|
359
|
-
if java_model.get("textures", {}) and not java_model.get("elements"):
|
|
360
|
-
return self.missing_block
|
|
361
|
-
|
|
362
|
-
# set up some variables
|
|
363
|
-
texture_paths: dict[str, int] = {}
|
|
364
|
-
mesh_parts: list[tuple[list[Vertex], list[Triangle]] | None] = [
|
|
365
|
-
None,
|
|
366
|
-
None,
|
|
367
|
-
None,
|
|
368
|
-
None,
|
|
369
|
-
None,
|
|
370
|
-
None,
|
|
371
|
-
None,
|
|
372
|
-
]
|
|
373
|
-
transparency = BlockMeshTransparency.Partial
|
|
374
|
-
|
|
375
|
-
for element in dynamic_cast(java_model.get("elements", []), list):
|
|
376
|
-
# iterate through elements (one cube per element)
|
|
377
|
-
element_faces = dynamic_cast(element.get("faces", {}), dict)
|
|
378
|
-
|
|
379
|
-
opaque_face_count = 0
|
|
380
|
-
if (
|
|
381
|
-
transparency
|
|
382
|
-
and "rotation" not in element
|
|
383
|
-
and element.get("to", [16, 16, 16]) == [16, 16, 16]
|
|
384
|
-
and element.get("from", [0, 0, 0]) == [0, 0, 0]
|
|
385
|
-
and len(element_faces) >= 6
|
|
386
|
-
):
|
|
387
|
-
# if the block is not yet defined as a solid block
|
|
388
|
-
# and this element is a full size element
|
|
389
|
-
# check if the texture is opaque
|
|
390
|
-
transparency = BlockMeshTransparency.FullTranslucent
|
|
391
|
-
check_faces = True
|
|
392
|
-
else:
|
|
393
|
-
check_faces = False
|
|
394
|
-
|
|
395
|
-
# lower and upper box coordinates
|
|
396
|
-
x1, y1, z1 = [v / 16.0 for v in element.get("from", [0, 0, 0])]
|
|
397
|
-
x2, y2, z2 = [v / 16.0 for v in element.get("to", [16, 16, 16])]
|
|
398
|
-
|
|
399
|
-
# vertex coordinates of the box
|
|
400
|
-
box_coordinates = numpy.array(
|
|
401
|
-
list(
|
|
402
|
-
itertools.product(
|
|
403
|
-
(min(x1, x2), max(x1, x2)),
|
|
404
|
-
(min(y1, y2), max(y1, y2)),
|
|
405
|
-
(min(z1, z2), max(z1, x2)),
|
|
406
|
-
)
|
|
407
|
-
)
|
|
408
|
-
)
|
|
409
|
-
|
|
410
|
-
for face_dir, face_data in element_faces.items():
|
|
411
|
-
if face_dir not in CUBE_FACE_LUT:
|
|
412
|
-
continue
|
|
413
|
-
|
|
414
|
-
# get the cull direction. If there is an opaque block in this direction then cull this face
|
|
415
|
-
cull_dir = face_data.get("cullface", None)
|
|
416
|
-
if cull_dir not in FACE_KEYS:
|
|
417
|
-
cull_dir = None
|
|
418
|
-
|
|
419
|
-
# get the relative texture path for the texture used
|
|
420
|
-
texture_relative_path = face_data.get("texture", None)
|
|
421
|
-
while isinstance(
|
|
422
|
-
texture_relative_path, str
|
|
423
|
-
) and texture_relative_path.startswith("#"):
|
|
424
|
-
texture_relative_path = java_model["textures"].get(
|
|
425
|
-
texture_relative_path[1:], None
|
|
426
|
-
)
|
|
427
|
-
texture_path_list = texture_relative_path.split(":", 1)
|
|
428
|
-
if len(texture_path_list) == 2:
|
|
429
|
-
namespace, texture_relative_path = texture_path_list
|
|
430
|
-
else:
|
|
431
|
-
namespace = "minecraft"
|
|
432
|
-
|
|
433
|
-
texture_path = self.get_texture_path(namespace, texture_relative_path)
|
|
434
|
-
|
|
435
|
-
if check_faces:
|
|
436
|
-
if self._texture_is_transparent[texture_path][1]:
|
|
437
|
-
check_faces = False
|
|
438
|
-
else:
|
|
439
|
-
opaque_face_count += 1
|
|
440
|
-
|
|
441
|
-
# texture index for the face
|
|
442
|
-
texture_index = texture_paths.setdefault(
|
|
443
|
-
texture_path, len(texture_paths)
|
|
444
|
-
)
|
|
445
|
-
|
|
446
|
-
# get the uv values for each vertex
|
|
447
|
-
texture_uv: tuple[float, float, float, float]
|
|
448
|
-
if "uv" in face_data:
|
|
449
|
-
uv = face_data["uv"]
|
|
450
|
-
texture_uv = (
|
|
451
|
-
uv[0] / 16.0,
|
|
452
|
-
uv[1] / 16.0,
|
|
453
|
-
uv[2] / 16.0,
|
|
454
|
-
uv[3] / 16.0,
|
|
455
|
-
)
|
|
456
|
-
else:
|
|
457
|
-
# TODO: get the uv based on box location if not defined
|
|
458
|
-
texture_uv = (0.0, 0.0, 1.0, 1.0)
|
|
459
|
-
|
|
460
|
-
texture_rotation = face_data.get("rotation", 0)
|
|
461
|
-
uv_slice = (
|
|
462
|
-
UV_ROTATION_LUT[2 * int(texture_rotation / 90) :]
|
|
463
|
-
+ UV_ROTATION_LUT[: 2 * int(texture_rotation / 90)]
|
|
464
|
-
)
|
|
465
|
-
|
|
466
|
-
# merge the vertex coordinates and texture coordinates
|
|
467
|
-
face_verts = box_coordinates[CUBE_FACE_LUT[face_dir]]
|
|
468
|
-
if "rotation" in element:
|
|
469
|
-
rotation = element["rotation"]
|
|
470
|
-
origin = [r / 16 for r in rotation.get("origin", [8, 8, 8])]
|
|
471
|
-
angle = rotation.get("angle", 0)
|
|
472
|
-
axis = rotation.get("axis", "x")
|
|
473
|
-
angles = [0, 0, 0]
|
|
474
|
-
if axis == "x":
|
|
475
|
-
angles[0] = -angle
|
|
476
|
-
elif axis == "y":
|
|
477
|
-
angles[1] = -angle
|
|
478
|
-
elif axis == "z":
|
|
479
|
-
angles[2] = -angle
|
|
480
|
-
face_verts = rotate_3d(face_verts, *angles, *origin)
|
|
481
|
-
|
|
482
|
-
cull_direction = CULL_DIRECTIONS[cull_dir]
|
|
483
|
-
part = mesh_parts[cull_direction]
|
|
484
|
-
if part is None:
|
|
485
|
-
mesh_parts[cull_direction] = part = ([], [])
|
|
486
|
-
verts, tris = part
|
|
487
|
-
vert_count = len(verts)
|
|
488
|
-
|
|
489
|
-
if "tintindex" in face_data:
|
|
490
|
-
# TODO: set this up for each supported block
|
|
491
|
-
tint_vec = FloatVec3(0, 1, 0)
|
|
492
|
-
else:
|
|
493
|
-
tint_vec = FloatVec3(1, 1, 1)
|
|
494
|
-
|
|
495
|
-
for i in range(4):
|
|
496
|
-
x, y, z = face_verts[i]
|
|
497
|
-
uvx = texture_uv[uv_slice[i * 2]]
|
|
498
|
-
uvy = texture_uv[uv_slice[i * 2 + 1]]
|
|
499
|
-
verts.append(
|
|
500
|
-
Vertex(
|
|
501
|
-
FloatVec3(x, y, z),
|
|
502
|
-
FloatVec2(uvx, uvy),
|
|
503
|
-
tint_vec,
|
|
504
|
-
)
|
|
505
|
-
)
|
|
506
|
-
|
|
507
|
-
for a, b, c in TRI_FACE.reshape((2, 3)):
|
|
508
|
-
tris.append(
|
|
509
|
-
Triangle(
|
|
510
|
-
a + vert_count,
|
|
511
|
-
b + vert_count,
|
|
512
|
-
c + vert_count,
|
|
513
|
-
texture_index,
|
|
514
|
-
)
|
|
515
|
-
)
|
|
516
|
-
|
|
517
|
-
if opaque_face_count == 6:
|
|
518
|
-
transparency = BlockMeshTransparency.FullOpaque
|
|
519
|
-
|
|
520
|
-
def create_part(
|
|
521
|
-
part: tuple[list[Vertex], list[Triangle]] | None
|
|
522
|
-
) -> BlockMeshPart | None:
|
|
523
|
-
return None if part is None else BlockMeshPart(*part)
|
|
524
|
-
|
|
525
|
-
return BlockMesh(
|
|
526
|
-
transparency,
|
|
527
|
-
list(texture_paths),
|
|
528
|
-
(
|
|
529
|
-
create_part(mesh_parts[0]),
|
|
530
|
-
create_part(mesh_parts[1]),
|
|
531
|
-
create_part(mesh_parts[2]),
|
|
532
|
-
create_part(mesh_parts[3]),
|
|
533
|
-
create_part(mesh_parts[4]),
|
|
534
|
-
create_part(mesh_parts[5]),
|
|
535
|
-
create_part(mesh_parts[6]),
|
|
536
|
-
),
|
|
537
|
-
)
|
|
538
|
-
|
|
539
|
-
def _recursive_load_block_model(self, model_path: str) -> dict:
|
|
540
|
-
"""Load a model json file and recursively load and merge the parent entries into one json file."""
|
|
541
|
-
model_path_list = model_path.split(":", 1)
|
|
542
|
-
if len(model_path_list) == 2:
|
|
543
|
-
namespace, model_path = model_path_list
|
|
544
|
-
else:
|
|
545
|
-
namespace = "minecraft"
|
|
546
|
-
if (namespace, model_path) in self._model_files:
|
|
547
|
-
model = self._model_files[(namespace, model_path)]
|
|
548
|
-
|
|
549
|
-
if "parent" in model:
|
|
550
|
-
parent_model = self._recursive_load_block_model(model["parent"])
|
|
551
|
-
else:
|
|
552
|
-
parent_model = {}
|
|
553
|
-
if "textures" in model:
|
|
554
|
-
if "textures" not in parent_model:
|
|
555
|
-
parent_model["textures"] = {}
|
|
556
|
-
for key, val in model["textures"].items():
|
|
557
|
-
parent_model["textures"][key] = val
|
|
558
|
-
if "elements" in model:
|
|
559
|
-
parent_model["elements"] = model["elements"]
|
|
560
|
-
|
|
561
|
-
return parent_model
|
|
562
|
-
|
|
563
|
-
return {}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
from amulet.resource_pack.abc.resource_pack import BaseResourcePack
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class UnknownResourcePack(BaseResourcePack):
|
|
5
|
-
def __repr__(self) -> str:
|
|
6
|
-
return f"UnknownResourcePack({self._root_dir})"
|
|
7
|
-
|
|
8
|
-
@staticmethod
|
|
9
|
-
def is_valid(pack_path: str) -> bool:
|
|
10
|
-
return True
|
amulet/selection/__init__.py
DELETED