flaremc 0.2.2__tar.gz → 0.2.4__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.
Files changed (48) hide show
  1. flaremc-0.2.4/PKG-INFO +82 -0
  2. flaremc-0.2.4/README.md +71 -0
  3. {flaremc-0.2.2 → flaremc-0.2.4}/flare/__init__.py +6 -4
  4. {flaremc-0.2.2 → flaremc-0.2.4}/flare/cli.py +8 -1
  5. {flaremc-0.2.2 → flaremc-0.2.4}/flare/command_parser.py +2 -2
  6. {flaremc-0.2.2 → flaremc-0.2.4}/flare/compiler.py +20 -20
  7. {flaremc-0.2.2 → flaremc-0.2.4}/flare/context.py +99 -34
  8. flaremc-0.2.4/flare/control_flow.py +276 -0
  9. {flaremc-0.2.2 → flaremc-0.2.4}/flare/execute_modifiers.py +12 -12
  10. {flaremc-0.2.2 → flaremc-0.2.4}/flare/preprocessor.py +54 -7
  11. {flaremc-0.2.2 → flaremc-0.2.4}/flare/validator/matchers.py +35 -2
  12. {flaremc-0.2.2 → flaremc-0.2.4}/flare/validator/schema.py +9 -1
  13. {flaremc-0.2.2 → flaremc-0.2.4}/flare/variables/__init__.py +1 -1
  14. flaremc-0.2.4/flare/variables/bigscore.py +492 -0
  15. {flaremc-0.2.2 → flaremc-0.2.4}/flare/variables/complex.py +17 -51
  16. {flaremc-0.2.2 → flaremc-0.2.4}/flare/variables/core.py +83 -2
  17. flaremc-0.2.4/flare/variables/float32.py +380 -0
  18. flaremc-0.2.4/flare/variables/float64.py +314 -0
  19. {flaremc-0.2.2 → flaremc-0.2.4}/flare/variables/nbt.py +249 -194
  20. flaremc-0.2.4/flare/variables/score.py +580 -0
  21. {flaremc-0.2.2 → flaremc-0.2.4}/flare/variables/selector.py +20 -9
  22. flaremc-0.2.4/flaremc.egg-info/PKG-INFO +82 -0
  23. {flaremc-0.2.2 → flaremc-0.2.4}/flaremc.egg-info/SOURCES.txt +1 -2
  24. {flaremc-0.2.2 → flaremc-0.2.4}/pyproject.toml +1 -1
  25. flaremc-0.2.2/PKG-INFO +0 -512
  26. flaremc-0.2.2/README.md +0 -501
  27. flaremc-0.2.2/flare/control_flow.py +0 -193
  28. flaremc-0.2.2/flare/variables/bigscore.py +0 -558
  29. flaremc-0.2.2/flare/variables/float32.py +0 -434
  30. flaremc-0.2.2/flare/variables/float64.py +0 -323
  31. flaremc-0.2.2/flare/variables/score.py +0 -599
  32. flaremc-0.2.2/flaremc.egg-info/PKG-INFO +0 -512
  33. flaremc-0.2.2/tests/test_flare.py +0 -96
  34. {flaremc-0.2.2 → flaremc-0.2.4}/LICENSE +0 -0
  35. {flaremc-0.2.2 → flaremc-0.2.4}/flare/__main__.py +0 -0
  36. {flaremc-0.2.2 → flaremc-0.2.4}/flare/math.py +0 -0
  37. {flaremc-0.2.2 → flaremc-0.2.4}/flare/nbt_schema.py +0 -0
  38. {flaremc-0.2.2 → flaremc-0.2.4}/flare/types.py +0 -0
  39. {flaremc-0.2.2 → flaremc-0.2.4}/flare/validator/__init__.py +0 -0
  40. {flaremc-0.2.2 → flaremc-0.2.4}/flare/validator/core.py +0 -0
  41. {flaremc-0.2.2 → flaremc-0.2.4}/flare/validator/parser.py +0 -0
  42. {flaremc-0.2.2 → flaremc-0.2.4}/flare/variables/storage.py +0 -0
  43. {flaremc-0.2.2 → flaremc-0.2.4}/flaremc.egg-info/dependency_links.txt +0 -0
  44. {flaremc-0.2.2 → flaremc-0.2.4}/flaremc.egg-info/entry_points.txt +0 -0
  45. {flaremc-0.2.2 → flaremc-0.2.4}/flaremc.egg-info/requires.txt +0 -0
  46. {flaremc-0.2.2 → flaremc-0.2.4}/flaremc.egg-info/top_level.txt +0 -0
  47. {flaremc-0.2.2 → flaremc-0.2.4}/flarevsc/node_modules/flatted/python/flatted.py +0 -0
  48. {flaremc-0.2.2 → flaremc-0.2.4}/setup.cfg +0 -0
