dfpyre 0.7.1__py3-none-any.whl → 0.7.3__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/actiondump.py +77 -77
- dfpyre/items.py +372 -372
- dfpyre/pyre.py +457 -457
- dfpyre/scriptgen.py +152 -152
- dfpyre/style.py +21 -21
- dfpyre/util.py +28 -28
- {dfpyre-0.7.1.dist-info → dfpyre-0.7.3.dist-info}/LICENSE +21 -21
- {dfpyre-0.7.1.dist-info → dfpyre-0.7.3.dist-info}/METADATA +2 -2
- dfpyre-0.7.3.dist-info/RECORD +12 -0
- dfpyre-0.7.1.dist-info/RECORD +0 -12
- {dfpyre-0.7.1.dist-info → dfpyre-0.7.3.dist-info}/WHEEL +0 -0
dfpyre/pyre.py
CHANGED
|
@@ -1,458 +1,458 @@
|
|
|
1
|
-
"""
|
|
2
|
-
A package for externally creating code templates for the DiamondFire Minecraft server.
|
|
3
|
-
|
|
4
|
-
By Amp
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import json
|
|
8
|
-
from difflib import get_close_matches
|
|
9
|
-
import datetime
|
|
10
|
-
from typing import Tuple
|
|
11
|
-
from enum import Enum
|
|
12
|
-
import socket
|
|
13
|
-
from mcitemlib.itemlib import Item as NbtItem
|
|
14
|
-
from dfpyre.util import *
|
|
15
|
-
from dfpyre.items import *
|
|
16
|
-
from dfpyre.scriptgen import generate_script, GeneratorFlags
|
|
17
|
-
from dfpyre.actiondump import CODEBLOCK_DATA, get_default_tags
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
VARIABLE_TYPES = {'txt', 'comp', 'num', 'item', 'loc', 'var', 'snd', 'part', 'pot', 'g_val', 'vec', 'pn_el'}
|
|
21
|
-
TEMPLATE_STARTERS = {'event', 'entity_event', 'func', 'process'}
|
|
22
|
-
DYNAMIC_CODEBLOCKS = {'func', 'process', 'call_func', 'start_process'}
|
|
23
|
-
|
|
24
|
-
TARGETS = ['Selection', 'Default', 'Killer', 'Damager', 'Shooter', 'Victim', 'AllPlayers', 'Projectile', 'AllEntities', 'AllMobs', 'LastEntity']
|
|
25
|
-
TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
|
|
26
|
-
|
|
27
|
-
CODECLIENT_URL = 'ws://localhost:31375'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class Target(Enum):
|
|
31
|
-
SELECTION = 0
|
|
32
|
-
DEFAULT = 1
|
|
33
|
-
KILLER = 2
|
|
34
|
-
DAMAGER = 3
|
|
35
|
-
SHOOTER = 4
|
|
36
|
-
VICTIM = 5
|
|
37
|
-
ALL_PLAYERS = 6
|
|
38
|
-
PROJECTILE = 7
|
|
39
|
-
ALL_ENTITIES = 8
|
|
40
|
-
ALL_MOBS = 9
|
|
41
|
-
LAST_ENTITY = 10
|
|
42
|
-
|
|
43
|
-
def get_string_value(self):
|
|
44
|
-
return TARGETS[self.value]
|
|
45
|
-
|
|
46
|
-
DEFAULT_TARGET = Target.SELECTION
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class CodeBlock:
|
|
50
|
-
def __init__(self, name: str, args: Tuple=(), target: Target=DEFAULT_TARGET, data: dict={}, tags: dict[str, str]={}):
|
|
51
|
-
self.name = name
|
|
52
|
-
self.args = args
|
|
53
|
-
self.target = target
|
|
54
|
-
self.data = data
|
|
55
|
-
self.tags = tags
|
|
56
|
-
|
|
57
|
-
def __repr__(self) -> str:
|
|
58
|
-
if self.name in DYNAMIC_CODEBLOCKS:
|
|
59
|
-
if self.name == 'else':
|
|
60
|
-
return 'CodeBlock(else)'
|
|
61
|
-
return f'CodeBlock({self.name}, {self.data["data"]})'
|
|
62
|
-
if 'block' in self.data:
|
|
63
|
-
return f'CodeBlock({self.data["block"]}, {self.name})'
|
|
64
|
-
return f'CodeBlock(bracket, {self.data["type"]}, {self.data["direct"]})'
|
|
65
|
-
|
|
66
|
-
def build(self, include_tags: bool=True) -> dict:
|
|
67
|
-
"""
|
|
68
|
-
Builds a properly formatted block from a CodeBlock object.
|
|
69
|
-
"""
|
|
70
|
-
built_block = self.data.copy()
|
|
71
|
-
codeblock_type = self.data.get('block')
|
|
72
|
-
|
|
73
|
-
# add target if necessary ('Selection' is the default when 'target' is blank)
|
|
74
|
-
if codeblock_type in TARGET_CODEBLOCKS and self.target != DEFAULT_TARGET:
|
|
75
|
-
built_block['target'] = self.target.get_string_value()
|
|
76
|
-
|
|
77
|
-
# add items into args
|
|
78
|
-
final_args = [arg.format(slot) for slot, arg in enumerate(self.args) if arg.type in VARIABLE_TYPES]
|
|
79
|
-
|
|
80
|
-
# check for unrecognized name, add tags
|
|
81
|
-
if codeblock_type is not None
|
|
82
|
-
if self.name not in CODEBLOCK_DATA[codeblock_type]:
|
|
83
|
-
_warn_unrecognized_name(codeblock_type, self.name)
|
|
84
|
-
elif include_tags:
|
|
85
|
-
tags = _get_codeblock_tags(codeblock_type, self.name, self.tags)
|
|
86
|
-
if len(final_args) + len(tags) > 27:
|
|
87
|
-
final_args = final_args[:(27-len(tags))] # trim list if over 27 elements
|
|
88
|
-
final_args.extend(tags) # add tags to end
|
|
89
|
-
|
|
90
|
-
# if final_args:
|
|
91
|
-
built_block['args'] = {'items': final_args}
|
|
92
|
-
return built_block
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def _warn_unrecognized_name(codeblock_type: str, codeblock_name: str):
|
|
96
|
-
close = get_close_matches(codeblock_name, CODEBLOCK_DATA[codeblock_type].keys())
|
|
97
|
-
if close:
|
|
98
|
-
warn(f'Code block name "{codeblock_name}" not recognized. Did you mean "{close[0]}"?')
|
|
99
|
-
else:
|
|
100
|
-
warn(f'Code block name "{codeblock_name}" not recognized. Try spell checking or retyping without spaces.')
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def _add_inverted(data, inverted):
|
|
104
|
-
"""
|
|
105
|
-
If inverted is true, add 'inverted': 'NOT' to data.
|
|
106
|
-
"""
|
|
107
|
-
if inverted:
|
|
108
|
-
data['inverted'] = 'NOT'
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def _convert_args(args):
|
|
112
|
-
return tuple(map(convert_argument, args))
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def _check_applied_tags(tags: list[dict], applied_tags: dict[str, str], codeblock_name: str) -> dict[str, str]:
|
|
116
|
-
if len(applied_tags) > 0 and len(tags) == 0:
|
|
117
|
-
warn(f'Action "{codeblock_name}" does not have any tags, but still received {len(applied_tags)}.')
|
|
118
|
-
return {}
|
|
119
|
-
valid_tags = {}
|
|
120
|
-
tags_formatted = {t['name']: t for t in tags}
|
|
121
|
-
for name, option in applied_tags.items():
|
|
122
|
-
if name not in tags_formatted:
|
|
123
|
-
tag_names_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted.keys()))
|
|
124
|
-
warn(f'Tag "{name}" does not exist for action "{codeblock_name}". Available tags:\n{tag_names_joined}')
|
|
125
|
-
elif option not in tags_formatted[name]['options']:
|
|
126
|
-
options_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted[name]['options']))
|
|
127
|
-
warn(f'Tag "{name}" does not have the option "{option}". Available tag options:\n{options_joined}')
|
|
128
|
-
else:
|
|
129
|
-
valid_tags[name] = option
|
|
130
|
-
return valid_tags
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def _reformat_codeblock_tags(tags: list[dict], codeblock_type: str, codeblock_name: str, applied_tags: dict[str, str]):
|
|
134
|
-
"""
|
|
135
|
-
Turns tag objects into DiamondFire formatted tag items
|
|
136
|
-
"""
|
|
137
|
-
|
|
138
|
-
valid_applied_tags = _check_applied_tags(tags, applied_tags, codeblock_name)
|
|
139
|
-
reformatted_tags = []
|
|
140
|
-
for tag_item in tags:
|
|
141
|
-
tag_name = tag_item['name']
|
|
142
|
-
tag_option = tag_item['default']
|
|
143
|
-
if tag_name in valid_applied_tags:
|
|
144
|
-
tag_option = valid_applied_tags[tag_name]
|
|
145
|
-
|
|
146
|
-
new_tag_item = {
|
|
147
|
-
'item': {
|
|
148
|
-
'id': 'bl_tag',
|
|
149
|
-
'data': {
|
|
150
|
-
'option': tag_option,
|
|
151
|
-
'tag': tag_name,
|
|
152
|
-
'action': codeblock_name,
|
|
153
|
-
'block': codeblock_type
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
'slot': tag_item['slot']
|
|
157
|
-
}
|
|
158
|
-
reformatted_tags.append(new_tag_item)
|
|
159
|
-
return reformatted_tags
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def _get_codeblock_tags(codeblock_type: str, codeblock_name: str, applied_tags: dict[str, str]):
|
|
163
|
-
"""
|
|
164
|
-
Get tags for the specified codeblock type and name
|
|
165
|
-
"""
|
|
166
|
-
action_data = CODEBLOCK_DATA[codeblock_type][codeblock_name]
|
|
167
|
-
if 'deprecatedNote' in action_data:
|
|
168
|
-
warn(f'Action "{codeblock_name}" is deprecated: {action_data["deprecatedNote"]}')
|
|
169
|
-
tags = action_data['tags']
|
|
170
|
-
return _reformat_codeblock_tags(tags, codeblock_type, codeblock_name, applied_tags)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def _get_template_item(template_code: str, name: str, author: str) -> NbtItem:
|
|
174
|
-
now = datetime.datetime.now()
|
|
175
|
-
|
|
176
|
-
template_item = NbtItem('yellow_shulker_box')
|
|
177
|
-
template_item.set_name(f'&x&f&f&5&c&0&0>> &x&f&f&c&7&0&0{name}')
|
|
178
|
-
template_item.set_lore([
|
|
179
|
-
f'&8Author: {author}',
|
|
180
|
-
f'&8Date: {now.strftime("%Y-%m-%d")}',
|
|
181
|
-
'',
|
|
182
|
-
'&7This template was generated by &6pyre&7.',
|
|
183
|
-
'&7https://github.com/Amp63/pyre'
|
|
184
|
-
])
|
|
185
|
-
|
|
186
|
-
pbv_tag = {
|
|
187
|
-
'hypercube:codetemplatedata': f'{{"author":"{author}","name":"{name}","version": 1,"code":"{template_code}"}}',
|
|
188
|
-
'hypercube:pyre_creation_timestamp': now.timestamp()
|
|
189
|
-
}
|
|
190
|
-
template_item.
|
|
191
|
-
|
|
192
|
-
return template_item
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
class DFTemplate:
|
|
196
|
-
"""
|
|
197
|
-
Represents a DiamondFire code template.
|
|
198
|
-
"""
|
|
199
|
-
def __init__(self, name: str=None, author: str='pyre'):
|
|
200
|
-
self.codeblocks: list[CodeBlock] = []
|
|
201
|
-
self.bracket_stack: list[str] = []
|
|
202
|
-
self.name = name
|
|
203
|
-
self.author = author
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
def __repr__(self) -> str:
|
|
207
|
-
return f'DFTemplate(name: {self.name}, author: {self.author}, codeblocks: {len(self.codeblocks)})'
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
@staticmethod
|
|
211
|
-
def from_code(template_code: str):
|
|
212
|
-
"""
|
|
213
|
-
Create a template object from an existing template code.
|
|
214
|
-
"""
|
|
215
|
-
template_dict = json.loads(df_decode(template_code))
|
|
216
|
-
template = DFTemplate()
|
|
217
|
-
for block_dict in template_dict['blocks']:
|
|
218
|
-
block_tags = get_default_tags(block_dict.get('block'), block_dict.get('action'))
|
|
219
|
-
if 'args' in block_dict:
|
|
220
|
-
args = []
|
|
221
|
-
for item_dict in block_dict['args']['items']:
|
|
222
|
-
if item_dict['item'].get('id') == 'bl_tag':
|
|
223
|
-
tag_data = item_dict['item']['data']
|
|
224
|
-
block_tags[tag_data['tag']] = tag_data['option']
|
|
225
|
-
parsed_item = item_from_dict(item_dict['item'])
|
|
226
|
-
if parsed_item is not None:
|
|
227
|
-
args.append(parsed_item)
|
|
228
|
-
target = Target(TARGETS.index(block_dict['target'])) if 'target' in block_dict else DEFAULT_TARGET
|
|
229
|
-
|
|
230
|
-
codeblock_action = 'bracket'
|
|
231
|
-
if block_dict.get('block') == 'else':
|
|
232
|
-
codeblock_action = 'else'
|
|
233
|
-
elif block_dict.get('block') in DYNAMIC_CODEBLOCKS:
|
|
234
|
-
codeblock_action = 'dynamic'
|
|
235
|
-
elif 'action' in block_dict:
|
|
236
|
-
codeblock_action = block_dict['action']
|
|
237
|
-
|
|
238
|
-
if codeblock_action == 'bracket' or block_dict['block'] == 'else':
|
|
239
|
-
codeblock = CodeBlock(codeblock_action, data=block_dict)
|
|
240
|
-
else:
|
|
241
|
-
codeblock = CodeBlock(codeblock_action, args, target, block_dict, tags=block_tags)
|
|
242
|
-
template.codeblocks.append(codeblock)
|
|
243
|
-
|
|
244
|
-
return template
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
@staticmethod
|
|
248
|
-
def receive_from_recode():
|
|
249
|
-
print('Waiting for item to be sent...')
|
|
250
|
-
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
251
|
-
s.connect(('localhost', 31372))
|
|
252
|
-
received = s.recv(8192)
|
|
253
|
-
print(received)
|
|
254
|
-
s.close()
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
def _set_template_name(self, first_block):
|
|
258
|
-
if self.name is not None:
|
|
259
|
-
return
|
|
260
|
-
if 'data' in first_block:
|
|
261
|
-
self.name = first_block['data']
|
|
262
|
-
if not self.name:
|
|
263
|
-
self.name = 'Unnamed Template'
|
|
264
|
-
else:
|
|
265
|
-
self.name = first_block['block'] + '_' + first_block['action']
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
def build(self, include_tags: bool=True) -> str:
|
|
269
|
-
"""
|
|
270
|
-
Build this template.
|
|
271
|
-
|
|
272
|
-
:param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
|
|
273
|
-
:return: String containing encoded template data.
|
|
274
|
-
"""
|
|
275
|
-
template_dict_blocks = [codeblock.build(include_tags) for codeblock in self.codeblocks]
|
|
276
|
-
template_dict = {'blocks': template_dict_blocks}
|
|
277
|
-
first_block = template_dict_blocks[0]
|
|
278
|
-
if first_block['block'] not in TEMPLATE_STARTERS:
|
|
279
|
-
warn('Template does not start with an event, function, or process.')
|
|
280
|
-
|
|
281
|
-
self._set_template_name(first_block)
|
|
282
|
-
|
|
283
|
-
json_string = json.dumps(template_dict, separators=(',', ':'))
|
|
284
|
-
return df_encode(json_string)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
def build_and_send(self, method: Literal['recode', 'codeclient'], include_tags: bool=True) -> int:
|
|
288
|
-
"""
|
|
289
|
-
Builds this template and sends it to DiamondFire automatically.
|
|
290
|
-
|
|
291
|
-
:param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
|
|
292
|
-
"""
|
|
293
|
-
template_code = self.build(include_tags)
|
|
294
|
-
template_item = _get_template_item(template_code, self.name, self.author)
|
|
295
|
-
return template_item.send_to_minecraft(method, 'pyre')
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
def clear(self):
|
|
299
|
-
"""
|
|
300
|
-
Clears this template's data.
|
|
301
|
-
"""
|
|
302
|
-
self.__init__()
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
def _add_codeblock(self, codeblock: CodeBlock, index: int|None):
|
|
306
|
-
if index is None:
|
|
307
|
-
self.codeblocks.append(codeblock)
|
|
308
|
-
else:
|
|
309
|
-
self.codeblocks.insert(index, codeblock)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
def _openbracket(self, index: int|None, btype: Literal['norm', 'repeat']='norm'):
|
|
313
|
-
bracket = CodeBlock('bracket', data={'id': 'bracket', 'direct': 'open', 'type': btype})
|
|
314
|
-
self._add_codeblock(bracket, index)
|
|
315
|
-
self.bracket_stack.append(btype)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
# command methods
|
|
319
|
-
def player_event(self, name: str, index: int|None=None):
|
|
320
|
-
cmd = CodeBlock(name, data={'id': 'block', 'block': 'event', 'action': name})
|
|
321
|
-
self._add_codeblock(cmd, index)
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
def entity_event(self, name: str, index: int|None=None):
|
|
325
|
-
cmd = CodeBlock(name, data={'id': 'block', 'block': 'entity_event', 'action': name})
|
|
326
|
-
self._add_codeblock(cmd, index)
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
def function(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
330
|
-
args = _convert_args(args)
|
|
331
|
-
cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'func', 'data': name}, tags=tags)
|
|
332
|
-
self._add_codeblock(cmd, index)
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
def process(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
336
|
-
args = _convert_args(args)
|
|
337
|
-
cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'process', 'data': name}, tags=tags)
|
|
338
|
-
self._add_codeblock(cmd, index)
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
def call_function(self, name: str, *args, index: int|None=None):
|
|
342
|
-
args = _convert_args(args)
|
|
343
|
-
cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'call_func', 'data': name})
|
|
344
|
-
self._add_codeblock(cmd, index)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
def start_process(self, name: str, tags: dict[str, str]={}, index: int|None=None):
|
|
348
|
-
cmd = CodeBlock('dynamic', data={'id': 'block', 'block': 'start_process', 'data': name}, tags=tags)
|
|
349
|
-
self._add_codeblock(cmd, index)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
def player_action(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, index: int|None=None):
|
|
353
|
-
args = _convert_args(args)
|
|
354
|
-
cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'player_action', 'action': name}, tags=tags)
|
|
355
|
-
self._add_codeblock(cmd, index)
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
def game_action(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
359
|
-
args = _convert_args(args)
|
|
360
|
-
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'game_action', 'action': name}, tags=tags)
|
|
361
|
-
self._add_codeblock(cmd, index)
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
def entity_action(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, index: int|None=None):
|
|
365
|
-
args = _convert_args(args)
|
|
366
|
-
cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'entity_action', 'action': name}, tags=tags)
|
|
367
|
-
self._add_codeblock(cmd, index)
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
def if_player(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
|
|
371
|
-
args = _convert_args(args)
|
|
372
|
-
data = {'id': 'block', 'block': 'if_player', 'action': name}
|
|
373
|
-
_add_inverted(data, inverted)
|
|
374
|
-
cmd = CodeBlock(name, args, target=target, data=data, tags=tags)
|
|
375
|
-
self._add_codeblock(cmd, index)
|
|
376
|
-
self._openbracket(index)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
def if_variable(self, name: str, *args, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
|
|
380
|
-
args = _convert_args(args)
|
|
381
|
-
data = {'id': 'block', 'block': 'if_var', 'action': name}
|
|
382
|
-
_add_inverted(data, inverted)
|
|
383
|
-
cmd = CodeBlock(name, args, data=data, tags=tags)
|
|
384
|
-
self._add_codeblock(cmd, index)
|
|
385
|
-
self._openbracket(index)
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
def if_game(self, name: str, *args, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
|
|
389
|
-
args = _convert_args(args)
|
|
390
|
-
data = {'id': 'block', 'block': 'if_game', 'action': name}
|
|
391
|
-
_add_inverted(data, inverted)
|
|
392
|
-
cmd = CodeBlock(name, args, data=data, tags=tags)
|
|
393
|
-
self._add_codeblock(cmd, index)
|
|
394
|
-
self._openbracket(index)
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
def if_entity(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
|
|
398
|
-
args = _convert_args(args)
|
|
399
|
-
data = {'id': 'block', 'block': 'if_entity', 'action': name}
|
|
400
|
-
_add_inverted(data, inverted)
|
|
401
|
-
cmd = CodeBlock(name, args, target=target, data=data, tags=tags)
|
|
402
|
-
self._add_codeblock(cmd, index)
|
|
403
|
-
self._openbracket(index)
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
def else_(self, index: int|None=None):
|
|
407
|
-
cmd = CodeBlock('else', data={'id': 'block', 'block': 'else'})
|
|
408
|
-
self._add_codeblock(cmd, index)
|
|
409
|
-
self._openbracket(index)
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
def repeat(self, name: str, *args, tags: dict[str, str]={}, sub_action: str=None, index: int|None=None):
|
|
413
|
-
args = _convert_args(args)
|
|
414
|
-
data = {'id': 'block', 'block': 'repeat', 'action': name}
|
|
415
|
-
if sub_action is not None:
|
|
416
|
-
data['subAction'] = sub_action
|
|
417
|
-
cmd = CodeBlock(name, args, data=data, tags=tags)
|
|
418
|
-
self._add_codeblock(cmd, index)
|
|
419
|
-
self._openbracket(index, 'repeat')
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
def bracket(self, *args, index: int|None=None):
|
|
423
|
-
args = _convert_args(args)
|
|
424
|
-
cmd = CodeBlock('bracket', data={'id': 'bracket', 'direct': 'close', 'type': self.bracket_stack.pop()})
|
|
425
|
-
self._add_codeblock(cmd, index)
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
def control(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
429
|
-
args = _convert_args(args)
|
|
430
|
-
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'control', 'action': name}, tags=tags)
|
|
431
|
-
self._add_codeblock(cmd, index)
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
def select_object(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
435
|
-
args = _convert_args(args)
|
|
436
|
-
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'select_obj', 'action': name}, tags=tags)
|
|
437
|
-
self._add_codeblock(cmd, index)
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
def set_variable(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
441
|
-
args = _convert_args(args)
|
|
442
|
-
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'set_var', 'action': name}, tags=tags)
|
|
443
|
-
self._add_codeblock(cmd, index)
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
def generate_script(self, output_path: str, indent_size: int=4, literal_shorthand: bool=True, var_shorthand: bool=False):
|
|
447
|
-
"""
|
|
448
|
-
Generate an equivalent python script for this template.
|
|
449
|
-
|
|
450
|
-
:param str output_path: The file path to write the script to.
|
|
451
|
-
:param int indent_size: The multiple of spaces to add when indenting lines.
|
|
452
|
-
:param bool literal_shorthand: If True, `text` and `num` items will be written as strings and ints respectively.
|
|
453
|
-
:param bool var_shorthand: If True, all variables will be written using variable shorthand.
|
|
454
|
-
"""
|
|
455
|
-
flags = GeneratorFlags(indent_size, literal_shorthand, var_shorthand)
|
|
456
|
-
with open(output_path, 'w', encoding='utf-8') as f:
|
|
457
|
-
f.write(generate_script(self, flags))
|
|
1
|
+
"""
|
|
2
|
+
A package for externally creating code templates for the DiamondFire Minecraft server.
|
|
3
|
+
|
|
4
|
+
By Amp
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from difflib import get_close_matches
|
|
9
|
+
import datetime
|
|
10
|
+
from typing import Tuple
|
|
11
|
+
from enum import Enum
|
|
12
|
+
import socket
|
|
13
|
+
from mcitemlib.itemlib import Item as NbtItem
|
|
14
|
+
from dfpyre.util import *
|
|
15
|
+
from dfpyre.items import *
|
|
16
|
+
from dfpyre.scriptgen import generate_script, GeneratorFlags
|
|
17
|
+
from dfpyre.actiondump import CODEBLOCK_DATA, get_default_tags
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
VARIABLE_TYPES = {'txt', 'comp', 'num', 'item', 'loc', 'var', 'snd', 'part', 'pot', 'g_val', 'vec', 'pn_el'}
|
|
21
|
+
TEMPLATE_STARTERS = {'event', 'entity_event', 'func', 'process'}
|
|
22
|
+
DYNAMIC_CODEBLOCKS = {'func', 'process', 'call_func', 'start_process'}
|
|
23
|
+
|
|
24
|
+
TARGETS = ['Selection', 'Default', 'Killer', 'Damager', 'Shooter', 'Victim', 'AllPlayers', 'Projectile', 'AllEntities', 'AllMobs', 'LastEntity']
|
|
25
|
+
TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
|
|
26
|
+
|
|
27
|
+
CODECLIENT_URL = 'ws://localhost:31375'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Target(Enum):
|
|
31
|
+
SELECTION = 0
|
|
32
|
+
DEFAULT = 1
|
|
33
|
+
KILLER = 2
|
|
34
|
+
DAMAGER = 3
|
|
35
|
+
SHOOTER = 4
|
|
36
|
+
VICTIM = 5
|
|
37
|
+
ALL_PLAYERS = 6
|
|
38
|
+
PROJECTILE = 7
|
|
39
|
+
ALL_ENTITIES = 8
|
|
40
|
+
ALL_MOBS = 9
|
|
41
|
+
LAST_ENTITY = 10
|
|
42
|
+
|
|
43
|
+
def get_string_value(self):
|
|
44
|
+
return TARGETS[self.value]
|
|
45
|
+
|
|
46
|
+
DEFAULT_TARGET = Target.SELECTION
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class CodeBlock:
|
|
50
|
+
def __init__(self, name: str, args: Tuple=(), target: Target=DEFAULT_TARGET, data: dict={}, tags: dict[str, str]={}):
|
|
51
|
+
self.name = name
|
|
52
|
+
self.args = args
|
|
53
|
+
self.target = target
|
|
54
|
+
self.data = data
|
|
55
|
+
self.tags = tags
|
|
56
|
+
|
|
57
|
+
def __repr__(self) -> str:
|
|
58
|
+
if self.name in DYNAMIC_CODEBLOCKS:
|
|
59
|
+
if self.name == 'else':
|
|
60
|
+
return 'CodeBlock(else)'
|
|
61
|
+
return f'CodeBlock({self.name}, {self.data["data"]})'
|
|
62
|
+
if 'block' in self.data:
|
|
63
|
+
return f'CodeBlock({self.data["block"]}, {self.name})'
|
|
64
|
+
return f'CodeBlock(bracket, {self.data["type"]}, {self.data["direct"]})'
|
|
65
|
+
|
|
66
|
+
def build(self, include_tags: bool=True) -> dict:
|
|
67
|
+
"""
|
|
68
|
+
Builds a properly formatted block from a CodeBlock object.
|
|
69
|
+
"""
|
|
70
|
+
built_block = self.data.copy()
|
|
71
|
+
codeblock_type = self.data.get('block')
|
|
72
|
+
|
|
73
|
+
# add target if necessary ('Selection' is the default when 'target' is blank)
|
|
74
|
+
if codeblock_type in TARGET_CODEBLOCKS and self.target != DEFAULT_TARGET:
|
|
75
|
+
built_block['target'] = self.target.get_string_value()
|
|
76
|
+
|
|
77
|
+
# add items into args
|
|
78
|
+
final_args = [arg.format(slot) for slot, arg in enumerate(self.args) if arg.type in VARIABLE_TYPES]
|
|
79
|
+
|
|
80
|
+
# check for unrecognized name, add tags
|
|
81
|
+
if codeblock_type is not None and codeblock_type != 'else':
|
|
82
|
+
if self.name not in CODEBLOCK_DATA[codeblock_type]:
|
|
83
|
+
_warn_unrecognized_name(codeblock_type, self.name)
|
|
84
|
+
elif include_tags:
|
|
85
|
+
tags = _get_codeblock_tags(codeblock_type, self.name, self.tags)
|
|
86
|
+
if len(final_args) + len(tags) > 27:
|
|
87
|
+
final_args = final_args[:(27-len(tags))] # trim list if over 27 elements
|
|
88
|
+
final_args.extend(tags) # add tags to end
|
|
89
|
+
|
|
90
|
+
# if final_args:
|
|
91
|
+
built_block['args'] = {'items': final_args}
|
|
92
|
+
return built_block
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _warn_unrecognized_name(codeblock_type: str, codeblock_name: str):
|
|
96
|
+
close = get_close_matches(codeblock_name, CODEBLOCK_DATA[codeblock_type].keys())
|
|
97
|
+
if close:
|
|
98
|
+
warn(f'Code block name "{codeblock_name}" not recognized. Did you mean "{close[0]}"?')
|
|
99
|
+
else:
|
|
100
|
+
warn(f'Code block name "{codeblock_name}" not recognized. Try spell checking or retyping without spaces.')
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _add_inverted(data, inverted):
|
|
104
|
+
"""
|
|
105
|
+
If inverted is true, add 'inverted': 'NOT' to data.
|
|
106
|
+
"""
|
|
107
|
+
if inverted:
|
|
108
|
+
data['inverted'] = 'NOT'
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _convert_args(args):
|
|
112
|
+
return tuple(map(convert_argument, args))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _check_applied_tags(tags: list[dict], applied_tags: dict[str, str], codeblock_name: str) -> dict[str, str]:
|
|
116
|
+
if len(applied_tags) > 0 and len(tags) == 0:
|
|
117
|
+
warn(f'Action "{codeblock_name}" does not have any tags, but still received {len(applied_tags)}.')
|
|
118
|
+
return {}
|
|
119
|
+
valid_tags = {}
|
|
120
|
+
tags_formatted = {t['name']: t for t in tags}
|
|
121
|
+
for name, option in applied_tags.items():
|
|
122
|
+
if name not in tags_formatted:
|
|
123
|
+
tag_names_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted.keys()))
|
|
124
|
+
warn(f'Tag "{name}" does not exist for action "{codeblock_name}". Available tags:\n{tag_names_joined}')
|
|
125
|
+
elif option not in tags_formatted[name]['options']:
|
|
126
|
+
options_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted[name]['options']))
|
|
127
|
+
warn(f'Tag "{name}" does not have the option "{option}". Available tag options:\n{options_joined}')
|
|
128
|
+
else:
|
|
129
|
+
valid_tags[name] = option
|
|
130
|
+
return valid_tags
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _reformat_codeblock_tags(tags: list[dict], codeblock_type: str, codeblock_name: str, applied_tags: dict[str, str]):
|
|
134
|
+
"""
|
|
135
|
+
Turns tag objects into DiamondFire formatted tag items
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
valid_applied_tags = _check_applied_tags(tags, applied_tags, codeblock_name)
|
|
139
|
+
reformatted_tags = []
|
|
140
|
+
for tag_item in tags:
|
|
141
|
+
tag_name = tag_item['name']
|
|
142
|
+
tag_option = tag_item['default']
|
|
143
|
+
if tag_name in valid_applied_tags:
|
|
144
|
+
tag_option = valid_applied_tags[tag_name]
|
|
145
|
+
|
|
146
|
+
new_tag_item = {
|
|
147
|
+
'item': {
|
|
148
|
+
'id': 'bl_tag',
|
|
149
|
+
'data': {
|
|
150
|
+
'option': tag_option,
|
|
151
|
+
'tag': tag_name,
|
|
152
|
+
'action': codeblock_name,
|
|
153
|
+
'block': codeblock_type
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
'slot': tag_item['slot']
|
|
157
|
+
}
|
|
158
|
+
reformatted_tags.append(new_tag_item)
|
|
159
|
+
return reformatted_tags
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _get_codeblock_tags(codeblock_type: str, codeblock_name: str, applied_tags: dict[str, str]):
|
|
163
|
+
"""
|
|
164
|
+
Get tags for the specified codeblock type and name
|
|
165
|
+
"""
|
|
166
|
+
action_data = CODEBLOCK_DATA[codeblock_type][codeblock_name]
|
|
167
|
+
if 'deprecatedNote' in action_data:
|
|
168
|
+
warn(f'Action "{codeblock_name}" is deprecated: {action_data["deprecatedNote"]}')
|
|
169
|
+
tags = action_data['tags']
|
|
170
|
+
return _reformat_codeblock_tags(tags, codeblock_type, codeblock_name, applied_tags)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _get_template_item(template_code: str, name: str, author: str) -> NbtItem:
|
|
174
|
+
now = datetime.datetime.now()
|
|
175
|
+
|
|
176
|
+
template_item = NbtItem('yellow_shulker_box')
|
|
177
|
+
template_item.set_name(f'&x&f&f&5&c&0&0>> &x&f&f&c&7&0&0{name}')
|
|
178
|
+
template_item.set_lore([
|
|
179
|
+
f'&8Author: {author}',
|
|
180
|
+
f'&8Date: {now.strftime("%Y-%m-%d")}',
|
|
181
|
+
'',
|
|
182
|
+
'&7This template was generated by &6pyre&7.',
|
|
183
|
+
'&7https://github.com/Amp63/pyre'
|
|
184
|
+
])
|
|
185
|
+
|
|
186
|
+
pbv_tag = {
|
|
187
|
+
'hypercube:codetemplatedata': f'{{"author":"{author}","name":"{name}","version": 1,"code":"{template_code}"}}',
|
|
188
|
+
'hypercube:pyre_creation_timestamp': now.timestamp()
|
|
189
|
+
}
|
|
190
|
+
template_item.set_custom_data('PublicBukkitValues', pbv_tag, raw=True)
|
|
191
|
+
|
|
192
|
+
return template_item
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class DFTemplate:
|
|
196
|
+
"""
|
|
197
|
+
Represents a DiamondFire code template.
|
|
198
|
+
"""
|
|
199
|
+
def __init__(self, name: str=None, author: str='pyre'):
|
|
200
|
+
self.codeblocks: list[CodeBlock] = []
|
|
201
|
+
self.bracket_stack: list[str] = []
|
|
202
|
+
self.name = name
|
|
203
|
+
self.author = author
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def __repr__(self) -> str:
|
|
207
|
+
return f'DFTemplate(name: {self.name}, author: {self.author}, codeblocks: {len(self.codeblocks)})'
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@staticmethod
|
|
211
|
+
def from_code(template_code: str):
|
|
212
|
+
"""
|
|
213
|
+
Create a template object from an existing template code.
|
|
214
|
+
"""
|
|
215
|
+
template_dict = json.loads(df_decode(template_code))
|
|
216
|
+
template = DFTemplate()
|
|
217
|
+
for block_dict in template_dict['blocks']:
|
|
218
|
+
block_tags = get_default_tags(block_dict.get('block'), block_dict.get('action'))
|
|
219
|
+
if 'args' in block_dict:
|
|
220
|
+
args = []
|
|
221
|
+
for item_dict in block_dict['args']['items']:
|
|
222
|
+
if item_dict['item'].get('id') == 'bl_tag':
|
|
223
|
+
tag_data = item_dict['item']['data']
|
|
224
|
+
block_tags[tag_data['tag']] = tag_data['option']
|
|
225
|
+
parsed_item = item_from_dict(item_dict['item'])
|
|
226
|
+
if parsed_item is not None:
|
|
227
|
+
args.append(parsed_item)
|
|
228
|
+
target = Target(TARGETS.index(block_dict['target'])) if 'target' in block_dict else DEFAULT_TARGET
|
|
229
|
+
|
|
230
|
+
codeblock_action = 'bracket'
|
|
231
|
+
if block_dict.get('block') == 'else':
|
|
232
|
+
codeblock_action = 'else'
|
|
233
|
+
elif block_dict.get('block') in DYNAMIC_CODEBLOCKS:
|
|
234
|
+
codeblock_action = 'dynamic'
|
|
235
|
+
elif 'action' in block_dict:
|
|
236
|
+
codeblock_action = block_dict['action']
|
|
237
|
+
|
|
238
|
+
if codeblock_action == 'bracket' or block_dict['block'] == 'else':
|
|
239
|
+
codeblock = CodeBlock(codeblock_action, data=block_dict)
|
|
240
|
+
else:
|
|
241
|
+
codeblock = CodeBlock(codeblock_action, args, target, block_dict, tags=block_tags)
|
|
242
|
+
template.codeblocks.append(codeblock)
|
|
243
|
+
|
|
244
|
+
return template
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@staticmethod
|
|
248
|
+
def receive_from_recode():
|
|
249
|
+
print('Waiting for item to be sent...')
|
|
250
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
251
|
+
s.connect(('localhost', 31372))
|
|
252
|
+
received = s.recv(8192)
|
|
253
|
+
print(received)
|
|
254
|
+
s.close()
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _set_template_name(self, first_block):
|
|
258
|
+
if self.name is not None:
|
|
259
|
+
return
|
|
260
|
+
if 'data' in first_block:
|
|
261
|
+
self.name = first_block['data']
|
|
262
|
+
if not self.name:
|
|
263
|
+
self.name = 'Unnamed Template'
|
|
264
|
+
else:
|
|
265
|
+
self.name = first_block['block'] + '_' + first_block['action']
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def build(self, include_tags: bool=True) -> str:
|
|
269
|
+
"""
|
|
270
|
+
Build this template.
|
|
271
|
+
|
|
272
|
+
:param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
|
|
273
|
+
:return: String containing encoded template data.
|
|
274
|
+
"""
|
|
275
|
+
template_dict_blocks = [codeblock.build(include_tags) for codeblock in self.codeblocks]
|
|
276
|
+
template_dict = {'blocks': template_dict_blocks}
|
|
277
|
+
first_block = template_dict_blocks[0]
|
|
278
|
+
if first_block['block'] not in TEMPLATE_STARTERS:
|
|
279
|
+
warn('Template does not start with an event, function, or process.')
|
|
280
|
+
|
|
281
|
+
self._set_template_name(first_block)
|
|
282
|
+
|
|
283
|
+
json_string = json.dumps(template_dict, separators=(',', ':'))
|
|
284
|
+
return df_encode(json_string)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def build_and_send(self, method: Literal['recode', 'codeclient'], include_tags: bool=True) -> int:
|
|
288
|
+
"""
|
|
289
|
+
Builds this template and sends it to DiamondFire automatically.
|
|
290
|
+
|
|
291
|
+
:param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
|
|
292
|
+
"""
|
|
293
|
+
template_code = self.build(include_tags)
|
|
294
|
+
template_item = _get_template_item(template_code, self.name, self.author)
|
|
295
|
+
return template_item.send_to_minecraft(method, 'pyre')
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def clear(self):
|
|
299
|
+
"""
|
|
300
|
+
Clears this template's data.
|
|
301
|
+
"""
|
|
302
|
+
self.__init__()
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _add_codeblock(self, codeblock: CodeBlock, index: int|None):
|
|
306
|
+
if index is None:
|
|
307
|
+
self.codeblocks.append(codeblock)
|
|
308
|
+
else:
|
|
309
|
+
self.codeblocks.insert(index, codeblock)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _openbracket(self, index: int|None, btype: Literal['norm', 'repeat']='norm'):
|
|
313
|
+
bracket = CodeBlock('bracket', data={'id': 'bracket', 'direct': 'open', 'type': btype})
|
|
314
|
+
self._add_codeblock(bracket, index)
|
|
315
|
+
self.bracket_stack.append(btype)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
# command methods
|
|
319
|
+
def player_event(self, name: str, index: int|None=None):
|
|
320
|
+
cmd = CodeBlock(name, data={'id': 'block', 'block': 'event', 'action': name})
|
|
321
|
+
self._add_codeblock(cmd, index)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def entity_event(self, name: str, index: int|None=None):
|
|
325
|
+
cmd = CodeBlock(name, data={'id': 'block', 'block': 'entity_event', 'action': name})
|
|
326
|
+
self._add_codeblock(cmd, index)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def function(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
330
|
+
args = _convert_args(args)
|
|
331
|
+
cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'func', 'data': name}, tags=tags)
|
|
332
|
+
self._add_codeblock(cmd, index)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def process(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
336
|
+
args = _convert_args(args)
|
|
337
|
+
cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'process', 'data': name}, tags=tags)
|
|
338
|
+
self._add_codeblock(cmd, index)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def call_function(self, name: str, *args, index: int|None=None):
|
|
342
|
+
args = _convert_args(args)
|
|
343
|
+
cmd = CodeBlock('dynamic', args, data={'id': 'block', 'block': 'call_func', 'data': name})
|
|
344
|
+
self._add_codeblock(cmd, index)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def start_process(self, name: str, tags: dict[str, str]={}, index: int|None=None):
|
|
348
|
+
cmd = CodeBlock('dynamic', data={'id': 'block', 'block': 'start_process', 'data': name}, tags=tags)
|
|
349
|
+
self._add_codeblock(cmd, index)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def player_action(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, index: int|None=None):
|
|
353
|
+
args = _convert_args(args)
|
|
354
|
+
cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'player_action', 'action': name}, tags=tags)
|
|
355
|
+
self._add_codeblock(cmd, index)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def game_action(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
359
|
+
args = _convert_args(args)
|
|
360
|
+
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'game_action', 'action': name}, tags=tags)
|
|
361
|
+
self._add_codeblock(cmd, index)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def entity_action(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, index: int|None=None):
|
|
365
|
+
args = _convert_args(args)
|
|
366
|
+
cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'entity_action', 'action': name}, tags=tags)
|
|
367
|
+
self._add_codeblock(cmd, index)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def if_player(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
|
|
371
|
+
args = _convert_args(args)
|
|
372
|
+
data = {'id': 'block', 'block': 'if_player', 'action': name}
|
|
373
|
+
_add_inverted(data, inverted)
|
|
374
|
+
cmd = CodeBlock(name, args, target=target, data=data, tags=tags)
|
|
375
|
+
self._add_codeblock(cmd, index)
|
|
376
|
+
self._openbracket(index)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def if_variable(self, name: str, *args, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
|
|
380
|
+
args = _convert_args(args)
|
|
381
|
+
data = {'id': 'block', 'block': 'if_var', 'action': name}
|
|
382
|
+
_add_inverted(data, inverted)
|
|
383
|
+
cmd = CodeBlock(name, args, data=data, tags=tags)
|
|
384
|
+
self._add_codeblock(cmd, index)
|
|
385
|
+
self._openbracket(index)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def if_game(self, name: str, *args, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
|
|
389
|
+
args = _convert_args(args)
|
|
390
|
+
data = {'id': 'block', 'block': 'if_game', 'action': name}
|
|
391
|
+
_add_inverted(data, inverted)
|
|
392
|
+
cmd = CodeBlock(name, args, data=data, tags=tags)
|
|
393
|
+
self._add_codeblock(cmd, index)
|
|
394
|
+
self._openbracket(index)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def if_entity(self, name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, inverted: bool=False, index: int|None=None):
|
|
398
|
+
args = _convert_args(args)
|
|
399
|
+
data = {'id': 'block', 'block': 'if_entity', 'action': name}
|
|
400
|
+
_add_inverted(data, inverted)
|
|
401
|
+
cmd = CodeBlock(name, args, target=target, data=data, tags=tags)
|
|
402
|
+
self._add_codeblock(cmd, index)
|
|
403
|
+
self._openbracket(index)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def else_(self, index: int|None=None):
|
|
407
|
+
cmd = CodeBlock('else', data={'id': 'block', 'block': 'else'})
|
|
408
|
+
self._add_codeblock(cmd, index)
|
|
409
|
+
self._openbracket(index)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def repeat(self, name: str, *args, tags: dict[str, str]={}, sub_action: str=None, index: int|None=None):
|
|
413
|
+
args = _convert_args(args)
|
|
414
|
+
data = {'id': 'block', 'block': 'repeat', 'action': name}
|
|
415
|
+
if sub_action is not None:
|
|
416
|
+
data['subAction'] = sub_action
|
|
417
|
+
cmd = CodeBlock(name, args, data=data, tags=tags)
|
|
418
|
+
self._add_codeblock(cmd, index)
|
|
419
|
+
self._openbracket(index, 'repeat')
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def bracket(self, *args, index: int|None=None):
|
|
423
|
+
args = _convert_args(args)
|
|
424
|
+
cmd = CodeBlock('bracket', data={'id': 'bracket', 'direct': 'close', 'type': self.bracket_stack.pop()})
|
|
425
|
+
self._add_codeblock(cmd, index)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def control(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
429
|
+
args = _convert_args(args)
|
|
430
|
+
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'control', 'action': name}, tags=tags)
|
|
431
|
+
self._add_codeblock(cmd, index)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def select_object(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
435
|
+
args = _convert_args(args)
|
|
436
|
+
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'select_obj', 'action': name}, tags=tags)
|
|
437
|
+
self._add_codeblock(cmd, index)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def set_variable(self, name: str, *args, tags: dict[str, str]={}, index: int|None=None):
|
|
441
|
+
args = _convert_args(args)
|
|
442
|
+
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'set_var', 'action': name}, tags=tags)
|
|
443
|
+
self._add_codeblock(cmd, index)
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def generate_script(self, output_path: str, indent_size: int=4, literal_shorthand: bool=True, var_shorthand: bool=False):
|
|
447
|
+
"""
|
|
448
|
+
Generate an equivalent python script for this template.
|
|
449
|
+
|
|
450
|
+
:param str output_path: The file path to write the script to.
|
|
451
|
+
:param int indent_size: The multiple of spaces to add when indenting lines.
|
|
452
|
+
:param bool literal_shorthand: If True, `text` and `num` items will be written as strings and ints respectively.
|
|
453
|
+
:param bool var_shorthand: If True, all variables will be written using variable shorthand.
|
|
454
|
+
"""
|
|
455
|
+
flags = GeneratorFlags(indent_size, literal_shorthand, var_shorthand)
|
|
456
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
|
457
|
+
f.write(generate_script(self, flags))
|
|
458
458
|
|