dfpyre 0.8.16__tar.gz → 0.8.18__tar.gz

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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dfpyre
3
- Version: 0.8.16
3
+ Version: 0.8.18
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
@@ -9,18 +9,26 @@ import websocket
9
9
  from mcitemlib.itemlib import Item as NbtItem, MCItemlibException
10
10
  from amulet_nbt import DoubleTag, StringTag, CompoundTag
11
11
  from dfpyre.style import is_ampersand_coded, ampersand_to_minimessage
12
- from dfpyre.util import PyreException, warn, COL_SUCCESS, COL_ERROR, COL_RESET
12
+ from dfpyre.util import PyreException, warn, is_number, COL_SUCCESS, COL_ERROR, COL_RESET
13
13
  from dfpyre.action_literals import GAME_VALUE_NAME, SOUND_NAME, POTION_NAME
14
14
 
15
15
 
16
- NUMBER_REGEX = r'^-?\d*\.?\d+$'
16
+ VAR_ITEM_TYPES = [
17
+ 'String', 'Str', 'Text', 'Number', 'Num', 'Item', 'Location', 'Loc',
18
+ 'Variable', 'Var', 'Sound', 'Snd', 'Particle', 'Potion', 'Pot', 'GameValue',
19
+ 'Vector', 'Vec', 'ParameterType', 'Parameter'
20
+ ]
21
+
22
+ __all__ = ['convert_literals', 'item_from_dict', 'VAR_ITEM_TYPES'] + VAR_ITEM_TYPES
23
+
24
+
17
25
  VAR_SHORTHAND_REGEX = r'^\$([gsli]) (.+)$'
18
26
  VAR_SCOPES = {'g': 'unsaved', 's': 'saved', 'l': 'local', 'i': 'line'}
19
27
 
20
28
  CODECLIENT_URL = 'ws://localhost:31375'
21
29
 
22
30
 
23
- def convert_argument(arg: Any):
31
+ def convert_literals(arg: Any):
24
32
  if type(arg) in {int, float}:
25
33
  return Number(arg)
26
34
  elif isinstance(arg, str):
@@ -420,7 +428,7 @@ class Parameter:
420
428
  self.optional = optional
421
429
  self.description = description
422
430
  self.note = note
423
- self.default_value = convert_argument(default_value)
431
+ self.default_value = convert_literals(default_value)
424
432
  self.slot = slot
425
433
 
426
434
  def format(self, slot: int):
@@ -473,7 +481,7 @@ class _Tag:
473
481
  return f'{self.__class__.__name__}({self.tag_data})'
474
482
 
475
483
 
476
- def item_from_dict(item_dict: dict, preserve_item_slots: bool) -> Any:
484
+ def item_from_dict(item_dict: dict, preserve_item_slots: bool):
477
485
  item_id = item_dict['item']['id']
478
486
  item_data = item_dict['item']['data']
479
487
  item_slot = item_dict['slot'] if preserve_item_slots else None
@@ -491,7 +499,7 @@ def item_from_dict(item_dict: dict, preserve_item_slots: bool) -> Any:
491
499
 
492
500
  elif item_id == 'num':
493
501
  num_value = item_data['name']
494
- if re.match(NUMBER_REGEX, num_value):
502
+ if is_number(num_value):
495
503
  num_value = float(item_data['name'])
496
504
  if num_value % 1 == 0:
497
505
  num_value = int(num_value)
@@ -7,13 +7,20 @@ By Amp
7
7
  import json
8
8
  from difflib import get_close_matches
9
9
  import datetime
10
+ import platform
10
11
  from enum import Enum
11
- from amulet_nbt import CompoundTag
12
- from dfpyre.util import *
12
+ from amulet_nbt import CompoundTag, StringTag, DoubleTag
13
+ from dfpyre.util import df_encode, df_decode, flatten
13
14
  from dfpyre.items import *
14
- from dfpyre.scriptgen import generate_script, GeneratorFlags
15
15
  from dfpyre.actiondump import CODEBLOCK_DATA, get_default_tags
16
16
  from dfpyre.action_literals import *
17
+ from dfpyre.scriptgen import generate_script, GeneratorFlags
18
+
19
+ __all__ = [
20
+ 'Target', 'CodeBlock', 'DFTemplate',
21
+ 'player_event', 'entity_event', 'function', 'process', 'call_function', 'start_process', 'player_action', 'game_action',
22
+ 'entity_action', 'if_player', 'if_variable', 'if_game', 'if_entity', 'else_', 'repeat', 'control', 'select_object', 'set_variable'
23
+ ] + VAR_ITEM_TYPES
17
24
 