flaremc-0.2.4/PKG-INFO ADDED
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: flaremc
3
+ Version: 0.2.4
4
+ Summary: Flare datapack compiler framework
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: mcemu
9
+ Requires-Dist: watchdog
10
+ Dynamic: license-file
11
+
12
+ <div align="center">
13
+ <img src="docs/public/assets/icon_transparent.png" width="200" alt="Flare Logo">
14
+ <h1>Flare 🔥</h1>
15
+ <p><b>Programmatic Minecraft Datapacks in Python</b></p>
16
+ <p>Write Minecraft logic using full Python power: scores, NBT, execute chains, recursion, and more. Compile to optimized datapacks instantly.</p>
17
+ </div>
18
+
19
+ <br>
20
+
21
+ **Read the full documentation at: [flare.oguzhanumutlu.com](https://flare.oguzhanumutlu.com)**
22
+
23
+ ---
24
+
25
+ ## What is Flare?
26
+
27
+ Flare is a modern framework for building Minecraft datapacks natively in Python. It bridges the gap between Python's high-level elegance and Minecraft's native `mcfunction` performance. You can use standard Python syntax, variables, and math, and Flare automatically translates and compiles your logic into highly-optimized, scoreboard-driven datapacks.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install flaremc
33
+ ```
34
+
35
+ ## Quick Start: Advanced Math & NBT
36
+
37
+ With Flare, writing advanced datapack logic is incredibly clean. Below is a quick example of defining variables, doing advanced floating-point math natively in Minecraft, running terminal commands, and interacting with NBT.
38
+
39
+ ```python
40
+ from flare import namespace, score, math, nbt, expand
41
+
42
+ # Define your datapack namespace
43
+ namespace("my_pack")
44
+
45
+ # Declare a scoreboard variable and initialize it to 10
46
+ x = score(10)
47
+
48
+ # Compute math dynamically using native scoreboard approximations (Taylor series, CORDIC, etc.)
49
+ # All complex math compiles to highly optimized raw scoreboard operations!
50
+ result = math.sin(x) * math.sqrt(x)
51
+
52
+ # Print the dynamic float result back to the game seamlessly
53
+ print(f"The result is: {result}")
54
+
55
+ # Interact seamlessly with Minecraft's NBT environment
56
+ player_data = @a.Data[dict]
57
+
58
+ # Flare smartly manages conditional blocks and inlines commands when appropriate
59
+ if expand(x > 5):
60
+ say "X is greater than 5!"
61
+ kill @e[type=zombie, distance=..10]
62
+ ```
63
+
64
+ ## Compile & Run
65
+
66
+ To compile your datapack to a `.mcfunction` structure, simply run:
67
+
68
+ ```bash
69
+ flare main.py
70
+ ```
71
+
72
+ To compile and immediately run it using the built-in emulator:
73
+
74
+ ```bash
75
+ flare main.py --run
76
+ ```
77
+
78
+ ## Documentation
79
+
80
+ Ready to unleash the full power of Python in Minecraft?
81
+
82
+ Check out the interactive playground and full documentation at **[flare.oguzhanumutlu.com](https://flare.oguzhanumutlu.com)**!
@@ -0,0 +1,71 @@
1
+ <div align="center">
2
+ <img src="docs/public/assets/icon_transparent.png" width="200" alt="Flare Logo">
3
+ <h1>Flare 🔥</h1>
4
+ <p><b>Programmatic Minecraft Datapacks in Python</b></p>
5
+ <p>Write Minecraft logic using full Python power: scores, NBT, execute chains, recursion, and more. Compile to optimized datapacks instantly.</p>
6
+ </div>
7
+
8
+ <br>
9
+
10
+ **Read the full documentation at: [flare.oguzhanumutlu.com](https://flare.oguzhanumutlu.com)**
11
+
12
+ ---
13
+
14
+ ## What is Flare?
15
+
16
+ Flare is a modern framework for building Minecraft datapacks natively in Python. It bridges the gap between Python's high-level elegance and Minecraft's native `mcfunction` performance. You can use standard Python syntax, variables, and math, and Flare automatically translates and compiles your logic into highly-optimized, scoreboard-driven datapacks.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install flaremc
22
+ ```
23
+
24
+ ## Quick Start: Advanced Math & NBT
25
+
26
+ With Flare, writing advanced datapack logic is incredibly clean. Below is a quick example of defining variables, doing advanced floating-point math natively in Minecraft, running terminal commands, and interacting with NBT.
27
+
28
+ ```python
29
+ from flare import namespace, score, math, nbt, expand
30
+
31
+ # Define your datapack namespace
32
+ namespace("my_pack")
33
+
34
+ # Declare a scoreboard variable and initialize it to 10
35
+ x = score(10)
36
+
37
+ # Compute math dynamically using native scoreboard approximations (Taylor series, CORDIC, etc.)
38
+ # All complex math compiles to highly optimized raw scoreboard operations!
39
+ result = math.sin(x) * math.sqrt(x)
40
+
41
+ # Print the dynamic float result back to the game seamlessly
42
+ print(f"The result is: {result}")
43
+
44
+ # Interact seamlessly with Minecraft's NBT environment
45
+ player_data = @a.Data[dict]
46
+
47
+ # Flare smartly manages conditional blocks and inlines commands when appropriate
48
+ if expand(x > 5):
49
+ say "X is greater than 5!"
50
+ kill @e[type=zombie, distance=..10]
51
+ ```
52
+
53
+ ## Compile & Run
54
+
55
+ To compile your datapack to a `.mcfunction` structure, simply run:
56
+
57
+ ```bash
58
+ flare main.py
59
+ ```
60
+
61
+ To compile and immediately run it using the built-in emulator:
62
+
63
+ ```bash
64
+ flare main.py --run
65
+ ```
66
+
67
+ ## Documentation
68
+
69
+ Ready to unleash the full power of Python in Minecraft?
70
+
71
+ Check out the interactive playground and full documentation at **[flare.oguzhanumutlu.com](https://flare.oguzhanumutlu.com)**!
@@ -1,16 +1,18 @@
1
1
  from .compiler import _flatten_and, _eval_to_bool_score, _compile_relational
2
2
  from .context import namespace, export, tick, push_context, runcommand, files, temp_obj, constant_obj, vars_obj, \
3
- constants, _flare_assign, _flare_aug_assign, _flare_print, dbg, _flare_return
4
- from .control_flow import _flare_if, _flare_while, _flare_for, _flare_with, _flare_break, _flare_continue
3
+ constants, _flare_assign, _flare_aug_assign, _flare_print, dbg, _flare_return, _flare_in, _flare_notin
4
+ from .control_flow import _flare_if, _flare_while, _flare_for, _flare_with, _flare_break, _flare_continue, expand
5
5
  from .execute_modifiers import _as, at, positioned, aligned, facing, anchored, rotated, dimension, applyon, on, summon, \
6
6
  store, ExecuteChain, StoreExecuteChain
7
7
  from .math import round_, floor, ceil
8
8
  from .types import NBTType, byte, boolean, short, long, double, array
9
9
  from .variables import score, nbt, fixed, tagged, ref, getscore, storage, nbtbyte, nbtbool, nbtshort, nbtint, nbtlong, \
10
- nbtfloat, nbtdouble, nbtstr, nbtlist, nbtdict, nbtbytearray, nbtintarray, nbtlongarray, selector
10
+ nbtfloat, nbtdouble, nbtstr, nbtlist, nbtdict, nbtbytearray, nbtintarray, nbtlongarray, selector, bigscore, \
11
+ bigfixed, float64, float32, complex
11
12
 
12
13
  __all__ = ["round_", "floor", "ceil", "namespace", "export", "tick", "score", "nbt", "fixed", "tagged", "ref",
13
14
  "getscore", "storage", "_flare_print", "dbg", "nbtbyte", "nbtbool", "nbtshort", "nbtint", "nbtlong",
14
15
  "nbtfloat", "nbtdouble", "nbtstr", "nbtlist", "nbtdict", "nbtbytearray", "nbtintarray", "nbtlongarray",
15
16
  "selector", "_as", "at", "positioned", "aligned", "facing", "anchored", "rotated", "dimension", "applyon",
16
- "on", "summon", "store", "ExecuteChain", "StoreExecuteChain", "array"]
17
+ "on", "summon", "store", "ExecuteChain", "StoreExecuteChain", "array", "bigscore", "bigfixed", "float32",
18
+ "float64", "complex", "byte", "boolean", "short", "long", "double", "expand"]
@@ -95,7 +95,8 @@ def _build_datapack_inner(file_path: str, cli_overrides: dict = None):
95
95
 
96
96
  global_env = {"__name__": "__main__", "__file__": abs_path}
97
97
  exec(
98
- "from flare import _flare_assign, _flare_aug_assign, _flare_if, _flare_while, _flare_for, _flare_with, runcommand, _flare_return, _flare_break, _flare_continue\n"
98
+ "from flare import _flare_assign, _flare_aug_assign, _flare_if, _flare_while, _flare_for, _flare_with, runcommand, _flare_return, _flare_break, _flare_continue, _flare_in, _flare_notin\n"
99
+ "from flare import context as ctx\n"
99
100
  "from flare.command_parser import interpolate_command\n"
100
101
  "from flare import _flare_print as print, selector, _as, at, positioned, aligned, facing, anchored, rotated, dimension, applyon, on, summon, store\n"
101
102
  "from flare import nbt, score, fixed, tagged, ref, getscore, storage, array, byte, boolean, short, long, double\n"
@@ -153,8 +154,14 @@ def _build_datapack_inner(file_path: str, cli_overrides: dict = None):
153
154
  if ":" in filename:
154
155
  ns, name = filename.split(":", 1)
155
156
  file_p = build_dir / "data" / ns / "functions" / f"{name}.mcfunction"
157
+ is_top_level = "generated_" not in name and "while_" not in name and name not in ("main", "load")
156
158
  else:
157
159
  file_p = build_dir / "data" / context._current_namespace / "functions" / f"{filename}.mcfunction"
160
+ is_top_level = "generated_" not in filename and "while_" not in filename and filename not in ("main",
161
+ "load")
162
+
163
+ if is_top_level and lines and lines[-1] in ("return 1", "return 0"):
164
+ lines.pop()
158
165
 
159
166
  file_p.parent.mkdir(parents=True, exist_ok=True)
160
167
  with open(file_p, "w") as f:
@@ -71,7 +71,7 @@ def interpolate_command(command: str, local_vars: dict, global_vars: dict) -> st
71
71
  elif not is_key and ident in local_vars:
72
72
  val = local_vars[ident]
73
73
  if hasattr(val, "addr"):
74
- output.append(val.addr)
74
+ output.append(val._addr)
75
75
  elif hasattr(val, "target"):
76
76
  output.append(val.target)
77
77
  elif isinstance(val, dict) and output and output[-1].endswith("**"):
@@ -88,7 +88,7 @@ def interpolate_command(command: str, local_vars: dict, global_vars: dict) -> st
88
88
  elif not is_key and ident in global_vars:
89
89
  val = global_vars[ident]
90
90
  if hasattr(val, "addr"):
91
- output.append(val.addr)
91
+ output.append(val._addr)
92
92
  elif hasattr(val, "target"):
93
93
  output.append(val.target)
94
94
  elif isinstance(val, dict) and output and output[-1].endswith("**"):
@@ -1,6 +1,7 @@
1
1
  from . import context as ctx
2
2
  from .context import runcommand, temp_obj
3
3
  from .variables import score, BinaryOp, UnaryOp, getscore
4
+ from .variables.core import addr
4
5
 
5
6
 
6
7
  def _compile_relational(node, invert=False):
@@ -19,8 +20,7 @@ def _compile_relational(node, invert=False):
19
20
  if isinstance(left, (int, float)):
20
21
  left = getscore(left)
21
22
  else:
22
- t = score(addr=f"!c{ctx._temp_id} {temp_obj}")
23
- ctx._temp_id += 1
23
+ t = score(addr=f"!c{ctx.next_temp_id()} {temp_obj}")
24
24
  if isinstance(left, (BinaryOp, UnaryOp)):
25
25
  left._eval_into(t)
26
26
  else:
@@ -29,52 +29,52 @@ def _compile_relational(node, invert=False):
29
29
 
30
30
  if not isinstance(right, score):
31
31
  if isinstance(right, (int, float)):
32
- right = getscore(right, left.multiplier)
32
+ right = getscore(right, left._multiplier)
33
33
  else:
34
- t = score(addr=f"!c{ctx._temp_id} {temp_obj}", multiplier=left.multiplier)
35
- ctx._temp_id += 1
34
+ t = score(addr=f"!c{ctx.next_temp_id()} {temp_obj}", multiplier=left._multiplier)
36
35
  if isinstance(right, (BinaryOp, UnaryOp)):
37
36
  right._eval_into(t)
38
37
  else:
39
38
  t.__iset__(right)
40
39
  right = t
41
40
 
42
- if left.multiplier != right.multiplier:
43
- t = score(addr=f"!c{ctx._temp_id} {temp_obj}", multiplier=left.multiplier)
44
- ctx._temp_id += 1
41
+ if left._multiplier != right._multiplier:
42
+ t = score(addr=f"!c{ctx.next_temp_id()} {temp_obj}", multiplier=left._multiplier)
45
43
  t.__iset__(right)
46
44
  right = t
47
45
 
48
- return f"{keyword} score {left.addr} {mcop} {right.addr}"
46
+ return f"{keyword} score {addr(left)} {mcop} {addr(right)}"
49
47
 
50
48
 
51
49
  def _eval_to_bool_score(node):
52
- dest = score(addr=f"!b{ctx._temp_id} {temp_obj}")
53
- ctx._temp_id += 1
54
- runcommand(f"scoreboard players set {dest.addr} 0")
50
+ dest = score(addr=f"!b{ctx.next_temp_id()} {temp_obj}")
51
+ runcommand(f"scoreboard players set {addr(dest)} 0")
55
52
 
56
53
  if isinstance(node, BinaryOp) and node.op == "or":
57
54
  left_conds = _flatten_and(node.left)
58
- runcommand(f"execute {' '.join(left_conds)} run scoreboard players set {dest.addr} 1")
55
+ runcommand(f"execute {' '.join(left_conds)} run scoreboard players set {addr(dest)} 1")
59
56
  right_conds = _flatten_and(node.right)
60
57
  runcommand(
61
- f"execute if score {dest.addr} matches 0 {' '.join(right_conds)} run scoreboard players set {dest.addr} 1")
58
+ f"execute if score {addr(dest)} matches 0 {' '.join(right_conds)} run scoreboard players set {addr(dest)} 1")
62
59
  return dest
63
60
 
64
61
  if isinstance(node, UnaryOp) and node.op == "not":
65
62
  sub_dest = _eval_to_bool_score(node.operand)
66
- runcommand(f"execute if score {sub_dest.addr} matches 0 run scoreboard players set {dest.addr} 1")
63
+ runcommand(f"execute if score {addr(sub_dest)} matches 0 run scoreboard players set {addr(dest)} 1")
67
64
  return dest
68
65
 
69
66
  if isinstance(node, (BinaryOp, UnaryOp)):
70
- t = score(addr=f"!b{ctx._temp_id} {temp_obj}")
71
- ctx._temp_id += 1
67
+ t = score(addr=f"!b{ctx.next_temp_id()} {temp_obj}")
72
68
  node._eval_into(t)
73
- runcommand(f"execute unless score {t.addr} matches 0 run scoreboard players set {dest.addr} 1")
69
+ runcommand(f"execute unless score {addr(t)} matches 0 run scoreboard players set {addr(dest)} 1")
70
+ return dest
71
+
72
+ if hasattr(type(node), "_eval_into") or hasattr(node, "_addr"):
73
+ runcommand(f"execute unless score {addr(node)} matches 0 run scoreboard players set {addr(dest)} 1")
74
74
  return dest
75
75
 
76
76
  if node:
77
- runcommand(f"scoreboard players set {dest.addr} 1")
77
+ runcommand(f"scoreboard players set {addr(dest)} 1")
78
78
  return dest
79
79
 
80
80
 
@@ -84,4 +84,4 @@ def _flatten_and(node, invert=False):
84
84
 
85
85
  dest = _eval_to_bool_score(node)
86
86
  keyword = "unless" if invert else "if"
87
- return [f"{keyword} score {dest.addr} matches 1"]
87
+ return [f"{keyword} score {addr(dest)} matches 1"]
@@ -8,9 +8,39 @@ current_file = "main"
8
8
  _current_namespace = "flare"
9
9
  functions = {}
10
10
  constants = {}
11
- constant_obj = "__flare__constant__"
12
- vars_obj = "__flare__vars__"
13
- temp_obj = "__flare__temp__"
11
+
12
+
13
+ class DynamicVar:
14
+ def __init__(self, fmt):
15
+ self.fmt = fmt
16
+
17
+ def __str__(self):
18
+ return self.fmt.format(ns=_current_namespace)
19
+
20
+ def __format__(self, format_spec):
21
+ return format(str(self), format_spec)
22
+
23
+ def __add__(self, other):
24
+ return str(self) + other
25
+
26
+ def __radd__(self, other):
27
+ return other + str(self)
28
+
29
+ def __hash__(self):
30
+ return hash(str(self))
31
+
32
+ def __eq__(self, other):
33
+ return str(self) == str(other)
34
+
35
+
36
+ constant_obj = DynamicVar("__{ns}__constant__")
37
+ vars_obj = DynamicVar("__{ns}__vars__")
38
+ temp_obj = DynamicVar("__{ns}__temp__")
39
+ temp_storage = DynamicVar("{ns}:__flare_temp__")
40
+ vars_storage = DynamicVar("{ns}:__flare_vars__")
41
+ args_storage = DynamicVar("{ns}:__flare_args__")
42
+ returns_storage = DynamicVar("{ns}:__flare_returns__")
43
+
14
44
  _temp_id = 0
15
45
  _func_id = 0
16
46
  _objective_offset = 0
@@ -26,6 +56,20 @@ minecraft_version = "1.20.4"
26
56
  nbt_schema_missing = "error"
27
57
 
28
58
 
59
+ def next_temp_id():
60
+ global _temp_id
61
+ got = _temp_id
62
+ _temp_id += 1
63
+ return got
64
+
65
+
66
+ def next_func_id():
67
+ global _func_id
68
+ got = _func_id
69
+ _func_id += 1
70
+ return got
71
+
72
+
29
73
  def reset_context():
30
74
  global files, current_file, _current_namespace, functions, constants, _temp_id, _func_id, _objective_offset, _constant_offset, validation_level, minecraft_version, nbt_schema_missing, _recursive_functions, _in_recursive_context, return_types, _logical_func
31
75
  files = {"main": []}
@@ -91,9 +135,11 @@ def push_context(name: str):
91
135
  return _ContextManager(name)
92
136
 
93
137
 
94
- def namespace(name: str):
138
+ def namespace(name: str | None = None):
95
139
  global _current_namespace
96
- _current_namespace = name
140
+ if name is not None:
141
+ _current_namespace = name
142
+ return _current_namespace
97
143
 
98
144
 
99
145
  from .validator import validate_command, FlareCommandValidationError
@@ -138,28 +184,28 @@ def _flare_print(*args):
138
184
 
139
185
  if isinstance(arg, score):
140
186
  if getattr(arg, "multiplier", 1.0) != 1.0:
141
- scale_str = f"{arg.multiplier:.15f}".rstrip("0")
187
+ scale_str = f"{arg._multiplier:.15f}".rstrip("0")
142
188
  if scale_str.endswith("."):
143
189
  scale_str += "0"
144
190
  runcommand(
145
- f"execute store result storage flare:temp __flare_debug_{i} double {scale_str} run scoreboard players get {arg.addr}")
146
- components.append({"nbt": f"__flare_debug_{i}", "storage": "flare:temp"})
191
+ f"execute store result storage {temp_storage} __flare_debug_{i} double {scale_str} run scoreboard players get {addr(arg)}")
192
+ components.append({"nbt": f"__flare_debug_{i}", "storage": str(temp_storage)})
147
193
  else:
