minecraft-datapack-language 15.4.34__py3-none-any.whl → 15.4.36__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.
- minecraft_datapack_language/__init__.py +3 -1
- minecraft_datapack_language/_version.py +2 -2
- minecraft_datapack_language/mdl_compiler.py +88 -40
- minecraft_datapack_language/python_api.py +207 -0
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.36.dist-info}/METADATA +1 -1
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.36.dist-info}/RECORD +10 -9
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.36.dist-info}/WHEEL +0 -0
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.36.dist-info}/entry_points.txt +0 -0
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.36.dist-info}/licenses/LICENSE +0 -0
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.36.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@ from .mdl_lexer import MDLLexer, Token, TokenType
|
|
3
3
|
from .mdl_parser import MDLParser
|
4
4
|
from .ast_nodes import *
|
5
5
|
from .dir_map import DirMap
|
6
|
+
from .python_api import Pack
|
6
7
|
|
7
8
|
__all__ = [
|
8
9
|
"MDLLexer", "Token", "TokenType",
|
@@ -13,7 +14,8 @@ __all__ = [
|
|
13
14
|
"SayCommand", "TellrawCommand", "ExecuteCommand", "ScoreboardCommand",
|
14
15
|
"BinaryExpression", "UnaryExpression", "ParenthesizedExpression", "LiteralExpression",
|
15
16
|
"ScopeSelector",
|
16
|
-
"DirMap"
|
17
|
+
"DirMap",
|
18
|
+
"Pack"
|
17
19
|
]
|
18
20
|
|
19
21
|
# CLI entry point
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
28
28
|
commit_id: COMMIT_ID
|
29
29
|
__commit_id__: COMMIT_ID
|
30
30
|
|
31
|
-
__version__ = version = '15.4.
|
32
|
-
__version_tuple__ = version_tuple = (15, 4,
|
31
|
+
__version__ = version = '15.4.36'
|
32
|
+
__version_tuple__ = version_tuple = (15, 4, 36)
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
@@ -148,22 +148,25 @@ class MDLCompiler:
|
|
148
148
|
lines.append(f"# Scope: {func.scope}")
|
149
149
|
lines.append("")
|
150
150
|
|
151
|
-
#
|
152
|
-
if hasattr(self, '
|
153
|
-
self.
|
154
|
-
|
151
|
+
# Ensure a temp-command sink stack exists
|
152
|
+
if not hasattr(self, '_temp_sink_stack'):
|
153
|
+
self._temp_sink_stack = []
|
154
|
+
|
155
|
+
# Set current function context and reset per-function counters
|
156
|
+
self._current_function_name = func.name
|
157
|
+
self.if_counter = 0
|
158
|
+
self.else_counter = 0
|
159
|
+
self.while_counter = 0
|
160
|
+
|
161
|
+
# Route temp commands into this function's body by default
|
162
|
+
self._temp_sink_stack.append(lines)
|
155
163
|
# Generate commands from function body
|
156
164
|
for statement in func.body:
|
157
165
|
cmd = self._statement_to_command(statement)
|
158
166
|
if cmd:
|
159
167
|
lines.append(cmd)
|
160
|
-
|
161
|
-
|
162
|
-
if hasattr(self, 'temp_commands') and self.temp_commands:
|
163
|
-
lines.append("")
|
164
|
-
lines.append("# Temporary variable operations:")
|
165
|
-
for temp_cmd in self.temp_commands:
|
166
|
-
lines.append(temp_cmd)
|
168
|
+
# Done routing temp commands for this function body
|
169
|
+
self._temp_sink_stack.pop()
|
167
170
|
|
168
171
|
return "\n".join(lines)
|
169
172
|
|
@@ -395,6 +398,10 @@ class MDLCompiler:
|
|
395
398
|
|
396
399
|
# Generate the if body function content
|
397
400
|
if_body_lines = [f"# Function: {self.current_namespace}:{if_function_name}"]
|
401
|
+
# Route temp commands to the if-body function content
|
402
|
+
if not hasattr(self, '_temp_sink_stack'):
|
403
|
+
self._temp_sink_stack = []
|
404
|
+
self._temp_sink_stack.append(if_body_lines)
|
398
405
|
for stmt in if_stmt.then_body:
|
399
406
|
if isinstance(stmt, VariableAssignment):
|
400
407
|
cmd = self._variable_assignment_to_command(stmt)
|
@@ -413,6 +420,8 @@ class MDLCompiler:
|
|
413
420
|
elif isinstance(stmt, FunctionCall):
|
414
421
|
cmd = self._function_call_to_command(stmt)
|
415
422
|
if_body_lines.append(cmd)
|
423
|
+
# Stop routing temp commands for if-body
|
424
|
+
self._temp_sink_stack.pop()
|
416
425
|
|
417
426
|
# Handle else body if it exists
|
418
427
|
if if_stmt.else_body:
|
@@ -437,6 +446,10 @@ class MDLCompiler:
|
|
437
446
|
else:
|
438
447
|
lines.append(f"execute unless {condition} run function {self.current_namespace}:{else_function_name}")
|
439
448
|
else_body_lines = [f"# Function: {self.current_namespace}:{else_function_name}"]
|
449
|
+
# Route temp commands into the else-body
|
450
|
+
if not hasattr(self, '_temp_sink_stack'):
|
451
|
+
self._temp_sink_stack = []
|
452
|
+
self._temp_sink_stack.append(else_body_lines)
|
440
453
|
for stmt in if_stmt.else_body:
|
441
454
|
if isinstance(stmt, VariableAssignment):
|
442
455
|
cmd = self._variable_assignment_to_command(stmt)
|
@@ -455,6 +468,8 @@ class MDLCompiler:
|
|
455
468
|
elif isinstance(stmt, FunctionCall):
|
456
469
|
cmd = self._function_call_to_command(stmt)
|
457
470
|
else_body_lines.append(cmd)
|
471
|
+
# Stop routing temp commands for else-body
|
472
|
+
self._temp_sink_stack.pop()
|
458
473
|
self._store_generated_function(else_function_name, else_body_lines)
|
459
474
|
|
460
475
|
# Store the if function as its own file
|
@@ -477,6 +492,9 @@ class MDLCompiler:
|
|
477
492
|
loop_body_lines = [f"# Function: {self.current_namespace}:{loop_function_name}"]
|
478
493
|
|
479
494
|
# Add the loop body statements
|
495
|
+
if not hasattr(self, '_temp_sink_stack'):
|
496
|
+
self._temp_sink_stack = []
|
497
|
+
self._temp_sink_stack.append(loop_body_lines)
|
480
498
|
for stmt in while_loop.body:
|
481
499
|
if isinstance(stmt, VariableAssignment):
|
482
500
|
cmd = self._variable_assignment_to_command(stmt)
|
@@ -497,10 +515,10 @@ class MDLCompiler:
|
|
497
515
|
loop_body_lines.append(cmd)
|
498
516
|
|
499
517
|
# Add the recursive call at the end to continue the loop
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
518
|
+
cond_str, _inv = self._build_condition(while_loop.condition)
|
519
|
+
loop_body_lines.append(f"execute if {cond_str} run function {self.current_namespace}:{loop_function_name}")
|
520
|
+
# Stop routing temp commands for while-body
|
521
|
+
self._temp_sink_stack.pop()
|
504
522
|
|
505
523
|
# Store the loop function as its own file
|
506
524
|
self._store_generated_function(loop_function_name, loop_body_lines)
|
@@ -517,24 +535,21 @@ class MDLCompiler:
|
|
517
535
|
|
518
536
|
def _generate_if_function_name(self) -> str:
|
519
537
|
"""Generate a unique name for an if function."""
|
520
|
-
if not hasattr(self, 'if_counter'):
|
521
|
-
self.if_counter = 0
|
522
538
|
self.if_counter += 1
|
523
|
-
|
539
|
+
prefix = getattr(self, '_current_function_name', 'fn')
|
540
|
+
return f"{prefix}__if_{self.if_counter}"
|
524
541
|
|
525
542
|
def _generate_else_function_name(self) -> str:
|
526
543
|
"""Generate a unique name for an else function."""
|
527
|
-
if not hasattr(self, 'else_counter'):
|
528
|
-
self.else_counter = 0
|
529
544
|
self.else_counter += 1
|
530
|
-
|
545
|
+
prefix = getattr(self, '_current_function_name', 'fn')
|
546
|
+
return f"{prefix}__else_{self.else_counter}"
|
531
547
|
|
532
548
|
def _generate_while_function_name(self) -> str:
|
533
549
|
"""Generate a unique name for a while function."""
|
534
|
-
if not hasattr(self, 'while_counter'):
|
535
|
-
self.while_counter = 0
|
536
550
|
self.while_counter += 1
|
537
|
-
|
551
|
+
prefix = getattr(self, '_current_function_name', 'fn')
|
552
|
+
return f"{prefix}__while_{self.while_counter}"
|
538
553
|
|
539
554
|
def _store_generated_function(self, name: str, lines: List[str]):
|
540
555
|
"""Store a generated function as a separate file under the same namespace."""
|
@@ -679,10 +694,20 @@ class MDLCompiler:
|
|
679
694
|
if isinstance(expression.left, BinaryExpression):
|
680
695
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} = @s {left_temp}")
|
681
696
|
else:
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
697
|
+
# Assign from left value (score or literal)
|
698
|
+
if isinstance(expression.left, VariableSubstitution) or (isinstance(expression.left, str) and str(left_value).startswith("score ")):
|
699
|
+
parts = str(left_value).split()
|
700
|
+
scope = parts[1]
|
701
|
+
obj = parts[2]
|
702
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} = {scope} {obj}")
|
703
|
+
else:
|
704
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} {left_value}")
|
705
|
+
# Add right value
|
706
|
+
if isinstance(expression.right, VariableSubstitution) or (isinstance(expression.right, str) and str(right_value).startswith("score ")):
|
707
|
+
parts = str(right_value).split()
|
708
|
+
scope = parts[1]
|
709
|
+
obj = parts[2]
|
710
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} += {scope} {obj}")
|
686
711
|
else:
|
687
712
|
self._store_temp_command(f"scoreboard players add @s {temp_var} {right_value}")
|
688
713
|
|
@@ -690,10 +715,19 @@ class MDLCompiler:
|
|
690
715
|
if isinstance(expression.left, BinaryExpression):
|
691
716
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} = @s {left_temp}")
|
692
717
|
else:
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
718
|
+
if isinstance(expression.left, VariableSubstitution) or (isinstance(expression.left, str) and str(left_value).startswith("score ")):
|
719
|
+
parts = str(left_value).split()
|
720
|
+
scope = parts[1]
|
721
|
+
obj = parts[2]
|
722
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} = {scope} {obj}")
|
723
|
+
else:
|
724
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} {left_value}")
|
725
|
+
# Subtract right value
|
726
|
+
if isinstance(expression.right, VariableSubstitution) or (isinstance(expression.right, str) and str(right_value).startswith("score ")):
|
727
|
+
parts = str(right_value).split()
|
728
|
+
scope = parts[1]
|
729
|
+
obj = parts[2]
|
730
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} -= {scope} {obj}")
|
697
731
|
else:
|
698
732
|
self._store_temp_command(f"scoreboard players remove @s {temp_var} {right_value}")
|
699
733
|
|
@@ -701,12 +735,18 @@ class MDLCompiler:
|
|
701
735
|
if isinstance(expression.left, BinaryExpression):
|
702
736
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} = @s {left_temp}")
|
703
737
|
else:
|
704
|
-
|
738
|
+
if isinstance(expression.left, VariableSubstitution) or (isinstance(expression.left, str) and str(left_value).startswith("score ")):
|
739
|
+
parts = str(left_value).split()
|
740
|
+
scope = parts[1]
|
741
|
+
obj = parts[2]
|
742
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} = {scope} {obj}")
|
743
|
+
else:
|
744
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} {left_value}")
|
705
745
|
|
706
746
|
if isinstance(expression.right, BinaryExpression):
|
707
747
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} *= @s {right_temp}")
|
708
748
|
else:
|
709
|
-
# For literal values,
|
749
|
+
# For literal values, keep explicit multiply command for compatibility
|
710
750
|
if isinstance(expression.right, LiteralExpression):
|
711
751
|
self._store_temp_command(f"scoreboard players multiply @s {temp_var} {expression.right.value}")
|
712
752
|
else:
|
@@ -716,12 +756,18 @@ class MDLCompiler:
|
|
716
756
|
if isinstance(expression.left, BinaryExpression):
|
717
757
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} = @s {left_temp}")
|
718
758
|
else:
|
719
|
-
|
759
|
+
if isinstance(expression.left, VariableSubstitution) or (isinstance(expression.left, str) and str(left_value).startswith("score ")):
|
760
|
+
parts = str(left_value).split()
|
761
|
+
scope = parts[1]
|
762
|
+
obj = parts[2]
|
763
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} = {scope} {obj}")
|
764
|
+
else:
|
765
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} {left_value}")
|
720
766
|
|
721
767
|
if isinstance(expression.right, BinaryExpression):
|
722
768
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} /= @s {right_temp}")
|
723
769
|
else:
|
724
|
-
# For literal values,
|
770
|
+
# For literal values, keep explicit divide command for compatibility
|
725
771
|
if isinstance(expression.right, LiteralExpression):
|
726
772
|
self._store_temp_command(f"scoreboard players divide @s {temp_var} {expression.right.value}")
|
727
773
|
else:
|
@@ -731,10 +777,12 @@ class MDLCompiler:
|
|
731
777
|
self._store_temp_command(f"scoreboard players set @s {temp_var} 0")
|
732
778
|
|
733
779
|
def _store_temp_command(self, command: str):
|
734
|
-
"""
|
735
|
-
if
|
736
|
-
self.
|
737
|
-
|
780
|
+
"""Append a temporary command into the current output sink (function/if/while body)."""
|
781
|
+
if hasattr(self, '_temp_sink_stack') and self._temp_sink_stack:
|
782
|
+
self._temp_sink_stack[-1].append(command)
|
783
|
+
else:
|
784
|
+
# Fallback: do nothing, but keep behavior predictable
|
785
|
+
pass
|
738
786
|
|
739
787
|
def _generate_temp_variable_name(self) -> str:
|
740
788
|
"""Generate a unique temporary variable name."""
|
@@ -0,0 +1,207 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Callable, List, Optional, Union
|
5
|
+
|
6
|
+
from .ast_nodes import (
|
7
|
+
Program,
|
8
|
+
PackDeclaration,
|
9
|
+
NamespaceDeclaration,
|
10
|
+
TagDeclaration,
|
11
|
+
VariableDeclaration,
|
12
|
+
VariableAssignment,
|
13
|
+
VariableSubstitution,
|
14
|
+
FunctionDeclaration,
|
15
|
+
FunctionCall,
|
16
|
+
IfStatement,
|
17
|
+
WhileLoop,
|
18
|
+
RawBlock,
|
19
|
+
SayCommand,
|
20
|
+
BinaryExpression,
|
21
|
+
LiteralExpression,
|
22
|
+
)
|
23
|
+
from .mdl_compiler import MDLCompiler
|
24
|
+
|
25
|
+
|
26
|
+
# ---------- Expression helpers ----------
|
27
|
+
|
28
|
+
def num(value: Union[int, float]) -> LiteralExpression:
|
29
|
+
return LiteralExpression(value=value, type="number")
|
30
|
+
|
31
|
+
|
32
|
+
def var_read(name: str, scope: str) -> VariableSubstitution:
|
33
|
+
# scope must look like <@s>, <@a>, <@e[...]>, or <global>
|
34
|
+
return VariableSubstitution(name=name, scope=scope)
|
35
|
+
|
36
|
+
|
37
|
+
def binop(left, operator: str, right) -> BinaryExpression:
|
38
|
+
# operator one of: PLUS, MINUS, MULTIPLY, DIVIDE, GREATER, LESS, GREATER_EQUAL, LESS_EQUAL, EQUAL, NOT_EQUAL
|
39
|
+
return BinaryExpression(left=left, operator=operator, right=right)
|
40
|
+
|
41
|
+
|
42
|
+
# ---------- Python Bindings ----------
|
43
|
+
|
44
|
+
|
45
|
+
class Pack:
|
46
|
+
def __init__(self, name: str, description: str = "", pack_format: int = 82):
|
47
|
+
self._pack = PackDeclaration(name=name, description=description, pack_format=pack_format)
|
48
|
+
self._namespaces: List[Namespace] = []
|
49
|
+
self._variables: List[VariableDeclaration] = []
|
50
|
+
self._tags: List[TagDeclaration] = []
|
51
|
+
self._hooks: List = [] # HookDeclaration built by Namespace
|
52
|
+
|
53
|
+
def namespace(self, name: str) -> "Namespace":
|
54
|
+
ns = Namespace(self, name)
|
55
|
+
self._namespaces.append(ns)
|
56
|
+
return ns
|
57
|
+
|
58
|
+
# Lifecycle hooks reference functions by id "ns:name"
|
59
|
+
def on_load(self, function_id: str, scope: Optional[str] = None):
|
60
|
+
# defer to Namespace to create HookDeclaration during build
|
61
|
+
self._hooks.append(("on_load", function_id, scope))
|
62
|
+
|
63
|
+
def on_tick(self, function_id: str, scope: Optional[str] = None):
|
64
|
+
self._hooks.append(("on_tick", function_id, scope))
|
65
|
+
|
66
|
+
def tag(self, registry: str, name: str, values: Optional[List[str]] = None, replace: bool = False):
|
67
|
+
values = values or []
|
68
|
+
# We store TagDeclaration; the compiler writes tag files based on tag_type/name/file_path
|
69
|
+
# Here, we map registry + name to a tag reference name; file_path left as name for placeholder.
|
70
|
+
self._tags.append(TagDeclaration(tag_type=registry, name=name, file_path=name))
|
71
|
+
|
72
|
+
def declare_var(self, name: str, scope: str, initial_value: Union[int, float]) -> None:
|
73
|
+
self._variables.append(
|
74
|
+
VariableDeclaration(var_type="num", name=name, scope=scope, initial_value=num(initial_value))
|
75
|
+
)
|
76
|
+
|
77
|
+
def build(self, output_dir: str):
|
78
|
+
# Build Program AST
|
79
|
+
namespace_nodes: List[NamespaceDeclaration] = []
|
80
|
+
function_nodes: List[FunctionDeclaration] = []
|
81
|
+
hook_nodes: List = []
|
82
|
+
|
83
|
+
# Namespaces and functions
|
84
|
+
for ns in self._namespaces:
|
85
|
+
namespace_nodes.append(NamespaceDeclaration(name=ns.name))
|
86
|
+
function_nodes.extend(ns._functions)
|
87
|
+
hook_nodes.extend(ns._hooks)
|
88
|
+
|
89
|
+
# Hooks added via Pack-level convenience
|
90
|
+
for hook_type, function_id, scope in self._hooks:
|
91
|
+
ns_name, fn_name = function_id.split(":", 1)
|
92
|
+
from .ast_nodes import HookDeclaration
|
93
|
+
|
94
|
+
hook_nodes.append(
|
95
|
+
HookDeclaration(hook_type=hook_type, namespace=ns_name, name=fn_name, scope=scope)
|
96
|
+
)
|
97
|
+
|
98
|
+
program = Program(
|
99
|
+
pack=self._pack,
|
100
|
+
namespace=namespace_nodes[0] if namespace_nodes else None,
|
101
|
+
tags=self._tags,
|
102
|
+
variables=self._variables,
|
103
|
+
functions=function_nodes,
|
104
|
+
hooks=hook_nodes,
|
105
|
+
statements=[],
|
106
|
+
)
|
107
|
+
|
108
|
+
MDLCompiler(output_dir).compile(program, output_dir)
|
109
|
+
|
110
|
+
|
111
|
+
class Namespace:
|
112
|
+
def __init__(self, pack: Pack, name: str):
|
113
|
+
self._pack = pack
|
114
|
+
self.name = name
|
115
|
+
self._functions: List[FunctionDeclaration] = []
|
116
|
+
self._hooks: List = []
|
117
|
+
|
118
|
+
def function(self, name: str, *commands_or_builder: Union[str, Callable[["FunctionBuilder"], None]]):
|
119
|
+
builder = FunctionBuilder(self._pack, self, name)
|
120
|
+
|
121
|
+
# If a single callable is given, treat it as a builder lambda
|
122
|
+
if len(commands_or_builder) == 1 and callable(commands_or_builder[0]):
|
123
|
+
commands_or_builder[0](builder)
|
124
|
+
else:
|
125
|
+
# Interpret simple strings: say "..."; exec ns:name; raw lines fall back to RawBlock
|
126
|
+
for cmd in commands_or_builder:
|
127
|
+
if not isinstance(cmd, str):
|
128
|
+
continue
|
129
|
+
stripped = cmd.strip().rstrip(";")
|
130
|
+
if stripped.startswith("say "):
|
131
|
+
msg = stripped[len("say ") :].strip()
|
132
|
+
if msg.startswith("\"") and msg.endswith("\""):
|
133
|
+
msg = msg[1:-1]
|
134
|
+
builder.say(msg)
|
135
|
+
elif stripped.startswith("exec "):
|
136
|
+
target = stripped[len("exec ") :].strip()
|
137
|
+
# Optional scope in angle brackets e.g., util:helper<@s>
|
138
|
+
scope = None
|
139
|
+
if "<" in target and target.endswith(">"):
|
140
|
+
scope = target[target.index("<") :]
|
141
|
+
target = target[: target.index("<")]
|
142
|
+
builder.exec(target, scope)
|
143
|
+
else:
|
144
|
+
builder.raw(cmd)
|
145
|
+
|
146
|
+
func_node = FunctionDeclaration(namespace=self.name, name=name, scope=None, body=builder._body)
|
147
|
+
self._functions.append(func_node)
|
148
|
+
return func_node
|
149
|
+
|
150
|
+
# Convenience forwarding
|
151
|
+
def on_load(self, function_id: str, scope: Optional[str] = None):
|
152
|
+
from .ast_nodes import HookDeclaration
|
153
|
+
|
154
|
+
ns_name, fn_name = function_id.split(":", 1)
|
155
|
+
self._hooks.append(HookDeclaration(hook_type="on_load", namespace=ns_name, name=fn_name, scope=scope))
|
156
|
+
|
157
|
+
def on_tick(self, function_id: str, scope: Optional[str] = None):
|
158
|
+
from .ast_nodes import HookDeclaration
|
159
|
+
|
160
|
+
ns_name, fn_name = function_id.split(":", 1)
|
161
|
+
self._hooks.append(HookDeclaration(hook_type="on_tick", namespace=ns_name, name=fn_name, scope=scope))
|
162
|
+
|
163
|
+
|
164
|
+
class FunctionBuilder:
|
165
|
+
def __init__(self, pack: Pack, namespace: Namespace, function_name: str):
|
166
|
+
self._pack = pack
|
167
|
+
self._namespace = namespace
|
168
|
+
self._name = function_name
|
169
|
+
self._body: List = []
|
170
|
+
|
171
|
+
# Basics
|
172
|
+
def say(self, message: str):
|
173
|
+
self._body.append(SayCommand(message=message, variables=[]))
|
174
|
+
|
175
|
+
def raw(self, content: str):
|
176
|
+
self._body.append(RawBlock(content=content.rstrip(";")))
|
177
|
+
|
178
|
+
def exec(self, function_id: str, scope: Optional[str] = None):
|
179
|
+
ns, fn = function_id.split(":", 1)
|
180
|
+
self._body.append(FunctionCall(namespace=ns, name=fn, scope=scope))
|
181
|
+
|
182
|
+
# Variables
|
183
|
+
def declare_var(self, name: str, scope: str, initial_value: Union[int, float]):
|
184
|
+
self._pack.declare_var(name, scope, initial_value)
|
185
|
+
# Also set to initial value in this function
|
186
|
+
self.set(name, scope, num(initial_value))
|
187
|
+
|
188
|
+
def set(self, name: str, scope: str, value_expr) -> None:
|
189
|
+
self._body.append(VariableAssignment(name=name, scope=scope, value=value_expr))
|
190
|
+
|
191
|
+
# Control flow
|
192
|
+
def if_(self, condition_expr, then_builder: Callable[["FunctionBuilder"], None], else_builder: Optional[Callable[["FunctionBuilder"], None]] = None):
|
193
|
+
then_fb = FunctionBuilder(self._pack, self._namespace, self._name)
|
194
|
+
then_builder(then_fb)
|
195
|
+
else_body = None
|
196
|
+
if else_builder:
|
197
|
+
else_fb = FunctionBuilder(self._pack, self._namespace, self._name)
|
198
|
+
else_builder(else_fb)
|
199
|
+
else_body = else_fb._body
|
200
|
+
self._body.append(IfStatement(condition=condition_expr, then_body=then_fb._body, else_body=else_body))
|
201
|
+
|
202
|
+
def while_(self, condition_expr, body_builder: Callable[["FunctionBuilder"], None]):
|
203
|
+
body_fb = FunctionBuilder(self._pack, self._namespace, self._name)
|
204
|
+
body_builder(body_fb)
|
205
|
+
self._body.append(WhileLoop(condition=condition_expr, body=body_fb._body))
|
206
|
+
|
207
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: minecraft-datapack-language
|
3
|
-
Version: 15.4.
|
3
|
+
Version: 15.4.36
|
4
4
|
Summary: Compile MDL language with explicit scoping into a Minecraft datapack (1.21+ ready). Features variables, control flow, error handling, and VS Code extension.
|
5
5
|
Project-URL: Homepage, https://www.mcmdl.com
|
6
6
|
Project-URL: Documentation, https://www.mcmdl.com/docs
|
@@ -1,17 +1,18 @@
|
|
1
|
-
minecraft_datapack_language/__init__.py,sha256=
|
2
|
-
minecraft_datapack_language/_version.py,sha256
|
1
|
+
minecraft_datapack_language/__init__.py,sha256=0KVXBE4ScRaRUrf83aA2tVB-y8A_jplyaxVvtHH6Uw0,1199
|
2
|
+
minecraft_datapack_language/_version.py,sha256=-lqyDIq8xZADk9VgmkKo5oD27xSGH-vH7aUZSbeWTUQ,708
|
3
3
|
minecraft_datapack_language/ast_nodes.py,sha256=nbWrRz137MGMRpmnq8QkXNzrtlaCgyPEknytbkrS_M8,3899
|
4
4
|
minecraft_datapack_language/cli.py,sha256=-TMAL1HCCtwf0aG46x88MVBsYUswPRCVhy854li7X9c,9780
|
5
5
|
minecraft_datapack_language/dir_map.py,sha256=HmxFkuvWGkzHF8o_GFb4BpuMCRc6QMw8UbmcAI8JVdY,1788
|
6
|
-
minecraft_datapack_language/mdl_compiler.py,sha256=
|
6
|
+
minecraft_datapack_language/mdl_compiler.py,sha256=WNh1MFWyNHV0s3binx-afD_GAVGdRmG0P5id--btZxs,38393
|
7
7
|
minecraft_datapack_language/mdl_errors.py,sha256=r0Gu3KhoX1YLPAVW_iO7Q_fPgaf_Dv9tOGSOdKNSzmw,16114
|
8
8
|
minecraft_datapack_language/mdl_lexer.py,sha256=CjbEUpuuF4eU_ucA_WIhw6wSMcHGk2BchtQ0bLAGvwg,22033
|
9
9
|
minecraft_datapack_language/mdl_linter.py,sha256=z85xoAglENurCh30bR7kEHZ_JeMxcYaLDcGNRAl-RAI,17253
|
10
10
|
minecraft_datapack_language/mdl_parser.py,sha256=aQPKcmATM9BOMzO7vCXmMdxU1qjOJNLCSAKJopu5h3g,23429
|
11
|
+
minecraft_datapack_language/python_api.py,sha256=yU8SIhxRfCWsDW3qBheMQD2Ii0Y6-Tk9VMvVncEPlv4,8183
|
11
12
|
minecraft_datapack_language/utils.py,sha256=Aq0HAGlXqj9BUTEjaEilpvzEW0EtZYYMMwOqG9db6dE,684
|
12
|
-
minecraft_datapack_language-15.4.
|
13
|
-
minecraft_datapack_language-15.4.
|
14
|
-
minecraft_datapack_language-15.4.
|
15
|
-
minecraft_datapack_language-15.4.
|
16
|
-
minecraft_datapack_language-15.4.
|
17
|
-
minecraft_datapack_language-15.4.
|
13
|
+
minecraft_datapack_language-15.4.36.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
14
|
+
minecraft_datapack_language-15.4.36.dist-info/METADATA,sha256=7ZLAsFhF4cRd5kIMYe0MTK24UyL5dWzwK87_EJtulNU,8360
|
15
|
+
minecraft_datapack_language-15.4.36.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
minecraft_datapack_language-15.4.36.dist-info/entry_points.txt,sha256=c6vjBeCiyQflvPHBRyBk2nJCSfYt3Oc7Sc9V87ySi_U,108
|
17
|
+
minecraft_datapack_language-15.4.36.dist-info/top_level.txt,sha256=ADtFI476tbKLLxEAA-aJQAfg53MA3k_DOb0KTFiggfw,28
|
18
|
+
minecraft_datapack_language-15.4.36.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|