pylitematic 0.0.2__py3-none-any.whl → 0.0.4__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.
- pylitematic/__init__.py +3 -3
- pylitematic/block_property.py +13 -79
- pylitematic/block_state.py +20 -13
- pylitematic/geometry.py +70 -92
- pylitematic/region.py +339 -182
- pylitematic/resource_location.py +10 -6
- pylitematic/schematic.py +18 -13
- pylitematic/test.py +69 -36
- {pylitematic-0.0.2.dist-info → pylitematic-0.0.4.dist-info}/METADATA +7 -1
- pylitematic-0.0.4.dist-info/RECORD +12 -0
- pylitematic-0.0.2.dist-info/RECORD +0 -12
- {pylitematic-0.0.2.dist-info → pylitematic-0.0.4.dist-info}/WHEEL +0 -0
- {pylitematic-0.0.2.dist-info → pylitematic-0.0.4.dist-info}/top_level.txt +0 -0
pylitematic/__init__.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
__version__ = "0.0.
|
1
|
+
__version__ = "0.0.4"
|
2
2
|
|
3
3
|
from .block_state import BlockState
|
4
|
-
from .geometry import BlockPosition, Size3D
|
4
|
+
from .geometry import BlockPosition, Direction, Size3D
|
5
5
|
from .region import Region
|
6
|
-
from .resource_location import
|
6
|
+
from .resource_location import BlockId
|
7
7
|
from .schematic import Schematic
|
pylitematic/block_property.py
CHANGED
@@ -14,72 +14,6 @@ ENUM_VALUE_REGEX: str = r"[a-z]+(_[a-z]+)*" # snake case
|
|
14
14
|
ENUM_VALUE_PATTERN: re.Pattern = re.compile(ENUM_VALUE_REGEX)
|
15
15
|
|
16
16
|
|
17
|
-
class Property():
|
18
|
-
|
19
|
-
__slots__ = ("_name", "_value")
|
20
|
-
|
21
|
-
def __init__(self, name: str, value: Any | PropertyValue) -> None:
|
22
|
-
if not PROPERTY_NAME_PATTERN.fullmatch(name):
|
23
|
-
raise ValueError(f"Invalid property name {name!r}")
|
24
|
-
self._name = name
|
25
|
-
|
26
|
-
if not isinstance(value, PropertyValue):
|
27
|
-
value = PropertyValue.value_factory(value=value)
|
28
|
-
self._value = value
|
29
|
-
|
30
|
-
def __str__(self) -> str:
|
31
|
-
return f"{self._name}={self._value}"
|
32
|
-
|
33
|
-
def __repr__(self) -> str:
|
34
|
-
return (
|
35
|
-
f"{type(self).__name__}("
|
36
|
-
f"name: {self._name}, value: {self._value!r})")
|
37
|
-
|
38
|
-
def __eq__(self, other: Any) -> bool:
|
39
|
-
if not isinstance(other, Property):
|
40
|
-
return NotImplemented
|
41
|
-
return (self.name, self.value) == (other.name, other.value)
|
42
|
-
|
43
|
-
def __lt__(self, other: Any) -> bool:
|
44
|
-
if not isinstance(other, Property):
|
45
|
-
return NotImplemented
|
46
|
-
return (self.name, self.value) < (other.name, other.value)
|
47
|
-
|
48
|
-
@property
|
49
|
-
def name(self) -> str:
|
50
|
-
return self._name
|
51
|
-
|
52
|
-
@property
|
53
|
-
def value(self) -> Any:
|
54
|
-
return self._value.get()
|
55
|
-
|
56
|
-
@value.setter
|
57
|
-
def value(self, value: Any) -> None:
|
58
|
-
self._value.set(value)
|
59
|
-
|
60
|
-
def to_string(self) -> str:
|
61
|
-
return str(self)
|
62
|
-
|
63
|
-
@staticmethod
|
64
|
-
def from_string(string: str, value: str | None = None) -> Property:
|
65
|
-
if value is None:
|
66
|
-
# tread string as "name=value"
|
67
|
-
try:
|
68
|
-
string, value = string.split("=")
|
69
|
-
except ValueError as exc:
|
70
|
-
raise ValueError(f"Invalid property string {string!r}") from exc
|
71
|
-
return Property(name=string, value=PropertyValue.from_string(value))
|
72
|
-
|
73
|
-
def to_nbt(self) -> tuple[str, nbtlib.String]:
|
74
|
-
# return nbtlib.Compound(Name=nbtlib.String(self._name), Value=self._value.to_nbt()})
|
75
|
-
return self._name, self._value.to_nbt()
|
76
|
-
|
77
|
-
@staticmethod
|
78
|
-
def from_nbt(name: str, nbt: nbtlib.String) -> Property:
|
79
|
-
# return Property.from_string(name=nbt["Name"], value=str(nbt["Value"]))
|
80
|
-
return Property.from_string(string=name, value=str(nbt))
|
81
|
-
|
82
|
-
|
83
17
|
class Properties(dict):
|
84
18
|
|
85
19
|
def __init__(self, *args, **kwargs):
|
@@ -160,10 +94,10 @@ class Properties(dict):
|
|
160
94
|
def to_string(self) -> str:
|
161
95
|
return str(self)
|
162
96
|
|
163
|
-
@
|
164
|
-
def from_string(string: str) -> Properties:
|
97
|
+
@classmethod
|
98
|
+
def from_string(cls, string: str) -> Properties:
|
165
99
|
if string in ("", "[]"):
|
166
|
-
return
|
100
|
+
return cls()
|
167
101
|
|
168
102
|
if not (string.startswith("[") and string.endswith("]")):
|
169
103
|
raise ValueError(f"Invalid properties string {string!r}")
|
@@ -179,18 +113,18 @@ class Properties(dict):
|
|
179
113
|
ValueError(f"Duplicate property name {name!r}")
|
180
114
|
props[name] = PropertyValue.from_string(string=val_str).get()
|
181
115
|
|
182
|
-
return
|
116
|
+
return cls(props)
|
183
117
|
|
184
118
|
def to_nbt(self) -> nbtlib.Compound:
|
185
119
|
return nbtlib.Compound(
|
186
120
|
{name: value.to_nbt() for name, value in sorted(super().items())})
|
187
121
|
|
188
|
-
@
|
189
|
-
def from_nbt(nbt: nbtlib.Compound) -> Properties:
|
122
|
+
@classmethod
|
123
|
+
def from_nbt(cls, nbt: nbtlib.Compound) -> Properties:
|
190
124
|
props = {}
|
191
125
|
for name, value in nbt.items():
|
192
126
|
props[name] = PropertyValue.from_nbt(nbt=value).get()
|
193
|
-
return
|
127
|
+
return cls(props)
|
194
128
|
|
195
129
|
|
196
130
|
class PropertyValue(ABC):
|
@@ -270,20 +204,20 @@ class PropertyValue(ABC):
|
|
270
204
|
def to_string(self) -> str:
|
271
205
|
return str(self)
|
272
206
|
|
273
|
-
@
|
274
|
-
def from_string(string: str) -> PropertyValue:
|
207
|
+
@classmethod
|
208
|
+
def from_string(cls, string: str) -> PropertyValue:
|
275
209
|
try:
|
276
210
|
value = json.loads(string)
|
277
211
|
except json.JSONDecodeError:
|
278
212
|
value = string
|
279
|
-
return
|
213
|
+
return cls.value_factory(value)
|
280
214
|
|
281
215
|
def to_nbt(self) -> nbtlib.String:
|
282
216
|
return nbtlib.String(self)
|
283
217
|
|
284
|
-
@
|
285
|
-
def from_nbt(nbt: nbtlib.String) -> PropertyValue:
|
286
|
-
return
|
218
|
+
@classmethod
|
219
|
+
def from_nbt(cls, nbt: nbtlib.String) -> PropertyValue:
|
220
|
+
return cls.from_string(str(nbt))
|
287
221
|
|
288
222
|
|
289
223
|
class BooleanValue(PropertyValue):
|
pylitematic/block_state.py
CHANGED
@@ -4,7 +4,7 @@ from copy import deepcopy
|
|
4
4
|
from nbtlib import Compound
|
5
5
|
from typing import Any, Iterator
|
6
6
|
|
7
|
-
from .resource_location import
|
7
|
+
from .resource_location import BlockId
|
8
8
|
from .block_property import Properties
|
9
9
|
|
10
10
|
|
@@ -12,8 +12,15 @@ class BlockState:
|
|
12
12
|
|
13
13
|
__slots__ = ("_id", "_props")
|
14
14
|
|
15
|
-
def __init__(self, _id: str, **props: Any) -> None:
|
16
|
-
|
15
|
+
def __init__(self, _id: str | BlockId, **props: Any) -> None:
|
16
|
+
if isinstance(_id, str):
|
17
|
+
_id = BlockId.from_string(_id)
|
18
|
+
elif not isinstance(_id, BlockId):
|
19
|
+
raise TypeError(
|
20
|
+
f"'_id' has to be str or {BlockId.__name__}, got"
|
21
|
+
f" {type(_id).__name__}")
|
22
|
+
self._id: BlockId = _id
|
23
|
+
|
17
24
|
self._props: Properties = Properties(**props)
|
18
25
|
|
19
26
|
def __getitem__(self, name: str) -> Any:
|
@@ -58,8 +65,8 @@ class BlockState:
|
|
58
65
|
f"id: {self._id!r}, props: {self._props!r})")
|
59
66
|
|
60
67
|
@property
|
61
|
-
def id(self) ->
|
62
|
-
return
|
68
|
+
def id(self) -> BlockId:
|
69
|
+
return self._id
|
63
70
|
|
64
71
|
def props(self) -> Iterator[tuple[str, Any]]:
|
65
72
|
return self._props.items()
|
@@ -67,15 +74,15 @@ class BlockState:
|
|
67
74
|
def to_string(self) -> str:
|
68
75
|
return str(self)
|
69
76
|
|
70
|
-
@
|
71
|
-
def from_string(string: str) -> BlockState:
|
77
|
+
@classmethod
|
78
|
+
def from_string(cls, string: str) -> BlockState:
|
72
79
|
idx = string.find("[") # basic parsing to separate block:id[name=value]
|
73
80
|
if idx == -1:
|
74
81
|
id, props = string, ""
|
75
82
|
else:
|
76
83
|
id, props = string[:idx], string[idx:]
|
77
84
|
|
78
|
-
state =
|
85
|
+
state = cls(id)
|
79
86
|
state._props = Properties.from_string(props)
|
80
87
|
return state
|
81
88
|
|
@@ -86,19 +93,19 @@ class BlockState:
|
|
86
93
|
nbt["Properties"] = self._props.to_nbt()
|
87
94
|
return nbt
|
88
95
|
|
89
|
-
@
|
90
|
-
def from_nbt(nbt: Compound) -> BlockState:
|
91
|
-
state =
|
96
|
+
@classmethod
|
97
|
+
def from_nbt(cls, nbt: Compound) -> BlockState:
|
98
|
+
state = cls(str(nbt["Name"]))
|
92
99
|
state._props = Properties.from_nbt(nbt.get("Properties", Compound()))
|
93
100
|
return state
|
94
101
|
|
95
102
|
def with_id(self, id: str) -> BlockState:
|
96
|
-
state =
|
103
|
+
state = type(self)(id)
|
97
104
|
state._props = deepcopy(self._props)
|
98
105
|
return state
|
99
106
|
|
100
107
|
def with_props(self, **props: Any) -> BlockState:
|
101
|
-
state =
|
108
|
+
state = type(self)(self.id)
|
102
109
|
new_props = deepcopy(self._props)
|
103
110
|
for name, value in props.items():
|
104
111
|
if value is None:
|
pylitematic/geometry.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from dataclasses import dataclass
|
4
|
+
import enum
|
4
5
|
import nbtlib
|
5
6
|
import numpy as np
|
7
|
+
from typing import Iterator
|
6
8
|
|
7
9
|
|
8
10
|
@dataclass(frozen=True)
|
@@ -12,134 +14,89 @@ class Vec3i:
|
|
12
14
|
_c: int
|
13
15
|
|
14
16
|
def __post_init__(self) -> None:
|
15
|
-
object.__setattr__(self, "_a",
|
16
|
-
object.__setattr__(self, "_b",
|
17
|
-
object.__setattr__(self, "_c",
|
17
|
+
object.__setattr__(self, "_a", int(self._a))
|
18
|
+
object.__setattr__(self, "_b", int(self._b))
|
19
|
+
object.__setattr__(self, "_c", int(self._c))
|
20
|
+
|
21
|
+
def __getitem__(self, index: int) -> int:
|
22
|
+
return tuple(self)[index]
|
18
23
|
|
19
24
|
def __str__(self) -> str:
|
20
25
|
return str(list(self))
|
21
26
|
|
27
|
+
def __repr__(self) -> str:
|
28
|
+
return (
|
29
|
+
f"{type(self).__name__}(a={self._a}, b={self._b}, c={self._c})")
|
30
|
+
|
22
31
|
def __len__(self) -> int:
|
23
32
|
return 3
|
24
33
|
|
34
|
+
def __iter__(self) -> Iterator[int]:
|
35
|
+
return iter((self._a, self._b, self._c))
|
36
|
+
|
37
|
+
def __neg__(self) -> Vec3i:
|
38
|
+
return type(self)(*(-i for i in self))
|
39
|
+
|
40
|
+
def __abs__(self) -> Vec3i:
|
41
|
+
return type(self)(*(abs(i) for i in self))
|
42
|
+
|
43
|
+
def __array__(self, dtype: type | None = None, copy: bool = True):
|
44
|
+
arr = np.array(tuple(self), dtype=dtype)
|
45
|
+
return arr.copy() if copy else arr
|
46
|
+
|
25
47
|
def __add__(self, other) -> Vec3i:
|
26
|
-
|
27
|
-
other = self._to_array(other)
|
28
|
-
try:
|
29
|
-
result = arr + other
|
30
|
-
except Exception:
|
31
|
-
return NotImplemented
|
32
|
-
return type(self)(*result.astype(int))
|
48
|
+
return type(self)(*(np.array(self) + other))
|
33
49
|
|
34
50
|
def __radd__(self, other) -> Vec3i:
|
35
51
|
return self.__add__(other)
|
36
52
|
|
37
53
|
def __sub__(self, other) -> Vec3i:
|
38
|
-
|
39
|
-
other = self._to_array(other)
|
40
|
-
try:
|
41
|
-
result = arr - other
|
42
|
-
except Exception:
|
43
|
-
return NotImplemented
|
44
|
-
return type(self)(*result.astype(int))
|
54
|
+
return self.__add__(-other)
|
45
55
|
|
46
56
|
def __rsub__(self, other) -> Vec3i:
|
47
|
-
|
48
|
-
try:
|
49
|
-
result = other - arr
|
50
|
-
except Exception:
|
51
|
-
return NotImplemented
|
52
|
-
return type(self)(*result.astype(int))
|
57
|
+
return -self.__sub__(other)
|
53
58
|
|
54
59
|
def __mul__(self, other) -> Vec3i:
|
55
|
-
|
56
|
-
other = self._to_array(other)
|
57
|
-
try:
|
58
|
-
result = arr * other
|
59
|
-
except Exception:
|
60
|
-
return NotImplemented
|
61
|
-
return type(self)(*result.astype(int))
|
60
|
+
return type(self)(*(np.array(self) * other))
|
62
61
|
|
63
62
|
def __rmul__(self, other) -> Vec3i:
|
64
63
|
return self.__mul__(other)
|
65
64
|
|
66
65
|
def __floordiv__(self, other) -> Vec3i:
|
67
|
-
|
68
|
-
other = self._to_array(other)
|
69
|
-
try:
|
70
|
-
result = arr // other
|
71
|
-
except Exception:
|
72
|
-
return NotImplemented
|
73
|
-
return type(self)(*result.astype(int))
|
66
|
+
return type(self)(*(np.array(self) // other))
|
74
67
|
|
75
68
|
def __rfloordiv__(self, other) -> Vec3i:
|
76
|
-
|
77
|
-
try:
|
78
|
-
result = other // arr
|
79
|
-
except Exception:
|
80
|
-
return NotImplemented
|
81
|
-
return type(self)(*result.astype(int))
|
69
|
+
return type(self)(*(other // np.array(self)))
|
82
70
|
|
83
|
-
def
|
84
|
-
return
|
71
|
+
def __truediv__(self, other) -> Vec3i:
|
72
|
+
return self.__floordiv__(other)
|
85
73
|
|
86
|
-
def
|
87
|
-
return self.
|
74
|
+
def __rtruediv__(self, other) -> Vec3i:
|
75
|
+
return self.__rfloordiv__(other)
|
88
76
|
|
89
|
-
def
|
90
|
-
return
|
77
|
+
def __mod__(self, other) -> Vec3i:
|
78
|
+
return type(self)(*(np.array(self) % other))
|
91
79
|
|
92
|
-
def
|
93
|
-
return type(self)(*np.
|
80
|
+
def __rmod__(self, other) -> Vec3i:
|
81
|
+
return type(self)(*(other % np.array(self)))
|
82
|
+
|
83
|
+
def __eq__(self, other):
|
84
|
+
return np.array(self) == other
|
85
|
+
|
86
|
+
def __ne__(self, other):
|
87
|
+
return np.invert(self.__eq__(other))
|
94
88
|
|
95
89
|
def __lt__(self, other):
|
96
|
-
return np.array(self) <
|
90
|
+
return np.array(self) < other
|
97
91
|
|
98
92
|
def __le__(self, other):
|
99
|
-
return np.array(self) <=
|
93
|
+
return np.array(self) <= other
|
100
94
|
|
101
95
|
def __gt__(self, other):
|
102
|
-
return np.array(self) >
|
96
|
+
return np.array(self) > other
|
103
97
|
|
104
98
|
def __ge__(self, other):
|
105
|
-
return np.array(self) >=
|
106
|
-
|
107
|
-
def __eq__(self, other):
|
108
|
-
return np.array(self) == self._to_array(other)
|
109
|
-
|
110
|
-
def __ne__(self, other):
|
111
|
-
return np.array(self) != self._to_array(other)
|
112
|
-
|
113
|
-
def __array__(self, dtype: type | None = None, copy: bool = True):
|
114
|
-
arr = np.array([self._a, self._b, self._c], dtype=dtype)
|
115
|
-
if copy:
|
116
|
-
return arr.copy()
|
117
|
-
else:
|
118
|
-
return arr
|
119
|
-
|
120
|
-
def _to_array(self, other):
|
121
|
-
if isinstance(other, Vec3i):
|
122
|
-
return np.array(other)
|
123
|
-
else:
|
124
|
-
return other
|
125
|
-
|
126
|
-
@staticmethod
|
127
|
-
def _to_int(value) -> int:
|
128
|
-
if isinstance(value, (int, np.integer)):
|
129
|
-
return int(value)
|
130
|
-
elif isinstance(value, float):
|
131
|
-
if value.is_integer():
|
132
|
-
return int(value)
|
133
|
-
raise TypeError(
|
134
|
-
f"{type(value).__name__} value {value!r} is not"
|
135
|
-
" int, numpy integer, or whole float")
|
136
|
-
|
137
|
-
def to_tuple(self) -> tuple[int, int, int]:
|
138
|
-
return (self._a, self._b, self._c)
|
139
|
-
|
140
|
-
@classmethod
|
141
|
-
def from_tuple(cls, t: tuple[int, int, int]) -> Vec3i:
|
142
|
-
return cls(*t)
|
99
|
+
return np.array(self) >= other
|
143
100
|
|
144
101
|
def to_nbt(self) -> nbtlib.Compound:
|
145
102
|
return nbtlib.Compound({
|
@@ -172,6 +129,15 @@ class BlockPosition(Vec3i):
|
|
172
129
|
return f"{type(self).__name__}(x={self.x}, y={self.y}, z={self.z})"
|
173
130
|
|
174
131
|
|
132
|
+
class Direction(BlockPosition, enum.Enum):
|
133
|
+
NORTH = 0, 0, -1
|
134
|
+
SOUTH = 0, 0, 1
|
135
|
+
WEST = -1, 0, 0
|
136
|
+
EAST = 1, 0, 0
|
137
|
+
UP = 0, 1, 0
|
138
|
+
DOWN = 0, -1, 0
|
139
|
+
|
140
|
+
|
175
141
|
@dataclass(frozen=True)
|
176
142
|
class Size3D(Vec3i):
|
177
143
|
|
@@ -191,3 +157,15 @@ class Size3D(Vec3i):
|
|
191
157
|
return (
|
192
158
|
f"{type(self).__name__}("
|
193
159
|
f"width={self.width}, height={self.height}, length={self.length})")
|
160
|
+
|
161
|
+
@property
|
162
|
+
def volume(self) -> int:
|
163
|
+
return abs(self.width * self.height * self.length)
|
164
|
+
|
165
|
+
@property
|
166
|
+
def limit(self) -> BlockPosition:
|
167
|
+
return BlockPosition(*(self - self.sign))
|
168
|
+
|
169
|
+
@property
|
170
|
+
def sign(self) -> BlockPosition:
|
171
|
+
return BlockPosition(*np.sign(self))
|