dfpyre 0.4.6__py3-none-any.whl → 0.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dfpyre might be problematic. Click here for more details.
- dfpyre/actiondump.py +77 -0
- dfpyre/data/actiondump_min.json +1 -0
- dfpyre/items.py +218 -183
- dfpyre/pyre.py +466 -350
- dfpyre/scriptgen.py +193 -0
- dfpyre/style.py +14 -14
- dfpyre/util.py +39 -0
- {dfpyre-0.4.6.dist-info → dfpyre-0.8.1.dist-info}/LICENSE +1 -1
- dfpyre-0.8.1.dist-info/METADATA +514 -0
- dfpyre-0.8.1.dist-info/RECORD +12 -0
- dfpyre/data/data.json +0 -1
- dfpyre-0.4.6.dist-info/METADATA +0 -474
- dfpyre-0.4.6.dist-info/RECORD +0 -9
- {dfpyre-0.4.6.dist-info → dfpyre-0.8.1.dist-info}/WHEEL +0 -0
dfpyre/scriptgen.py
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import re
|
|
3
|
+
from dfpyre.items import *
|
|
4
|
+
from dfpyre.actiondump import get_default_tags
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
SCRIPT_START = '''from dfpyre import *\n\n'''
|
|
8
|
+
|
|
9
|
+
TEMPLATE_FUNCTION_LOOKUP = {
|
|
10
|
+
'event': 'player_event',
|
|
11
|
+
'entity_event': 'entity_event',
|
|
12
|
+
'func': 'function',
|
|
13
|
+
'process': 'process',
|
|
14
|
+
'call_func': 'call_function',
|
|
15
|
+
'start_process': 'start_process',
|
|
16
|
+
'player_action': 'player_action',
|
|
17
|
+
'game_action': 'game_action',
|
|
18
|
+
'entity_action': 'entity_action',
|
|
19
|
+
'if_player': 'if_player',
|
|
20
|
+
'if_var': 'if_variable',
|
|
21
|
+
'if_game': 'if_game',
|
|
22
|
+
'if_entity': 'if_entity',
|
|
23
|
+
'else': 'else_',
|
|
24
|
+
'repeat': 'repeat',
|
|
25
|
+
'control': 'control',
|
|
26
|
+
'select_obj': 'select_object',
|
|
27
|
+
'set_var': 'set_variable'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
|
|
31
|
+
CONTAINER_CODEBLOCKS = {'event', 'entity_event', 'func', 'process', 'if_player', 'if_entity', 'if_game', 'if_var', 'else', 'repeat'}
|
|
32
|
+
VAR_SCOPES = {'unsaved': 'g', 'saved': 's', 'local': 'l', 'line': 'i'}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclasses.dataclass
|
|
36
|
+
class GeneratorFlags:
|
|
37
|
+
indent_size: int
|
|
38
|
+
literal_shorthand: bool
|
|
39
|
+
var_shorthand: bool
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def item_to_string(class_name: str, i: Item):
|
|
43
|
+
i.nbt.data.pop('~DF_NBT', None)
|
|
44
|
+
stripped_id = i.get_id().replace('minecraft:', '')
|
|
45
|
+
if i.nbt.key_set() == {'~id', '~count'}:
|
|
46
|
+
if i.get_count() == 1:
|
|
47
|
+
return f'{class_name}("{stripped_id}")'
|
|
48
|
+
return f'{class_name}("{stripped_id}", {i.get_count()})'
|
|
49
|
+
return f'{class_name}.from_nbt("""{i.get_nbt()}""")'
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def argument_item_to_string(flags: GeneratorFlags, arg_item: object) -> str:
|
|
53
|
+
class_name = arg_item.__class__.__name__
|
|
54
|
+
if isinstance(arg_item, Item):
|
|
55
|
+
return item_to_string(class_name, arg_item)
|
|
56
|
+
|
|
57
|
+
if isinstance(arg_item, String):
|
|
58
|
+
value = arg_item.value.replace('\n', '\\n')
|
|
59
|
+
return f'{class_name}("{value}")'
|
|
60
|
+
|
|
61
|
+
if isinstance(arg_item, Text):
|
|
62
|
+
value = arg_item.value.replace('\n', '\\n')
|
|
63
|
+
if flags.literal_shorthand:
|
|
64
|
+
return f'"{value}"'
|
|
65
|
+
return f'{class_name}("{value}")'
|
|
66
|
+
|
|
67
|
+
if isinstance(arg_item, Number):
|
|
68
|
+
if not re.match(NUMBER_REGEX, str(arg_item.value)):
|
|
69
|
+
return f'{class_name}("{arg_item.value}")'
|
|
70
|
+
if flags.literal_shorthand:
|
|
71
|
+
return str(arg_item.value)
|
|
72
|
+
return f'{class_name}({arg_item.value})'
|
|
73
|
+
|
|
74
|
+
if isinstance(arg_item, Location):
|
|
75
|
+
loc_components = [arg_item.x, arg_item.y, arg_item.z]
|
|
76
|
+
if arg_item.pitch != 0:
|
|
77
|
+
loc_components.append(arg_item.pitch)
|
|
78
|
+
if arg_item.yaw != 0:
|
|
79
|
+
loc_components.append(arg_item.yaw)
|
|
80
|
+
return f'{class_name}({", ".join(str(c) for c in loc_components)})'
|
|
81
|
+
|
|
82
|
+
if isinstance(arg_item, Variable):
|
|
83
|
+
if flags.var_shorthand:
|
|
84
|
+
return f'"${VAR_SCOPES[arg_item.scope]} {arg_item.name}"'
|
|
85
|
+
if arg_item.scope == 'unsaved':
|
|
86
|
+
return f'{class_name}("{arg_item.name}")'
|
|
87
|
+
return f'{class_name}("{arg_item.name}", "{arg_item.scope}")'
|
|
88
|
+
|
|
89
|
+
if isinstance(arg_item, Sound):
|
|
90
|
+
return f'{class_name}("{arg_item.name}", {arg_item.pitch}, {arg_item.vol})'
|
|
91
|
+
|
|
92
|
+
if isinstance(arg_item, Particle):
|
|
93
|
+
return f'{class_name}({arg_item.particle_data})'
|
|
94
|
+
|
|
95
|
+
if isinstance(arg_item, Potion):
|
|
96
|
+
return f'{class_name}("{arg_item.name}", {arg_item.dur}, {arg_item.amp})'
|
|
97
|
+
|
|
98
|
+
if isinstance(arg_item, GameValue):
|
|
99
|
+
if arg_item.target == 'Default':
|
|
100
|
+
return f'{class_name}("{arg_item.name}")'
|
|
101
|
+
return f'{class_name}("{arg_item.name}", "{arg_item.target}")'
|
|
102
|
+
|
|
103
|
+
if isinstance(arg_item, Parameter):
|
|
104
|
+
param_type_class_name = arg_item.param_type.__class__.__name__
|
|
105
|
+
param_args = [f'"{arg_item.name}"', f'{param_type_class_name}.{arg_item.param_type.name}']
|
|
106
|
+
if arg_item.plural:
|
|
107
|
+
param_args.append('plural=True')
|
|
108
|
+
if arg_item.optional:
|
|
109
|
+
param_args.append('optional=True')
|
|
110
|
+
if arg_item.default_value is not None:
|
|
111
|
+
param_args.append(f'default_value={argument_item_to_string(flags, arg_item.default_value)}')
|
|
112
|
+
if arg_item.description:
|
|
113
|
+
param_args.append(f'description="{arg_item.description}"')
|
|
114
|
+
if arg_item.note:
|
|
115
|
+
param_args.append(f'note="{arg_item.note}"')
|
|
116
|
+
return f'{class_name}({", ".join(param_args)})'
|
|
117
|
+
|
|
118
|
+
if isinstance(arg_item, Vector):
|
|
119
|
+
return f'{class_name}({arg_item.x}, {arg_item.y}, {arg_item.z})'
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def add_script_line(flags: GeneratorFlags, script_lines: list[str], indent_level: int, line: str, add_comma: bool=True):
|
|
123
|
+
added_line = ' '*flags.indent_size*indent_level + line
|
|
124
|
+
if add_comma and indent_level > 0:
|
|
125
|
+
added_line += ','
|
|
126
|
+
script_lines.append(added_line)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def generate_script(template, flags: GeneratorFlags) -> str:
|
|
130
|
+
indent_level = 0
|
|
131
|
+
script_lines = []
|
|
132
|
+
|
|
133
|
+
def remove_comma_from_last_line():
|
|
134
|
+
script_lines[-1] = script_lines[-1][:-1]
|
|
135
|
+
|
|
136
|
+
for codeblock in template.codeblocks:
|
|
137
|
+
# Handle closing brackets
|
|
138
|
+
if codeblock.type == 'bracket':
|
|
139
|
+
if codeblock.data['direct'] == 'close':
|
|
140
|
+
remove_comma_from_last_line()
|
|
141
|
+
indent_level -= 1
|
|
142
|
+
add_script_line(flags, script_lines, indent_level, '])')
|
|
143
|
+
continue
|
|
144
|
+
|
|
145
|
+
# Get codeblock function and start its arguments with the action
|
|
146
|
+
function_name = TEMPLATE_FUNCTION_LOOKUP[codeblock.type]
|
|
147
|
+
function_args = [f'"{codeblock.action_name}"']
|
|
148
|
+
|
|
149
|
+
# Set function or process name if necessary
|
|
150
|
+
if codeblock.action_name == 'dynamic':
|
|
151
|
+
function_args[0] = f'"{codeblock.data["data"]}"'
|
|
152
|
+
|
|
153
|
+
# Convert argument objects to valid Python strings
|
|
154
|
+
codeblock_args = [argument_item_to_string(flags, i) for i in codeblock.args]
|
|
155
|
+
if codeblock_args:
|
|
156
|
+
function_args.extend(codeblock_args)
|
|
157
|
+
|
|
158
|
+
# Add target if necessary
|
|
159
|
+
if function_name in TARGET_CODEBLOCKS and codeblock.target.name != 'SELECTION':
|
|
160
|
+
function_args.append(f'target=Target.{codeblock.target.name}')
|
|
161
|
+
|
|
162
|
+
# Add tags
|
|
163
|
+
if codeblock.tags:
|
|
164
|
+
default_tags = get_default_tags(codeblock.data.get('block'), codeblock.action_name)
|
|
165
|
+
written_tags = {t: o for t, o in codeblock.tags.items() if default_tags[t] != o}
|
|
166
|
+
if written_tags:
|
|
167
|
+
function_args.append(f'tags={str(written_tags)}')
|
|
168
|
+
|
|
169
|
+
# Add sub-action for repeat
|
|
170
|
+
if codeblock.data.get('subAction'):
|
|
171
|
+
function_args.append(f'sub_action="{codeblock.data["subAction"]}"')
|
|
172
|
+
|
|
173
|
+
# Add inversion for NOT
|
|
174
|
+
if codeblock.data.get('attribute') == 'NOT':
|
|
175
|
+
function_args.append('inverted=True')
|
|
176
|
+
|
|
177
|
+
if codeblock.type in CONTAINER_CODEBLOCKS:
|
|
178
|
+
if codeblock.type == 'else':
|
|
179
|
+
line = f'{function_name}(['
|
|
180
|
+
elif codeblock.type in {'event', 'entity_event'}:
|
|
181
|
+
line = f'{function_name}({", ".join(function_args)}, [' # omit `codeblocks=` when we don't need it
|
|
182
|
+
else:
|
|
183
|
+
line = f'{function_name}({", ".join(function_args)}, codeblocks=['
|
|
184
|
+
add_script_line(flags, script_lines, indent_level, line, False)
|
|
185
|
+
indent_level += 1
|
|
186
|
+
else:
|
|
187
|
+
line = f'{function_name}({", ".join(function_args)})'
|
|
188
|
+
add_script_line(flags, script_lines, indent_level, line)
|
|
189
|
+
|
|
190
|
+
remove_comma_from_last_line()
|
|
191
|
+
indent_level -= 1
|
|
192
|
+
add_script_line(flags, script_lines, indent_level, '])') # add final closing brackets
|
|
193
|
+
return SCRIPT_START + '\n'.join(script_lines)
|
dfpyre/style.py
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from mcitemlib.style import STYLE_CODE_REGEX, FORMAT_CODES, StyledString
|
|
3
3
|
|
|
4
|
-
def
|
|
4
|
+
def is_ampersand_coded(s: str) -> bool:
|
|
5
5
|
return bool(re.match(STYLE_CODE_REGEX, s))
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def
|
|
8
|
+
def ampersand_to_minimessage(ampersand_code: str) -> str:
|
|
9
9
|
ampersand_code = ampersand_code.replace('&r', '<reset>') # bad but should work most of the time
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
for substring in
|
|
13
|
-
|
|
14
|
-
for
|
|
15
|
-
if
|
|
16
|
-
|
|
17
|
-
if
|
|
18
|
-
|
|
10
|
+
styled_string = StyledString.from_codes(ampersand_code)
|
|
11
|
+
formatted_string_list = []
|
|
12
|
+
for substring in styled_string.substrings:
|
|
13
|
+
formatted_substring_list = []
|
|
14
|
+
for style_type, value in substring.data.items():
|
|
15
|
+
if style_type in FORMAT_CODES.values() and value:
|
|
16
|
+
formatted_substring_list.append(f'<{style_type}>')
|
|
17
|
+
if style_type == 'color':
|
|
18
|
+
formatted_substring_list.append(f'<{value}>')
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return ''.join(
|
|
20
|
+
formatted_substring_list.append(substring.data['text'])
|
|
21
|
+
formatted_string_list.append(''.join(formatted_substring_list))
|
|
22
|
+
return ''.join(formatted_string_list)
|
dfpyre/util.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import gzip
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
COL_WARN = '\x1b[33m'
|
|
6
|
+
COL_RESET = '\x1b[0m'
|
|
7
|
+
COL_SUCCESS = '\x1b[32m'
|
|
8
|
+
COL_ERROR = '\x1b[31m'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PyreException(Exception):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def warn(message: str):
|
|
16
|
+
print(f'{COL_WARN}! WARNING ! {message}{COL_RESET}')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def df_encode(json_string: str) -> str:
|
|
20
|
+
"""
|
|
21
|
+
Encodes a stringified json.
|
|
22
|
+
"""
|
|
23
|
+
encoded_string = gzip.compress(json_string.encode('utf-8'))
|
|
24
|
+
return base64.b64encode(encoded_string).decode('utf-8')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def df_decode(encoded_string: str) -> str:
|
|
28
|
+
return gzip.decompress(base64.b64decode(encoded_string)).decode('utf-8')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def flatten(nested_list: list):
|
|
32
|
+
"""
|
|
33
|
+
Flattens a list.
|
|
34
|
+
"""
|
|
35
|
+
for item in nested_list:
|
|
36
|
+
if isinstance(item, list):
|
|
37
|
+
yield from flatten(item)
|
|
38
|
+
else:
|
|
39
|
+
yield item
|