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/pyre.py
CHANGED
|
@@ -1,40 +1,27 @@
|
|
|
1
1
|
"""
|
|
2
|
-
A package for
|
|
2
|
+
A package for making code templates for the DiamondFire Minecraft server.
|
|
3
3
|
|
|
4
4
|
By Amp
|
|
5
|
-
2/24/2024
|
|
6
5
|
"""
|
|
7
6
|
|
|
8
|
-
import base64
|
|
9
|
-
import gzip
|
|
10
|
-
import socket
|
|
11
|
-
import websocket
|
|
12
|
-
import time
|
|
13
7
|
import json
|
|
14
|
-
import os
|
|
15
8
|
from difflib import get_close_matches
|
|
16
9
|
import datetime
|
|
17
|
-
from typing import Tuple, List, Dict
|
|
18
10
|
from enum import Enum
|
|
19
11
|
from mcitemlib.itemlib import Item as NbtItem
|
|
12
|
+
from dfpyre.util import *
|
|
20
13
|
from dfpyre.items import *
|
|
14
|
+
from dfpyre.scriptgen import generate_script, GeneratorFlags
|
|
15
|
+
from dfpyre.actiondump import CODEBLOCK_DATA, get_default_tags
|
|
21
16
|
|
|
22
|
-
COL_WARN = '\x1b[33m'
|
|
23
|
-
COL_RESET = '\x1b[0m'
|
|
24
|
-
COL_SUCCESS = '\x1b[32m'
|
|
25
|
-
COL_ERROR = '\x1b[31m'
|
|
26
|
-
|
|
27
|
-
CODEBLOCK_DATA_PATH = os.path.join(os.path.dirname(__file__), 'data/data.json')
|
|
28
17
|
|
|
29
18
|
VARIABLE_TYPES = {'txt', 'comp', 'num', 'item', 'loc', 'var', 'snd', 'part', 'pot', 'g_val', 'vec', 'pn_el'}
|
|
30
19
|
TEMPLATE_STARTERS = {'event', 'entity_event', 'func', 'process'}
|
|
20
|
+
DYNAMIC_CODEBLOCKS = {'func', 'process', 'call_func', 'start_process'}
|
|
31
21
|
|
|
32
22
|
TARGETS = ['Selection', 'Default', 'Killer', 'Damager', 'Shooter', 'Victim', 'AllPlayers', 'Projectile', 'AllEntities', 'AllMobs', 'LastEntity']
|
|
33
23
|
TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
|
|
34
24
|
|
|
35
|
-
VAR_SHORTHAND_CHAR = '$'
|
|
36
|
-
VAR_SCOPES = {'g': 'unsaved', 's': 'saved', 'l': 'local', 'i': 'line'}
|
|
37
|
-
|
|
38
25
|
CODECLIENT_URL = 'ws://localhost:31375'
|
|
39
26
|
|
|
40
27
|
|
|
@@ -51,153 +38,171 @@ class Target(Enum):
|
|
|
51
38
|
ALL_MOBS = 9
|
|
52
39
|
LAST_ENTITY = 10
|
|
53
40
|
|
|
54
|
-
def
|
|
41
|
+
def get_string_value(self):
|
|
55
42
|
return TARGETS[self.value]
|
|
56
43
|
|
|
57
44
|
DEFAULT_TARGET = Target.SELECTION
|
|
58
45
|
|
|
59
46
|
|
|
47
|
+
def _convert_args(args):
|
|
48
|
+
return tuple(map(convert_argument, args))
|
|
49
|
+
|
|
50
|
+
|
|
60
51
|
class CodeBlock:
|
|
61
|
-
def __init__(self,
|
|
62
|
-
self.
|
|
52
|
+
def __init__(self, codeblock_type: str, action_name: str, args: tuple=(), target: Target=DEFAULT_TARGET, data: dict={}, tags: dict[str, str]={}):
|
|
53
|
+
self.type = codeblock_type
|
|
54
|
+
self.action_name = action_name
|
|
63
55
|
self.args = args
|
|
64
56
|
self.target = target
|
|
65
57
|
self.data = data
|
|
58
|
+
self.tags = tags
|
|
59
|
+
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
def
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
@classmethod
|
|
62
|
+
def new_action(cls, codeblock_type: str, action_name: str, args: tuple, tags: dict[str, str], target: Target=DEFAULT_TARGET) -> "CodeBlock":
|
|
63
|
+
args = _convert_args(args)
|
|
64
|
+
return cls(codeblock_type, action_name, args=args, data={'id': 'block', 'block': codeblock_type, 'action': action_name}, tags=tags, target=target)
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def new_data(cls, codeblock_type: str, data_value: str, args: tuple, tags: dict[str, str]) -> "CodeBlock":
|
|
68
|
+
args = _convert_args(args)
|
|
69
|
+
return cls(codeblock_type, 'dynamic', args=args, data={'id': 'block', 'block': codeblock_type, 'data': data_value}, tags=tags)
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def new_conditional(cls, codeblock_type: str, action_name: str, args: tuple, tags: dict[str, str], inverted: bool, target: Target=DEFAULT_TARGET) -> "CodeBlock":
|
|
73
|
+
args = _convert_args(args)
|
|
74
|
+
data = {'id': 'block', 'block': codeblock_type, 'action': action_name}
|
|
75
|
+
if inverted:
|
|
76
|
+
data['attribute'] = 'NOT'
|
|
77
|
+
return cls(codeblock_type, action_name, args=args, data=data, tags=tags, target=target)
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def new_repeat(cls, action_name: str, args: tuple, tags: dict[str, str], sub_action: str|None, inverted: bool) -> "CodeBlock":
|
|
81
|
+
args = _convert_args(args)
|
|
82
|
+
data = {'id': 'block', 'block': 'repeat', 'action': action_name}
|
|
83
|
+
if inverted:
|
|
84
|
+
data['attribute'] = 'NOT'
|
|
85
|
+
if sub_action is not None:
|
|
86
|
+
data['subAction'] = sub_action
|
|
87
|
+
return cls('repeat', action_name, args=args, data=data, tags=tags)
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def new_else(cls) -> "CodeBlock":
|
|
91
|
+
return cls('else', 'else', data={'id': 'block', 'block': 'else'})
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def new_bracket(cls, direction: Literal['open', 'close'], bracket_type: Literal['norm', 'repeat']) -> "CodeBlock":
|
|
95
|
+
return cls('bracket', 'bracket', data={'id': 'bracket', 'direct': direction, 'type': bracket_type})
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def __repr__(self) -> str:
|
|
99
|
+
if self.action_name == 'dynamic':
|
|
100
|
+
return f'CodeBlock({self.data["block"]}, {self.data["data"]})'
|
|
101
|
+
if self.action_name == 'else':
|
|
102
|
+
return 'CodeBlock(else)'
|
|
103
|
+
if 'block' in self.data:
|
|
104
|
+
return f'CodeBlock({self.data["block"]}, {self.action_name})'
|
|
105
|
+
return f'CodeBlock(bracket, {self.data["type"]}, {self.data["direct"]})'
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def build(self, include_tags: bool=True) -> dict:
|
|
109
|
+
"""
|
|
110
|
+
Builds a properly formatted block from a CodeBlock object.
|
|
111
|
+
"""
|
|
112
|
+
built_block = self.data.copy()
|
|
113
|
+
|
|
114
|
+
# add target if necessary ('Selection' is the default when 'target' is blank)
|
|
115
|
+
if self.type in TARGET_CODEBLOCKS and self.target != DEFAULT_TARGET:
|
|
116
|
+
built_block['target'] = self.target.get_string_value()
|
|
117
|
+
|
|
118
|
+
# add items into args
|
|
119
|
+
final_args = [arg.format(slot) for slot, arg in enumerate(self.args) if arg.type in VARIABLE_TYPES]
|
|
120
|
+
|
|
121
|
+
# check for unrecognized name, add tags
|
|
122
|
+
if self.type not in {'bracket', 'else'}:
|
|
123
|
+
if self.action_name not in CODEBLOCK_DATA[self.type]:
|
|
124
|
+
_warn_unrecognized_name(self.type, self.action_name)
|
|
125
|
+
elif include_tags:
|
|
126
|
+
tags = _get_codeblock_tags(self.type, self.action_name, self.tags)
|
|
127
|
+
if len(final_args) + len(tags) > 27:
|
|
128
|
+
final_args = final_args[:(27-len(tags))] # trim list if over 27 elements
|
|
129
|
+
final_args.extend(tags) # add tags to end
|
|
130
|
+
|
|
131
|
+
built_block['args'] = {'items': final_args}
|
|
132
|
+
return built_block
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _warn_unrecognized_name(codeblock_type: str, codeblock_name: str):
|
|
136
|
+
close = get_close_matches(codeblock_name, CODEBLOCK_DATA[codeblock_type].keys())
|
|
74
137
|
if close:
|
|
75
|
-
|
|
138
|
+
warn(f'Code block name "{codeblock_name}" not recognized. Did you mean "{close[0]}"?')
|
|
76
139
|
else:
|
|
77
|
-
|
|
140
|
+
warn(f'Code block name "{codeblock_name}" not recognized. Try spell checking or retyping without spaces.')
|
|
78
141
|
|
|
79
142
|
|
|
80
|
-
def
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
tagData = json.load(f)
|
|
85
|
-
else:
|
|
86
|
-
_warn('data.json not found -- Item tags and error checking will not work.')
|
|
87
|
-
return ({}, set(), set())
|
|
143
|
+
def _check_applied_tags(tags: list[dict], applied_tags: dict[str, str], codeblock_name: str) -> dict[str, str]:
|
|
144
|
+
if len(applied_tags) > 0 and len(tags) == 0:
|
|
145
|
+
warn(f'Action "{codeblock_name}" does not have any tags, but still received {len(applied_tags)}.')
|
|
146
|
+
return {}
|
|
88
147
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
TAGDATA, TAGDATA_EXTRAS_KEYS, ALL_CODEBLOCK_NAMES = _loadCodeblockData()
|
|
99
|
-
|
|
100
|
-
def _addInverted(data, inverted):
|
|
101
|
-
"""
|
|
102
|
-
If inverted is true, add 'inverted': 'NOT' to data.
|
|
103
|
-
"""
|
|
104
|
-
if inverted:
|
|
105
|
-
data['inverted'] = 'NOT'
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def _convertDataTypes(args):
|
|
109
|
-
convertedArgs = []
|
|
110
|
-
for value in args:
|
|
111
|
-
if type(value) in {int, float}:
|
|
112
|
-
convertedArgs.append(num(value))
|
|
113
|
-
elif type(value) is str:
|
|
114
|
-
if value[0] == VAR_SHORTHAND_CHAR and value[1] in VAR_SCOPES:
|
|
115
|
-
varObject = var(value[2:], VAR_SCOPES[value[1]])
|
|
116
|
-
convertedArgs.append(varObject)
|
|
117
|
-
else:
|
|
118
|
-
convertedArgs.append(text(value))
|
|
148
|
+
valid_tags = {}
|
|
149
|
+
tags_formatted = {t['name']: t for t in tags}
|
|
150
|
+
for name, option in applied_tags.items():
|
|
151
|
+
if name not in tags_formatted:
|
|
152
|
+
tag_names_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted.keys()))
|
|
153
|
+
warn(f'Tag "{name}" does not exist for action "{codeblock_name}". Available tags:\n{tag_names_joined}')
|
|
154
|
+
elif option not in tags_formatted[name]['options']:
|
|
155
|
+
options_joined = '\n'.join(map(lambda s: ' - '+s, tags_formatted[name]['options']))
|
|
156
|
+
warn(f'Tag "{name}" does not have the option "{option}". Available tag options:\n{options_joined}')
|
|
119
157
|
else:
|
|
120
|
-
|
|
121
|
-
return
|
|
158
|
+
valid_tags[name] = option
|
|
159
|
+
return valid_tags
|
|
122
160
|
|
|
123
161
|
|
|
124
|
-
def
|
|
162
|
+
def _reformat_codeblock_tags(tags: list[dict], codeblock_type: str, codeblock_action: str, applied_tags: dict[str, str]):
|
|
125
163
|
"""
|
|
126
|
-
Turns
|
|
164
|
+
Turns tag objects into DiamondFire formatted tag items
|
|
127
165
|
"""
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
newTagItem = {
|
|
166
|
+
|
|
167
|
+
def format_tag(option: str, name: str):
|
|
168
|
+
return {
|
|
132
169
|
'item': {
|
|
133
170
|
'id': 'bl_tag',
|
|
134
|
-
'data': {
|
|
135
|
-
'option': tagItem['option'],
|
|
136
|
-
'tag': tagItem['tag'],
|
|
137
|
-
'action': actionValue,
|
|
138
|
-
'block': codeblockType
|
|
139
|
-
}
|
|
171
|
+
'data': {'option': option, 'tag': name, 'action': codeblock_action, 'block': codeblock_type}
|
|
140
172
|
},
|
|
141
|
-
'slot':
|
|
173
|
+
'slot': tag_item['slot']
|
|
142
174
|
}
|
|
143
|
-
reformattedTags.append(newTagItem)
|
|
144
|
-
return reformattedTags
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def _getCodeblockTags(codeblockType: str, codeblockName: str):
|
|
148
|
-
"""
|
|
149
|
-
Get tags for the specified codeblock type and name
|
|
150
|
-
"""
|
|
151
|
-
tags = None
|
|
152
|
-
if codeblockType in TAGDATA_EXTRAS_KEYS:
|
|
153
|
-
tags = TAGDATA['extras'][codeblockType]
|
|
154
|
-
else:
|
|
155
|
-
tags = TAGDATA[codeblockType].get(codeblockName)
|
|
156
|
-
return _reformatCodeblockTags(tags, codeblockType, codeblockName)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def _buildBlock(codeblock: CodeBlock, includeTags: bool):
|
|
160
|
-
"""
|
|
161
|
-
Builds a properly formatted block from a CodeBlock object.
|
|
162
|
-
"""
|
|
163
|
-
finalBlock = codeblock.data.copy()
|
|
164
|
-
codeblockType = codeblock.data.get('block')
|
|
165
|
-
|
|
166
|
-
# add target if necessary ('Selection' is the default when 'target' is blank)
|
|
167
|
-
if codeblockType in TARGET_CODEBLOCKS and codeblock.target != DEFAULT_TARGET:
|
|
168
|
-
finalBlock['target'] = codeblock.target.getStringValue()
|
|
169
175
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if
|
|
176
|
-
|
|
177
|
-
elif includeTags:
|
|
178
|
-
tags = _getCodeblockTags(codeblockType, codeblock.name)
|
|
179
|
-
if len(finalArgs) + len(tags) > 27:
|
|
180
|
-
finalArgs = finalArgs[:(27-len(tags))] # trim list if over 27 elements
|
|
181
|
-
finalArgs.extend(tags) # add tags to end
|
|
182
|
-
|
|
183
|
-
finalBlock['args'] = {'items': finalArgs}
|
|
184
|
-
return finalBlock
|
|
176
|
+
valid_applied_tags = _check_applied_tags(tags, applied_tags, codeblock_action)
|
|
177
|
+
reformatted_tags = []
|
|
178
|
+
for tag_item in tags:
|
|
179
|
+
tag_name = tag_item['name']
|
|
180
|
+
tag_option = tag_item['default']
|
|
181
|
+
if tag_name in valid_applied_tags:
|
|
182
|
+
tag_option = valid_applied_tags[tag_name]
|
|
185
183
|
|
|
184
|
+
new_tag_item = format_tag(tag_option, tag_name)
|
|
185
|
+
reformatted_tags.append(new_tag_item)
|
|
186
|
+
return reformatted_tags
|
|
186
187
|
|
|
187
|
-
|
|
188
|
+
|
|
189
|
+
def _get_codeblock_tags(codeblock_type: str, codeblock_name: str, applied_tags: dict[str, str]):
|
|
188
190
|
"""
|
|
189
|
-
|
|
191
|
+
Get tags for the specified codeblock type and name
|
|
190
192
|
"""
|
|
191
|
-
|
|
192
|
-
|
|
193
|
+
action_data = CODEBLOCK_DATA[codeblock_type][codeblock_name]
|
|
194
|
+
if 'deprecatedNote' in action_data:
|
|
195
|
+
warn(f'Action "{codeblock_name}" is deprecated: {action_data["deprecatedNote"]}')
|
|
196
|
+
tags = action_data['tags']
|
|
197
|
+
return _reformat_codeblock_tags(tags, codeblock_type, codeblock_name, applied_tags)
|
|
193
198
|
|
|
194
199
|
|
|
195
|
-
def
|
|
200
|
+
def _get_template_item(template_code: str, name: str, author: str) -> NbtItem:
|
|
196
201
|
now = datetime.datetime.now()
|
|
197
202
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
203
|
+
template_item = NbtItem('yellow_shulker_box')
|
|
204
|
+
template_item.set_name(f'&x&f&f&5&c&0&0>> &x&f&f&c&7&0&0{name}')
|
|
205
|
+
template_item.set_lore([
|
|
201
206
|
f'&8Author: {author}',
|
|
202
207
|
f'&8Date: {now.strftime("%Y-%m-%d")}',
|
|
203
208
|
'',
|
|
@@ -205,275 +210,386 @@ def getTemplateItem(templateCode: str, name: str, author: str) -> NbtItem:
|
|
|
205
210
|
'&7https://github.com/Amp63/pyre'
|
|
206
211
|
])
|
|
207
212
|
|
|
208
|
-
|
|
209
|
-
'hypercube:codetemplatedata': f'{{"author":"{author}","name":"{name}","version": 1,"code":"{
|
|
213
|
+
pbv_tag = {
|
|
214
|
+
'hypercube:codetemplatedata': f'{{"author":"{author}","name":"{name}","version": 1,"code":"{template_code}"}}',
|
|
210
215
|
'hypercube:pyre_creation_timestamp': now.timestamp()
|
|
211
216
|
}
|
|
212
|
-
|
|
217
|
+
template_item.set_custom_data('PublicBukkitValues', pbv_tag, raw=True)
|
|
213
218
|
|
|
214
|
-
return
|
|
219
|
+
return template_item
|
|
215
220
|
|
|
216
221
|
|
|
217
|
-
|
|
222
|
+
class DFTemplate:
|
|
218
223
|
"""
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
:param str templateCode: The code for the template as a base64 string.
|
|
222
|
-
:param str name: The name of the template.
|
|
223
|
-
:param str author: The author of the template.
|
|
224
|
-
|
|
225
|
-
:return: status code
|
|
226
|
-
- `0` = Success
|
|
227
|
-
- `1` = Connection refused
|
|
228
|
-
- `2` = Other socket error
|
|
224
|
+
Represents a DiamondFire code template.
|
|
229
225
|
"""
|
|
226
|
+
def __init__(self, codeblocks: list[CodeBlock], author: str='pyre'):
|
|
227
|
+
self.codeblocks = codeblocks
|
|
228
|
+
self.author = author
|
|
230
229
|
|
|
231
|
-
templateItem = getTemplateItem(templateCode, name, author)
|
|
232
|
-
data = {'type': 'nbt', 'source': f'pyre Template - {name}', 'data': templateItem.get_nbt()}
|
|
233
|
-
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
234
|
-
try:
|
|
235
|
-
s.connect(('127.0.0.1', 31372))
|
|
236
|
-
except ConnectionRefusedError:
|
|
237
|
-
print(f"""{COL_ERROR}Could not connect to recode item API. Possible problems:
|
|
238
|
-
- Minecraft is not open
|
|
239
|
-
- Recode is not installed (get it here: https://modrinth.com/mod/recode or join the discord here: https://discord.gg/GWxWtcwA2C){COL_RESET}""")
|
|
240
|
-
s.close()
|
|
241
|
-
return 1
|
|
242
|
-
|
|
243
|
-
s.send((str(data) + '\n').encode('utf-8'))
|
|
244
|
-
received = json.loads(s.recv(1024).decode())
|
|
245
|
-
status = received['status']
|
|
246
|
-
s.close()
|
|
247
|
-
time.sleep(0.5)
|
|
248
|
-
|
|
249
|
-
if status == 'success':
|
|
250
|
-
print(f'{COL_SUCCESS}Template sent to client successfully.{COL_RESET}')
|
|
251
|
-
return 0
|
|
252
|
-
error = received['error']
|
|
253
|
-
print(f'{COL_ERROR}Error sending template: {error}{COL_RESET}')
|
|
254
|
-
return 2
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
def sendCodeClient(templateCode: str, name: str='Unnamed Template', author: str='pyre') -> int:
|
|
258
|
-
try:
|
|
259
|
-
ws = websocket.WebSocket()
|
|
260
|
-
ws.connect(CODECLIENT_URL)
|
|
261
|
-
print(f'{COL_SUCCESS}Connected. {COL_WARN}Please run /auth in game.{COL_RESET}')
|
|
262
|
-
|
|
263
|
-
ws.recv() # auth response
|
|
264
230
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
231
|
+
def _get_template_name(self):
|
|
232
|
+
first_block_data = self.codeblocks[0].data
|
|
233
|
+
if 'data' in first_block_data:
|
|
234
|
+
name = first_block_data['data']
|
|
235
|
+
return name if name else 'Unnamed Template'
|
|
236
|
+
return first_block_data['block'] + '_' + first_block_data['action']
|
|
269
237
|
|
|
270
|
-
print(f'{COL_SUCCESS}Template sent to client successfully.{COL_RESET}')
|
|
271
|
-
return 0
|
|
272
|
-
|
|
273
|
-
except Exception as e:
|
|
274
|
-
if isinstance(e, ConnectionRefusedError):
|
|
275
|
-
print(f'{COL_ERROR}Could not connect to CodeClient API. Possible problems:')
|
|
276
|
-
print(f' - Minecraft is not open')
|
|
277
|
-
print(f' - CodeClient is not installed (get it here: https://modrinth.com/mod/codeclient)')
|
|
278
|
-
print(f' - CodeClient API is not enabled (enable it in CodeClient general settings)')
|
|
279
|
-
return 1
|
|
280
|
-
|
|
281
|
-
print(f'Connection failed: {e}')
|
|
282
|
-
return 2
|
|
283
238
|
|
|
239
|
+
def __repr__(self) -> str:
|
|
240
|
+
return f'DFTemplate(name: "{self._get_template_name()}", author: "{self.author}", codeblocks: {len(self.codeblocks)})'
|
|
284
241
|
|
|
285
|
-
class DFTemplate:
|
|
286
|
-
"""
|
|
287
|
-
Represents a DiamondFire code template.
|
|
288
|
-
"""
|
|
289
|
-
def __init__(self, name: str=None, author: str='pyre'):
|
|
290
|
-
self.codeBlocks: List[CodeBlock] = []
|
|
291
|
-
self.closebracket = None
|
|
292
|
-
self.name = name
|
|
293
|
-
self.author = author
|
|
294
242
|
|
|
243
|
+
@staticmethod
|
|
244
|
+
def from_code(template_code: str):
|
|
245
|
+
"""
|
|
246
|
+
Create a template object from an existing template code.
|
|
247
|
+
"""
|
|
248
|
+
template_dict = json.loads(df_decode(template_code))
|
|
249
|
+
codeblocks: list[CodeBlock] = []
|
|
250
|
+
for block_dict in template_dict['blocks']:
|
|
251
|
+
block_tags = get_default_tags(block_dict.get('block'), block_dict.get('action'))
|
|
252
|
+
if 'args' in block_dict:
|
|
253
|
+
block_args = []
|
|
254
|
+
for item_dict in block_dict['args']['items']:
|
|
255
|
+
if item_dict['item'].get('id') == 'bl_tag':
|
|
256
|
+
tag_data = item_dict['item']['data']
|
|
257
|
+
block_tags[tag_data['tag']] = tag_data['option']
|
|
258
|
+
parsed_item = item_from_dict(item_dict['item'])
|
|
259
|
+
if parsed_item is not None:
|
|
260
|
+
block_args.append(parsed_item)
|
|
261
|
+
block_target = Target(TARGETS.index(block_dict['target'])) if 'target' in block_dict else DEFAULT_TARGET
|
|
262
|
+
|
|
263
|
+
codeblock_type = block_dict.get('block')
|
|
264
|
+
|
|
265
|
+
if codeblock_type is None:
|
|
266
|
+
codeblock = CodeBlock.new_bracket(block_dict['direct'], block_dict['type'])
|
|
267
|
+
if codeblock_type == 'else':
|
|
268
|
+
codeblock = CodeBlock.new_else()
|
|
269
|
+
elif codeblock_type in DYNAMIC_CODEBLOCKS:
|
|
270
|
+
codeblock = CodeBlock.new_data(codeblock_type, block_dict['data'], block_args, block_tags)
|
|
271
|
+
elif 'action' in block_dict:
|
|
272
|
+
codeblock = CodeBlock.new_action(codeblock_type, block_dict['action'], block_args, block_tags, block_target)
|
|
273
|
+
codeblocks.append(codeblock)
|
|
274
|
+
|
|
275
|
+
return DFTemplate(codeblocks)
|
|
295
276
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
277
|
+
|
|
278
|
+
def insert(self, insert_codeblocks: CodeBlock|list[CodeBlock], index: int=-1) -> "DFTemplate":
|
|
279
|
+
"""
|
|
280
|
+
Insert `insert_codeblocks` into this template at `index`.
|
|
281
|
+
|
|
282
|
+
:param CodeBlock|list[CodeBlock] insert_codeblocks: The block(s) to insert
|
|
283
|
+
:param int index: The index to insert at.
|
|
284
|
+
:return: self
|
|
285
|
+
"""
|
|
286
|
+
if isinstance(insert_codeblocks, list):
|
|
287
|
+
insert_codeblocks = list(flatten(insert_codeblocks))
|
|
288
|
+
if index == -1:
|
|
289
|
+
self.codeblocks.extend(insert_codeblocks)
|
|
290
|
+
else:
|
|
291
|
+
self.codeblocks[index:index+len(insert_codeblocks)] = insert_codeblocks
|
|
292
|
+
elif isinstance(insert_codeblocks, CodeBlock):
|
|
293
|
+
self.codeblocks.insert(index, insert_codeblocks)
|
|
303
294
|
else:
|
|
304
|
-
|
|
295
|
+
raise PyreException('Expected CodeBlock or list[CodeBlock] to insert.')
|
|
296
|
+
return self
|
|
305
297
|
|
|
306
298
|
|
|
307
|
-
def build(self,
|
|
299
|
+
def build(self, include_tags: bool=True) -> str:
|
|
308
300
|
"""
|
|
309
301
|
Build this template.
|
|
310
302
|
|
|
311
|
-
:param bool
|
|
303
|
+
:param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
|
|
312
304
|
:return: String containing encoded template data.
|
|
313
305
|
"""
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
print(f'{COL_SUCCESS}Template built successfully.{COL_RESET}')
|
|
323
|
-
|
|
324
|
-
jsonString = json.dumps(templateDict, separators=(',', ':'))
|
|
325
|
-
return _dfEncode(jsonString)
|
|
306
|
+
template_dict_blocks = [codeblock.build(include_tags) for codeblock in self.codeblocks]
|
|
307
|
+
template_dict = {'blocks': template_dict_blocks}
|
|
308
|
+
first_block = template_dict_blocks[0]
|
|
309
|
+
if first_block['block'] not in TEMPLATE_STARTERS:
|
|
310
|
+
warn('Template does not start with an event, function, or process.')
|
|
311
|
+
|
|
312
|
+
json_string = json.dumps(template_dict, separators=(',', ':'))
|
|
313
|
+
return df_encode(json_string)
|
|
326
314
|
|
|
327
315
|
|
|
328
|
-
def
|
|
316
|
+
def build_and_send(self, method: Literal['recode', 'codeclient'], include_tags: bool=True) -> int:
|
|
329
317
|
"""
|
|
330
318
|
Builds this template and sends it to DiamondFire automatically.
|
|
331
319
|
|
|
332
|
-
:param bool
|
|
320
|
+
:param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
|
|
333
321
|
"""
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if sendMethod == 'codeclient':
|
|
338
|
-
return sendCodeClient(templateCode, name=self.name, author=self.author)
|
|
339
|
-
return -1
|
|
322
|
+
template_code = self.build(include_tags)
|
|
323
|
+
template_item = _get_template_item(template_code, self._get_template_name(), self.author)
|
|
324
|
+
return template_item.send_to_minecraft(method, 'pyre')
|
|
340
325
|
|
|
341
|
-
|
|
342
|
-
def
|
|
326
|
+
|
|
327
|
+
def generate_script(self, output_path: str, indent_size: int=4, literal_shorthand: bool=True, var_shorthand: bool=False):
|
|
343
328
|
"""
|
|
344
|
-
|
|
329
|
+
Generate an equivalent python script for this template.
|
|
330
|
+
|
|
331
|
+
:param str output_path: The file path to write the script to.
|
|
332
|
+
:param int indent_size: The multiple of spaces to add when indenting lines.
|
|
333
|
+
:param bool literal_shorthand: If True, `text` and `num` items will be written as strings and ints respectively.
|
|
334
|
+
:param bool var_shorthand: If True, all variables will be written using variable shorthand.
|
|
345
335
|
"""
|
|
346
|
-
|
|
347
|
-
|
|
336
|
+
flags = GeneratorFlags(indent_size, literal_shorthand, var_shorthand)
|
|
337
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
|
338
|
+
f.write(generate_script(self, flags))
|
|
348
339
|
|
|
349
|
-
def _openbracket(self, btype: Literal['norm', 'repeat']='norm'):
|
|
350
|
-
bracket = CodeBlock('Bracket', data={'id': 'bracket', 'direct': 'open', 'type': btype})
|
|
351
|
-
self.codeBlocks.append(bracket)
|
|
352
|
-
self.closebracket = btype
|
|
353
|
-
|
|
354
340
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
341
|
+
def _assemble_template(starting_block: CodeBlock, codeblocks: list[CodeBlock], author: str|None) -> DFTemplate:
|
|
342
|
+
"""
|
|
343
|
+
Create a DFTemplate object from a starting block and a list of codeblocks.
|
|
344
|
+
`codeblocks` can contain nested lists of CodeBlock objects, so it must be flattened.
|
|
345
|
+
"""
|
|
346
|
+
if author is None:
|
|
347
|
+
author = 'pyre'
|
|
348
|
+
template_codeblocks = [starting_block] + list(flatten(codeblocks)) # flatten codeblocks list and insert starting block
|
|
349
|
+
return DFTemplate(template_codeblocks, author)
|
|
360
350
|
|
|
361
|
-
def entityEvent(self, name: str):
|
|
362
|
-
cmd = CodeBlock(name, data={'id': 'block', 'block': 'entity_event', 'action': name})
|
|
363
|
-
self.codeBlocks.append(cmd)
|
|
364
|
-
|
|
365
351
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
self.codeBlocks.append(cmd)
|
|
370
|
-
|
|
352
|
+
def player_event(event_name: str, codeblocks: list[CodeBlock]=(), author: str|None=None) -> DFTemplate:
|
|
353
|
+
"""
|
|
354
|
+
Represents a Player Event codeblock.
|
|
371
355
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
356
|
+
:param str event_name: The name of the event. (Ex: "Join")
|
|
357
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks in this template.
|
|
358
|
+
:param str|None author: The author of this template.
|
|
359
|
+
"""
|
|
360
|
+
starting_block = CodeBlock.new_action('event', event_name, (), {})
|
|
361
|
+
return _assemble_template(starting_block, codeblocks, author)
|
|
376
362
|
|
|
377
|
-
def callFunction(self, name: str, *args):
|
|
378
|
-
args = _convertDataTypes(args)
|
|
379
|
-
cmd = CodeBlock('call_func', args, data={'id': 'block', 'block': 'call_func', 'data': name})
|
|
380
|
-
self.codeBlocks.append(cmd)
|
|
381
|
-
|
|
382
363
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
364
|
+
def entity_event(event_name: str, codeblocks: list[CodeBlock]=[], author: str|None=None) -> DFTemplate:
|
|
365
|
+
"""
|
|
366
|
+
Represents an Entity Event codeblock.
|
|
386
367
|
|
|
368
|
+
:param str event_name: The name of the event. (Ex: "EntityDmg")
|
|
369
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks in this template.
|
|
370
|
+
:param str|None author: The author of this template.
|
|
371
|
+
"""
|
|
372
|
+
starting_block = CodeBlock.new_action('entity_event', event_name, (), {})
|
|
373
|
+
return _assemble_template(starting_block, codeblocks, author)
|
|
387
374
|
|
|
388
|
-
def playerAction(self, name: str, *args, target: Target=DEFAULT_TARGET):
|
|
389
|
-
args = _convertDataTypes(args)
|
|
390
|
-
cmd = CodeBlock(name, args, target=target, data={'id': 'block', 'block': 'player_action', 'action': name})
|
|
391
|
-
self.codeBlocks.append(cmd)
|
|
392
|
-
|
|
393
375
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
self.codeBlocks.append(cmd)
|
|
398
|
-
|
|
376
|
+
def function(function_name: str, *args, tags: dict[str, str]={}, codeblocks: list[CodeBlock]=[], author: str|None=None) -> DFTemplate:
|
|
377
|
+
"""
|
|
378
|
+
Represents a Function codeblock.
|
|
399
379
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
380
|
+
:param str event_name: The name of the function.
|
|
381
|
+
:param tuple args: The argument items to include.
|
|
382
|
+
:param dict[str, str] tags: The tags to include.
|
|
383
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks in this template.
|
|
384
|
+
:param str|None author: The author of this template.
|
|
385
|
+
"""
|
|
386
|
+
starting_block = CodeBlock.new_data('func', function_name, args, tags)
|
|
387
|
+
return _assemble_template(starting_block, codeblocks, author)
|
|
405
388
|
|
|
406
|
-
def ifPlayer(self, name: str, *args, target: Target=DEFAULT_TARGET, inverted: bool=False):
|
|
407
|
-
args = _convertDataTypes(args)
|
|
408
|
-
data = {'id': 'block', 'block': 'if_player', 'action': name}
|
|
409
|
-
_addInverted(data, inverted)
|
|
410
|
-
cmd = CodeBlock(name, args, target=target, data=data)
|
|
411
|
-
self.codeBlocks.append(cmd)
|
|
412
|
-
self._openbracket()
|
|
413
|
-
|
|
414
389
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
_addInverted(data, inverted)
|
|
419
|
-
cmd = CodeBlock(name, args, data=data)
|
|
420
|
-
self.codeBlocks.append(cmd)
|
|
421
|
-
self._openbracket()
|
|
422
|
-
|
|
390
|
+
def process(process_name: str, *args, tags: dict[str, str]={}, codeblocks: list[CodeBlock]=[], author: str|None=None) -> DFTemplate:
|
|
391
|
+
"""
|
|
392
|
+
Represents a Process codeblock.
|
|
423
393
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
394
|
+
:param str event_name: The name of the process.
|
|
395
|
+
:param tuple args: The argument items to include.
|
|
396
|
+
:param dict[str, str] tags: The tags to include.
|
|
397
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks in this template.
|
|
398
|
+
:param str|None author: The author of this template.
|
|
399
|
+
"""
|
|
400
|
+
starting_block = CodeBlock.new_data('process', process_name, args, tags)
|
|
401
|
+
return _assemble_template(starting_block, codeblocks, author)
|
|
432
402
|
|
|
433
|
-
def ifEntity(self, name: str, *args, target: Target=DEFAULT_TARGET, inverted: bool=False):
|
|
434
|
-
args = _convertDataTypes(args)
|
|
435
|
-
data = {'id': 'block', 'block': 'if_entity', 'action': name}
|
|
436
|
-
_addInverted(data, inverted)
|
|
437
|
-
cmd = CodeBlock(name, args, target=target, data=data)
|
|
438
|
-
self.codeBlocks.append(cmd)
|
|
439
|
-
self._openbracket()
|
|
440
403
|
|
|
404
|
+
def call_function(function_name: str, *args) -> CodeBlock:
|
|
405
|
+
"""
|
|
406
|
+
Represents a Call Function codeblock.
|
|
441
407
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
408
|
+
:param str event_name: The name of the function.
|
|
409
|
+
:param tuple args: The argument items to include.
|
|
410
|
+
"""
|
|
411
|
+
return CodeBlock.new_data('call_func', function_name, args, {})
|
|
447
412
|
|
|
448
|
-
def repeat(self, name: str, *args, subAction: str=None):
|
|
449
|
-
args = _convertDataTypes(args)
|
|
450
|
-
data = {'id': 'block', 'block': 'repeat', 'action': name}
|
|
451
|
-
if subAction is not None:
|
|
452
|
-
data['subAction'] = subAction
|
|
453
|
-
cmd = CodeBlock(name, args, data=data)
|
|
454
|
-
self.codeBlocks.append(cmd)
|
|
455
|
-
self._openbracket('repeat')
|
|
456
413
|
|
|
414
|
+
def start_process(process_name: str, *args, tags: dict[str, str]={}) -> CodeBlock:
|
|
415
|
+
"""
|
|
416
|
+
Represents a Call Function codeblock.
|
|
457
417
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
418
|
+
:param str event_name: The name of the function.
|
|
419
|
+
:param tuple args: The argument items to include.
|
|
420
|
+
"""
|
|
421
|
+
return CodeBlock.new_data('start_process', process_name, args, tags)
|
|
463
422
|
|
|
464
|
-
def control(self, name: str, *args):
|
|
465
|
-
args = _convertDataTypes(args)
|
|
466
|
-
cmd = CodeBlock(name, args, data={'id': 'block', 'block': 'control', 'action': name})
|
|
467
|
-
self.codeBlocks.append(cmd)
|
|
468
|
-
|
|
469
423
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
424
|
+
def player_action(action_name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}) -> CodeBlock:
|
|
425
|
+
"""
|
|
426
|
+
Represents a Player Action codeblock.
|
|
427
|
+
|
|
428
|
+
:param str action_name: The name of the action.
|
|
429
|
+
:param tuple args: The argument items to include.
|
|
430
|
+
:param Target target: The target for the action.
|
|
431
|
+
:param dict[str, str] tags: The tags to include.
|
|
432
|
+
"""
|
|
433
|
+
return CodeBlock.new_action('player_action', action_name, args, tags, target=target)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def entity_action(action_name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}) -> CodeBlock:
|
|
437
|
+
"""
|
|
438
|
+
Represents an Entity Action codeblock.
|
|
439
|
+
|
|
440
|
+
:param str action_name: The name of the action.
|
|
441
|
+
:param tuple args: The argument items to include.
|
|
442
|
+
:param Target target: The target for the action.
|
|
443
|
+
:param dict[str, str] tags: The tags to include.
|
|
444
|
+
"""
|
|
445
|
+
return CodeBlock.new_action('entity_action', action_name, args, tags, target=target)
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def game_action(action_name: str, *args, tags: dict[str, str]={}) -> CodeBlock:
|
|
449
|
+
"""
|
|
450
|
+
Represents a Game Action codeblock.
|
|
451
|
+
|
|
452
|
+
:param str action_name: The name of the action.
|
|
453
|
+
:param tuple args: The argument items to include.
|
|
454
|
+
:param dict[str, str] tags: The tags to include.
|
|
455
|
+
"""
|
|
456
|
+
return CodeBlock.new_action('game_action', action_name, args, tags)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def if_player(action_name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, inverted: bool=False, codeblocks: list[CodeBlock]=[]) -> list[CodeBlock]:
|
|
460
|
+
"""
|
|
461
|
+
Represents an If Player codeblock.
|
|
462
|
+
|
|
463
|
+
:param str action_name: The name of the condition.
|
|
464
|
+
:param tuple args: The argument items to include.
|
|
465
|
+
:param Target target: The target for the condition.
|
|
466
|
+
:param dict[str, str] tags: The tags to include.
|
|
467
|
+
:param bool inverted: Whether the condition should be inverted.
|
|
468
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks inside the brackets.
|
|
469
|
+
"""
|
|
470
|
+
return [
|
|
471
|
+
CodeBlock.new_conditional('if_player', action_name, args, tags, inverted, target),
|
|
472
|
+
CodeBlock.new_bracket('open', 'norm')
|
|
473
|
+
] + list(codeblocks) + [
|
|
474
|
+
CodeBlock.new_bracket('close', 'norm')
|
|
475
|
+
]
|
|
476
|
+
|
|
477
|
+
def if_entity(action_name: str, *args, target: Target=DEFAULT_TARGET, tags: dict[str, str]={}, inverted: bool=False, codeblocks: list[CodeBlock]=[]) -> list[CodeBlock]:
|
|
478
|
+
"""
|
|
479
|
+
Represents an If Entity codeblock.
|
|
480
|
+
|
|
481
|
+
:param str action_name: The name of the condition.
|
|
482
|
+
:param tuple args: The argument items to include.
|
|
483
|
+
:param Target target: The target for the condition.
|
|
484
|
+
:param dict[str, str] tags: The tags to include.
|
|
485
|
+
:param bool inverted: Whether the condition should be inverted.
|
|
486
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks inside the brackets.
|
|
487
|
+
"""
|
|
488
|
+
return [
|
|
489
|
+
CodeBlock.new_conditional('if_entity', action_name, args, tags, inverted, target),
|
|
490
|
+
CodeBlock.new_bracket('open', 'norm')
|
|
491
|
+
] + list(codeblocks) + [
|
|
492
|
+
CodeBlock.new_bracket('close', 'norm')
|
|
493
|
+
]
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def if_game(action_name: str, *args, tags: dict[str, str]={}, inverted: bool=False, codeblocks: list[CodeBlock]=[]) -> list[CodeBlock]:
|
|
497
|
+
"""
|
|
498
|
+
Represents an If Game codeblock.
|
|
499
|
+
|
|
500
|
+
:param str action_name: The name of the condition.
|
|
501
|
+
:param tuple args: The argument items to include.
|
|
502
|
+
:param dict[str, str] tags: The tags to include.
|
|
503
|
+
:param bool inverted: Whether the condition should be inverted.
|
|
504
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks inside the brackets.
|
|
505
|
+
"""
|
|
506
|
+
return [
|
|
507
|
+
CodeBlock.new_conditional('if_game', action_name, args, tags, inverted),
|
|
508
|
+
CodeBlock.new_bracket('open', 'norm')
|
|
509
|
+
] + list(codeblocks) + [
|
|
510
|
+
CodeBlock.new_bracket('close', 'norm')
|
|
511
|
+
]
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def if_variable(action_name: str, *args, tags: dict[str, str]={}, inverted: bool=False, codeblocks: list[CodeBlock]=[]) -> list[CodeBlock]:
|
|
515
|
+
"""
|
|
516
|
+
Represents an If Variable codeblock.
|
|
517
|
+
|
|
518
|
+
:param str action_name: The name of the condition.
|
|
519
|
+
:param tuple args: The argument items to include.
|
|
520
|
+
:param dict[str, str] tags: The tags to include.
|
|
521
|
+
:param bool inverted: Whether the condition should be inverted.
|
|
522
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks inside the brackets.
|
|
523
|
+
"""
|
|
524
|
+
return [
|
|
525
|
+
CodeBlock.new_conditional('if_var', action_name, args, tags, inverted),
|
|
526
|
+
CodeBlock.new_bracket('open', 'norm')
|
|
527
|
+
] + list(codeblocks) + [
|
|
528
|
+
CodeBlock.new_bracket('close', 'norm')
|
|
529
|
+
]
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def else_(codeblocks: list[CodeBlock]=[]) -> list[CodeBlock]:
|
|
533
|
+
"""
|
|
534
|
+
Represents an Else codeblock.
|
|
535
|
+
|
|
536
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks inside the brackets.
|
|
537
|
+
"""
|
|
538
|
+
return [
|
|
539
|
+
CodeBlock.new_else(),
|
|
540
|
+
CodeBlock.new_bracket('open', 'norm')
|
|
541
|
+
] + list(codeblocks) + [
|
|
542
|
+
CodeBlock.new_bracket('close', 'norm')
|
|
543
|
+
]
|
|
475
544
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
545
|
+
|
|
546
|
+
def repeat(action_name: str, *args, tags: dict[str, str]={}, sub_action: str|None=None, inverted: bool=False, codeblocks: list[CodeBlock]=[]) -> CodeBlock:
|
|
547
|
+
"""
|
|
548
|
+
Represents a Repeat codeblock.
|
|
549
|
+
|
|
550
|
+
:param str action_name: The name of the action.
|
|
551
|
+
:param tuple args: The argument items to include.
|
|
552
|
+
:param dict[str, str] tags: The tags to include.
|
|
553
|
+
:param str|None sub_action: The sub-action for the repeat action (Only relevant for `While`)
|
|
554
|
+
:param bool inverted: Whether the sub-action condition should be inverted.
|
|
555
|
+
:param list[CodeBlock] codeblocks: The list of codeblocks inside the brackets.
|
|
556
|
+
"""
|
|
557
|
+
return [
|
|
558
|
+
CodeBlock.new_repeat(action_name, args, tags, sub_action, inverted),
|
|
559
|
+
CodeBlock.new_bracket('open', 'repeat')
|
|
560
|
+
] + list(codeblocks) + [
|
|
561
|
+
CodeBlock.new_bracket('close', 'repeat')
|
|
562
|
+
]
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def control(action_name: str, *args, tags: dict[str, str]={}) -> CodeBlock:
|
|
566
|
+
"""
|
|
567
|
+
Represents a Control codeblock.
|
|
568
|
+
|
|
569
|
+
:param str action_name: The name of the action.
|
|
570
|
+
:param tuple args: The argument items to include.
|
|
571
|
+
:param dict[str, str] tags: The tags to include.
|
|
572
|
+
"""
|
|
573
|
+
return CodeBlock.new_action('control', action_name, args, tags)
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def select_object(action_name: str, *args, tags: dict[str, str]={}) -> CodeBlock:
|
|
577
|
+
"""
|
|
578
|
+
Represents a Select Object codeblock.
|
|
579
|
+
|
|
580
|
+
:param str action_name: The name of the action.
|
|
581
|
+
:param tuple args: The argument items to include.
|
|
582
|
+
:param dict[str, str] tags: The tags to include.
|
|
583
|
+
"""
|
|
584
|
+
return CodeBlock.new_action('select_obj', action_name, args, tags)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def set_variable(action_name: str, *args, tags: dict[str, str]={}) -> CodeBlock:
|
|
588
|
+
"""
|
|
589
|
+
Represents a Set Variable codeblock.
|
|
590
|
+
|
|
591
|
+
:param str action_name: The name of the action.
|
|
592
|
+
:param tuple args: The argument items to include.
|
|
593
|
+
:param dict[str, str] tags: The tags to include.
|
|
594
|
+
"""
|
|
595
|
+
return CodeBlock.new_action('set_var', action_name, args, tags)
|