dfpyre 0.4.5__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/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
- import re
2
- from mcitemlib.style import STYLE_CODE_REGEX, FORMAT_CODES, StyledString
3
-
4
- def isAmpersandCoded(s: str) -> bool:
5
- return bool(re.match(STYLE_CODE_REGEX, s))
6
-
7
-
8
- def ampersandToMinimessage(ampersand_code: str) -> str:
9
- ampersand_code = ampersand_code.replace('&r', '<reset>') # bad but should work most of the time
10
- styledString = StyledString.from_codes(ampersand_code)
11
- formattedStringList = []
12
- for substring in styledString.substrings:
13
- formattedSubstringList = []
14
- for styleType, value in substring.data.items():
15
- if styleType in FORMAT_CODES.values() and value:
16
- formattedSubstringList.append(f'<{styleType}>')
17
- if styleType == 'color':
18
- formattedSubstringList.append(f'<{value}>')
19
-
20
- formattedSubstringList.append(substring.data['text'])
21
- formattedStringList.append(''.join(formattedSubstringList))
22
- return ''.join(formattedStringList)
1
+ import re
2
+ from mcitemlib.style import STYLE_CODE_REGEX, FORMAT_CODES, StyledString
3
+
4
+ def is_ampersand_coded(s: str) -> bool:
5
+ return bool(re.match(STYLE_CODE_REGEX, s))
6
+
7
+
8
+ def ampersand_to_minimessage(ampersand_code: str) -> str:
9
+ ampersand_code = ampersand_code.replace('&r', '<reset>') # bad but should work most of the time
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
+
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
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2023 Amp
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Amp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.