148
- name, obj = arg.addr.split(" ", 1)
194
+ name, obj = arg._addr.split(" ", 1)
149
195
  components.append({"score": {"name": name, "objective": obj}})
150
196
  elif isinstance(arg, nbt):
151
- nbt_comp = {"nbt": arg.path or "{}"}
152
- if arg.path == "":
197
+ nbt_comp = {"nbt": arg._path or "{}"}
198
+ if arg._path == "":
153
199
  nbt_comp["nbt"] = "{}"
154
200
 
155
- if arg.target_type == "storage":
156
- nbt_comp["storage"] = arg.target
157
- elif arg.target_type == "entity":
158
- nbt_comp["entity"] = arg.target
159
- elif arg.target_type == "block":
160
- nbt_comp["block"] = arg.target
201
+ if arg._target_type == "storage":
202
+ nbt_comp["storage"] = arg._target
203
+ elif arg._target_type == "entity":
204
+ nbt_comp["entity"] = arg._target
205
+ elif arg._target_type == "block":
206
+ nbt_comp["block"] = arg._target
161
207
 
162
- if arg.path == "":
208
+ if arg._path == "":
163
209
  nbt_comp["nbt"] = "{}"
164
210
 
165
211
  components.append(nbt_comp)
@@ -178,15 +224,21 @@ def _flare_print(*args):
178
224
  runcommand(f"tellraw @a {cmd_text}")