18
25
 
19
26
  VARIABLE_TYPES = {'txt', 'comp', 'num', 'item', 'loc', 'var', 'snd', 'part', 'pot', 'g_val', 'vec', 'pn_el', 'bl_tag'}
@@ -25,6 +32,8 @@ TARGET_CODEBLOCKS = {'player_action', 'entity_action', 'if_player', 'if_entity'}
25
32
 
26
33
  CODECLIENT_URL = 'ws://localhost:31375'
27
34
 
35
+ DATE_FORMAT_STR = "%b %#d, %Y" if platform.system() == "Windows" else "%b %-d, %Y"
36
+
28
37
 
29
38
  class Target(Enum):
30
39
  SELECTION = 0
@@ -46,7 +55,7 @@ DEFAULT_TARGET = Target.SELECTION
46
55
 
47
56
 
48
57
  def _convert_args(args):
49
- return tuple(map(convert_argument, args))
58
+ return tuple(map(convert_literals, args))
50
59
 
51
60
 
52
61
  class CodeBlock:
@@ -106,7 +115,7 @@ class CodeBlock:
106
115
  return f'CodeBlock(bracket, {self.data["type"]}, {self.data["direct"]})'
107
116
 
108
117
 
109
- def build(self, include_tags: bool=True) -> dict:
118
+ def build(self) -> dict:
110
119
  """
111
120
  Builds a properly formatted block from a CodeBlock object.
112
121
  """
@@ -125,16 +134,15 @@ class CodeBlock:
125
134
  if self.action_name not in CODEBLOCK_DATA[self.type]:
126
135
  _warn_unrecognized_name(self.type, self.action_name)
127
136
 
128
- elif include_tags:
129
- tags = _get_codeblock_tags(self.type, self.action_name, self.tags)
130
- for i, tag_data in enumerate(tags):
131
- already_applied_tag_data = already_applied_tags.get(tag_data['item']['data']['tag'])
132
- if already_applied_tag_data is not None:
133
- tags[i] = already_applied_tag_data
134
-
135
- if len(final_args) + len(tags) > 27:
136
- final_args = final_args[:(27-len(tags))] # trim list if over 27 elements
137
- final_args.extend(tags) # add tags to end
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
138
146
 
139
147
  built_block['args'] = {'items': final_args}
140
148
  return built_block
