dfpyre 0.8.20__py3-none-any.whl → 0.9.0__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/action_literals.py +13 -13
- dfpyre/actiondump.py +5 -0
- dfpyre/codeblock.py +202 -0
- dfpyre/data/actiondump_min.json +1 -1
- dfpyre/pyre.py +25 -193
- dfpyre/scriptgen.py +19 -9
- dfpyre/slice.py +200 -0
- {dfpyre-0.8.20.dist-info → dfpyre-0.9.0.dist-info}/METADATA +2 -2
- dfpyre-0.9.0.dist-info/RECORD +15 -0
- dfpyre-0.8.20.dist-info/RECORD +0 -13
- {dfpyre-0.8.20.dist-info → dfpyre-0.9.0.dist-info}/LICENSE +0 -0
- {dfpyre-0.8.20.dist-info → dfpyre-0.9.0.dist-info}/WHEEL +0 -0
dfpyre/pyre.py
CHANGED
|
@@ -5,16 +5,16 @@ By Amp
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
-
from difflib import get_close_matches
|
|
9
8
|
import datetime
|
|
10
9
|
import platform
|
|
11
|
-
from enum import Enum
|
|
12
10
|
from amulet_nbt import CompoundTag, StringTag, DoubleTag
|
|
13
11
|
from dfpyre.util import df_encode, df_decode, flatten
|
|
14
12
|
from dfpyre.items import *
|
|
15
|
-
from dfpyre.
|
|
13
|
+
from dfpyre.codeblock import CodeBlock, Target, TARGETS, DEFAULT_TARGET, CONDITIONAL_CODEBLOCKS, TEMPLATE_STARTERS
|
|
14
|
+
from dfpyre.actiondump import get_default_tags
|
|
16
15
|
from dfpyre.action_literals import *
|
|
17
16
|
from dfpyre.scriptgen import generate_script, GeneratorFlags
|
|
17
|
+
from dfpyre.slice import slice_template
|
|
18
18
|
|
|
19
19
|
__all__ = [
|
|
20
20
|
'Target', 'CodeBlock', 'DFTemplate',
|
|
@@ -23,196 +23,13 @@ __all__ = [
|
|
|
23
23
|
] + VAR_ITEM_TYPES
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
VARIABLE_TYPES = {'txt', 'comp', 'num', 'item', 'loc', 'var', 'snd', 'part', 'pot', 'g_val', 'vec', 'pn_el', 'bl_tag'}
|
|
27
|
-
TEMPLATE_STARTERS = {'event', 'entity_event', 'func', 'process'}
|
|
28
26
|
DYNAMIC_CODEBLOCKS = {'func', 'process', 'call_func', 'start_process'}
|
|
29
27
|
|
|
30
|
-
TARGETS = ['Selection', 'Default', 'Killer', 'Damager', 'Shooter', 'Victim', 'AllPlayers', 'Projectile', 'AllEntities', 'AllMobs', 'LastEntity']
|
|
31
|
-
TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
|
|
32
|
-
|
|
33
28
|
CODECLIENT_URL = 'ws://localhost:31375'
|
|
34
29
|
|
|
35
30
|
DATE_FORMAT_STR = "%b %#d, %Y" if platform.system() == "Windows" else "%b %-d, %Y"
|
|
36
31
|
|
|
37
32
|
|
|
38
|
-
class Target(Enum):
|
|
39
|
-
SELECTION = 0
|
|
40
|
-
DEFAULT = 1
|
|
41
|
-
KILLER = 2
|
|
42
|
-
DAMAGER = 3
|
|
43
|
-
SHOOTER = 4
|
|
44
|
-
VICTIM = 5
|
|
45
|
-
ALL_PLAYERS = 6
|
|
46
|
-
PROJECTILE = 7
|
|
47
|
-
ALL_ENTITIES = 8
|
|
48
|
-
ALL_MOBS = 9
|
|
49
|
-
LAST_ENTITY = 10
|
|
50
|
-
|
|
51
|
-
def get_string_value(self):
|
|
52
|
-
return TARGETS[self.value]
|
|
53
|
-
|
|
54
|
-
DEFAULT_TARGET = Target.SELECTION
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def _convert_args(args):
|
|
58
|
-
return tuple(map(convert_literals, args))
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class CodeBlock:
|
|
62
|
-
def __init__(self, codeblock_type: str, action_name: str, args: tuple=(), target: Target=DEFAULT_TARGET, data: dict={}, tags: dict[str, str]={}):
|
|
63
|
-
self.type = codeblock_type
|
|
64
|
-
self.action_name = action_name
|
|
65
|
-
self.args = args
|
|
66
|
-
self.target = target
|
|
67
|
-
self.data = data
|
|
68
|
-
self.tags = tags
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@classmethod
|
|
72
|
-
def new_action(cls, codeblock_type: str, action_name: str, args: tuple, tags: dict[str, str], target: Target=DEFAULT_TARGET) -> "CodeBlock":
|
|
73
|
-
args = _convert_args(args)
|
|
74
|
-
return cls(codeblock_type, action_name, args=args, data={'id': 'block', 'block': codeblock_type, 'action': action_name}, tags=tags, target=target)
|
|
75
|
-
|
|
76
|
-
@classmethod
|
|
77
|
-
def new_data(cls, codeblock_type: str, data_value: str, args: tuple, tags: dict[str, str]) -> "CodeBlock":
|
|
78
|
-
args = _convert_args(args)
|
|
79
|
-
return cls(codeblock_type, 'dynamic', args=args, data={'id': 'block', 'block': codeblock_type, 'data': data_value}, tags=tags)
|
|
80
|
-
|
|
81
|
-
@classmethod
|
|
82
|
-
def new_conditional(cls, codeblock_type: str, action_name: str, args: tuple, tags: dict[str, str], inverted: bool, target: Target=DEFAULT_TARGET) -> "CodeBlock":
|
|
83
|
-
args = _convert_args(args)
|
|
84
|
-
data = {'id': 'block', 'block': codeblock_type, 'action': action_name}
|
|
85
|
-
if inverted:
|
|
86
|
-
data['attribute'] = 'NOT'
|
|
87
|
-
return cls(codeblock_type, action_name, args=args, data=data, tags=tags, target=target)
|
|
88
|
-
|
|
89
|
-
@classmethod
|
|
90
|
-
def new_repeat(cls, action_name: str, args: tuple, tags: dict[str, str], sub_action: str|None, inverted: bool) -> "CodeBlock":
|
|
91
|
-
args = _convert_args(args)
|
|
92
|
-
data = {'id': 'block', 'block': 'repeat', 'action': action_name}
|
|
93
|
-
if inverted:
|
|
94
|
-
data['attribute'] = 'NOT'
|
|
95
|
-
if sub_action is not None:
|
|
96
|
-
data['subAction'] = sub_action
|
|
97
|
-
return cls('repeat', action_name, args=args, data=data, tags=tags)
|
|
98
|
-
|
|
99
|
-
@classmethod
|
|
100
|
-
def new_else(cls) -> "CodeBlock":
|
|
101
|
-
return cls('else', 'else', data={'id': 'block', 'block': 'else'})
|
|
102
|
-
|
|
103
|
-
@classmethod
|
|
104
|
-
def new_bracket(cls, direction: Literal['open', 'close'], bracket_type: Literal['norm', 'repeat']) -> "CodeBlock":
|
|
105
|
-
return cls('bracket', 'bracket', data={'id': 'bracket', 'direct': direction, 'type': bracket_type})
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def __repr__(self) -> str:
|
|
109
|
-
if self.action_name == 'dynamic':
|
|
110
|
-
return f'CodeBlock({self.data["block"]}, {self.data["data"]})'
|
|
111
|
-
if self.action_name == 'else':
|
|
112
|
-
return 'CodeBlock(else)'
|
|
113
|
-
if 'block' in self.data:
|
|
114
|
-
return f'CodeBlock({self.data["block"]}, {self.action_name})'
|
|
115
|
-
return f'CodeBlock(bracket, {self.data["type"]}, {self.data["direct"]})'
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def build(self) -> dict:
|
|
119
|
-
"""
|
|
120
|
-
Builds a properly formatted block from a CodeBlock object.
|
|
121
|
-
"""
|
|
122
|
-
built_block = self.data.copy()
|
|
123
|
-
|
|
124
|
-
# add target if necessary ('Selection' is the default when 'target' is blank)
|
|
125
|
-
if self.type in TARGET_CODEBLOCKS and self.target != DEFAULT_TARGET:
|
|
126
|
-
built_block['target'] = self.target.get_string_value()
|
|
127
|
-
|
|
128
|
-
# add items into args
|
|
129
|
-
final_args = [arg.format(slot) for slot, arg in enumerate(self.args) if arg.type in VARIABLE_TYPES]
|
|
130
|
-
already_applied_tags: dict[str, dict] = {a['item']['data']['tag']: a for a in final_args if a['item']['id'] == 'bl_tag'}
|
|
131
|
-
|
|
132
|
-
# check for unrecognized name, add tags
|
|
133
|
-
if self.type not in {'bracket', 'else'}:
|
|
134
|
-
if self.action_name not in CODEBLOCK_DATA[self.type]:
|
|
135
|
-
_warn_unrecognized_name(self.type, self.action_name)
|
|
136
|
-
|
|
137
|
-
tags = _get_codeblock_tags(self.type, self.action_name, self.tags)
|
|
138
|
-
for i, tag_data in enumerate(tags):
|
|
139
|
-
already_applied_tag_data = already_applied_tags.get(tag_data['item']['data']['tag'])
|
|
140
|
-
if already_applied_tag_data is not None:
|
|
141
|
-
tags[i] = already_applied_tag_data
|
|
142
|
-
|
|
143
|
-
if len(final_args) + len(tags) > 27:
|
|
144
|
-
final_args = final_args[:(27-len(tags))] # trim list if over 27 elements
|
|
145
|
-
final_args.extend(tags) # add tags to end
|
|
146
|
-
|
|
147
|
-
built_block['args'] = {'items': final_args}
|
|
148
|
-
return built_block
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def _warn_unrecognized_name(codeblock_type: str, codeblock_name: str):
|
|
152
|
-
close = get_close_matches(codeblock_name, CODEBLOCK_DATA[codeblock_type].keys())
|
|
153
|
-
if close:
|
|
154
|
-
warn(f'Code block name "{codeblock_name}" not recognized. Did you mean "{close[0]}"?')
|
|
155
|
-
else:
|
|
156
|
-
warn(f'Code block name "{codeblock_name}" not recognized. Try spell checking or retyping without spaces.')
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def _check_applied_tags(tags: list[dict], applied_tags: dict[str, str], codeblock_name: str) -> dict[str, str]:
|
|
160
|
-
if len(applied_tags) > 0 and len(tags) == 0:
|
|
161
|
-
warn(f'Action "{codeblock_name}" does not have any tags, but still received {len(applied_tags)}.')
|
|
162
|
-
return {}
|
|
163
|
-
|
|
164
|
-
valid_tags = {}
|
|
165
|
-
tags_formatted = {t['name']: t for t in tags}
|
|
166
|
-
for name, option in applied_tags.items():
|
|
167
|
-
if name not in tags_formatted:
|
|
168
|
-
tag_names_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted.keys()))
|
|
169
|
-
warn(f'Tag "{name}" does not exist for action "{codeblock_name}". Available tags:\n{tag_names_joined}')
|
|
170
|
-
elif option not in tags_formatted[name]['options']:
|
|
171
|
-
options_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted[name]['options']))
|
|
172
|
-
warn(f'Tag "{name}" does not have the option "{option}". Available tag options:\n{options_joined}')
|
|
173
|
-
else:
|
|
174
|
-
valid_tags[name] = option
|
|
175
|
-
return valid_tags
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
def _reformat_codeblock_tags(tags: list[dict], codeblock_type: str, codeblock_action: str, applied_tags: dict[str, str]) -> list[dict]:
|
|
179
|
-
"""
|
|
180
|
-
Turns tag objects into DiamondFire formatted tag items.
|
|
181
|
-
"""
|
|
182
|
-
|
|
183
|
-
def format_tag(option: str, name: str):
|
|
184
|
-
return {
|
|
185
|
-
'item': {
|
|
186
|
-
'id': 'bl_tag',
|
|
187
|
-
'data': {'option': option, 'tag': name, 'action': codeblock_action, 'block': codeblock_type}
|
|
188
|
-
},
|
|
189
|
-
'slot': tag_item['slot']
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
valid_applied_tags = _check_applied_tags(tags, applied_tags, codeblock_action)
|
|
193
|
-
reformatted_tags = []
|
|
194
|
-
for tag_item in tags:
|
|
195
|
-
tag_name = tag_item['name']
|
|
196
|
-
tag_option = tag_item['default']
|
|
197
|
-
if tag_name in valid_applied_tags:
|
|
198
|
-
tag_option = valid_applied_tags[tag_name]
|
|
199
|
-
|
|
200
|
-
new_tag_item = format_tag(tag_option, tag_name)
|
|
201
|
-
reformatted_tags.append(new_tag_item)
|
|
202
|
-
return reformatted_tags
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
def _get_codeblock_tags(codeblock_type: str, codeblock_name: str, applied_tags: dict[str, str]) -> list[dict]:
|
|
206
|
-
"""
|
|
207
|
-
Get tags for the specified codeblock type and name.
|
|
208
|
-
"""
|
|
209
|
-
action_data = CODEBLOCK_DATA[codeblock_type][codeblock_name]
|
|
210
|
-
if 'deprecatedNote' in action_data:
|
|
211
|
-
warn(f'Action "{codeblock_name}" is deprecated: {action_data["deprecatedNote"]}')
|
|
212
|
-
tags = action_data['tags']
|
|
213
|
-
return _reformat_codeblock_tags(tags, codeblock_type, codeblock_name, applied_tags)
|
|
214
|
-
|
|
215
|
-
|
|
216
33
|
class DFTemplate:
|
|
217
34
|
"""
|
|
218
35
|
Represents a DiamondFire code template.
|
|
@@ -256,8 +73,8 @@ class DFTemplate:
|
|
|
256
73
|
parsed_item = item_from_dict(item_dict, preserve_item_slots)
|
|
257
74
|
if parsed_item is not None:
|
|
258
75
|
block_args.append(parsed_item)
|
|
259
|
-
block_target = Target(TARGETS.index(block_dict['target'])) if 'target' in block_dict else DEFAULT_TARGET
|
|
260
76
|
|
|
77
|
+
codeblock_target = Target(TARGETS.index(block_dict['target'])) if 'target' in block_dict else DEFAULT_TARGET
|
|
261
78
|
codeblock_type = block_dict.get('block')
|
|
262
79
|
|
|
263
80
|
if codeblock_type is None:
|
|
@@ -267,7 +84,15 @@ class DFTemplate:
|
|
|
267
84
|
elif codeblock_type in DYNAMIC_CODEBLOCKS:
|
|
268
85
|
codeblock = CodeBlock.new_data(codeblock_type, block_dict['data'], block_args, block_tags)
|
|
269
86
|
elif 'action' in block_dict:
|
|
270
|
-
|
|
87
|
+
codeblock_action = block_dict['action']
|
|
88
|
+
inverted = block_dict.get('attribute') == 'NOT'
|
|
89
|
+
sub_action = block_dict.get('subAction')
|
|
90
|
+
if sub_action is not None:
|
|
91
|
+
codeblock = CodeBlock.new_subaction_block(codeblock_type, codeblock_action, block_args, block_tags, sub_action, inverted)
|
|
92
|
+
elif codeblock_type in CONDITIONAL_CODEBLOCKS:
|
|
93
|
+
codeblock = CodeBlock.new_conditional(codeblock_type, codeblock_action, block_args, block_tags, inverted, codeblock_target)
|
|
94
|
+
else:
|
|
95
|
+
codeblock = CodeBlock.new_action(codeblock_type, codeblock_action, block_args, block_tags, codeblock_target)
|
|
271
96
|
codeblocks.append(codeblock)
|
|
272
97
|
|
|
273
98
|
return DFTemplate(codeblocks, author)
|
|
@@ -362,7 +187,12 @@ class DFTemplate:
|
|
|
362
187
|
:param bool build_and_send: If True, `.build_and_send()` will be added to the end of the generated template.
|
|
363
188
|
"""
|
|
364
189
|
flags = GeneratorFlags(indent_size, literal_shorthand, var_shorthand, preserve_slots, assign_variable, include_import, build_and_send)
|
|
365
|
-
return generate_script(self, flags)
|
|
190
|
+
return generate_script(self.codeblocks, flags)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def slice(self, target_length: int) -> list['DFTemplate']:
|
|
194
|
+
sliced_templates = slice_template(self.codeblocks, target_length, self._get_template_name())
|
|
195
|
+
return [DFTemplate(t, self.author) for t in sliced_templates]
|
|
366
196
|
|
|
367
197
|
|
|
368
198
|
def _assemble_template(starting_block: CodeBlock, codeblocks: list[CodeBlock], author: str|None) -> DFTemplate:
|
|
@@ -570,7 +400,7 @@ def else_(codeblocks: list[CodeBlock]=[]) -> list[CodeBlock]:
|
|
|
570
400
|
]
|
|
571
401
|
|
|
572
402
|
|
|
573
|
-
def repeat(action_name: REPEAT_ACTION, *args, tags: dict[str, str]={}, sub_action:
|
|
403
|
+
def repeat(action_name: REPEAT_ACTION, *args, tags: dict[str, str]={}, sub_action: SUBACTION|None=None, inverted: bool=False, codeblocks: list[CodeBlock]=[]) -> CodeBlock:
|
|
574
404
|
"""
|
|
575
405
|
Represents a Repeat codeblock.
|
|
576
406
|
|
|
@@ -582,7 +412,7 @@ def repeat(action_name: REPEAT_ACTION, *args, tags: dict[str, str]={}, sub_actio
|
|
|
582
412
|
:param list[CodeBlock] codeblocks: The list of codeblocks inside the brackets.
|
|
583
413
|
"""
|
|
584
414
|
return [
|
|
585
|
-
CodeBlock.
|
|
415
|
+
CodeBlock.new_subaction_block('repeat', action_name, args, tags, sub_action, inverted),
|
|
586
416
|
CodeBlock.new_bracket('open', 'repeat')
|
|
587
417
|
] + list(codeblocks) + [
|
|
588
418
|
CodeBlock.new_bracket('close', 'repeat')
|
|
@@ -600,15 +430,17 @@ def control(action_name: CONTROL_ACTION, *args, tags: dict[str, str]={}) -> Code
|
|
|
600
430
|
return CodeBlock.new_action('control', action_name, args, tags)
|
|
601
431
|
|
|
602
432
|
|
|
603
|
-
def select_object(action_name: SELECT_OBJ_ACTION, *args, tags: dict[str, str]={}) -> CodeBlock:
|
|
433
|
+
def select_object(action_name: SELECT_OBJ_ACTION, *args, tags: dict[str, str]={}, sub_action: SUBACTION|None=None, inverted: bool=False) -> CodeBlock:
|
|
604
434
|
"""
|
|
605
435
|
Represents a Select Object codeblock.
|
|
606
436
|
|
|
607
437
|
:param str action_name: The name of the action.
|
|
608
438
|
:param tuple args: The argument items to include.
|
|
609
439
|
:param dict[str, str] tags: The tags to include.
|
|
440
|
+
:param str|None sub_action: The sub-action to use. (Not relevant for all actions)
|
|
441
|
+
:param bool inverted: Whether the sub-action condition should be inverted.
|
|
610
442
|
"""
|
|
611
|
-
return CodeBlock.
|
|
443
|
+
return CodeBlock.new_subaction_block('select_obj', action_name, args, tags, sub_action, inverted)
|
|
612
444
|
|
|
613
445
|
|
|
614
446
|
def set_variable(action_name: SET_VAR_ACTION, *args, tags: dict[str, str]={}) -> CodeBlock:
|
dfpyre/scriptgen.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import dataclasses
|
|
2
|
-
import re
|
|
3
2
|
from dfpyre.util import is_number
|
|
4
3
|
from dfpyre.items import *
|
|
5
4
|
from dfpyre.actiondump import get_default_tags
|
|
5
|
+
from dfpyre.codeblock import CodeBlock
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
IMPORT_STATEMENT = 'from dfpyre import *'
|
|
@@ -30,6 +30,7 @@ TEMPLATE_FUNCTION_LOOKUP = {
|
|
|
30
30
|
|
|
31
31
|
TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
|
|
32
32
|
CONTAINER_CODEBLOCKS = {'event', 'entity_event', 'func', 'process', 'if_player', 'if_entity', 'if_game', 'if_var', 'else', 'repeat'}
|
|
33
|
+
CONDITIONAL_CODEBLOCKS = {'if_player', 'if_var', 'if_game', 'if_entity'}
|
|
33
34
|
VAR_SCOPES = {'unsaved': 'g', 'saved': 's', 'local': 'l', 'line': 'i'}
|
|
34
35
|
|
|
35
36
|
|
|
@@ -154,7 +155,7 @@ def add_script_line(flags: GeneratorFlags, script_lines: list[str], indent_level
|
|
|
154
155
|
script_lines.append(added_line)
|
|
155
156
|
|
|
156
157
|
|
|
157
|
-
def generate_script(
|
|
158
|
+
def generate_script(codeblocks: list[CodeBlock], flags: GeneratorFlags) -> str:
|
|
158
159
|
indent_level = 0
|
|
159
160
|
script_lines = []
|
|
160
161
|
variable_assigned = False
|
|
@@ -167,7 +168,7 @@ def generate_script(template, flags: GeneratorFlags) -> str:
|
|
|
167
168
|
script_lines[-1] = script_lines[-1][:-1]
|
|
168
169
|
|
|
169
170
|
def get_var_assignment_snippet() -> str:
|
|
170
|
-
first_block_data =
|
|
171
|
+
first_block_data = codeblocks[0].data
|
|
171
172
|
if 'data' in first_block_data:
|
|
172
173
|
name = first_block_data['data']
|
|
173
174
|
var_name = name if name else 'unnamed_template'
|
|
@@ -176,7 +177,7 @@ def generate_script(template, flags: GeneratorFlags) -> str:
|
|
|
176
177
|
return f'{string_to_python_name(var_name)} = '
|
|
177
178
|
|
|
178
179
|
|
|
179
|
-
for codeblock in
|
|
180
|
+
for codeblock in codeblocks:
|
|
180
181
|
# Handle closing brackets
|
|
181
182
|
if codeblock.type == 'bracket':
|
|
182
183
|
if codeblock.data['direct'] == 'close':
|
|
@@ -208,17 +209,26 @@ def generate_script(template, flags: GeneratorFlags) -> str:
|
|
|
208
209
|
if function_name in TARGET_CODEBLOCKS and codeblock.target.name != 'SELECTION':
|
|
209
210
|
function_args.append(f'target=Target.{codeblock.target.name}')
|
|
210
211
|
|
|
212
|
+
# Add sub-action for repeat and select object
|
|
213
|
+
sub_action = codeblock.data.get('subAction')
|
|
214
|
+
if sub_action is not None:
|
|
215
|
+
function_args.append(f"sub_action='{sub_action}'")
|
|
216
|
+
|
|
211
217
|
# Add tags
|
|
212
218
|
if codeblock.tags:
|
|
213
|
-
default_tags =
|
|
219
|
+
default_tags = codeblock.tags
|
|
220
|
+
if sub_action is not None:
|
|
221
|
+
for conditional_block_type in CONDITIONAL_CODEBLOCKS:
|
|
222
|
+
default_tags = get_default_tags(conditional_block_type, sub_action)
|
|
223
|
+
if default_tags:
|
|
224
|
+
break
|
|
225
|
+
else:
|
|
226
|
+
default_tags = get_default_tags(codeblock.data.get('block'), codeblock.action_name)
|
|
227
|
+
|
|
214
228
|
written_tags = {t: o for t, o in codeblock.tags.items() if default_tags[t] != o}
|
|
215
229
|
if written_tags:
|
|
216
230
|
function_args.append(f'tags={str(written_tags)}')
|
|
217
231
|
|
|
218
|
-
# Add sub-action for repeat
|
|
219
|
-
if codeblock.data.get('subAction'):
|
|
220
|
-
function_args.append(f"sub_action='{codeblock.data["subAction"]}'")
|
|
221
|
-
|
|
222
232
|
# Add inversion for NOT
|
|
223
233
|
if codeblock.data.get('attribute') == 'NOT':
|
|
224
234
|
function_args.append('inverted=True')
|
dfpyre/slice.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
from typing import Iterator
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from collections import deque
|
|
4
|
+
from dfpyre.codeblock import CodeBlock, CONDITIONAL_CODEBLOCKS, TEMPLATE_STARTERS
|
|
5
|
+
from dfpyre.items import Variable, Parameter, ParameterType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
BRACKET_CODEBLOCKS = CONDITIONAL_CODEBLOCKS
|
|
9
|
+
BRACKET_CODEBLOCKS.add('repeat')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class TemplateChunk:
|
|
14
|
+
length: int
|
|
15
|
+
start_index: int
|
|
16
|
+
end_index: int
|
|
17
|
+
contents1: list['TemplateChunk'] | None # Inside brackets
|
|
18
|
+
contents2: list['TemplateChunk'] | None # Inside `else` brackets
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_referenced_line_vars(codeblocks: list[CodeBlock]) -> set[str]:
|
|
22
|
+
referenced_vars = set()
|
|
23
|
+
for codeblock in codeblocks:
|
|
24
|
+
for argument in codeblock.args:
|
|
25
|
+
if isinstance(argument, Variable) and argument.scope == 'line':
|
|
26
|
+
referenced_vars.add(argument.name)
|
|
27
|
+
return referenced_vars
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def find_closing_bracket(codeblocks: list[CodeBlock], start_index: int) -> int:
|
|
31
|
+
"""
|
|
32
|
+
Returns the index of the cooresponding closing bracket assuming
|
|
33
|
+
that `start_index` is the index of the first codeblock inside the brackets.
|
|
34
|
+
"""
|
|
35
|
+
nested_level = 1
|
|
36
|
+
for i in range(start_index, len(codeblocks)):
|
|
37
|
+
codeblock = codeblocks[i]
|
|
38
|
+
if codeblock.type != 'bracket':
|
|
39
|
+
continue
|
|
40
|
+
|
|
41
|
+
direction = codeblock.data['direct']
|
|
42
|
+
if direction == 'open':
|
|
43
|
+
nested_level += 1
|
|
44
|
+
else: # Closed
|
|
45
|
+
nested_level -= 1
|
|
46
|
+
|
|
47
|
+
if nested_level == 0:
|
|
48
|
+
return i
|
|
49
|
+
|
|
50
|
+
return -1
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_bracket_ranges(codeblocks: list[CodeBlock], start_index: int):
|
|
54
|
+
bracket_range_end = find_closing_bracket(codeblocks, start_index)
|
|
55
|
+
|
|
56
|
+
if len(codeblocks) >= bracket_range_end and codeblocks[bracket_range_end+1].type == 'else':
|
|
57
|
+
else_range_start = bracket_range_end+3 # Add 3 to move inside `else` brackets
|
|
58
|
+
else_range_end = find_closing_bracket(codeblocks, else_range_start)
|
|
59
|
+
else_range = (else_range_start, else_range_end)
|
|
60
|
+
else:
|
|
61
|
+
else_range = None
|
|
62
|
+
|
|
63
|
+
bracket_range = (start_index, bracket_range_end)
|
|
64
|
+
return (bracket_range, else_range)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_template_length(codeblocks: list[CodeBlock]) -> int:
|
|
68
|
+
return sum(b.get_length() for b in codeblocks)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def get_template_chunks(codeblocks: list[CodeBlock], start_index: int, end_index: int) -> list[TemplateChunk]:
|
|
72
|
+
chunks: list[TemplateChunk] = []
|
|
73
|
+
|
|
74
|
+
index = start_index
|
|
75
|
+
while index < end_index:
|
|
76
|
+
codeblock = codeblocks[index]
|
|
77
|
+
if codeblock.type == 'bracket' or codeblock.type in TEMPLATE_STARTERS:
|
|
78
|
+
index += 1
|
|
79
|
+
continue
|
|
80
|
+
|
|
81
|
+
if codeblock.type in BRACKET_CODEBLOCKS:
|
|
82
|
+
bracket_range, else_range = get_bracket_ranges(codeblocks, index+2)
|
|
83
|
+
inside_bracket = codeblocks[bracket_range[0]:bracket_range[1]]
|
|
84
|
+
inside_bracket_length = get_template_length(inside_bracket)
|
|
85
|
+
chunk_contents1 = get_template_chunks(codeblocks, bracket_range[0], bracket_range[1])
|
|
86
|
+
if else_range is None:
|
|
87
|
+
chunk_length = inside_bracket_length + 4
|
|
88
|
+
chunk_end_index = bracket_range[1] + 1
|
|
89
|
+
chunk_contents2 = None
|
|
90
|
+
else:
|
|
91
|
+
inside_else = codeblocks[else_range[0]:else_range[1]]
|
|
92
|
+
inside_else_length = get_template_length(inside_else)
|
|
93
|
+
chunk_length = inside_bracket_length + inside_else_length + 8
|
|
94
|
+
chunk_end_index = else_range[1] + 1
|
|
95
|
+
chunk_contents2 = get_template_chunks(codeblocks, else_range[0], else_range[1])
|
|
96
|
+
|
|
97
|
+
chunk = TemplateChunk(length=chunk_length, start_index=index, end_index=chunk_end_index, contents1=chunk_contents1, contents2=chunk_contents2)
|
|
98
|
+
chunks.append(chunk)
|
|
99
|
+
index = chunk_end_index-1
|
|
100
|
+
|
|
101
|
+
else:
|
|
102
|
+
chunk = TemplateChunk(length=2, start_index=index, end_index=index+1, contents1=None, contents2=None)
|
|
103
|
+
chunks.append(chunk)
|
|
104
|
+
|
|
105
|
+
index += 1
|
|
106
|
+
|
|
107
|
+
return chunks
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def extract_one_template(codeblocks: list[CodeBlock], target_length: int, extracted_template_name: str) -> tuple[list[CodeBlock], list[CodeBlock]]:
|
|
111
|
+
chunks = get_template_chunks(codeblocks, 0, len(codeblocks))
|
|
112
|
+
current_slice_length = 2
|
|
113
|
+
current_slice_start = -1
|
|
114
|
+
current_slice_end = -1
|
|
115
|
+
|
|
116
|
+
slices: dict[tuple[int, int], int] = {}
|
|
117
|
+
|
|
118
|
+
chunks_to_iterate: deque[list[TemplateChunk]] = deque()
|
|
119
|
+
chunks_to_iterate.append(chunks)
|
|
120
|
+
|
|
121
|
+
def save_current_slice():
|
|
122
|
+
nonlocal current_slice_start, current_slice_end, current_slice_length, slices
|
|
123
|
+
current_slice_range = (current_slice_start, current_slice_end)
|
|
124
|
+
slices[current_slice_range] = current_slice_length
|
|
125
|
+
current_slice_length = 2
|
|
126
|
+
current_slice_start = -1
|
|
127
|
+
current_slice_end = -1
|
|
128
|
+
|
|
129
|
+
while chunks_to_iterate:
|
|
130
|
+
current_chunks = chunks_to_iterate.pop()
|
|
131
|
+
for chunk in reversed(current_chunks):
|
|
132
|
+
if chunk.contents1:
|
|
133
|
+
chunks_to_iterate.append(chunk.contents1)
|
|
134
|
+
if chunk.contents2:
|
|
135
|
+
chunks_to_iterate.append(chunk.contents2)
|
|
136
|
+
|
|
137
|
+
if current_slice_start == -1:
|
|
138
|
+
current_slice_start = chunk.start_index
|
|
139
|
+
if current_slice_end == -1:
|
|
140
|
+
current_slice_end = chunk.end_index
|
|
141
|
+
|
|
142
|
+
# Check if chunk is too long
|
|
143
|
+
if chunk.length > target_length - 2:
|
|
144
|
+
save_current_slice()
|
|
145
|
+
continue
|
|
146
|
+
|
|
147
|
+
new_slice_length = current_slice_length + chunk.length
|
|
148
|
+
if new_slice_length <= target_length:
|
|
149
|
+
current_slice_length = new_slice_length
|
|
150
|
+
current_slice_start = chunk.start_index
|
|
151
|
+
else:
|
|
152
|
+
current_slice_range = (current_slice_start, current_slice_end)
|
|
153
|
+
slices[current_slice_range] = current_slice_length
|
|
154
|
+
current_slice_length = chunk.length + 2
|
|
155
|
+
current_slice_start = chunk.start_index
|
|
156
|
+
current_slice_end = chunk.end_index
|
|
157
|
+
|
|
158
|
+
save_current_slice()
|
|
159
|
+
|
|
160
|
+
sliced_range = max(slices.items(), key=lambda kv: kv[1])[0] # Extract the longest slice
|
|
161
|
+
extracted_codeblocks = codeblocks[sliced_range[0]:sliced_range[1]]
|
|
162
|
+
del codeblocks[sliced_range[0]:sliced_range[1]]
|
|
163
|
+
|
|
164
|
+
original_line_vars = get_referenced_line_vars(codeblocks)
|
|
165
|
+
extracted_line_vars = get_referenced_line_vars(extracted_codeblocks)
|
|
166
|
+
param_line_vars = set.intersection(original_line_vars, extracted_line_vars)
|
|
167
|
+
function_parameters = []
|
|
168
|
+
function_call_args = []
|
|
169
|
+
for line_var in param_line_vars:
|
|
170
|
+
function_parameters.append(Parameter(line_var, ParameterType.VAR))
|
|
171
|
+
function_call_args.append(Variable(line_var, 'line'))
|
|
172
|
+
|
|
173
|
+
function_codeblock = CodeBlock.new_data('func', extracted_template_name, tuple(function_parameters), tags={'Is Hidden': 'True'})
|
|
174
|
+
extracted_codeblocks.insert(0, function_codeblock)
|
|
175
|
+
|
|
176
|
+
call_function_codeblock = CodeBlock.new_data('call_func', extracted_template_name, tuple(function_call_args), {})
|
|
177
|
+
codeblocks.insert(sliced_range[0], call_function_codeblock)
|
|
178
|
+
|
|
179
|
+
return codeblocks, extracted_codeblocks
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def slice_template(codeblocks: list[CodeBlock], target_length: int, template_name: str) -> list[list[CodeBlock]]:
|
|
183
|
+
template_length = get_template_length(codeblocks)
|
|
184
|
+
if template_length < target_length:
|
|
185
|
+
return [codeblocks]
|
|
186
|
+
|
|
187
|
+
codeblocks = codeblocks.copy()
|
|
188
|
+
|
|
189
|
+
sliced_templates: list[list[CodeBlock]] = []
|
|
190
|
+
|
|
191
|
+
# Extract single templates until the original template meets the target length
|
|
192
|
+
template_number = 1
|
|
193
|
+
while get_template_length(codeblocks) > target_length:
|
|
194
|
+
extracted_template_name = template_name + '_' + str(template_number)
|
|
195
|
+
codeblocks, extracted_codeblocks = extract_one_template(codeblocks, target_length, extracted_template_name)
|
|
196
|
+
sliced_templates.append(extracted_codeblocks)
|
|
197
|
+
template_number += 1
|
|
198
|
+
|
|
199
|
+
sliced_templates.insert(0, codeblocks)
|
|
200
|
+
return sliced_templates
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dfpyre
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: A package for creating and modifying 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.4.
|
|
15
|
+
Requires-Dist: mcitemlib (>=0.4.5,<0.5.0)
|
|
16
16
|
Project-URL: Repository, https://github.com/Amp63/pyre
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
dfpyre/__init__.py,sha256=apPsSxJ1Tztfl71MoORoSmDfX7LyKLYlLwOGeLQUitw,25
|
|
2
|
+
dfpyre/action_literals.py,sha256=0aYS5v8pj3tyQVoiW_ueKBDQ0nY5VduPp4HeW_kpFio,55600
|
|
3
|
+
dfpyre/actiondump.py,sha256=l6_h811AnKkeI6WrrRlS-vDOgenh6XU9qvEuPf2DpSs,3720
|
|
4
|
+
dfpyre/codeblock.py,sha256=NwUapwVP1qrnFaN4WlKov4MTJW9_l2ujNhY1P0pzboU,8577
|
|
5
|
+
dfpyre/data/actiondump_min.json,sha256=zdUYVuua6a93wxFewHWXBHYRuuvwDZK6c3J2558BAIg,2642808
|
|
6
|
+
dfpyre/items.py,sha256=zdT_b7D38ofFVEYtjHb6x6IU0XMJJCJPuQUXW5MNsm0,17681
|
|
7
|
+
dfpyre/pyre.py,sha256=WQhIXmrd7A1APcRobjmT5eBGHNf7V12qlcPvI1QM7R8,19331
|
|
8
|
+
dfpyre/scriptgen.py,sha256=UNUbRVAUlO0gCGoo17Qpiaa5XOXTVZIEHGN2ckEdXaM,10231
|
|
9
|
+
dfpyre/slice.py,sha256=azKC5H7sxXvKSa1uFHQNoS2MGLqgl-_0ftD8F9fRn_Y,7980
|
|
10
|
+
dfpyre/style.py,sha256=mLW1CFvvi8_9fk8JaH10I5S4WI0YBdQIXHtI3G_4sR8,980
|
|
11
|
+
dfpyre/util.py,sha256=_ndjGyn_pvMfEBmUjt0ARjYvGZfZz7Av-KSYPmvx0N0,934
|
|
12
|
+
dfpyre-0.9.0.dist-info/LICENSE,sha256=_vuDskB0ja2c-Fgm7Gt8Q8cO9NsLNpZAVyvmZwX7E6o,1060
|
|
13
|
+
dfpyre-0.9.0.dist-info/METADATA,sha256=acAZkSAbA6FfFckEiOdA6eQy1hljGo62p_T1V0ZBwjo,11948
|
|
14
|
+
dfpyre-0.9.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
15
|
+
dfpyre-0.9.0.dist-info/RECORD,,
|
dfpyre-0.8.20.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
dfpyre/__init__.py,sha256=apPsSxJ1Tztfl71MoORoSmDfX7LyKLYlLwOGeLQUitw,25
|
|
2
|
-
dfpyre/action_literals.py,sha256=bwdLVDi2sU_4HUmvyOJtCguPOWJga_fQTPLtzPm4Mr4,52084
|
|
3
|
-
dfpyre/actiondump.py,sha256=5Q4RmT_DyVbPvkF0AFzMAqtqR1bmqu91yed_pRK5MkU,3571
|
|
4
|
-
dfpyre/data/actiondump_min.json,sha256=ZF_Aa6uB1khzsINAEAljCOIMmfh_5ihmBygZSP_bHrs,2482346
|
|
5
|
-
dfpyre/items.py,sha256=zdT_b7D38ofFVEYtjHb6x6IU0XMJJCJPuQUXW5MNsm0,17681
|
|
6
|
-
dfpyre/pyre.py,sha256=T-rnvCgIucWKFdhcRuBM_5NTaszuZ4M2VIcu44jrLIY,26047
|
|
7
|
-
dfpyre/scriptgen.py,sha256=NABQKGgnoWZCkV42Av_4Is8CdVCWUt6Wk9-r-F44Als,9742
|
|
8
|
-
dfpyre/style.py,sha256=mLW1CFvvi8_9fk8JaH10I5S4WI0YBdQIXHtI3G_4sR8,980
|
|
9
|
-
dfpyre/util.py,sha256=_ndjGyn_pvMfEBmUjt0ARjYvGZfZz7Av-KSYPmvx0N0,934
|
|
10
|
-
dfpyre-0.8.20.dist-info/LICENSE,sha256=_vuDskB0ja2c-Fgm7Gt8Q8cO9NsLNpZAVyvmZwX7E6o,1060
|
|
11
|
-
dfpyre-0.8.20.dist-info/METADATA,sha256=M0RBjcjMhSPG1nVP5ZGuirKmFMpzrBDpBwRgfQRqr08,11949
|
|
12
|
-
dfpyre-0.8.20.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
13
|
-
dfpyre-0.8.20.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|