179
225
 
180
226
 
181
- def export(func=None, *, append=False):
227
+ def export(func=None, *, name=None, append=False):
182
228
  from flare import score # avoid circular import
229
+
230
+ if isinstance(func, str):
231
+ name = func
232
+ func = None
233
+
183
234
  if func is None:
184
235
  def wrapper(f):
185
- return export(f, append=append)
236
+ return export(f, name=name, append=append)
186
237
 
187
238
  return wrapper
188
239
 
189
- func_name = f"{_current_namespace}:{func.__name__}"
240
+ actual_name = name if name is not None else func.__name__
241
+ func_name = f"{_current_namespace}:{actual_name}"
190
242
  if func_name in files and not append:
191
243
  raise ValueError(f"Function {func_name} already exists. Use @export(append=True) to append.")
192
244
 
@@ -208,9 +260,9 @@ def export(func=None, *, append=False):
208
260
  kwargs[name] = score(addr=f"{func.__name__}_{name} {vars_obj}")
209
261
  elif hasattr(anno, "__name__") and anno.__name__ in ("nbt", "_TypedNBT"):
210
262
  if is_recursive:
211
- kwargs[name] = anno(addr=f"storage flare:args {func.__name__}_{name}[-1]")
263
+ kwargs[name] = anno(addr=f"storage {args_storage} {func.__name__}_{name}[-1]")
212
264
  else:
