amulet-core 2.0a7__cp312-cp312-win_amd64.whl → 2.0a8__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/__init__.cp312-win_amd64.pyd +0 -0
- amulet/__init__.py.cpp +2 -0
- amulet/__init__.pyi +2 -0
- amulet/_version.py +3 -3
- amulet/chunk.hpp +2 -1
- amulet/level/abc/_chunk_handle.py +45 -22
- amulet/mesh/block/__init__.pyi +301 -0
- amulet/mesh/block/_cube.py +198 -0
- amulet/mesh/block/{missing_block.py → _missing_block.py} +2 -2
- amulet/mesh/block/block_mesh.cpp +107 -0
- amulet/mesh/block/block_mesh.hpp +207 -0
- amulet/resource_pack/__init__.py +16 -15
- amulet/resource_pack/abc/resource_pack_manager.py +3 -5
- amulet/resource_pack/java/resource_pack_manager.py +185 -173
- amulet/utils/cast.py +10 -0
- amulet/utils/shareable_lock.py +2 -2
- {amulet_core-2.0a7.dist-info → amulet_core-2.0a8.dist-info}/METADATA +2 -2
- {amulet_core-2.0a7.dist-info → amulet_core-2.0a8.dist-info}/RECORD +21 -75
- {amulet_core-2.0a7.dist-info → amulet_core-2.0a8.dist-info}/WHEEL +1 -1
- amulet/mesh/block/__init__.py +0 -1
- amulet/mesh/block/block_mesh.py +0 -369
- amulet/mesh/block/cube.py +0 -149
- amulet/resource_pack/bedrock/__init__.py +0 -2
- amulet/resource_pack/bedrock/bedrock_vanilla_fix/pack_icon.png +0 -0
- amulet/resource_pack/bedrock/bedrock_vanilla_fix/textures/blocks/grass_carried.png +0 -0
- amulet/resource_pack/bedrock/bedrock_vanilla_fix/textures/blocks/grass_side_carried.png +0 -0
- amulet/resource_pack/bedrock/bedrock_vanilla_fix/textures/blocks/water.png +0 -0
- amulet/resource_pack/bedrock/blockshapes/__init__.py +0 -31
- amulet/resource_pack/bedrock/blockshapes/air.py +0 -35
- amulet/resource_pack/bedrock/blockshapes/base_blockshape.py +0 -29
- amulet/resource_pack/bedrock/blockshapes/bubble_column.py +0 -29
- amulet/resource_pack/bedrock/blockshapes/cake.py +0 -46
- amulet/resource_pack/bedrock/blockshapes/chest.py +0 -54
- amulet/resource_pack/bedrock/blockshapes/comparator.py +0 -51
- amulet/resource_pack/bedrock/blockshapes/cross_texture.py +0 -186
- amulet/resource_pack/bedrock/blockshapes/cross_texture0.py +0 -17
- amulet/resource_pack/bedrock/blockshapes/cross_texture_green.py +0 -16
- amulet/resource_pack/bedrock/blockshapes/cube.py +0 -38
- amulet/resource_pack/bedrock/blockshapes/default.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/door.py +0 -38
- amulet/resource_pack/bedrock/blockshapes/door1.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/door2.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/door3.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/door4.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/door5.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/door6.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/double_plant.py +0 -40
- amulet/resource_pack/bedrock/blockshapes/enchanting_table.py +0 -22
- amulet/resource_pack/bedrock/blockshapes/farmland.py +0 -22
- amulet/resource_pack/bedrock/blockshapes/fence.py +0 -22
- amulet/resource_pack/bedrock/blockshapes/flat.py +0 -55
- amulet/resource_pack/bedrock/blockshapes/flat_wall.py +0 -55
- amulet/resource_pack/bedrock/blockshapes/furnace.py +0 -44
- amulet/resource_pack/bedrock/blockshapes/furnace_lit.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/green_cube.py +0 -39
- amulet/resource_pack/bedrock/blockshapes/ladder.py +0 -36
- amulet/resource_pack/bedrock/blockshapes/lilypad.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/partial_block.py +0 -57
- amulet/resource_pack/bedrock/blockshapes/piston.py +0 -44
- amulet/resource_pack/bedrock/blockshapes/piston_arm.py +0 -72
- amulet/resource_pack/bedrock/blockshapes/portal_frame.py +0 -22
- amulet/resource_pack/bedrock/blockshapes/pressure_plate.py +0 -29
- amulet/resource_pack/bedrock/blockshapes/pumpkin.py +0 -36
- amulet/resource_pack/bedrock/blockshapes/pumpkin_carved.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/pumpkin_lit.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/red_dust.py +0 -14
- amulet/resource_pack/bedrock/blockshapes/repeater.py +0 -53
- amulet/resource_pack/bedrock/blockshapes/slab.py +0 -33
- amulet/resource_pack/bedrock/blockshapes/slab_double.py +0 -15
- amulet/resource_pack/bedrock/blockshapes/tree.py +0 -41
- amulet/resource_pack/bedrock/blockshapes/turtle_egg.py +0 -15
- amulet/resource_pack/bedrock/blockshapes/vine.py +0 -52
- amulet/resource_pack/bedrock/blockshapes/wall.py +0 -22
- amulet/resource_pack/bedrock/blockshapes/water.py +0 -38
- amulet/resource_pack/bedrock/download_resources.py +0 -147
- amulet/resource_pack/bedrock/resource_pack.py +0 -40
- amulet/resource_pack/bedrock/resource_pack_manager.py +0 -361
- amulet/resource_pack/bedrock/sort_blockshapes.py +0 -15
- {amulet_core-2.0a7.dist-info → amulet_core-2.0a8.dist-info}/entry_points.txt +0 -0
- {amulet_core-2.0a7.dist-info → amulet_core-2.0a8.dist-info}/top_level.txt +0 -0
|
Binary file
|
amulet/__init__.py.cpp
CHANGED
|
@@ -11,6 +11,7 @@ void init_palette(py::module);
|
|
|
11
11
|
void init_chunk(py::module);
|
|
12
12
|
void init_chunk_components(py::module);
|
|
13
13
|
void init_level(py::module);
|
|
14
|
+
void init_block_mesh(py::module);
|
|
14
15
|
|
|
15
16
|
static bool init_run = false;
|
|
16
17
|
|
|
@@ -37,6 +38,7 @@ void init_amulet(py::module m){
|
|
|
37
38
|
init_chunk(m);
|
|
38
39
|
init_chunk_components(m);
|
|
39
40
|
init_level(m);
|
|
41
|
+
init_block_mesh(m);
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
PYBIND11_MODULE(__init__, m) { init_amulet(m); }
|
amulet/__init__.pyi
CHANGED
amulet/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2024-
|
|
11
|
+
"date": "2024-10-27T10:30:17+0000",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.
|
|
14
|
+
"full-revisionid": "7844bec50b93c8711ae703840b1a0e43b8283df6",
|
|
15
|
+
"version": "2.0a8"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
amulet/chunk.hpp
CHANGED
|
@@ -90,7 +90,8 @@ namespace Amulet {
|
|
|
90
90
|
void reconstruct_chunk(SerialisedComponents component_data) override {
|
|
91
91
|
(
|
|
92
92
|
[&]{
|
|
93
|
-
|
|
93
|
+
auto node = component_data.extract(Components::ComponentID);
|
|
94
|
+
Components::deserialise(node ? node.mapped() : std::nullopt);
|
|
94
95
|
}(),
|
|
95
96
|
...
|
|
96
97
|
);
|
|
@@ -12,6 +12,7 @@ from amulet.chunk import Chunk, get_null_chunk
|
|
|
12
12
|
from amulet.data_types import DimensionId
|
|
13
13
|
from amulet.errors import ChunkDoesNotExist, ChunkLoadError
|
|
14
14
|
from amulet.utils.signal import Signal
|
|
15
|
+
from amulet.utils.shareable_lock import ShareableRLock
|
|
15
16
|
|
|
16
17
|
from ._level import LevelFriend, LevelT
|
|
17
18
|
from ._history import HistoryManagerLayer
|
|
@@ -58,7 +59,7 @@ class ChunkHandle(
|
|
|
58
59
|
Some internal synchronisation is done to catch some threading issues.
|
|
59
60
|
"""
|
|
60
61
|
|
|
61
|
-
_lock:
|
|
62
|
+
_lock: ShareableRLock
|
|
62
63
|
_dimension: DimensionId
|
|
63
64
|
_key: ChunkKey
|
|
64
65
|
_chunk_history: HistoryManagerLayer[ChunkKey]
|
|
@@ -84,7 +85,7 @@ class ChunkHandle(
|
|
|
84
85
|
cz: int,
|
|
85
86
|
) -> None:
|
|
86
87
|
super().__init__(level_ref)
|
|
87
|
-
self._lock =
|
|
88
|
+
self._lock = ShareableRLock()
|
|
88
89
|
self._dimension_id = dimension_id
|
|
89
90
|
self._key = ChunkKey(cx, cz)
|
|
90
91
|
self._chunk_history = chunk_history
|
|
@@ -135,13 +136,7 @@ class ChunkHandle(
|
|
|
135
136
|
:raises:
|
|
136
137
|
LockNotAcquired: If the lock could not be acquired.
|
|
137
138
|
"""
|
|
138
|
-
|
|
139
|
-
# Thread was not acquired
|
|
140
|
-
raise LockNotAcquired("Lock was not acquired.")
|
|
141
|
-
try:
|
|
142
|
-
yield
|
|
143
|
-
finally:
|
|
144
|
-
self._lock.release()
|
|
139
|
+
return self._lock.unique(blocking, timeout)
|
|
145
140
|
|
|
146
141
|
@contextmanager
|
|
147
142
|
def edit(
|
|
@@ -171,7 +166,7 @@ class ChunkHandle(
|
|
|
171
166
|
:raises:
|
|
172
167
|
LockNotAcquired: If the lock could not be acquired.
|
|
173
168
|
"""
|
|
174
|
-
with self.
|
|
169
|
+
with self._lock.unique(blocking=blocking, timeout=timeout):
|
|
175
170
|
chunk = self.get(components)
|
|
176
171
|
yield chunk
|
|
177
172
|
# If an exception occurs in user code, this line won't be run.
|
|
@@ -187,14 +182,18 @@ class ChunkHandle(
|
|
|
187
182
|
|
|
188
183
|
:return: True if the chunk exists. Calling get on this chunk handle may still throw ChunkLoadError
|
|
189
184
|
"""
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
185
|
+
with self._lock.shared():
|
|
186
|
+
if self._chunk_history.has_resource(self._key):
|
|
187
|
+
return self._chunk_history.resource_exists(self._key)
|
|
188
|
+
else:
|
|
189
|
+
# The history system is not aware of the chunk. Look in the level data
|
|
190
|
+
return self._get_raw_dimension().has_chunk(self.cx, self.cz)
|
|
195
191
|
|
|
196
192
|
def _preload(self) -> None:
|
|
197
|
-
"""
|
|
193
|
+
"""
|
|
194
|
+
Load the chunk data if it has not already been loaded.
|
|
195
|
+
The lock must be acquired in unique mode before calling this.
|
|
196
|
+
"""
|
|
198
197
|
if not self._chunk_history.has_resource(self._key):
|
|
199
198
|
# The history system is not aware of the chunk. Load from the level data
|
|
200
199
|
chunk: Chunk
|
|
@@ -260,8 +259,9 @@ class ChunkHandle(
|
|
|
260
259
|
:param components: None to load all components or an iterable of component strings to load.
|
|
261
260
|
:return: A unique copy of the chunk data.
|
|
262
261
|
"""
|
|
263
|
-
|
|
264
|
-
|
|
262
|
+
|
|
263
|
+
def get_chunk() -> ChunkT:
|
|
264
|
+
nonlocal components
|
|
265
265
|
chunk = self._get_null_chunk()
|
|
266
266
|
if components is None:
|
|
267
267
|
components = chunk.component_ids
|
|
@@ -276,8 +276,25 @@ class ChunkHandle(
|
|
|
276
276
|
chunk.reconstruct_chunk(chunk_components)
|
|
277
277
|
return chunk
|
|
278
278
|
|
|
279
|
+
# Block if the chunk is locked in unique mode.
|
|
280
|
+
with self._lock.shared():
|
|
281
|
+
if self._chunk_history.has_resource(self._key):
|
|
282
|
+
# Does not need loading from disk.
|
|
283
|
+
return get_chunk()
|
|
284
|
+
|
|
285
|
+
# Acquire the lock in unique mode.
|
|
286
|
+
with self._lock.unique():
|
|
287
|
+
# If it wasn't already loaded by another thread.
|
|
288
|
+
if not self._chunk_history.has_resource(self._key):
|
|
289
|
+
# Load it from disk.
|
|
290
|
+
self._preload()
|
|
291
|
+
|
|
292
|
+
with self._lock.shared():
|
|
293
|
+
# If it was loaded in another thread just read it from the cache.
|
|
294
|
+
return get_chunk()
|
|
295
|
+
|
|
279
296
|
def _set(self, chunk: ChunkT | None) -> None:
|
|
280
|
-
"""
|
|
297
|
+
"""lock must be acquired in unique mode before calling this."""
|
|
281
298
|
history = self._chunk_history
|
|
282
299
|
if not history.has_resource(self._key):
|
|
283
300
|
if self._l.history_enabled:
|
|
@@ -322,14 +339,20 @@ class ChunkHandle(
|
|
|
322
339
|
:raises:
|
|
323
340
|
LockNotAcquired: If the chunk is already locked by another thread.
|
|
324
341
|
"""
|
|
325
|
-
with self.
|
|
342
|
+
with self._lock.unique(blocking=False):
|
|
326
343
|
self._set(chunk)
|
|
327
344
|
self.changed.emit()
|
|
328
345
|
self._l.changed.emit()
|
|
329
346
|
|
|
330
347
|
def delete(self) -> None:
|
|
331
|
-
"""
|
|
332
|
-
|
|
348
|
+
"""
|
|
349
|
+
Delete the chunk from the level.
|
|
350
|
+
You must acquire the chunk lock before deleting.
|
|
351
|
+
|
|
352
|
+
:raises:
|
|
353
|
+
LockNotAcquired: If the chunk is already locked by another thread.
|
|
354
|
+
"""
|
|
355
|
+
with self._lock.unique(blocking=False):
|
|
333
356
|
self._set(None)
|
|
334
357
|
self.changed.emit()
|
|
335
358
|
self._l.changed.emit()
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import collections.abc
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
import numpy
|
|
7
|
+
import pybind11_stubgen.typing_ext
|
|
8
|
+
from amulet.mesh.block._cube import get_cube, get_unit_cube
|
|
9
|
+
from amulet.mesh.block._missing_block import get_missing_block
|
|
10
|
+
|
|
11
|
+
from . import _cube, _missing_block
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"BlockMesh",
|
|
15
|
+
"BlockMeshCullDirection",
|
|
16
|
+
"BlockMeshPart",
|
|
17
|
+
"BlockMeshTransparency",
|
|
18
|
+
"CUBE_FACE_LUT",
|
|
19
|
+
"FACE_KEYS",
|
|
20
|
+
"FloatVec2",
|
|
21
|
+
"FloatVec3",
|
|
22
|
+
"TRI_FACE",
|
|
23
|
+
"Triangle",
|
|
24
|
+
"UV_ROTATION_LUT",
|
|
25
|
+
"Vertex",
|
|
26
|
+
"get_cube",
|
|
27
|
+
"get_missing_block",
|
|
28
|
+
"get_unit_cube",
|
|
29
|
+
"merge_block_meshes",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
class BlockMesh:
|
|
33
|
+
"""
|
|
34
|
+
All the data that makes up a block mesh.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
transparency: BlockMeshTransparency,
|
|
40
|
+
textures: list[str],
|
|
41
|
+
parts: tuple[
|
|
42
|
+
BlockMeshPart | None,
|
|
43
|
+
BlockMeshPart | None,
|
|
44
|
+
BlockMeshPart | None,
|
|
45
|
+
BlockMeshPart | None,
|
|
46
|
+
BlockMeshPart | None,
|
|
47
|
+
BlockMeshPart | None,
|
|
48
|
+
BlockMeshPart | None,
|
|
49
|
+
],
|
|
50
|
+
) -> None: ...
|
|
51
|
+
def rotate(self, rotx: int, roty: int) -> BlockMesh:
|
|
52
|
+
"""
|
|
53
|
+
Rotate the mesh in the x and y axis. Accepted values are -3 to 3 which corrospond to 90 degree rotations.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def parts(
|
|
58
|
+
self,
|
|
59
|
+
) -> typing.Annotated[
|
|
60
|
+
list[BlockMeshPart | None], pybind11_stubgen.typing_ext.FixedSize(7)
|
|
61
|
+
]:
|
|
62
|
+
"""
|
|
63
|
+
The mesh parts that make up this mesh. The index corrosponds to the value of BlockMeshCullDirection.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
@parts.setter
|
|
67
|
+
def parts(
|
|
68
|
+
self,
|
|
69
|
+
arg0: typing.Annotated[
|
|
70
|
+
list[BlockMeshPart | None], pybind11_stubgen.typing_ext.FixedSize(7)
|
|
71
|
+
],
|
|
72
|
+
) -> None: ...
|
|
73
|
+
@property
|
|
74
|
+
def textures(self) -> list[str]:
|
|
75
|
+
"""
|
|
76
|
+
The texture paths used in this block mesh. The Triangle's texture_index attribute is an index into this list.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
@textures.setter
|
|
80
|
+
def textures(self, arg0: list[str]) -> None: ...
|
|
81
|
+
@property
|
|
82
|
+
def transparency(self) -> BlockMeshTransparency:
|
|
83
|
+
"""
|
|
84
|
+
The transparency state of this block mesh.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
@transparency.setter
|
|
88
|
+
def transparency(self, arg0: BlockMeshTransparency) -> None: ...
|
|
89
|
+
|
|
90
|
+
class BlockMeshCullDirection:
|
|
91
|
+
"""
|
|
92
|
+
The direction a mesh part is culled by. The value corrosponds to the index in the mesh parts array.
|
|
93
|
+
|
|
94
|
+
Members:
|
|
95
|
+
|
|
96
|
+
CullNone : Is not culled by any neighbouring blocks.
|
|
97
|
+
|
|
98
|
+
CullUp : Is culled by an opaque block above.
|
|
99
|
+
|
|
100
|
+
CullDown : Is culled by an opaque block below.
|
|
101
|
+
|
|
102
|
+
CullNorth : Is culled by an opaque block to the north.
|
|
103
|
+
|
|
104
|
+
CullEast : Is culled by an opaque block to the east.
|
|
105
|
+
|
|
106
|
+
CullSouth : Is culled by an opaque block to the south.
|
|
107
|
+
|
|
108
|
+
CullWest : Is culled by an opaque block to the west.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
CullDown: typing.ClassVar[
|
|
112
|
+
BlockMeshCullDirection
|
|
113
|
+
] # value = <BlockMeshCullDirection.CullDown: 2>
|
|
114
|
+
CullEast: typing.ClassVar[
|
|
115
|
+
BlockMeshCullDirection
|
|
116
|
+
] # value = <BlockMeshCullDirection.CullEast: 4>
|
|
117
|
+
CullNone: typing.ClassVar[
|
|
118
|
+
BlockMeshCullDirection
|
|
119
|
+
] # value = <BlockMeshCullDirection.CullNone: 0>
|
|
120
|
+
CullNorth: typing.ClassVar[
|
|
121
|
+
BlockMeshCullDirection
|
|
122
|
+
] # value = <BlockMeshCullDirection.CullNorth: 3>
|
|
123
|
+
CullSouth: typing.ClassVar[
|
|
124
|
+
BlockMeshCullDirection
|
|
125
|
+
] # value = <BlockMeshCullDirection.CullSouth: 5>
|
|
126
|
+
CullUp: typing.ClassVar[
|
|
127
|
+
BlockMeshCullDirection
|
|
128
|
+
] # value = <BlockMeshCullDirection.CullUp: 1>
|
|
129
|
+
CullWest: typing.ClassVar[
|
|
130
|
+
BlockMeshCullDirection
|
|
131
|
+
] # value = <BlockMeshCullDirection.CullWest: 6>
|
|
132
|
+
__members__: typing.ClassVar[
|
|
133
|
+
dict[str, BlockMeshCullDirection]
|
|
134
|
+
] # value = {'CullNone': <BlockMeshCullDirection.CullNone: 0>, 'CullUp': <BlockMeshCullDirection.CullUp: 1>, 'CullDown': <BlockMeshCullDirection.CullDown: 2>, 'CullNorth': <BlockMeshCullDirection.CullNorth: 3>, 'CullEast': <BlockMeshCullDirection.CullEast: 4>, 'CullSouth': <BlockMeshCullDirection.CullSouth: 5>, 'CullWest': <BlockMeshCullDirection.CullWest: 6>}
|
|
135
|
+
def __and__(self, other: typing.Any) -> typing.Any: ...
|
|
136
|
+
def __eq__(self, other: typing.Any) -> bool: ...
|
|
137
|
+
def __ge__(self, other: typing.Any) -> bool: ...
|
|
138
|
+
def __gt__(self, other: typing.Any) -> bool: ...
|
|
139
|
+
def __hash__(self) -> int: ...
|
|
140
|
+
def __index__(self) -> int: ...
|
|
141
|
+
def __init__(self, value: int) -> None: ...
|
|
142
|
+
def __int__(self) -> int: ...
|
|
143
|
+
def __invert__(self) -> typing.Any: ...
|
|
144
|
+
def __le__(self, other: typing.Any) -> bool: ...
|
|
145
|
+
def __lt__(self, other: typing.Any) -> bool: ...
|
|
146
|
+
def __ne__(self, other: typing.Any) -> bool: ...
|
|
147
|
+
def __or__(self, other: typing.Any) -> typing.Any: ...
|
|
148
|
+
def __rand__(self, other: typing.Any) -> typing.Any: ...
|
|
149
|
+
def __repr__(self) -> str: ...
|
|
150
|
+
def __ror__(self, other: typing.Any) -> typing.Any: ...
|
|
151
|
+
def __rxor__(self, other: typing.Any) -> typing.Any: ...
|
|
152
|
+
def __str__(self) -> str: ...
|
|
153
|
+
def __xor__(self, other: typing.Any) -> typing.Any: ...
|
|
154
|
+
@property
|
|
155
|
+
def name(self) -> str: ...
|
|
156
|
+
@property
|
|
157
|
+
def value(self) -> int: ...
|
|
158
|
+
|
|
159
|
+
class BlockMeshPart:
|
|
160
|
+
"""
|
|
161
|
+
A part of a block mesh for one of the culling directions.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
def __init__(self, verts: list[Vertex], triangles: list[Triangle]) -> None: ...
|
|
165
|
+
@property
|
|
166
|
+
def triangles(self) -> list[Triangle]:
|
|
167
|
+
"""
|
|
168
|
+
The triangles in this block mesh part.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
@triangles.setter
|
|
172
|
+
def triangles(self, arg0: list[Triangle]) -> None: ...
|
|
173
|
+
@property
|
|
174
|
+
def verts(self) -> list[Vertex]:
|
|
175
|
+
"""
|
|
176
|
+
The vertices in this block mesh part.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
@verts.setter
|
|
180
|
+
def verts(self, arg0: list[Vertex]) -> None: ...
|
|
181
|
+
|
|
182
|
+
class BlockMeshTransparency:
|
|
183
|
+
"""
|
|
184
|
+
The transparency of a block mesh.
|
|
185
|
+
|
|
186
|
+
Members:
|
|
187
|
+
|
|
188
|
+
FullOpaque : A block that occupies the whole block and is opaque.
|
|
189
|
+
|
|
190
|
+
FullTranslucent : A block that occupies the whole block and has at least one translucent face.
|
|
191
|
+
|
|
192
|
+
Partial : A block that does not occupy the whole block.
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
FullOpaque: typing.ClassVar[
|
|
196
|
+
BlockMeshTransparency
|
|
197
|
+
] # value = <BlockMeshTransparency.FullOpaque: 0>
|
|
198
|
+
FullTranslucent: typing.ClassVar[
|
|
199
|
+
BlockMeshTransparency
|
|
200
|
+
] # value = <BlockMeshTransparency.FullTranslucent: 1>
|
|
201
|
+
Partial: typing.ClassVar[
|
|
202
|
+
BlockMeshTransparency
|
|
203
|
+
] # value = <BlockMeshTransparency.Partial: 2>
|
|
204
|
+
__members__: typing.ClassVar[
|
|
205
|
+
dict[str, BlockMeshTransparency]
|
|
206
|
+
] # value = {'FullOpaque': <BlockMeshTransparency.FullOpaque: 0>, 'FullTranslucent': <BlockMeshTransparency.FullTranslucent: 1>, 'Partial': <BlockMeshTransparency.Partial: 2>}
|
|
207
|
+
def __eq__(self, other: typing.Any) -> bool: ...
|
|
208
|
+
def __ge__(self, other: typing.Any) -> bool: ...
|
|
209
|
+
def __gt__(self, other: typing.Any) -> bool: ...
|
|
210
|
+
def __hash__(self) -> int: ...
|
|
211
|
+
def __index__(self) -> int: ...
|
|
212
|
+
def __init__(self, value: int) -> None: ...
|
|
213
|
+
def __int__(self) -> int: ...
|
|
214
|
+
def __le__(self, other: typing.Any) -> bool: ...
|
|
215
|
+
def __lt__(self, other: typing.Any) -> bool: ...
|
|
216
|
+
def __ne__(self, other: typing.Any) -> bool: ...
|
|
217
|
+
def __repr__(self) -> str: ...
|
|
218
|
+
def __str__(self) -> str: ...
|
|
219
|
+
@property
|
|
220
|
+
def name(self) -> str: ...
|
|
221
|
+
@property
|
|
222
|
+
def value(self) -> int: ...
|
|
223
|
+
|
|
224
|
+
class FloatVec2:
|
|
225
|
+
"""
|
|
226
|
+
A 2D floating point vector
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
x: float
|
|
230
|
+
y: float
|
|
231
|
+
def __init__(self, x: float, y: float) -> None: ...
|
|
232
|
+
|
|
233
|
+
class FloatVec3:
|
|
234
|
+
"""
|
|
235
|
+
A 3D floating point vector
|
|
236
|
+
"""
|
|
237
|
+
|
|
238
|
+
x: float
|
|
239
|
+
y: float
|
|
240
|
+
z: float
|
|
241
|
+
def __init__(self, x: float, y: float, z: float) -> None: ...
|
|
242
|
+
|
|
243
|
+
class Triangle:
|
|
244
|
+
"""
|
|
245
|
+
The vertex and texture indexes that make up a triangle.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
texture_index: int
|
|
249
|
+
vert_index_a: int
|
|
250
|
+
vert_index_b: int
|
|
251
|
+
vert_index_c: int
|
|
252
|
+
def __init__(
|
|
253
|
+
self,
|
|
254
|
+
vert_index_a: int,
|
|
255
|
+
vert_index_b: int,
|
|
256
|
+
vert_index_c: int,
|
|
257
|
+
texture_index: int,
|
|
258
|
+
) -> None: ...
|
|
259
|
+
|
|
260
|
+
class Vertex:
|
|
261
|
+
"""
|
|
262
|
+
Attributes for a single vertex.
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
def __init__(
|
|
266
|
+
self, coord: FloatVec3, texture_coord: FloatVec2, tint: FloatVec3
|
|
267
|
+
) -> None: ...
|
|
268
|
+
@property
|
|
269
|
+
def coord(self) -> FloatVec3:
|
|
270
|
+
"""
|
|
271
|
+
The spatial coordinate of the vertex.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
@coord.setter
|
|
275
|
+
def coord(self, arg0: FloatVec3) -> None: ...
|
|
276
|
+
@property
|
|
277
|
+
def texture_coord(self) -> FloatVec2:
|
|
278
|
+
"""
|
|
279
|
+
The texture coordinate of the vertex.
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
@texture_coord.setter
|
|
283
|
+
def texture_coord(self, arg0: FloatVec2) -> None: ...
|
|
284
|
+
@property
|
|
285
|
+
def tint(self) -> FloatVec3:
|
|
286
|
+
"""
|
|
287
|
+
The tint colour for the vertex.
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
@tint.setter
|
|
291
|
+
def tint(self, arg0: FloatVec3) -> None: ...
|
|
292
|
+
|
|
293
|
+
def merge_block_meshes(meshes: collections.abc.Sequence[BlockMesh]) -> BlockMesh:
|
|
294
|
+
"""
|
|
295
|
+
Merge multiple block mesh objects into one block mesh.
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
CUBE_FACE_LUT: dict # value = {'down': array([0, 4, 5, 1]), 'up': array([3, 7, 6, 2]), 'north': array([4, 0, 2, 6]), 'east': array([5, 4, 6, 7]), 'south': array([1, 5, 7, 3]), 'west': array([0, 1, 3, 2])}
|
|
299
|
+
FACE_KEYS: dict # value = {None: <BlockMeshCullDirection.CullNone: 0>, 'up': <BlockMeshCullDirection.CullUp: 1>, 'down': <BlockMeshCullDirection.CullDown: 2>, 'north': <BlockMeshCullDirection.CullNorth: 3>, 'east': <BlockMeshCullDirection.CullEast: 4>, 'south': <BlockMeshCullDirection.CullSouth: 5>, 'west': <BlockMeshCullDirection.CullWest: 6>}
|
|
300
|
+
TRI_FACE: numpy.ndarray # value = array([0, 1, 2, 0, 2, 3], dtype=uint32)
|
|
301
|
+
UV_ROTATION_LUT: list = [0, 3, 2, 3, 2, 1, 0, 1]
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
from typing import TypeAlias
|
|
2
|
+
import numpy
|
|
3
|
+
import itertools
|
|
4
|
+
|
|
5
|
+
from amulet.mesh.block import (
|
|
6
|
+
BlockMesh,
|
|
7
|
+
BlockMeshPart,
|
|
8
|
+
Triangle,
|
|
9
|
+
Vertex,
|
|
10
|
+
FloatVec3,
|
|
11
|
+
FloatVec2,
|
|
12
|
+
BlockMeshTransparency,
|
|
13
|
+
BlockMeshCullDirection,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
BoundsType: TypeAlias = tuple[
|
|
17
|
+
tuple[float, float], tuple[float, float], tuple[float, float]
|
|
18
|
+
]
|
|
19
|
+
TextureUVType: TypeAlias = tuple[
|
|
20
|
+
tuple[float, float, float, float],
|
|
21
|
+
tuple[float, float, float, float],
|
|
22
|
+
tuple[float, float, float, float],
|
|
23
|
+
tuple[float, float, float, float],
|
|
24
|
+
tuple[float, float, float, float],
|
|
25
|
+
tuple[float, float, float, float],
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
UNIT_BOX_COORDINATES = numpy.array(
|
|
29
|
+
list(itertools.product((0, 1), (0, 1), (0, 1)))
|
|
30
|
+
) # X, Y, Z
|
|
31
|
+
|
|
32
|
+
CULL_DIRECTION_NAMES = (
|
|
33
|
+
"down",
|
|
34
|
+
"up",
|
|
35
|
+
"north",
|
|
36
|
+
"east",
|
|
37
|
+
"south",
|
|
38
|
+
"west",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# This maps face direction to the vertices used (defined in UNIT_BOX_COORDINATES)
|
|
42
|
+
VERTEX_INDEXES = (
|
|
43
|
+
numpy.array([0, 4, 5, 1]),
|
|
44
|
+
numpy.array([3, 7, 6, 2]),
|
|
45
|
+
numpy.array([4, 0, 2, 6]),
|
|
46
|
+
numpy.array([5, 4, 6, 7]),
|
|
47
|
+
numpy.array([1, 5, 7, 3]),
|
|
48
|
+
numpy.array([0, 1, 3, 2]),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# This maps face direction to the vertices used (defined in UNIT_BOX_COORDINATES)
|
|
52
|
+
CUBE_FACE_LUT = dict(zip(CULL_DIRECTION_NAMES, VERTEX_INDEXES))
|
|
53
|
+
|
|
54
|
+
TRI_FACE = numpy.array([0, 1, 2, 0, 2, 3], numpy.uint32)
|
|
55
|
+
|
|
56
|
+
# cube_vert_lut = { # This maps from vertex index to index in [minx, miny, minz, maxx, maxy, maxz]
|
|
57
|
+
# 1: [0, 1, 5],
|
|
58
|
+
# 3: [0, 4, 5],
|
|
59
|
+
# 0: [0, 1, 2],
|
|
60
|
+
# 2: [0, 4, 2],
|
|
61
|
+
# 5: [3, 1, 5],
|
|
62
|
+
# 7: [3, 4, 5],
|
|
63
|
+
# 4: [3, 1, 2],
|
|
64
|
+
# 6: [3, 4, 2],
|
|
65
|
+
# }
|
|
66
|
+
#
|
|
67
|
+
# # combines the above two to map from face to index in [minx, miny, minz, maxx, maxy, maxz]. Used to index a numpy array
|
|
68
|
+
# # The above two have been kept separate because the merged result is unintuitive and difficult to edit.
|
|
69
|
+
# cube_lut = {
|
|
70
|
+
# face_dir_: [
|
|
71
|
+
# vert_coord_ for vert_ in vert_index_ for vert_coord_ in cube_vert_lut[vert_]
|
|
72
|
+
# ]
|
|
73
|
+
# for face_dir_, vert_index_ in CUBE_FACE_LUT.items()
|
|
74
|
+
# }
|
|
75
|
+
|
|
76
|
+
UV_ROTATION_LUT = [0, 3, 2, 3, 2, 1, 0, 1] # remap
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# tvert_lut = { # TODO: implement this for the cases where the UV is not defined
|
|
80
|
+
# 'down': [],
|
|
81
|
+
# 'up': [],
|
|
82
|
+
# 'north': [],
|
|
83
|
+
# 'east': [],
|
|
84
|
+
# 'south': [],
|
|
85
|
+
# 'west': []
|
|
86
|
+
# }
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_cube(
|
|
90
|
+
down: str,
|
|
91
|
+
up: str,
|
|
92
|
+
north: str,
|
|
93
|
+
east: str,
|
|
94
|
+
south: str,
|
|
95
|
+
west: str,
|
|
96
|
+
transparency: BlockMeshTransparency = BlockMeshTransparency.FullOpaque,
|
|
97
|
+
tint: tuple[int, int, int] = (1, 1, 1),
|
|
98
|
+
bounds: BoundsType = ((0, 1), (0, 1), (0, 1)),
|
|
99
|
+
texture_uv: TextureUVType = ((0, 0, 1, 1),) * 6,
|
|
100
|
+
do_not_cull: tuple[bool, bool, bool, bool, bool, bool] = (
|
|
101
|
+
False,
|
|
102
|
+
False,
|
|
103
|
+
False,
|
|
104
|
+
False,
|
|
105
|
+
False,
|
|
106
|
+
False,
|
|
107
|
+
),
|
|
108
|
+
) -> BlockMesh:
|
|
109
|
+
texture_paths: dict[str, int] = {}
|
|
110
|
+
mesh_parts: list[tuple[list[Vertex], list[Triangle]] | None] = [
|
|
111
|
+
None,
|
|
112
|
+
None,
|
|
113
|
+
None,
|
|
114
|
+
None,
|
|
115
|
+
None,
|
|
116
|
+
None,
|
|
117
|
+
None,
|
|
118
|
+
]
|
|
119
|
+
box_coordinates = list(itertools.product(*bounds))
|
|
120
|
+
tint_vec = FloatVec3(*tint)
|
|
121
|
+
|
|
122
|
+
for (
|
|
123
|
+
cull_direction,
|
|
124
|
+
vertex_index,
|
|
125
|
+
do_not_cull_face,
|
|
126
|
+
texture_path,
|
|
127
|
+
texture_coords,
|
|
128
|
+
) in zip(
|
|
129
|
+
(
|
|
130
|
+
BlockMeshCullDirection.CullDown,
|
|
131
|
+
BlockMeshCullDirection.CullUp,
|
|
132
|
+
BlockMeshCullDirection.CullNorth,
|
|
133
|
+
BlockMeshCullDirection.CullEast,
|
|
134
|
+
BlockMeshCullDirection.CullSouth,
|
|
135
|
+
BlockMeshCullDirection.CullWest,
|
|
136
|
+
),
|
|
137
|
+
VERTEX_INDEXES,
|
|
138
|
+
do_not_cull,
|
|
139
|
+
(down, up, north, east, south, west),
|
|
140
|
+
texture_uv,
|
|
141
|
+
):
|
|
142
|
+
# Get the index of the texture path. Add if it is not contained.
|
|
143
|
+
texture_index = texture_paths.setdefault(texture_path, len(texture_paths))
|
|
144
|
+
if do_not_cull_face:
|
|
145
|
+
cull_direction = BlockMeshCullDirection.CullNone
|
|
146
|
+
part = mesh_parts[cull_direction]
|
|
147
|
+
if part is None:
|
|
148
|
+
mesh_parts[cull_direction] = part = ([], [])
|
|
149
|
+
verts, tris = part
|
|
150
|
+
vert_count = len(verts)
|
|
151
|
+
|
|
152
|
+
for i in range(4):
|
|
153
|
+
x, y, z = box_coordinates[vertex_index[i]]
|
|
154
|
+
uvx = texture_coords[UV_ROTATION_LUT[i * 2]]
|
|
155
|
+
uvy = texture_coords[UV_ROTATION_LUT[i * 2 + 1]]
|
|
156
|
+
verts.append(
|
|
157
|
+
Vertex(
|
|
158
|
+
FloatVec3(x, y, z),
|
|
159
|
+
FloatVec2(uvx, uvy),
|
|
160
|
+
tint_vec,
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
for a, b, c in TRI_FACE.reshape((2, 3)):
|
|
164
|
+
tris.append(
|
|
165
|
+
Triangle(a + vert_count, b + vert_count, c + vert_count, texture_index)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def create_part(
|
|
169
|
+
part: tuple[list[Vertex], list[Triangle]] | None
|
|
170
|
+
) -> BlockMeshPart | None:
|
|
171
|
+
return None if part is None else BlockMeshPart(*part)
|
|
172
|
+
|
|
173
|
+
return BlockMesh(
|
|
174
|
+
transparency,
|
|
175
|
+
list(texture_paths),
|
|
176
|
+
(
|
|
177
|
+
create_part(mesh_parts[0]),
|
|
178
|
+
create_part(mesh_parts[1]),
|
|
179
|
+
create_part(mesh_parts[2]),
|
|
180
|
+
create_part(mesh_parts[3]),
|
|
181
|
+
create_part(mesh_parts[4]),
|
|
182
|
+
create_part(mesh_parts[5]),
|
|
183
|
+
create_part(mesh_parts[6]),
|
|
184
|
+
),
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def get_unit_cube(
|
|
189
|
+
down: str,
|
|
190
|
+
up: str,
|
|
191
|
+
north: str,
|
|
192
|
+
east: str,
|
|
193
|
+
south: str,
|
|
194
|
+
west: str,
|
|
195
|
+
transparency: BlockMeshTransparency = BlockMeshTransparency.FullOpaque,
|
|
196
|
+
tint: tuple[int, int, int] = (1, 1, 1),
|
|
197
|
+
) -> BlockMesh:
|
|
198
|
+
return get_cube(down, up, north, east, south, west, transparency, tint)
|