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/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.actiondump import CODEBLOCK_DATA, get_default_tags
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
- codeblock = CodeBlock.new_action(codeblock_type, block_dict['action'], block_args, block_tags, block_target)
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: REPEAT_SUBACTION|None=None, inverted: bool=False, codeblocks: list[CodeBlock]=[]) -> CodeBlock:
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.new_repeat(action_name, args, tags, sub_action, inverted),
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.new_action('select_obj', action_name, args, tags)
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(template, flags: GeneratorFlags) -> str:
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 = template.codeblocks[0].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 template.codeblocks:
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 = get_default_tags(codeblock.data.get('block'), codeblock.action_name)
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.8.20
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.3,<0.5.0)
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,,
@@ -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,,