213
- kwargs[name] = anno(addr=f"storage flare:args {func.__name__}_{name}")
265
+ kwargs[name] = anno(addr=f"storage {args_storage} {func.__name__}_{name}")
214
266
  elif anno is not inspect.Signature.empty:
215
267
  raise TypeError(f"Argument '{name}' must be typed as score or nbt, not {anno}")
216
268
  else:
@@ -235,24 +287,25 @@ def export(func=None, *, append=False):
235
287
  global _temp_id
236
288
  bound = sig.bind(*args, **call_kwargs)
237
289
  bound.apply_defaults()
290
+ from .variables.core import addr
238
291
  for arg_name, arg_val in bound.arguments.items():
239
292
  target = kwargs[arg_name]
240
293
 
241
294
  if is_recursive and isinstance(target, nbt):
242
- base_addr = f"storage flare:args {func.__name__}_{arg_name}"
295
+ base_addr = f"storage {args_storage} {func.__name__}_{arg_name}"
243
296
  if isinstance(arg_val, (int, float, str)):
244
297
  runcommand(f"data modify {base_addr} append value {json.dumps(arg_val)}")
245
298
  elif isinstance(arg_val, nbt):
246
- runcommand(f"data modify {base_addr} append from {arg_val.addr}")
299
+ runcommand(f"data modify {base_addr} append from {addr(arg_val)}")
247
300
  elif isinstance(arg_val, score):
