dfpyre 0.5.0__py3-none-any.whl → 0.6.1__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/items.py +72 -29
- dfpyre/pyre.py +146 -70
- dfpyre/scriptgen.py +146 -0
- {dfpyre-0.5.0.dist-info → dfpyre-0.6.1.dist-info}/LICENSE +1 -1
- {dfpyre-0.5.0.dist-info → dfpyre-0.6.1.dist-info}/METADATA +32 -4
- dfpyre-0.6.1.dist-info/RECORD +10 -0
- dfpyre-0.5.0.dist-info/RECORD +0 -9
- {dfpyre-0.5.0.dist-info → dfpyre-0.6.1.dist-info}/WHEEL +0 -0
dfpyre/items.py
CHANGED
|
@@ -3,15 +3,24 @@ Contains class definitions for code items.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from enum import Enum
|
|
6
|
-
|
|
6
|
+
import re
|
|
7
|
+
from typing import Literal, Dict, Any
|
|
7
8
|
from dfpyre.style import is_ampersand_coded, ampersand_to_minimessage
|
|
8
9
|
from mcitemlib.itemlib import Item as NbtItem
|
|
9
10
|
|
|
10
11
|
|
|
12
|
+
NUMBER_REGEX = r'-?\d*\.?\d+'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PyreException(Exception):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
11
19
|
def _add_slot(d: Dict, slot: int|None):
|
|
12
20
|
if slot is not None:
|
|
13
21
|
d['slot'] = slot
|
|
14
22
|
|
|
23
|
+
|
|
15
24
|
class item(NbtItem):
|
|
16
25
|
"""
|
|
17
26
|
Represents a Minecraft item.
|
|
@@ -62,7 +71,7 @@ class num:
|
|
|
62
71
|
"""
|
|
63
72
|
type = 'num'
|
|
64
73
|
|
|
65
|
-
def __init__(self, num: int|float):
|
|
74
|
+
def __init__(self, num: int|float|str):
|
|
66
75
|
self.value = num
|
|
67
76
|
|
|
68
77
|
def format(self, slot: int|None):
|
|
@@ -140,34 +149,11 @@ class particle:
|
|
|
140
149
|
Represents a DiamondFire particle object.
|
|
141
150
|
"""
|
|
142
151
|
type = 'part'
|
|
143
|
-
def __init__(self,
|
|
144
|
-
|
|
145
|
-
self.name = name
|
|
146
|
-
self.amount = amount
|
|
147
|
-
self.horizontal = horizontal
|
|
148
|
-
self.vertical = vertical
|
|
149
|
-
self.x = x
|
|
150
|
-
self.y = y
|
|
151
|
-
self.z = z
|
|
152
|
-
self.motionVariation = motionVariation
|
|
152
|
+
def __init__(self, particle_data: dict):
|
|
153
|
+
self.particle_data = particle_data
|
|
153
154
|
|
|
154
155
|
def format(self, slot: int|None):
|
|
155
|
-
formatted_dict = {"item": {"id": self.type,
|
|
156
|
-
"data": {
|
|
157
|
-
"particle": self.name,
|
|
158
|
-
"cluster": {
|
|
159
|
-
"amount": self.amount,
|
|
160
|
-
"horizontal": self.horizontal,
|
|
161
|
-
"vertical": self.vertical
|
|
162
|
-
},
|
|
163
|
-
"data": {
|
|
164
|
-
"x": self.x,
|
|
165
|
-
"y": self.y,
|
|
166
|
-
"z": self.z,
|
|
167
|
-
"motionVariation": self.motionVariation
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}}
|
|
156
|
+
formatted_dict = {"item": {"id": self.type, "data": self.particle_data}}
|
|
171
157
|
_add_slot(formatted_dict, slot)
|
|
172
158
|
return formatted_dict
|
|
173
159
|
|
|
@@ -276,4 +262,61 @@ class parameter:
|
|
|
276
262
|
if self.default_value is not None and not self.plural and self.optional:
|
|
277
263
|
formatted_dict['item']['data']['default_value'] = self.default_value.format(None)['item']
|
|
278
264
|
|
|
279
|
-
return formatted_dict
|
|
265
|
+
return formatted_dict
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _some_or(value: Any, none_value: Any):
|
|
269
|
+
"""
|
|
270
|
+
Returns `none_value` if `value` is None, otherwise returns `value`.
|
|
271
|
+
"""
|
|
272
|
+
if value is None:
|
|
273
|
+
return none_value
|
|
274
|
+
return value
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def item_from_dict(item_dict: Dict) -> object:
|
|
278
|
+
item_id = item_dict['id']
|
|
279
|
+
item_data = item_dict['data']
|
|
280
|
+
|
|
281
|
+
if item_id == 'item':
|
|
282
|
+
return item.from_nbt(item_data['item'])
|
|
283
|
+
elif item_id == 'txt':
|
|
284
|
+
return string(item_data['name'])
|
|
285
|
+
elif item_id == 'comp':
|
|
286
|
+
return text(item_data['name'])
|
|
287
|
+
elif item_id == 'num':
|
|
288
|
+
num_value = item_data['name']
|
|
289
|
+
if re.match(NUMBER_REGEX, num_value):
|
|
290
|
+
num_value = float(item_data['name'])
|
|
291
|
+
if num_value % 1 == 0:
|
|
292
|
+
num_value = int(num_value)
|
|
293
|
+
return num(num_value)
|
|
294
|
+
return num(num_value)
|
|
295
|
+
elif item_id == 'loc':
|
|
296
|
+
item_loc = item_data['loc']
|
|
297
|
+
return loc(item_loc['x'], item_loc['y'], item_loc['z'], item_loc['pitch'], item_loc['yaw'])
|
|
298
|
+
elif item_id == 'var':
|
|
299
|
+
return var(item_data['name'], item_data['scope'])
|
|
300
|
+
elif item_id == 'snd':
|
|
301
|
+
return sound(item_data['sound'], item_data['pitch'], item_data['vol'])
|
|
302
|
+
elif item_id == 'part':
|
|
303
|
+
return particle(item_data)
|
|
304
|
+
elif item_id == 'pot':
|
|
305
|
+
return potion(item_data['pot'], item_data['dur'], item_data['amp'])
|
|
306
|
+
elif item_id == 'g_val':
|
|
307
|
+
return gamevalue(item_data['type'], item_data['target'])
|
|
308
|
+
elif item_id == 'vec':
|
|
309
|
+
return vector(item_data['x'], item_data['y'], item_data['z'])
|
|
310
|
+
elif item_id == 'pn_el':
|
|
311
|
+
description = _some_or(item_data.get('description'), '')
|
|
312
|
+
note = _some_or(item_data.get('note'), '')
|
|
313
|
+
param_type = ParameterType(PARAMETER_TYPE_LOOKUP.index(item_data['type']))
|
|
314
|
+
if item_data['optional']:
|
|
315
|
+
param = parameter(item_data['name'], param_type, item_data['plural'], True, description, note, item_from_dict(item_data['default_value']))
|
|
316
|
+
else:
|
|
317
|
+
param = parameter(item_data['name'], param_type, item_data['plural'], False, description, note)
|
|
318
|
+
return param
|
|
319
|
+
elif item_id == 'bl_tag':
|
|
320
|
+
return
|
|
321
|
+
else:
|
|
322
|
+
raise PyreException(f'Unrecognized item id `{item_id}`')
|
dfpyre/pyre.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
A package for externally creating code templates for the DiamondFire Minecraft server.
|
|
3
3
|
|
|
4
4
|
By Amp
|
|
5
|
-
2/24/2024
|
|
6
5
|
"""
|
|
7
6
|
|
|
8
7
|
import base64
|
|
@@ -13,8 +12,10 @@ from difflib import get_close_matches
|
|
|
13
12
|
import datetime
|
|
14
13
|
from typing import Tuple, List, Dict
|
|
15
14
|
from enum import Enum
|
|
15
|
+
import socket
|
|
16
16
|
from mcitemlib.itemlib import Item as NbtItem
|
|
17
17
|
from dfpyre.items import *
|
|
18
|
+
from dfpyre.scriptgen import generate_script, GeneratorFlags
|
|
18
19
|
|
|
19
20
|
COL_WARN = '\x1b[33m'
|
|
20
21
|
COL_RESET = '\x1b[0m'
|
|
@@ -25,6 +26,7 @@ CODEBLOCK_DATA_PATH = os.path.join(os.path.dirname(__file__), 'data/data.json')
|
|
|
25
26
|
|
|
26
27
|
VARIABLE_TYPES = {'txt', 'comp', 'num', 'item', 'loc', 'var', 'snd', 'part', 'pot', 'g_val', 'vec', 'pn_el'}
|
|
27
28
|
TEMPLATE_STARTERS = {'event', 'entity_event', 'func', 'process'}
|
|
29
|
+
SINGLE_NAME_CODEBLOCKS = {'func', 'process', 'call_func', 'start_process', 'else'}
|
|
28
30
|
|
|
29
31
|
TARGETS = ['Selection', 'Default', 'Killer', 'Damager', 'Shooter', 'Victim', 'AllPlayers', 'Projectile', 'AllEntities', 'AllMobs', 'LastEntity']
|
|
30
32
|
TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
|
|
@@ -60,6 +62,15 @@ class CodeBlock:
|
|
|
60
62
|
self.args = args
|
|
61
63
|
self.target = target
|
|
62
64
|
self.data = data
|
|
65
|
+
|
|
66
|
+
def __repr__(self) -> str:
|
|
67
|
+
if self.name in SINGLE_NAME_CODEBLOCKS:
|
|
68
|
+
if self.name == 'else':
|
|
69
|
+
return 'CodeBlock(else)'
|
|
70
|
+
return f'CodeBlock({self.name}, {self.data["data"]})'
|
|
71
|
+
elif 'block' in self.data:
|
|
72
|
+
return f'CodeBlock({self.data["block"]}, {self.name})'
|
|
73
|
+
return f'CodeBlock(bracket, {self.data["type"]}, {self.data["direct"]})'
|
|
63
74
|
|
|
64
75
|
|
|
65
76
|
def _warn(message):
|
|
@@ -108,7 +119,7 @@ def _convert_data_types(args):
|
|
|
108
119
|
if type(value) in {int, float}:
|
|
109
120
|
converted_args.append(num(value))
|
|
110
121
|
elif type(value) is str:
|
|
111
|
-
if value[0] == VAR_SHORTHAND_CHAR and value[1] in VAR_SCOPES:
|
|
122
|
+
if len(value) > 2 and value[0] == VAR_SHORTHAND_CHAR and value[1] in VAR_SCOPES:
|
|
112
123
|
var_object = var(value[2:], VAR_SCOPES[value[1]])
|
|
113
124
|
converted_args.append(var_object)
|
|
114
125
|
else:
|
|
@@ -157,12 +168,12 @@ def _build_block(codeblock: CodeBlock, include_tags: bool):
|
|
|
157
168
|
"""
|
|
158
169
|
Builds a properly formatted block from a CodeBlock object.
|
|
159
170
|
"""
|
|
160
|
-
|
|
171
|
+
built_block = codeblock.data.copy()
|
|
161
172
|
codeblock_type = codeblock.data.get('block')
|
|
162
173
|
|
|
163
174
|
# add target if necessary ('Selection' is the default when 'target' is blank)
|
|
164
175
|
if codeblock_type in TARGET_CODEBLOCKS and codeblock.target != DEFAULT_TARGET:
|
|
165
|
-
|
|
176
|
+
built_block['target'] = codeblock.target.get_string_value()
|
|
166
177
|
|
|
167
178
|
# add items into args
|
|
168
179
|
final_args = [arg.format(slot) for slot, arg in enumerate(codeblock.args) if arg.type in VARIABLE_TYPES]
|
|
@@ -177,16 +188,20 @@ def _build_block(codeblock: CodeBlock, include_tags: bool):
|
|
|
177
188
|
final_args = final_args[:(27-len(tags))] # trim list if over 27 elements
|
|
178
189
|
final_args.extend(tags) # add tags to end
|
|
179
190
|
|
|
180
|
-
|
|
181
|
-
return
|
|
191
|
+
built_block['args'] = {'items': final_args}
|
|
192
|
+
return built_block
|
|
182
193
|
|
|
183
194
|
|
|
184
|
-
def _df_encode(
|
|
195
|
+
def _df_encode(json_string: str) -> str:
|
|
185
196
|
"""
|
|
186
197
|
Encodes a stringified json.
|
|
187
198
|
"""
|
|
188
|
-
|
|
189
|
-
return base64.b64encode(
|
|
199
|
+
encoded_string = gzip.compress(json_string.encode('utf-8'))
|
|
200
|
+
return base64.b64encode(encoded_string).decode('utf-8')
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _df_decode(encoded_string: str) -> str:
|
|
204
|
+
return gzip.decompress(base64.b64decode(encoded_string)).decode('utf-8')
|
|
190
205
|
|
|
191
206
|
|
|
192
207
|
def _get_template_item(template_code: str, name: str, author: str) -> NbtItem:
|
|
@@ -217,9 +232,50 @@ class DFTemplate:
|
|
|
217
232
|
"""
|
|
218
233
|
def __init__(self, name: str=None, author: str='pyre'):
|
|
219
234
|
self.codeblocks: List[CodeBlock] = []
|
|
220
|
-
self.
|
|
235
|
+
self.bracket_stack: list[str] = []
|
|
221
236
|
self.name = name
|
|
222
237
|
self.author = author
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def __repr__(self) -> str:
|
|
241
|
+
return f'DFTemplate(name: {self.name}, author: {self.author}, codeblocks: {len(self.codeblocks)})'
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@staticmethod
|
|
245
|
+
def from_code(template_code: str):
|
|
246
|
+
"""
|
|
247
|
+
Create a template object from an existing template code.
|
|
248
|
+
"""
|
|
249
|
+
template_dict = json.loads(_df_decode(template_code))
|
|
250
|
+
template = DFTemplate()
|
|
251
|
+
for block_dict in template_dict['blocks']:
|
|
252
|
+
if 'args' in block_dict:
|
|
253
|
+
args = []
|
|
254
|
+
for item_dict in block_dict['args']['items']:
|
|
255
|
+
parsed_item = item_from_dict(item_dict['item'])
|
|
256
|
+
if parsed_item is not None:
|
|
257
|
+
args.append(parsed_item)
|
|
258
|
+
target = Target(TARGETS.index(block_dict['target'])) if 'target' in block_dict else DEFAULT_TARGET
|
|
259
|
+
|
|
260
|
+
codeblock_name = 'bracket'
|
|
261
|
+
if 'block' in block_dict and block_dict['block'] in SINGLE_NAME_CODEBLOCKS:
|
|
262
|
+
codeblock_name = block_dict['block']
|
|
263
|
+
elif 'action' in block_dict:
|
|
264
|
+
codeblock_name = block_dict['action']
|
|
265
|
+
codeblock = CodeBlock(codeblock_name, args, target, block_dict)
|
|
266
|
+
template.codeblocks.append(codeblock)
|
|
267
|
+
|
|
268
|
+
return template
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
def receive_from_recode():
|
|
273
|
+
print('Waiting for item to be sent...')
|
|
274
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
275
|
+
s.connect(('localhost', 31372))
|
|
276
|
+
received = s.recv(8192)
|
|
277
|
+
print(received)
|
|
278
|
+
s.close()
|
|
223
279
|
|
|
224
280
|
|
|
225
281
|
def _set_template_name(self, first_block):
|
|
@@ -237,7 +293,7 @@ class DFTemplate:
|
|
|
237
293
|
"""
|
|
238
294
|
Build this template.
|
|
239
295
|
|
|
240
|
-
:param bool
|
|
296
|
+
:param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
|
|
241
297
|
:return: String containing encoded template data.
|
|
242
298
|
"""
|
|
243
299
|
template_dict_blocks = [_build_block(codeblock, include_tags) for codeblock in self.codeblocks]
|
|
@@ -248,21 +304,19 @@ class DFTemplate:
|
|
|
248
304
|
|
|
249
305
|
self._set_template_name(first_block)
|
|
250
306
|
|
|
251
|
-
print(f'{COL_SUCCESS}Template built successfully.{COL_RESET}')
|
|
252
|
-
|
|
253
307
|
json_string = json.dumps(template_dict, separators=(',', ':'))
|
|
254
308
|
return _df_encode(json_string)
|
|
255
309
|
|
|
256
310
|
|
|
257
|
-
def build_and_send(self, method: Literal['recode', 'codeclient'],
|
|
311
|
+
def build_and_send(self, method: Literal['recode', 'codeclient'], include_tags: bool=True) -> int:
|
|
258
312
|
"""
|
|
259
313
|
Builds this template and sends it to DiamondFire automatically.
|
|
260
314
|
|
|
261
|
-
:param bool
|
|
315
|
+
:param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
|
|
262
316
|
"""
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return
|
|
317
|
+
template_code = self.build(include_tags)
|
|
318
|
+
template_item = _get_template_item(template_code, self.name, self.author)
|
|
319
|
+
return template_item.send_to_minecraft(method, 'pyre')
|
|
266
320
|
|
|
267
321
|
|
|
268
322
|
def clear(self):
|
|
@@ -272,134 +326,156 @@ class DFTemplate:
|
|
|
272
326
|
self.__init__()
|
|
273
327
|
|
|
274
328
|
|
|
275
|
-
def
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
329
|
+
def _add_codeblock(self, codeblock: CodeBlock, index: int|None):
|
|
330
|
+
if index is None:
|
|
331
|
+
self.codeblocks.append(codeblock)
|
|
332
|
+
else:
|
|
333
|
+
self.codeblocks.insert(index, codeblock)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _openbracket(self, index: int|None, btype: Literal['norm', 'repeat']='norm'):
|
|
337
|
+
bracket = CodeBlock('bracket', data={'id': 'bracket', 'direct': 'open', 'type': btype})
|
|
338
|
+
self._add_codeblock(bracket, index+1)
|
|
339
|
+
self.bracket_stack.append(btype)
|
|
279
340
|
|
|
280
341
|
|
|
281
342
|
# command methods
|
|
282
|
-
def player_event(self, name: str):
|
|
343
|
+
def player_event(self, name: str, index: int|None=None):
|
|
283
344
|
cmd = CodeBlock(name, data={'id': 'block', 'block': 'event', 'action': name})
|
|
284
|
-
self.
|
|
345
|
+
self._add_codeblock(cmd, index)
|
|
285
346
|
|
|
286
347
|
|
|
287
|
-
def entity_event(self, name: str):
|
|
348
|
+
def entity_event(self, name: str, index: int|None=None):
|
|
288
349
|
cmd = CodeBlock(name, data={'id': 'block', 'block': 'entity_event', 'action': name})
|
|
289
|
-
self.
|
|
350
|
+
self._add_codeblock(cmd, index)
|
|
290
351
|
|
|
291
352
|
|
|
292
|
-
def function(self, name: str, *args):
|
|
353
|
+
def function(self, name: str, *args, index: int|None=None):
|
|
293
354
|
args = _convert_data_types(args)
|
|
294
|
-
cmd = CodeBlock('
|
|
295
|
-
self.
|
|
355
|
+
cmd = CodeBlock('func', args, data={'id': 'block', 'block': 'func', 'data': name})
|
|
356
|
+
self._add_codeblock(cmd, index)
|
|
296
357
|
|
|
297
358
|
|
|
298
|
-
def process(self, name: str):
|
|
299
|
-
|
|
300
|
-
|
|
359
|
+
def process(self, name: str, *args, index: int|None=None):
|
|
360
|
+
args = _convert_data_types(args)
|
|
361
|
+
cmd = CodeBlock('process', args, data={'id': 'block', 'block': 'process', 'data': name})
|
|
362
|
+
self._add_codeblock(cmd, index)
|
|
301
363
|
|
|
302
364
|
|
|
303
|
-
def call_function(self, name: str, *args):
|
|
365
|
+
def call_function(self, name: str, *args, index: int|None=None):
|
|
304
366
|
args = _convert_data_types(args)
|
|
305
367
|
cmd = CodeBlock('call_func', args, data={'id': 'block', 'block': 'call_func', 'data': name})
|
|
306
|
-
self.
|
|
307
|
-
|
|
368
|
+
self._add_codeblock(cmd, index)
|
|
308
369
|
|
|
309
|
-
def start_process(self, name: str):
|
|
370
|
+
def start_process(self, name: str, index: int|None=None):
|
|
310
371
|
cmd = CodeBlock('start_process', data={'id': 'block', 'block': 'start_process', 'data': name})
|
|
311
|
-
self.
|
|
372
|
+
self._add_codeblock(cmd, index)
|
|
312
373
|
|
|
313
374
|
|
|
314
|
-
def player_action(self, name: str, *args, target: Target=DEFAULT_TARGET):
|
|
375
|
+
def player_action(self, name: str, *args, target: Target=DEFAULT_TARGET, index: int|None=None):
|
|
315
376
|
args = _convert_data_types(args)
|
|
316
377
|
cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'player_action', 'action': name})
|
|
317
|
-
self.
|
|
378
|
+
self._add_codeblock(cmd, index)
|
|
318
379
|
|
|
319
380
|
|
|
320
|
-
def game_action(self, name: str, *args):
|
|
381
|
+
def game_action(self, name: str, *args, index: int|None=None):
|
|
321
382
|
args = _convert_data_types(args)
|
|
322
383
|
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'game_action', 'action': name})
|
|
323
|
-
self.
|
|
384
|
+
self._add_codeblock(cmd, index)
|
|
324
385
|
|
|
325
386
|
|
|
326
|
-
def entity_action(self, name: str, *args, target: Target=DEFAULT_TARGET):
|
|
387
|
+
def entity_action(self, name: str, *args, target: Target=DEFAULT_TARGET, index: int|None=None):
|
|
327
388
|
args = _convert_data_types(args)
|
|
328
389
|
cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'entity_action', 'action': name})
|
|
329
|
-
self.
|
|
390
|
+
self._add_codeblock(cmd, index)
|
|
330
391
|
|
|
331
392
|
|
|
332
|
-
def if_player(self, name: str, *args, target: Target=DEFAULT_TARGET, inverted: bool=False):
|
|
393
|
+
def if_player(self, name: str, *args, target: Target=DEFAULT_TARGET, inverted: bool=False, index: int|None=None):
|
|
333
394
|
args = _convert_data_types(args)
|
|
334
395
|
data = {'id': 'block', 'block': 'if_player', 'action': name}
|
|
335
396
|
_add_inverted(data, inverted)
|
|
336
397
|
cmd = CodeBlock(name, args, target=target, data=data)
|
|
337
|
-
self.
|
|
338
|
-
self._openbracket()
|
|
398
|
+
self._add_codeblock(cmd, index)
|
|
399
|
+
self._openbracket(index)
|
|
339
400
|
|
|
340
401
|
|
|
341
|
-
def if_variable(self, name: str, *args, inverted: bool=False):
|
|
402
|
+
def if_variable(self, name: str, *args, inverted: bool=False, index: int|None=None):
|
|
342
403
|
args = _convert_data_types(args)
|
|
343
404
|
data = {'id': 'block', 'block': 'if_var', 'action': name}
|
|
344
405
|
_add_inverted(data, inverted)
|
|
345
406
|
cmd = CodeBlock(name, args, data=data)
|
|
346
|
-
self.
|
|
347
|
-
self._openbracket()
|
|
407
|
+
self._add_codeblock(cmd, index)
|
|
408
|
+
self._openbracket(index)
|
|
348
409
|
|
|
349
410
|
|
|
350
|
-
def if_game(self, name: str, *args, inverted: bool=False):
|
|
411
|
+
def if_game(self, name: str, *args, inverted: bool=False, index: int|None=None):
|
|
351
412
|
args = _convert_data_types(args)
|
|
352
413
|
data = {'id': 'block', 'block': 'if_game', 'action': name}
|
|
353
414
|
_add_inverted(data, inverted)
|
|
354
415
|
cmd = CodeBlock(name, args, data=data)
|
|
355
|
-
self.
|
|
356
|
-
self._openbracket()
|
|
416
|
+
self._add_codeblock(cmd, index)
|
|
417
|
+
self._openbracket(index)
|
|
357
418
|
|
|
358
419
|
|
|
359
|
-
def if_entity(self, name: str, *args, target: Target=DEFAULT_TARGET, inverted: bool=False):
|
|
420
|
+
def if_entity(self, name: str, *args, target: Target=DEFAULT_TARGET, inverted: bool=False, index: int|None=None):
|
|
360
421
|
args = _convert_data_types(args)
|
|
361
422
|
data = {'id': 'block', 'block': 'if_entity', 'action': name}
|
|
362
423
|
_add_inverted(data, inverted)
|
|
363
424
|
cmd = CodeBlock(name, args, target=target, data=data)
|
|
364
|
-
self.
|
|
365
|
-
self._openbracket()
|
|
425
|
+
self._add_codeblock(cmd, index)
|
|
426
|
+
self._openbracket(index)
|
|
366
427
|
|
|
367
428
|
|
|
368
|
-
def else_(self):
|
|
429
|
+
def else_(self, index: int|None=None):
|
|
369
430
|
cmd = CodeBlock('else', data={'id': 'block', 'block': 'else'})
|
|
370
|
-
self.
|
|
371
|
-
self._openbracket()
|
|
431
|
+
self._add_codeblock(cmd, index)
|
|
432
|
+
self._openbracket(index)
|
|
372
433
|
|
|
373
434
|
|
|
374
|
-
def repeat(self, name: str, *args, sub_action: str=None):
|
|
435
|
+
def repeat(self, name: str, *args, sub_action: str=None, index: int|None=None):
|
|
375
436
|
args = _convert_data_types(args)
|
|
376
437
|
data = {'id': 'block', 'block': 'repeat', 'action': name}
|
|
377
438
|
if sub_action is not None:
|
|
378
439
|
data['subAction'] = sub_action
|
|
379
440
|
cmd = CodeBlock(name, args, data=data)
|
|
380
|
-
self.
|
|
381
|
-
self._openbracket('repeat')
|
|
441
|
+
self._add_codeblock(cmd, index)
|
|
442
|
+
self._openbracket(index, 'repeat')
|
|
382
443
|
|
|
383
444
|
|
|
384
|
-
def bracket(self, *args):
|
|
445
|
+
def bracket(self, *args, index: int|None=None):
|
|
385
446
|
args = _convert_data_types(args)
|
|
386
|
-
cmd = CodeBlock('
|
|
387
|
-
self.
|
|
447
|
+
cmd = CodeBlock('bracket', data={'id': 'bracket', 'direct': 'close', 'type': self.bracket_stack.pop()})
|
|
448
|
+
self._add_codeblock(cmd, index)
|
|
388
449
|
|
|
389
450
|
|
|
390
|
-
def control(self, name: str, *args):
|
|
451
|
+
def control(self, name: str, *args, index: int|None=None):
|
|
391
452
|
args = _convert_data_types(args)
|
|
392
453
|
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'control', 'action': name})
|
|
393
|
-
self.
|
|
454
|
+
self._add_codeblock(cmd, index)
|
|
394
455
|
|
|
395
456
|
|
|
396
|
-
def select_object(self, name: str, *args):
|
|
457
|
+
def select_object(self, name: str, *args, index: int|None=None):
|
|
397
458
|
args = _convert_data_types(args)
|
|
398
459
|
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'select_obj', 'action': name})
|
|
399
|
-
self.
|
|
460
|
+
self._add_codeblock(cmd, index)
|
|
400
461
|
|
|
401
462
|
|
|
402
|
-
def set_variable(self, name: str, *args):
|
|
463
|
+
def set_variable(self, name: str, *args, index: int|None=None):
|
|
403
464
|
args = _convert_data_types(args)
|
|
404
465
|
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'set_var', 'action': name})
|
|
405
|
-
self.
|
|
466
|
+
self._add_codeblock(cmd, index)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def generate_script(self, output_path: str, indent_size: int=4, literal_shorthand: bool=True, var_shorthand: bool=False):
|
|
470
|
+
"""
|
|
471
|
+
Generate an equivalent python script for this template.
|
|
472
|
+
|
|
473
|
+
:param str output_path: The file path to write the script to.
|
|
474
|
+
:param int indent_size: The multiple of spaces to add when indenting lines.
|
|
475
|
+
:param bool literal_shorthand: If True, `text` and `num` items will be written as strings and ints respectively.
|
|
476
|
+
:param bool var_shorthand: If True, all variables will be written using variable shorthand.
|
|
477
|
+
"""
|
|
478
|
+
flags = GeneratorFlags(indent_size, literal_shorthand, var_shorthand)
|
|
479
|
+
with open(output_path, 'w') as f:
|
|
480
|
+
f.write(generate_script(self, flags))
|
|
481
|
+
|
dfpyre/scriptgen.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import re
|
|
3
|
+
from dfpyre.items import *
|
|
4
|
+
|
|
5
|
+
SCRIPT_START = '''from dfpyre import *
|
|
6
|
+
t = DFTemplate()
|
|
7
|
+
'''
|
|
8
|
+
|
|
9
|
+
TEMPLATE_METHOD_LOOKUP = {
|
|
10
|
+
'event': 'player_event',
|
|
11
|
+
'entity_event': 'entity_event',
|
|
12
|
+
'func': 'function',
|
|
13
|
+
'process': 'process',
|
|
14
|
+
'call_func': 'call_function',
|
|
15
|
+
'start_process': 'start_process',
|
|
16
|
+
'player_action': 'player_action',
|
|
17
|
+
'game_action': 'game_action',
|
|
18
|
+
'entity_action': 'entity_action',
|
|
19
|
+
'if_player': 'if_player',
|
|
20
|
+
'if_var': 'if_variable',
|
|
21
|
+
'if_game': 'if_game',
|
|
22
|
+
'if_entity': 'if_entity',
|
|
23
|
+
'else': 'else_',
|
|
24
|
+
'repeat': 'repeat',
|
|
25
|
+
'control': 'control',
|
|
26
|
+
'select_obj': 'select_object',
|
|
27
|
+
'set_var': 'set_variable'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
|
|
31
|
+
SINGLE_NAME_CODEBLOCKS = {'func', 'process', 'call_func', 'start_process'}
|
|
32
|
+
VAR_SCOPES = {'unsaved': 'g', 'saved': 's', 'local': 'l', 'line': 'i'}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclasses.dataclass
|
|
36
|
+
class GeneratorFlags:
|
|
37
|
+
indent_size: int
|
|
38
|
+
literal_shorthand: bool
|
|
39
|
+
var_shorthand: bool
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def argument_item_to_string(flags: GeneratorFlags, arg_item: object) -> str:
|
|
43
|
+
class_name = arg_item.__class__.__name__
|
|
44
|
+
if isinstance(arg_item, item):
|
|
45
|
+
return f'{class_name}.from_nbt("""{arg_item.get_nbt()}""")'
|
|
46
|
+
|
|
47
|
+
if isinstance(arg_item, string):
|
|
48
|
+
value = arg_item.value.replace('\n', '\\n')
|
|
49
|
+
return f'{class_name}("{value}")'
|
|
50
|
+
|
|
51
|
+
if isinstance(arg_item, text):
|
|
52
|
+
value = arg_item.value.replace('\n', '\\n')
|
|
53
|
+
if flags.literal_shorthand:
|
|
54
|
+
return f'"{value}"'
|
|
55
|
+
return f'{class_name}("{value}")'
|
|
56
|
+
|
|
57
|
+
if isinstance(arg_item, num):
|
|
58
|
+
if not re.match(NUMBER_REGEX, str(arg_item.value)):
|
|
59
|
+
return f'{class_name}("{arg_item.value}")'
|
|
60
|
+
if flags.literal_shorthand:
|
|
61
|
+
return str(arg_item.value)
|
|
62
|
+
return f'{class_name}({arg_item.value})'
|
|
63
|
+
|
|
64
|
+
if isinstance(arg_item, loc):
|
|
65
|
+
loc_components = [arg_item.x, arg_item.y, arg_item.z]
|
|
66
|
+
if arg_item.pitch != 0:
|
|
67
|
+
loc_components.append(arg_item.pitch)
|
|
68
|
+
if arg_item.yaw != 0:
|
|
69
|
+
loc_components.append(arg_item.yaw)
|
|
70
|
+
return f'{class_name}({", ".join(str(c) for c in loc_components)})'
|
|
71
|
+
|
|
72
|
+
if isinstance(arg_item, var):
|
|
73
|
+
if flags.var_shorthand:
|
|
74
|
+
return f'"${VAR_SCOPES[arg_item.scope]}{arg_item.name}"'
|
|
75
|
+
if arg_item.scope == 'unsaved':
|
|
76
|
+
return f'{class_name}("{arg_item.name}")'
|
|
77
|
+
return f'{class_name}("{arg_item.name}", "{arg_item.scope}")'
|
|
78
|
+
|
|
79
|
+
if isinstance(arg_item, sound):
|
|
80
|
+
return f'{class_name}("{arg_item.name}", {arg_item.pitch}, {arg_item.vol})'
|
|
81
|
+
|
|
82
|
+
if isinstance(arg_item, particle):
|
|
83
|
+
return f'{class_name}({arg_item.particle_data})'
|
|
84
|
+
|
|
85
|
+
if isinstance(arg_item, potion):
|
|
86
|
+
return f'{class_name}("{arg_item.name}", {arg_item.dur}, {arg_item.amp})'
|
|
87
|
+
|
|
88
|
+
if isinstance(arg_item, gamevalue):
|
|
89
|
+
return f'{class_name}("{arg_item.name}", "{arg_item.target}")'
|
|
90
|
+
|
|
91
|
+
if isinstance(arg_item, parameter):
|
|
92
|
+
param_type_class_name = arg_item.param_type.__class__.__name__
|
|
93
|
+
param_args = [f'"{arg_item.name}"', f'{param_type_class_name}.{arg_item.param_type.name}']
|
|
94
|
+
if arg_item.plural:
|
|
95
|
+
param_args.append('plural=True')
|
|
96
|
+
if arg_item.optional:
|
|
97
|
+
param_args.append('optional=True')
|
|
98
|
+
if arg_item.default_value is not None:
|
|
99
|
+
param_args.append(f'default_value={argument_item_to_string(arg_item.default_value)}')
|
|
100
|
+
if arg_item.description:
|
|
101
|
+
param_args.append(f'description="{arg_item.description}"')
|
|
102
|
+
if arg_item.note:
|
|
103
|
+
param_args.append(f'note="{arg_item.note}"')
|
|
104
|
+
return f'{class_name}({", ".join(param_args)})'
|
|
105
|
+
|
|
106
|
+
if isinstance(arg_item, vector):
|
|
107
|
+
return f'{class_name}({arg_item.x}, {arg_item.y}, {arg_item.z})'
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def add_script_line(flags: GeneratorFlags, script_lines: list[str], indent_level: int, line: str, add_comma: bool=True):
|
|
111
|
+
added_line = ' '*flags.indent_size*indent_level + line
|
|
112
|
+
if add_comma and indent_level > 0:
|
|
113
|
+
added_line += ','
|
|
114
|
+
script_lines.append(added_line)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def generate_script(template, flags: GeneratorFlags) -> str:
|
|
118
|
+
indent_level = 0
|
|
119
|
+
script_lines = []
|
|
120
|
+
for codeblock in template.codeblocks:
|
|
121
|
+
if codeblock.name == 'bracket':
|
|
122
|
+
if codeblock.data['direct'] == 'open':
|
|
123
|
+
add_script_line(flags, script_lines, indent_level, 't.bracket(', False)
|
|
124
|
+
indent_level += 1
|
|
125
|
+
elif codeblock.data['direct'] == 'close':
|
|
126
|
+
indent_level -= 1
|
|
127
|
+
add_script_line(flags, script_lines, indent_level, ')')
|
|
128
|
+
continue
|
|
129
|
+
if codeblock.name == 'else':
|
|
130
|
+
add_script_line(flags, script_lines, indent_level, 't.else_()')
|
|
131
|
+
continue
|
|
132
|
+
|
|
133
|
+
method_name = TEMPLATE_METHOD_LOOKUP[codeblock.data['block']]
|
|
134
|
+
method_args = [f'"{codeblock.name}"']
|
|
135
|
+
if codeblock.name in SINGLE_NAME_CODEBLOCKS:
|
|
136
|
+
method_args[0] = f'"{codeblock.data["data"]}"'
|
|
137
|
+
|
|
138
|
+
codeblock_args = [argument_item_to_string(flags, i) for i in codeblock.args]
|
|
139
|
+
if codeblock_args:
|
|
140
|
+
method_args.extend(codeblock_args)
|
|
141
|
+
if method_name in TARGET_CODEBLOCKS and codeblock.target.name != 'SELECTION':
|
|
142
|
+
method_args.append(f'target=Target.{codeblock.target.name}')
|
|
143
|
+
|
|
144
|
+
line = f't.{method_name}({", ".join(method_args)})'
|
|
145
|
+
add_script_line(flags, script_lines, indent_level, line)
|
|
146
|
+
return SCRIPT_START + '\n'.join(script_lines)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dfpyre
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: A package for external creation of code templates for the DiamondFire Minecraft server.
|
|
5
5
|
Home-page: https://github.com/Amp63/pyre
|
|
6
6
|
License: MIT
|
|
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Requires-Dist: mcitemlib (>=0.
|
|
15
|
+
Requires-Dist: mcitemlib (>=0.2.4,<0.3.0)
|
|
16
16
|
Project-URL: Repository, https://github.com/Amp63/pyre
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
|
|
@@ -70,6 +70,8 @@ pip install dfpyre
|
|
|
70
70
|
|
|
71
71
|
## Extras
|
|
72
72
|
|
|
73
|
+
- [Importing from Code](#importing-from-code)
|
|
74
|
+
- [Script Generation](#script-generation)
|
|
73
75
|
- [Method List](#method-list)
|
|
74
76
|
|
|
75
77
|
___
|
|
@@ -279,7 +281,7 @@ t.player_action('PlaySound', sound('Grass Place'))
|
|
|
279
281
|
Represents a diamondfire particle item:
|
|
280
282
|
|
|
281
283
|
```py
|
|
282
|
-
particle(
|
|
284
|
+
particle({'particle':'Cloud','cluster':{'amount':1,'horizontal':0.0,'vertical':0.0},'data':{'x':1.0,'y':0.0,'z':0.0,'motionVariation':100}})
|
|
283
285
|
```
|
|
284
286
|
|
|
285
287
|
Example:
|
|
@@ -289,7 +291,8 @@ Example:
|
|
|
289
291
|
from dfpyre import *
|
|
290
292
|
t = DFTemplate()
|
|
291
293
|
t.player_event('Join')
|
|
292
|
-
|
|
294
|
+
part = particle({'particle':'Cloud','cluster':{'amount':1,'horizontal':0.0,'vertical':0.0},'data':{'x':1.0,'y':0.0,'z':0.0,'motionVariation':100}})
|
|
295
|
+
t.player_action('Particle', part, loc(5, 50, 5))
|
|
293
296
|
```
|
|
294
297
|
|
|
295
298
|
Currently, the particle object does not support colors.
|
|
@@ -441,6 +444,31 @@ t = DFTemplate()
|
|
|
441
444
|
t.player_event('Join')
|
|
442
445
|
t.call_function('doStuff')
|
|
443
446
|
```
|
|
447
|
+
|
|
448
|
+
### Importing from Code
|
|
449
|
+
|
|
450
|
+
You can import existing templates from their built code using the `from_code` method:
|
|
451
|
+
|
|
452
|
+
```py
|
|
453
|
+
from dfpyre import *
|
|
454
|
+
template_code = 'H4sIAGVyIGYC/3WOMQ7CMAxFz4LnDsw5AhITI6qQSaw2IrGrxkJCVe5eh3boAJP9n/Kfs8AziX8VcPcFYgC3Zej26YDexGoZvUZhAxeJ3PI8WMtKSrnV+1q7P4op4Yfmx244qG7E4Uql4EA/jNv2Jc3qJU/2KqBiY4yZjI6UkpzAjkNJouDO1X7S1xUDaGUl2QAAAA=='
|
|
455
|
+
|
|
456
|
+
t = DFTemplate.from_code(template_code)
|
|
457
|
+
# add onto the template from here
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
### Script Generation
|
|
462
|
+
|
|
463
|
+
You can also generate an equivalent python script for a template from a template object:
|
|
464
|
+
|
|
465
|
+
```py
|
|
466
|
+
from dfpyre import *
|
|
467
|
+
template_code = 'H4sIAGVyIGYC/3WOMQ7CMAxFz4LnDsw5AhITI6qQSaw2IrGrxkJCVe5eh3boAJP9n/Kfs8AziX8VcPcFYgC3Zej26YDexGoZvUZhAxeJ3PI8WMtKSrnV+1q7P4op4Yfmx244qG7E4Uql4EA/jNv2Jc3qJU/2KqBiY4yZjI6UkpzAjkNJouDO1X7S1xUDaGUl2QAAAA=='
|
|
468
|
+
|
|
469
|
+
t = DFTemplate.from_code(template_code)
|
|
470
|
+
t.generate_script('my_template.py') # generated python script will be written to my_template.py
|
|
471
|
+
```
|
|
444
472
|
|
|
445
473
|
### Method List
|
|
446
474
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
dfpyre/__init__.py,sha256=apPsSxJ1Tztfl71MoORoSmDfX7LyKLYlLwOGeLQUitw,25
|
|
2
|
+
dfpyre/data/data.json,sha256=M4EHXKkh7Cx7y3BQ6c3csvmNmSqP2oE4txLI9MZcDDA,30347
|
|
3
|
+
dfpyre/items.py,sha256=t9KsvhPOEe36_E7CNdgxNmEKtOF6nMvNZURyYFiXJb4,9215
|
|
4
|
+
dfpyre/pyre.py,sha256=OHsdTP9kTzuLXakhqS2ncl5frw75akl3zQ9oQ45NqHs,17616
|
|
5
|
+
dfpyre/scriptgen.py,sha256=TG_qYp2GChkwCD0f9WVCJOORDDL4RueuJeRkddB4YJw,5568
|
|
6
|
+
dfpyre/style.py,sha256=mLW1CFvvi8_9fk8JaH10I5S4WI0YBdQIXHtI3G_4sR8,980
|
|
7
|
+
dfpyre-0.6.1.dist-info/LICENSE,sha256=_vuDskB0ja2c-Fgm7Gt8Q8cO9NsLNpZAVyvmZwX7E6o,1060
|
|
8
|
+
dfpyre-0.6.1.dist-info/METADATA,sha256=tvnWndGOuItw_G-dzsxRPGXkvPiTn7zLuADsHWGJ87w,11344
|
|
9
|
+
dfpyre-0.6.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
10
|
+
dfpyre-0.6.1.dist-info/RECORD,,
|
dfpyre-0.5.0.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
dfpyre/__init__.py,sha256=apPsSxJ1Tztfl71MoORoSmDfX7LyKLYlLwOGeLQUitw,25
|
|
2
|
-
dfpyre/data/data.json,sha256=M4EHXKkh7Cx7y3BQ6c3csvmNmSqP2oE4txLI9MZcDDA,30347
|
|
3
|
-
dfpyre/items.py,sha256=L2e9b9BZQrI7AIBw46puENReDQRlWgHnw7T9NBG1Vcs,7688
|
|
4
|
-
dfpyre/pyre.py,sha256=5UryjtwsNRxl6mGknsKm8iM2DP49-B-tqwkr9LdoRJ8,13805
|
|
5
|
-
dfpyre/style.py,sha256=mLW1CFvvi8_9fk8JaH10I5S4WI0YBdQIXHtI3G_4sR8,980
|
|
6
|
-
dfpyre-0.5.0.dist-info/LICENSE,sha256=atkly29RNUY2evLoPyurzCJeQnhP-VCAD-JZEbq3mno,1060
|
|
7
|
-
dfpyre-0.5.0.dist-info/METADATA,sha256=RpuPps-V4FruPh1p0L7wroEDwZfC5lP6ITgl14334Cs,10142
|
|
8
|
-
dfpyre-0.5.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
9
|
-
dfpyre-0.5.0.dist-info/RECORD,,
|
|
File without changes
|