dfpyre 0.4.2__py3-none-any.whl → 0.10.5__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 dfpyre might be problematic. Click here for more details.
- dfpyre/__init__.py +3 -1
- dfpyre/core/actiondump.py +277 -0
- dfpyre/core/codeblock.py +207 -0
- dfpyre/core/items.py +580 -0
- dfpyre/core/template.py +220 -0
- dfpyre/data/actiondump_min.json +1 -0
- dfpyre/data/deprecated_actions.json +172 -0
- dfpyre/data/method_templates/action.txt +5 -0
- dfpyre/data/method_templates/conditional.txt +7 -0
- dfpyre/data/method_templates/event.txt +6 -0
- dfpyre/data/method_templates/notarget_action.txt +5 -0
- dfpyre/data/method_templates/notarget_conditional.txt +6 -0
- dfpyre/data/method_templates/repeat.txt +5 -0
- dfpyre/data/method_templates/repeat_while.txt +9 -0
- dfpyre/data/method_templates/select_obj_subaction.txt +8 -0
- dfpyre/export/action_classes.py +10891 -0
- dfpyre/export/block_functions.py +90 -0
- dfpyre/gen/action_class_data.py +203 -0
- dfpyre/gen/action_literals.py +20 -0
- dfpyre/scripts/action_gen.py +222 -0
- dfpyre/scripts/action_literal_gen.py +43 -0
- dfpyre/tool/scriptgen.py +274 -0
- dfpyre/tool/slice.py +199 -0
- dfpyre/util/style.py +23 -0
- dfpyre/util/util.py +65 -0
- dfpyre-0.10.5.dist-info/METADATA +64 -0
- dfpyre-0.10.5.dist-info/RECORD +29 -0
- {dfpyre-0.4.2.dist-info → dfpyre-0.10.5.dist-info}/WHEEL +1 -2
- {dfpyre-0.4.2.dist-info → dfpyre-0.10.5.dist-info/licenses}/LICENSE +21 -21
- dfpyre/data/data.json +0 -1
- dfpyre/items.py +0 -244
- dfpyre/pyre.py +0 -407
- dfpyre/style.py +0 -21
- dfpyre-0.4.2.dist-info/METADATA +0 -11
- dfpyre-0.4.2.dist-info/RECORD +0 -10
- dfpyre-0.4.2.dist-info/top_level.txt +0 -1
dfpyre/core/items.py
ADDED
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Class definitions for code items.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from enum import Enum
|
|
7
|
+
import re
|
|
8
|
+
from typing import Literal, Any, Union
|
|
9
|
+
import websocket
|
|
10
|
+
from mcitemlib.itemlib import Item as NbtItem, MCItemlibException
|
|
11
|
+
from rapidnbt import DoubleTag, StringTag, CompoundTag
|
|
12
|
+
from dfpyre.util.style import is_ampersand_coded, ampersand_to_minimessage
|
|
13
|
+
from dfpyre.util.util import PyreException, warn, is_number, COL_SUCCESS, COL_ERROR, COL_RESET
|
|
14
|
+
from dfpyre.gen.action_literals import GAME_VALUE_NAME, SOUND_NAME, POTION_NAME
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
VAR_ITEM_TYPES = [
|
|
18
|
+
'String', 'Str', 'Text', 'Number', 'Num', 'Item', 'Location', 'Loc',
|
|
19
|
+
'Variable', 'Var', 'Sound', 'Snd', 'Particle', 'Potion', 'Pot', 'GameValue',
|
|
20
|
+
'Vector', 'Vec', 'ParameterType', 'Parameter'
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
__all__ = ['convert_literals', 'item_from_dict', 'CodeItem', 'ArgValue', 'VAR_ITEM_TYPES'] + VAR_ITEM_TYPES
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
PARAMETER_TYPE_LOOKUP = ['txt', 'comp', 'num', 'loc', 'vec', 'snd', 'part', 'pot', 'item', 'any', 'var', 'list', 'dict']
|
|
27
|
+
|
|
28
|
+
VAR_SHORTHAND_REGEX = r'^\$([gsli]) (.+)$'
|
|
29
|
+
VAR_SCOPE_LOOKUP = {'g': 'unsaved', 's': 'saved', 'l': 'local', 'i': 'line'}
|
|
30
|
+
|
|
31
|
+
CODECLIENT_URL = 'ws://localhost:31375'
|
|
32
|
+
|
|
33
|
+
# Valid types that can be passed as args for a CodeBlock function
|
|
34
|
+
ArgValue = Union["CodeItem", str, int, float]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _add_slot(d: dict, slot: int|None):
|
|
38
|
+
if slot is not None:
|
|
39
|
+
d['slot'] = slot
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class CodeItem(ABC):
|
|
43
|
+
type = '_codeitem'
|
|
44
|
+
|
|
45
|
+
def __init__(self, slot: int|None):
|
|
46
|
+
self.slot = slot
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def format(self, slot: int|None) -> dict[str, dict[str, Any]]:
|
|
50
|
+
"""
|
|
51
|
+
Returns a dictionary containing this code item's data formatted
|
|
52
|
+
for a DF template JSON.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def convert_literals(arg: ArgValue) -> CodeItem:
|
|
57
|
+
if type(arg) in {int, float}:
|
|
58
|
+
return Number(arg)
|
|
59
|
+
|
|
60
|
+
elif isinstance(arg, str):
|
|
61
|
+
shorthand_match = re.match(VAR_SHORTHAND_REGEX, arg)
|
|
62
|
+
if shorthand_match:
|
|
63
|
+
scope = VAR_SCOPE_LOOKUP[shorthand_match.group(1)]
|
|
64
|
+
return Variable(shorthand_match.group(2), scope)
|
|
65
|
+
|
|
66
|
+
return String(arg)
|
|
67
|
+
|
|
68
|
+
return arg
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class String(CodeItem):
|
|
72
|
+
"""
|
|
73
|
+
Represents a DiamondFire string object. (`txt`)
|
|
74
|
+
"""
|
|
75
|
+
type = 'txt'
|
|
76
|
+
|
|
77
|
+
def __init__(self, value: str, slot: int|None=None):
|
|
78
|
+
super().__init__(slot)
|
|
79
|
+
self.value = value
|
|
80
|
+
|
|
81
|
+
def format(self, slot: int|None):
|
|
82
|
+
formatted_dict = {"item": {"id": self.type, "data": {"name": self.value}}}
|
|
83
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
84
|
+
return formatted_dict
|
|
85
|
+
|
|
86
|
+
def __repr__(self) -> str:
|
|
87
|
+
return f'{self.__class__.__name__}("{self.value}")'
|
|
88
|
+
|
|
89
|
+
Str = String # String alias
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class Text(CodeItem):
|
|
93
|
+
"""
|
|
94
|
+
Represents a DiamondFire styled text object (`comp`)
|
|
95
|
+
"""
|
|
96
|
+
type = 'comp'
|
|
97
|
+
|
|
98
|
+
def __init__(self, value: str, slot: int|None=None):
|
|
99
|
+
super().__init__(slot)
|
|
100
|
+
|
|
101
|
+
if is_ampersand_coded(value):
|
|
102
|
+
value = ampersand_to_minimessage(value)
|
|
103
|
+
self.value = value
|
|
104
|
+
|
|
105
|
+
def format(self, slot: int|None):
|
|
106
|
+
formatted_dict = {"item": {"id": self.type, "data": {"name": self.value}}}
|
|
107
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
108
|
+
return formatted_dict
|
|
109
|
+
|
|
110
|
+
def __repr__(self) -> str:
|
|
111
|
+
return f'{self.__class__.__name__}("{self.value}")'
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class Number(CodeItem):
|
|
115
|
+
"""
|
|
116
|
+
Represents a DiamondFire number object.
|
|
117
|
+
"""
|
|
118
|
+
type = 'num'
|
|
119
|
+
|
|
120
|
+
def __init__(self, num: int|float|str, slot: int|None=None):
|
|
121
|
+
super().__init__(slot)
|
|
122
|
+
self.value = num
|
|
123
|
+
|
|
124
|
+
def format(self, slot: int|None):
|
|
125
|
+
formatted_dict = {"item": {"id": self.type, "data": {"name": str(self.value)}}}
|
|
126
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
127
|
+
return formatted_dict
|
|
128
|
+
|
|
129
|
+
def __repr__(self) -> str:
|
|
130
|
+
return f'{self.__class__.__name__}({self.value})'
|
|
131
|
+
|
|
132
|
+
Num = Number # Number alias
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class Item(CodeItem, NbtItem):
|
|
136
|
+
"""
|
|
137
|
+
Represents a Minecraft item.
|
|
138
|
+
"""
|
|
139
|
+
type = 'item'
|
|
140
|
+
|
|
141
|
+
def __init__(self, item_id: str, count: int=1, slot: int | None=None):
|
|
142
|
+
NbtItem.__init__(self, item_id, count)
|
|
143
|
+
CodeItem.__init__(self, slot)
|
|
144
|
+
|
|
145
|
+
def format(self, slot: int|None):
|
|
146
|
+
formatted_dict = {"item": {"id": self.type, "data": {"item": self.get_snbt()}}}
|
|
147
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
148
|
+
return formatted_dict
|
|
149
|
+
|
|
150
|
+
def __repr__(self) -> str:
|
|
151
|
+
return f'{self.__class__.__name__}({self.get_id()}, {self.get_count()})'
|
|
152
|
+
|
|
153
|
+
def set_tag(self, tag_name: str, tag_value: str|int|float|String|Number):
|
|
154
|
+
"""
|
|
155
|
+
Add a DiamondFire custom tag to this item.
|
|
156
|
+
"""
|
|
157
|
+
if isinstance(tag_value, String):
|
|
158
|
+
tag = StringTag(tag_value.value)
|
|
159
|
+
elif isinstance(tag_value, str):
|
|
160
|
+
tag = StringTag(tag_value)
|
|
161
|
+
elif isinstance(tag_value, Number):
|
|
162
|
+
tag = DoubleTag(float(tag_value.value))
|
|
163
|
+
elif isinstance(tag_value, (int, float)):
|
|
164
|
+
tag = DoubleTag(float(tag_value))
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
custom_data_tag = self.get_component('minecraft:custom_data')
|
|
168
|
+
if 'PublicBukkitValues' in custom_data_tag:
|
|
169
|
+
pbv_tag = custom_data_tag['PublicBukkitValues']
|
|
170
|
+
else:
|
|
171
|
+
pbv_tag = CompoundTag()
|
|
172
|
+
except MCItemlibException:
|
|
173
|
+
custom_data_tag = CompoundTag()
|
|
174
|
+
pbv_tag = CompoundTag()
|
|
175
|
+
|
|
176
|
+
custom_data_tag['PublicBukkitValues'] = pbv_tag
|
|
177
|
+
|
|
178
|
+
pbv_tag[f'hypercube:{tag_name}'] = tag
|
|
179
|
+
self.set_component('minecraft:custom_data', custom_data_tag)
|
|
180
|
+
|
|
181
|
+
def get_tag(self, tag_name: str) -> str|float|None:
|
|
182
|
+
"""
|
|
183
|
+
Get a DiamondFire custom tag from this item.
|
|
184
|
+
"""
|
|
185
|
+
try:
|
|
186
|
+
custom_data_tag = self.get_component('minecraft:custom_data')
|
|
187
|
+
except MCItemlibException:
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
if custom_data_tag.is_null():
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
pbv_tag = custom_data_tag['PublicBukkitValues']
|
|
194
|
+
if pbv_tag.is_null():
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
df_tag_value = pbv_tag[f'hypercube:{tag_name}']
|
|
198
|
+
if df_tag_value.is_null():
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
if isinstance(df_tag_value, DoubleTag):
|
|
202
|
+
return float(df_tag_value)
|
|
203
|
+
if isinstance(df_tag_value, StringTag):
|
|
204
|
+
return str(df_tag_value)
|
|
205
|
+
|
|
206
|
+
def remove_tag(self, tag_name: str):
|
|
207
|
+
"""
|
|
208
|
+
Remove a DiamondFire custom tag from this item.
|
|
209
|
+
|
|
210
|
+
Raises:
|
|
211
|
+
MCItemibException: If the tag does not exist
|
|
212
|
+
"""
|
|
213
|
+
custom_data_tag = self.get_component('minecraft:custom_data')
|
|
214
|
+
pbv_tag = custom_data_tag['PublicBukkitValues']
|
|
215
|
+
del pbv_tag[f'hypercube:{tag_name}']
|
|
216
|
+
|
|
217
|
+
return True
|
|
218
|
+
|
|
219
|
+
def send_to_minecraft(self):
|
|
220
|
+
"""
|
|
221
|
+
Sends this item to Minecraft automatically.
|
|
222
|
+
"""
|
|
223
|
+
try:
|
|
224
|
+
ws = websocket.WebSocket()
|
|
225
|
+
ws.connect(CODECLIENT_URL)
|
|
226
|
+
print(f'{COL_SUCCESS}Connected.{COL_RESET}')
|
|
227
|
+
|
|
228
|
+
command = f'give {self.get_snbt()}'
|
|
229
|
+
ws.send(command)
|
|
230
|
+
ws.close()
|
|
231
|
+
|
|
232
|
+
print(f'{COL_SUCCESS}Item sent to client successfully.{COL_RESET}')
|
|
233
|
+
return 0
|
|
234
|
+
|
|
235
|
+
except ConnectionRefusedError as e:
|
|
236
|
+
print(f'{COL_ERROR}Could not connect to CodeClient API. Possible problems:')
|
|
237
|
+
print(f' - Minecraft is not open')
|
|
238
|
+
print(f' - CodeClient is not installed (get it here: https://modrinth.com/mod/codeclient)')
|
|
239
|
+
print(f' - CodeClient API is not enabled (enable it in CodeClient general settings){COL_RESET}')
|
|
240
|
+
return 1
|
|
241
|
+
|
|
242
|
+
except Exception as e:
|
|
243
|
+
print(f'Connection failed: {e}')
|
|
244
|
+
return 2
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class Location(CodeItem):
|
|
248
|
+
"""
|
|
249
|
+
Represents a DiamondFire location object.
|
|
250
|
+
"""
|
|
251
|
+
type = 'loc'
|
|
252
|
+
|
|
253
|
+
def __init__(self, x: float=0, y: float=0, z: float=0, pitch: float=0, yaw: float=0, slot: int | None=None):
|
|
254
|
+
super().__init__(slot)
|
|
255
|
+
self.x = float(x)
|
|
256
|
+
self.y = float(y)
|
|
257
|
+
self.z = float(z)
|
|
258
|
+
self.pitch = float(pitch)
|
|
259
|
+
self.yaw = float(yaw)
|
|
260
|
+
|
|
261
|
+
def format(self, slot: int|None):
|
|
262
|
+
formatted_dict = {"item": {
|
|
263
|
+
"id": self.type,
|
|
264
|
+
"data": {
|
|
265
|
+
"isBlock": False,
|
|
266
|
+
"loc": {
|
|
267
|
+
"x": self.x,
|
|
268
|
+
"y": self.y,
|
|
269
|
+
"z": self.z,
|
|
270
|
+
"pitch": self.pitch,
|
|
271
|
+
"yaw": self.yaw
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}}
|
|
275
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
276
|
+
return formatted_dict
|
|
277
|
+
|
|
278
|
+
def __repr__(self) -> str:
|
|
279
|
+
return f'{self.__class__.__name__}({self.x}, {self.y}, {self.z}, {self.pitch}, {self.yaw})'
|
|
280
|
+
|
|
281
|
+
Loc = Location # Location alias
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class Variable(CodeItem):
|
|
285
|
+
"""
|
|
286
|
+
Represents a DiamondFire variable object.
|
|
287
|
+
"""
|
|
288
|
+
type = 'var'
|
|
289
|
+
|
|
290
|
+
def __init__(self, name: str, scope: Literal['unsaved', 'game', 'saved', 'local', 'line']='unsaved', slot: int | None=None):
|
|
291
|
+
super().__init__(slot)
|
|
292
|
+
self.name = name
|
|
293
|
+
|
|
294
|
+
if scope == 'game':
|
|
295
|
+
scope = 'unsaved'
|
|
296
|
+
self.scope = scope
|
|
297
|
+
|
|
298
|
+
def format(self, slot: int|None):
|
|
299
|
+
formatted_dict = {"item": {"id": self.type,"data": {"name": self.name, "scope": self.scope}}}
|
|
300
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
301
|
+
return formatted_dict
|
|
302
|
+
|
|
303
|
+
def __repr__(self) -> str:
|
|
304
|
+
return f'{self.__class__.__name__}({self.scope}, "{self.name}")'
|
|
305
|
+
|
|
306
|
+
Var = Variable # Variable alias
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class Sound(CodeItem):
|
|
310
|
+
"""
|
|
311
|
+
Represents a DiamondFire sound object.
|
|
312
|
+
"""
|
|
313
|
+
type = 'snd'
|
|
314
|
+
|
|
315
|
+
def __init__(self, name: SOUND_NAME, pitch: float=1.0, vol: float=2.0, slot: int | None=None):
|
|
316
|
+
super().__init__(slot)
|
|
317
|
+
if name not in set(SOUND_NAME.__args__):
|
|
318
|
+
warn(f'Sound name "{name}" not found.')
|
|
319
|
+
|
|
320
|
+
self.name = name
|
|
321
|
+
self.pitch = pitch
|
|
322
|
+
self.vol = vol
|
|
323
|
+
|
|
324
|
+
def format(self, slot: int|None):
|
|
325
|
+
formatted_dict = {"item": {"id": self.type,"data": {"sound": self.name, "pitch": self.pitch, "vol": self.vol}}}
|
|
326
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
327
|
+
return formatted_dict
|
|
328
|
+
|
|
329
|
+
def __repr__(self) -> str:
|
|
330
|
+
return f'{self.__class__.__name__}(pitch: {self.pitch}, volume: {self.vol})'
|
|
331
|
+
|
|
332
|
+
Snd = Sound # Sound alias
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
class Particle(CodeItem):
|
|
336
|
+
"""
|
|
337
|
+
Represents a DiamondFire particle object.
|
|
338
|
+
"""
|
|
339
|
+
type = 'part'
|
|
340
|
+
|
|
341
|
+
def __init__(self, particle_data: dict, slot: int | None=None):
|
|
342
|
+
super().__init__(slot)
|
|
343
|
+
self.particle_data = particle_data
|
|
344
|
+
|
|
345
|
+
def format(self, slot: int|None):
|
|
346
|
+
formatted_dict = {"item": {"id": self.type, "data": self.particle_data}}
|
|
347
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
348
|
+
return formatted_dict
|
|
349
|
+
|
|
350
|
+
def __repr__(self) -> str:
|
|
351
|
+
return f'{self.__class__.__name__}({self.particle_data})'
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class Potion(CodeItem):
|
|
355
|
+
"""
|
|
356
|
+
Represents a DiamondFire potion object.
|
|
357
|
+
"""
|
|
358
|
+
type = 'pot'
|
|
359
|
+
|
|
360
|
+
def __init__(self, name: POTION_NAME, dur: int=1000000, amp: int=0, slot: int | None=None):
|
|
361
|
+
super().__init__(slot)
|
|
362
|
+
|
|
363
|
+
if name not in set(POTION_NAME.__args__):
|
|
364
|
+
warn(f'Potion name "{name}" not found.')
|
|
365
|
+
|
|
366
|
+
self.name = name
|
|
367
|
+
self.dur = dur
|
|
368
|
+
self.amp = amp
|
|
369
|
+
|
|
370
|
+
def format(self, slot: int|None):
|
|
371
|
+
formatted_dict = {"item": {"id": self.type,"data": {"pot": self.name, "dur": self.dur, "amp": self.amp}}}
|
|
372
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
373
|
+
return formatted_dict
|
|
374
|
+
|
|
375
|
+
def __repr__(self) -> str:
|
|
376
|
+
return f'{self.__class__.__name__}(effect: {self.name}, duration: {self.dur}, amplifier: {self.amp})'
|
|
377
|
+
|
|
378
|
+
Pot = Potion # Potion alias
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class GameValue(CodeItem):
|
|
382
|
+
"""
|
|
383
|
+
Represents a DiamondFire game value object.
|
|
384
|
+
"""
|
|
385
|
+
type = 'g_val'
|
|
386
|
+
|
|
387
|
+
def __init__(self, name: GAME_VALUE_NAME, target: str='Default', slot: int | None=None):
|
|
388
|
+
super().__init__(slot)
|
|
389
|
+
|
|
390
|
+
if name not in set(GAME_VALUE_NAME.__args__):
|
|
391
|
+
warn(f'Game value name "{name}" not found.')
|
|
392
|
+
|
|
393
|
+
self.name = name
|
|
394
|
+
self.target = target
|
|
395
|
+
|
|
396
|
+
def format(self, slot: int|None):
|
|
397
|
+
formatted_dict = {"item": {"id": self.type, "data": {"type": self.name, "target": self.target}}}
|
|
398
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
399
|
+
return formatted_dict
|
|
400
|
+
|
|
401
|
+
def __repr__(self) -> str:
|
|
402
|
+
return f'{self.__class__.__name__}({self.name}, target: {self.target})'
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
class Vector(CodeItem):
|
|
406
|
+
"""
|
|
407
|
+
Represents a DiamondFire vector object.
|
|
408
|
+
"""
|
|
409
|
+
type = 'vec'
|
|
410
|
+
|
|
411
|
+
def __init__(self, x: float=0.0, y: float=0.0, z: float=0.0, slot: int | None=None):
|
|
412
|
+
super().__init__(slot)
|
|
413
|
+
self.x = float(x)
|
|
414
|
+
self.y = float(y)
|
|
415
|
+
self.z = float(z)
|
|
416
|
+
|
|
417
|
+
def format(self, slot: int|None):
|
|
418
|
+
formatted_dict = {"item": {"id": self.type, "data": {"x": self.x, "y": self.y, "z": self.z}}}
|
|
419
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
420
|
+
return formatted_dict
|
|
421
|
+
|
|
422
|
+
def __repr__(self) -> str:
|
|
423
|
+
return f'{self.__class__.__name__}({self.x}, {self.y}, {self.z})'
|
|
424
|
+
|
|
425
|
+
Vec = Vector # Vector alias
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
class ParameterType(Enum):
|
|
429
|
+
STRING = 0
|
|
430
|
+
TEXT = 1
|
|
431
|
+
NUMBER = 2
|
|
432
|
+
LOCATION = 3
|
|
433
|
+
VECTOR = 4
|
|
434
|
+
SOUND = 5
|
|
435
|
+
PARTICLE = 6
|
|
436
|
+
POTION_EFFECT = 7
|
|
437
|
+
ITEM = 8
|
|
438
|
+
ANY = 9
|
|
439
|
+
VAR = 10
|
|
440
|
+
LIST = 11
|
|
441
|
+
DICT = 12
|
|
442
|
+
|
|
443
|
+
def get_string_value(self) -> str:
|
|
444
|
+
return PARAMETER_TYPE_LOOKUP[self.value]
|
|
445
|
+
|
|
446
|
+
class Parameter(CodeItem):
|
|
447
|
+
"""
|
|
448
|
+
Represents a DiamondFire parameter object.
|
|
449
|
+
"""
|
|
450
|
+
type = 'pn_el'
|
|
451
|
+
|
|
452
|
+
def __init__(self, name: str, param_type: ParameterType, plural: bool=False, optional: bool=False,
|
|
453
|
+
description: str="", note: str="", default_value=None, slot: int | None=None):
|
|
454
|
+
super().__init__(slot)
|
|
455
|
+
self.name = name
|
|
456
|
+
self.param_type = param_type
|
|
457
|
+
self.plural = plural
|
|
458
|
+
self.optional = optional
|
|
459
|
+
self.description = description
|
|
460
|
+
self.note = note
|
|
461
|
+
self.default_value = convert_literals(default_value)
|
|
462
|
+
|
|
463
|
+
def format(self, slot: int):
|
|
464
|
+
formatted_dict = {"item": {
|
|
465
|
+
"id": self.type,
|
|
466
|
+
"data": {
|
|
467
|
+
"name": self.name,
|
|
468
|
+
"type": self.param_type.get_string_value(),
|
|
469
|
+
"plural": self.plural,
|
|
470
|
+
"optional": self.optional,
|
|
471
|
+
}}
|
|
472
|
+
}
|
|
473
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
474
|
+
|
|
475
|
+
if self.description:
|
|
476
|
+
formatted_dict['item']['data']['description'] = self.description
|
|
477
|
+
if self.note:
|
|
478
|
+
formatted_dict['item']['data']['note'] = self.note
|
|
479
|
+
if self.default_value is not None:
|
|
480
|
+
if not self.optional:
|
|
481
|
+
warn(f'For parameter "{self.name}": Default value cannot be set if optional is False.')
|
|
482
|
+
elif self.plural:
|
|
483
|
+
warn(f'For parameter "{self.name}": Default value cannot be set while plural is True.')
|
|
484
|
+
else:
|
|
485
|
+
formatted_dict['item']['data']['default_value'] = self.default_value.format(None)['item']
|
|
486
|
+
|
|
487
|
+
return formatted_dict
|
|
488
|
+
|
|
489
|
+
def __repr__(self) -> str:
|
|
490
|
+
raw_type = str(self.param_type).partition('.')[2]
|
|
491
|
+
return f'{self.__class__.__name__}({self.name}, type: {raw_type})'
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
class _Tag(CodeItem):
|
|
495
|
+
"""
|
|
496
|
+
Represents a CodeBlock action tag.
|
|
497
|
+
"""
|
|
498
|
+
type = 'bl_tag'
|
|
499
|
+
|
|
500
|
+
def __init__(self, tag_data: dict, slot: int | None=None):
|
|
501
|
+
super().__init__(slot)
|
|
502
|
+
self.tag_data = tag_data
|
|
503
|
+
|
|
504
|
+
def format(self, slot: int|None):
|
|
505
|
+
formatted_dict = {"item": {"id": self.type, "data": self.tag_data}}
|
|
506
|
+
_add_slot(formatted_dict, self.slot or slot)
|
|
507
|
+
return formatted_dict
|
|
508
|
+
|
|
509
|
+
def __repr__(self) -> str:
|
|
510
|
+
return f'{self.__class__.__name__}({self.tag_data})'
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
def item_from_dict(item_dict: dict, preserve_item_slots: bool):
|
|
514
|
+
item_id = item_dict['item']['id']
|
|
515
|
+
item_data = item_dict['item']['data']
|
|
516
|
+
item_slot = item_dict['slot'] if preserve_item_slots else None
|
|
517
|
+
|
|
518
|
+
if item_id == 'item':
|
|
519
|
+
item = Item.from_snbt(item_data['item'])
|
|
520
|
+
item.slot = item_slot
|
|
521
|
+
return item
|
|
522
|
+
|
|
523
|
+
elif item_id == 'txt':
|
|
524
|
+
return String(item_data['name'], item_slot)
|
|
525
|
+
|
|
526
|
+
elif item_id == 'comp':
|
|
527
|
+
return Text(item_data['name'], item_slot)
|
|
528
|
+
|
|
529
|
+
elif item_id == 'num':
|
|
530
|
+
num_value = item_data['name']
|
|
531
|
+
if is_number(num_value):
|
|
532
|
+
num_value = float(item_data['name'])
|
|
533
|
+
if num_value % 1 == 0:
|
|
534
|
+
num_value = int(num_value)
|
|
535
|
+
return Number(num_value, item_slot)
|
|
536
|
+
return Number(num_value, item_slot)
|
|
537
|
+
|
|
538
|
+
elif item_id == 'loc':
|
|
539
|
+
item_loc = item_data['loc']
|
|
540
|
+
return Location(item_loc['x'], item_loc['y'], item_loc['z'], item_loc['pitch'], item_loc['yaw'], item_slot)
|
|
541
|
+
|
|
542
|
+
elif item_id == 'var':
|
|
543
|
+
return Variable(item_data['name'], item_data['scope'], item_slot)
|
|
544
|
+
|
|
545
|
+
elif item_id == 'snd':
|
|
546
|
+
return Sound(item_data['sound'], item_data['pitch'], item_data['vol'], item_slot)
|
|
547
|
+
|
|
548
|
+
elif item_id == 'part':
|
|
549
|
+
return Particle(item_data, item_slot)
|
|
550
|
+
|
|
551
|
+
elif item_id == 'pot':
|
|
552
|
+
return Potion(item_data['pot'], item_data['dur'], item_data['amp'], item_slot)
|
|
553
|
+
|
|
554
|
+
elif item_id == 'g_val':
|
|
555
|
+
return GameValue(item_data['type'], item_data['target'], item_slot)
|
|
556
|
+
|
|
557
|
+
elif item_id == 'vec':
|
|
558
|
+
return Vector(item_data['x'], item_data['y'], item_data['z'], item_slot)
|
|
559
|
+
|
|
560
|
+
elif item_id == 'pn_el':
|
|
561
|
+
description = item_data.get('description') or ''
|
|
562
|
+
note = item_data.get('note') or ''
|
|
563
|
+
param_type = ParameterType(PARAMETER_TYPE_LOOKUP.index(item_data['type']))
|
|
564
|
+
if item_data['optional']:
|
|
565
|
+
if 'default_value' in item_data:
|
|
566
|
+
default_value_dict = {'item': item_data['default_value'], 'slot': None}
|
|
567
|
+
default_value_item = item_from_dict(default_value_dict, preserve_item_slots)
|
|
568
|
+
return Parameter(item_data['name'], param_type, item_data['plural'], True, description, note, default_value_item, item_slot)
|
|
569
|
+
return Parameter(item_data['name'], param_type, item_data['plural'], True, description, note, slot=item_slot)
|
|
570
|
+
return Parameter(item_data['name'], param_type, item_data['plural'], False, description, note, slot=item_slot)
|
|
571
|
+
|
|
572
|
+
elif item_id == 'bl_tag':
|
|
573
|
+
if 'variable' in item_data:
|
|
574
|
+
return _Tag(item_data, item_slot)
|
|
575
|
+
|
|
576
|
+
elif item_id == 'hint': # Ignore hints
|
|
577
|
+
return
|
|
578
|
+
|
|
579
|
+
else:
|
|
580
|
+
raise PyreException(f'Unrecognized item id `{item_id}`')
|