248
301
  runcommand(f"data modify {base_addr} append value 0")
249
302
  runcommand(
250
- f"execute store result {base_addr}[-1] int {1 / arg_val.multiplier} run scoreboard players get {arg_val.addr}")
303
+ f"execute store result {base_addr}[-1] int {1 / arg_val._multiplier} run scoreboard players get {addr(arg_val)}")
251
304
  elif hasattr(type(arg_val), "_eval_into"):
252
- temp = nbt(addr=f"storage flare:temp !t{_temp_id}", datatype=target.type)
305
+ temp = nbt(addr=f"storage {temp_storage} !t{_temp_id}", datatype=target._type)
253
306
  _temp_id += 1
254
307
  arg_val._eval_into(temp)
255
- runcommand(f"data modify {base_addr} append from {temp.addr}")
308
+ runcommand(f"data modify {base_addr} append from {addr(temp)}")
256
309
  else:
257
310
  target.__iset__(arg_val)
258
311
 
@@ -261,7 +314,7 @@ def export(func=None, *, append=False):
261
314
  if is_recursive:
262
315
  for arg_name in bound.arguments.keys():
263
316
  if isinstance(kwargs[arg_name], nbt):
264
- base_addr = f"storage flare:args {func.__name__}_{arg_name}"
317
+ base_addr = f"storage {args_storage} {func.__name__}_{arg_name}"
265
318
  runcommand(f"data remove {base_addr}[-1]")