@@ -205,30 +213,6 @@ def _get_codeblock_tags(codeblock_type: str, codeblock_name: str, applied_tags:
205
213
  return _reformat_codeblock_tags(tags, codeblock_type, codeblock_name, applied_tags)
206
214
 
207
215
 
208
- def _generate_template_item(template_code: str, name: str, author: str) -> Item:
209
- now = datetime.datetime.now()
210
-
211
- template_item = Item('yellow_shulker_box')
212
- template_item.set_name(f'&x&f&f&5&c&0&0>> &x&f&f&c&7&0&0{name}')
213
- template_item.set_lore([
214
- f'&8Author: {author}',
215
- f'&8Date: {now.strftime("%Y-%m-%d")}',
216
- '',
217
- '&7This template was generated by &6pyre&7.',
218
- '&7https://github.com/Amp63/pyre'
219
- ])
220
-
221
- custom_data_tag = CompoundTag({
222
- 'PublicBukkitValues': CompoundTag({
223
- 'hypercube:codetemplatedata': StringTag(f'{{"author":"{author}","name":"{name}","version": 1,"code":"{template_code}"}}'),
224
- 'hypercube:pyre_creation_timestamp': DoubleTag(now.timestamp())
225
- })
226
- })
227
- template_item.set_component('minecraft:custom_data', custom_data_tag)
228
-
229
- return template_item
230
-
231
-
232
216
  class DFTemplate:
233
217
  """
234
218
  Represents a DiamondFire code template.
@@ -251,12 +235,13 @@ class DFTemplate:
251
235
 
252
236
 
253
237
  @staticmethod
254
- def from_code(template_code: str, preserve_item_slots: bool=True):
238
+ def from_code(template_code: str, preserve_item_slots: bool=True, author: str='pyre'):
255
239
  """
256
240
  Create a template object from an existing template code.
257
241
 
258
242
  :param str template_code: The base64 string to create a template from.
259
243
  :param bool preserve_item_slots: If True, the positions of items within chests will be saved.
244
+ :param str author: The author of this template.
260
245
  """
261
246
  template_dict = json.loads(df_decode(template_code))
262
247
  codeblocks: list[CodeBlock] = []
@@ -285,14 +270,41 @@ class DFTemplate:
285
270
  codeblock = CodeBlock.new_action(codeblock_type, block_dict['action'], block_args, block_tags, block_target)
286
271
  codeblocks.append(codeblock)
287
272
 
288
- return DFTemplate(codeblocks)
273
+ return DFTemplate(codeblocks, author)
274
+
275
+
276
+ def generate_template_item(self) -> Item:
277
+ template_code = self.build()
278
+
279
+ now = datetime.datetime.now()
280
+ name = self._get_template_name()
281
+
282
+ template_item = Item('yellow_shulker_box')
283
+ template_item.set_name(f'&x&f&f&5&c&0&0>> &x&f&f&c&7&0&0{name}')
284
+ template_item.set_lore([
285
+ f'&8Author: {self.author}',
286
+ f'&8Date: {now.strftime(DATE_FORMAT_STR)}',
287
+ '',
288
+ '&7This template was generated by &6pyre&7.',
289
+ '&7https://github.com/Amp63/pyre'
290
+ ])
291
+
292
+ custom_data_tag = CompoundTag({
293
+ 'PublicBukkitValues': CompoundTag({
294
+ 'hypercube:codetemplatedata': StringTag(f'{{"author":"{self.author}","name":"{name}","version": 1,"code":"{template_code}"}}'),
295
+ 'hypercube:pyre_creation_timestamp': DoubleTag(now.timestamp())
296
+ })
297
+ })
298
+ template_item.set_component('minecraft:custom_data', custom_data_tag)
299
+
300
+ return template_item
289
301
 
290
302
 
291
- def insert(self, insert_codeblocks: CodeBlock|list[CodeBlock], index: int=-1) -> "DFTemplate":
303
+ def insert(self, insert_codeblocks: CodeBlock|list[CodeBlock], index: int=-1):
292
304
  """
293
305
  Insert `insert_codeblocks` into this template at `index`.
294
306
 
295
- :param CodeBlock|list[CodeBlock] insert_codeblocks: The block(s) to insert
307
+ :param CodeBlock|list[CodeBlock] insert_codeblocks: The block(s) to insert.
296
308
  :param int index: The index to insert at.
297
309
  :return: self
298
310
  """
@@ -311,14 +323,13 @@ class DFTemplate:
311
323
  return self
312
324
 
313
325
 
314
- def build(self, include_tags: bool=True) -> str:
326
+ def build(self) -> str:
315
327
  """
316
328
  Build this template.
317
329
 
318
- :param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
319
330
  :return: String containing encoded template data.
320
331
  """
321
- template_dict_blocks = [codeblock.build(include_tags) for codeblock in self.codeblocks]
332
+ template_dict_blocks = [codeblock.build() for codeblock in self.codeblocks]
322
333
  template_dict = {'blocks': template_dict_blocks}
323
334
  first_block = template_dict_blocks[0]
324
335
  if first_block['block'] not in TEMPLATE_STARTERS:
@@ -328,14 +339,11 @@ class DFTemplate:
328
339
  return df_encode(json_string)
329
340
 
330
341
 
331
- def build_and_send(self, include_tags: bool=True) -> int:
342
+ def build_and_send(self) -> int:
332
343
  """
333
344
  Builds this template and sends it to DiamondFire automatically.
334
-
335
- :param bool include_tags: If True, include item tags in code blocks. Otherwise omit them.
336
345
  """
337
- template_code = self.build(include_tags)
338
- template_item = _generate_template_item(template_code, self._get_template_name(), self.author)
346
+ template_item = self.generate_template_item()
339
347
  return template_item.send_to_minecraft()
340
348
 
341
349
 
@@ -1,5 +1,6 @@
1
1
  import dataclasses
2
2
  import re
3
+ from dfpyre.util import is_number
3
4
  from dfpyre.items import *
4
5
  from dfpyre.actiondump import get_default_tags
5
6
 
@@ -48,9 +49,11 @@ def item_to_string(class_name: str, i: Item, slot_argument: str):
48
49
  stripped_id = i.get_id().replace('minecraft:', '')
49
50
  if set(i.nbt.keys()) == {'id', 'count'}:
50
51
  if i.get_count() == 1:
51
- return f'{class_name}("{stripped_id}"{slot_argument})'
52
- return f'{class_name}("{stripped_id}", {i.get_count()}{slot_argument})'
53
- return f'{class_name}.from_snbt("""{i.get_snbt()}""")'
52
+ return f"{class_name}('{stripped_id}'{slot_argument})"
53
+ return f"{class_name}('{stripped_id}', {i.get_count()}{slot_argument})"
54
+
55
+ snbt_string = i.get_snbt().replace('\\"', '\\\\"')
56
+ return f'{class_name}.from_snbt("""{snbt_string}""")'
54
57
 
55
58
 
56
59
  def argument_item_to_string(flags: GeneratorFlags, arg_item: object) -> str:
@@ -64,16 +67,16 @@ def argument_item_to_string(flags: GeneratorFlags, arg_item: object) -> str:
64
67
  if isinstance(arg_item, String):
65
68
  value = arg_item.value.replace('\n', '\\n')
66
69
  if not has_slot and flags.literal_shorthand:
67
- return f'"{value}"'
68
- return f'{class_name}("{value}"{slot_argument})'
70
+ return f"'{value}'"
71
+ return f"{class_name}('{value}'{slot_argument})"
69
72
 
70
73
  if isinstance(arg_item, Text):
71
74
  value = arg_item.value.replace('\n', '\\n')
72
- return f'{class_name}("{value}"{slot_argument})'
75
+ return f"{class_name}('{value}'{slot_argument})"
73
76
 
74
77
  if isinstance(arg_item, Number):
75
- if not re.match(NUMBER_REGEX, str(arg_item.value)):
76
- return f'{class_name}("{arg_item.value}"{slot_argument})'
78
+ if not is_number(str(arg_item.value)): # Probably a math expression
79
+ return f"{class_name}('{arg_item.value}'{slot_argument})"
77
80
  if not has_slot and flags.literal_shorthand:
78
81
  return str(arg_item.value)
79
82
  return f'{class_name}({arg_item.value}{slot_argument})'
@@ -88,28 +91,28 @@ def argument_item_to_string(flags: GeneratorFlags, arg_item: object) -> str:
88
91
 
89
92
  if isinstance(arg_item, Variable):
90
93
  if not has_slot and flags.var_shorthand:
91
- return f'"${VAR_SCOPES[arg_item.scope]} {arg_item.name}"'
94
+ return f"'${VAR_SCOPES[arg_item.scope]} {arg_item.name}'"
92
95
  if arg_item.scope == 'unsaved':
93
- return f'{class_name}("{arg_item.name}"{slot_argument})'
94
- return f'{class_name}("{arg_item.name}", "{arg_item.scope}"{slot_argument})'
96
+ return f"{class_name}('{arg_item.name}'{slot_argument})"
97
+ return f"{class_name}('{arg_item.name}', '{arg_item.scope}'{slot_argument})"
95
98
 
96
99
  if isinstance(arg_item, Sound):
97
- return f'{class_name}("{arg_item.name}", {arg_item.pitch}, {arg_item.vol}{slot_argument})'
100
+ return f"{class_name}('{arg_item.name}', {arg_item.pitch}, {arg_item.vol}{slot_argument})"
98
101
 
99
102
  if isinstance(arg_item, Particle):
100
103
  return f'{class_name}({arg_item.particle_data})'
101
104
 
102
105
  if isinstance(arg_item, Potion):
103
- return f'{class_name}("{arg_item.name}", {arg_item.dur}, {arg_item.amp}{slot_argument})'
106
+ return f"{class_name}('{arg_item.name}', {arg_item.dur}, {arg_item.amp}{slot_argument})"
104
107
 
105
108
  if isinstance(arg_item, GameValue):
106
109
  if arg_item.target == 'Default':
107
- return f'{class_name}("{arg_item.name}"{slot_argument})'
108
- return f'{class_name}("{arg_item.name}", "{arg_item.target}"{slot_argument})'
110
+ return f"{class_name}('{arg_item.name}'{slot_argument})"
111
+ return f"{class_name}('{arg_item.name}', '{arg_item.target}'{slot_argument})"
109
112
 
110
113
  if isinstance(arg_item, Parameter):
111
114
  param_type_class_name = arg_item.param_type.__class__.__name__
112
- param_args = [f'"{arg_item.name}"', f'{param_type_class_name}.{arg_item.param_type.name}']
115
+ param_args = [f"'{arg_item.name}'", f'{param_type_class_name}.{arg_item.param_type.name}']
113
116
  if arg_item.plural:
114
117
  param_args.append('plural=True')
115
118
  if arg_item.optional:
@@ -117,9 +120,9 @@ def argument_item_to_string(flags: GeneratorFlags, arg_item: object) -> str:
117
120
  if arg_item.default_value is not None:
118
121
  param_args.append(f'default_value={argument_item_to_string(flags, arg_item.default_value)}')
119
122
  if arg_item.description:
120
- param_args.append(f'description="{arg_item.description}"')
123
+ param_args.append(f"description='{arg_item.description}'")
121
124
  if arg_item.note:
122
- param_args.append(f'note="{arg_item.note}"')
125
+ param_args.append(f"note='{arg_item.note}'")
123
126
  return f'{class_name}({", ".join(param_args)}{slot_argument})'
124
127
 
125
128
  if isinstance(arg_item, Vector):
@@ -173,7 +176,7 @@ def generate_script(template, flags: GeneratorFlags) -> str:
173
176
 
174
177
  # Get codeblock function and start its arguments with the action
175
178
  function_name = TEMPLATE_FUNCTION_LOOKUP[codeblock.type]
176
- function_args = [f'"{codeblock.action_name}"']
179
+ function_args = [f"'{codeblock.action_name}'"]
177
180
 
178
181
  # Add variable assignment if necessary
179
182
  var_assignment_snippet = ''
@@ -183,7 +186,7 @@ def generate_script(template, flags: GeneratorFlags) -> str:
183
186
 
184
187
  # Set function or process name if necessary
185
188
  if codeblock.action_name == 'dynamic':
186
- function_args[0] = f'"{codeblock.data["data"]}"'
189
+ function_args[0] = f"'{codeblock.data["data"]}'"
187
190
 
188
191
  # Convert argument objects to valid Python strings
189
192
  codeblock_args = [argument_item_to_string(flags, i) for i in codeblock.args]
@@ -203,7 +206,7 @@ def generate_script(template, flags: GeneratorFlags) -> str:
203
206
 
204
207
  # Add sub-action for repeat
205
208
  if codeblock.data.get('subAction'):
206
- function_args.append(f'sub_action="{codeblock.data["subAction"]}"')
209
+ function_args.append(f"sub_action='{codeblock.data["subAction"]}'")
207
210
 
208
211
  # Add inversion for NOT
209
212
  if codeblock.data.get('attribute') == 'NOT':
@@ -214,7 +217,7 @@ def generate_script(template, flags: GeneratorFlags) -> str:
214
217
  if codeblock.type == 'else':
215
218
  line = f'{function_name}(['
216
219
  elif codeblock.type in {'event', 'entity_event'}:
217
- line = f'{function_name}({", ".join(function_args)}, [' # omit `codeblocks=` when we don't need it
220
+ line = f'{var_assignment_snippet}{function_name}({", ".join(function_args)}, [' # omit `codeblocks=` when we don't need it
218
221
  else:
219
222
  line = f'{var_assignment_snippet}{function_name}({", ".join(function_args)}, codeblocks=['
220
223
  add_script_line(flags, script_lines, indent_level, line, False)
@@ -1,5 +1,6 @@
1
1
  import base64
2
2
  import gzip
3
+ import re
3
4
 
4
5
 
5
6
  COL_WARN = '\x1b[33m'
@@ -7,6 +8,8 @@ COL_RESET = '\x1b[0m'
7
8
  COL_SUCCESS = '\x1b[32m'
8
9
  COL_ERROR = '\x1b[31m'
9
10
 
11
+ NUMBER_REGEX = re.compile(r'^-?\d*\.?\d+$')
12
+
10
13
 
11
14
  class PyreException(Exception):
12
15
  pass
@@ -16,6 +19,10 @@ def warn(message: str):
16
19
  print(f'{COL_WARN}! WARNING ! {message}{COL_RESET}')
17
20
 
18
21
 
22
+ def is_number(s: str) -> bool:
23
+ return bool(NUMBER_REGEX.match(s))
24
+
25
+
19
26
  def df_encode(json_string: str) -> str:
20
27
  """
21
28
  Encodes a stringified json.
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "dfpyre"
3
- version = "0.8.16"
3
+ version = "0.8.18"
4
4
  description = "A package for creating and modifying code templates for the DiamondFire Minecraft server."
5
5
  authors = ["Amp"]
6
6
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes
File without changes