266
319
 
267
320
  ret_anno = return_types.get(func_name, sig.return_annotation)
@@ -272,15 +325,15 @@ def export(func=None, *, append=False):
272
325
  temp_ret = score(addr=f"!ret{_temp_id} {temp_obj}")
273
326
  _temp_id += 1
274
327
  runcommand(
275
- f"scoreboard players operation {temp_ret.addr} = {func_name.replace(":", "_")}_ret {vars_obj}")
328
+ f"scoreboard players operation {addr(temp_ret)} = {func_name.replace(":", "_")}_ret {vars_obj}")
276
329
  if ret_anno.__name__ in ("fixed", "_PrecisionScore"):
277
330
  pass
278
331
  return temp_ret
279
332
  else:
280
- temp_ret = nbt(addr=f"storage flare:temp !ret{_temp_id}")
333
+ temp_ret = nbt(addr=f"storage {temp_storage} !ret{_temp_id}")
281
334
  _temp_id += 1
282
335
  runcommand(
283
- f"data modify {temp_ret.addr} set from storage flare:returns {func_name.replace(":", "_")}")
336
+ f"data modify {addr(temp_ret)} set from storage {returns_storage} {func_name.replace(':', '_')}")
284
337
  return temp_ret
285
338
 
286
339
  proxy = ProxyFunction()
@@ -310,6 +363,18 @@ def export(func=None, *, append=False):
310
363
  return proxy
311
364
 
312
365
 
366
+ def _flare_in(item, container):
367
+ if hasattr(container, "__in__"):
368
+ return container.__in__(item)
369
+ return item in container
370
+
371
+ def _flare_notin(item, container):
372
+ if hasattr(container, "__notin__"):
373
+ return container.__notin__(item)
374
+ if hasattr(container, "__in__"):
375
+ return ~container.__in__(item)
376
+ return item not in container
377
+
313
378
  def _flare_assign(var_name, value, local_env, global_env):
314
379
  if var_name in local_env:
315
380
  target = local_env[var_name]
@@ -402,12 +467,12 @@ def _flare_return(value):
402
467
  target.__iset__(value)
403
468
  else:
404
469
  if inspect.isclass(ret_anno) and issubclass(ret_anno, nbt):
405
- target = ret_anno(addr=f"storage flare:returns {func_name.replace(":", "_")}")
470
+ target = ret_anno(addr=f"storage {returns_storage} {func_name.replace(':', '_')}")
406
471
  else:
407
472
  datatype = None
408
473
  if hasattr(ret_anno, "__origin__") or isinstance(ret_anno, type):
409
474
  datatype = getattr(ret_anno, "__origin__", ret_anno)
410
- target = nbt(addr=f"storage flare:returns {func_name.replace(":", "_")}", datatype=datatype)
475
+ target = nbt(addr=f"storage {returns_storage} {func_name.replace(':', '_')}", datatype=datatype)
411
476
  target.__iset__(value)
412
477
 
413
478
  runcommand("return 1")