Python API
The MDL Python API provides a clean, programmatic way to create Minecraft datapacks. It’s fully compatible with the new JavaScript-style MDL language and supports all advanced features including variables, control flow, complex nesting, and the explicit scope system.
Quick Start
from minecraft_datapack_language import Pack
# Create a datapack
p = Pack("My Pack", "A cool datapack", 82)
# Add a namespace
ns = p.namespace("example")
# Add functions
ns.function("hello", "say Hello World!")
ns.function("welcome", "tellraw @a {\"text\":\"Welcome!\",\"color\":\"green\"}")
# Hook into Minecraft lifecycle
p.on_load("example:hello")
p.on_tick("example:welcome")
# Build the datapack
p.build("dist")
Core Classes
Pack
The main class for creating datapacks.
from minecraft_datapack_language import Pack
# Create a pack
p = Pack(
name="My Pack", # Pack name
description="Description", # Optional description
pack_format=82 # Minecraft pack format (default: 82)
)
Methods:
namespace(name)
- Create a namespaceon_load(function_id)
- Hook function to world loadon_tick(function_id)
- Hook function to ticktag(registry, name, values=[], replace=False)
- Create tagsbuild(output_dir)
- Build the datapack
Namespace
Represents a namespace for organizing functions.
ns = p.namespace("example")
# Add functions to the namespace
ns.function("function_name", "command1", "command2", ...)
Methods:
function(name, *commands)
- Add a function with commands
Basic Examples
Hello World
from minecraft_datapack_language import Pack
def create_hello_world():
p = Pack("Hello World", "A simple hello world datapack", 82)
ns = p.namespace("example")
ns.function("hello",
"say Hello, Minecraft!",
"tellraw @a {\"text\":\"Welcome to my datapack!\",\"color\":\"green\"}"
)
# Hook into world load
p.on_load("example:hello")
return p
# Create and build
pack = create_hello_world()
pack.build("dist")
Particle Effects
from minecraft_datapack_language import Pack
def create_particle_pack():
p = Pack("Particle Effects", "Creates particle effects around players", 82)
ns = p.namespace("particles")
ns.function("tick",
"execute as @a run particle minecraft:end_rod ~ ~ ~ 0.1 0.1 0.1 0.01 1",
"execute as @a run particle minecraft:firework ~ ~ ~ 0.2 0.2 0.2 0.02 2"
)
ns.function("init", "say Particle effects enabled!")
# Hook into lifecycle
p.on_load("particles:init")
p.on_tick("particles:tick")
return p
Advanced Features
Variables and Control Flow
The Python API supports all the advanced features of the JavaScript-style MDL language including the explicit scope system:
from minecraft_datapack_language import Pack
def create_advanced_pack():
p = Pack("Advanced Features", "Demonstrates advanced features", 82)
ns = p.namespace("advanced")
# Functions with variables and control flow using explicit scopes
ns.function("variable_demo",
"var num counter scope<global> = 0",
"counter<global> = 10",
"counter<global> = counter<global> + 5",
"if \"$counter$ >= 15\" {",
" say Counter is 15!",
" counter<global> = counter<global> - 5",
"}",
"say Counter is 15!"
)
ns.function("control_flow_demo",
"var num playerHealth = 20",
"if \"$playerHealth$ < 10\" {",
" say Health is low!",
" playerHealth<@s> = playerHealth<@s> + 5",
"} else {",
" say Health is good",
"}"
)
ns.function("loop_demo",
"var num countdown scope<global> = 5",
"while \"$countdown$ > 0\" {",
" say Countdown: $countdown$",
" countdown<global> = countdown<global> - 1",
"}",
"say Blast off!"
)
p.on_tick("advanced:variable_demo")
p.on_tick("advanced:control_flow_demo")
p.on_tick("advanced:loop_demo")
return p
Function Calls and Cross-Namespace References
from minecraft_datapack_language import Pack
def create_function_pack():
p = Pack("Function Calls", "Demonstrates function calls", 82)
# Core namespace
core = p.namespace("core")
core.function("init", "say Initializing...")
core.function("tick", "say Tick...")
# Utility namespace
util = p.namespace("util")
util.function("helper", "say Helper function")
util.function("helper2", "say Another helper")
# Main namespace with cross-namespace calls
main = p.namespace("main")
main.function("start",
"say Starting...",
"function core:init",
"function util:helper"
)
main.function("update",
"function core:tick",
"function util:helper2"
)
# Lifecycle hooks
p.on_load("main:start")
p.on_tick("main:update")
return p
Tags and Data
from minecraft_datapack_language import Pack
def create_tag_pack():
p = Pack("Tags and Data", "Demonstrates tags and data", 82)
ns = p.namespace("example")
ns.function("init", "say Tags initialized!")
# Function tags
p.tag("function", "minecraft:load", values=["example:init"])
p.tag("function", "minecraft:tick", values=["example:tick"])
# Item tags
p.tag("item", "example:swords", values=[
"minecraft:diamond_sword",
"minecraft:netherite_sword"
])
# Block tags
p.tag("block", "example:glassy", values=[
"minecraft:glass",
"minecraft:tinted_glass"
])
return p
Multi-Namespace Projects
from minecraft_datapack_language import Pack
def create_complex_pack():
p = Pack("Complex Pack", "Multi-namespace project", 82)
# Core systems
core = p.namespace("core")
core.function("init", "say Core systems initialized")
core.function("tick", "say Core tick")
# Combat system
combat = p.namespace("combat")
combat.function("weapon_effects",
"execute as @a[nbt={SelectedItem:{id:\"minecraft:diamond_sword\"}}] run effect give @s minecraft:strength 1 0 true"
)
combat.function("update_combat",
"function core:tick",
"function combat:weapon_effects"
)
# UI system
ui = p.namespace("ui")
ui.function("hud", "title @a actionbar {\"text\":\"Pack Active\",\"color\":\"gold\"}")
ui.function("update_ui",
"function ui:hud",
"function combat:update_combat"
)
# Lifecycle hooks
p.on_load("core:init")
p.on_tick("ui:update_ui")
return p
Error Handling and Validation
from minecraft_datapack_language import Pack
def create_safe_pack():
p = Pack("Safe Pack", "Demonstrates error handling", 82)
ns = p.namespace("safe")
# Safe function calls
ns.function("safe_teleport",
"execute as @a if entity @s run tp @s ~ ~ ~",
"execute unless entity @a run tellraw @a {\"text\":\"No players to teleport\",\"color\":\"red\"}"
)
# Conditional effects
ns.function("conditional_effects",
"execute as @a[nbt={SelectedItem:{id:\"minecraft:diamond\"}}] run effect give @s minecraft:strength 1 0 true",
"execute as @a unless entity @s[nbt={SelectedItem:{id:\"minecraft:diamond\"}}] run effect clear @s minecraft:strength"
)
p.on_tick("safe:safe_teleport")
p.on_tick("safe:conditional_effects")
return p
Building and Output
Basic Build
from minecraft_datapack_language import Pack
p = Pack("My Pack", "Description", 82)
ns = p.namespace("example")
ns.function("hello", "say Hello World")
# Build to directory
p.build("dist")
Custom Output
# Build with custom options
p.build("output_dir", wrapper="my_pack")
Integration with MDL Files
You can use the Python API alongside MDL files:
from minecraft_datapack_language import Pack
from minecraft_datapack_language.mdl_parser_js import parse_mdl_js
def create_hybrid_pack():
# Parse MDL file
with open("my_functions.mdl", "r") as f:
mdl_content = f.read()
ast = parse_mdl_js(mdl_content)
# Create pack via Python API
p = Pack("Hybrid Pack", "Combines MDL and Python", 82)
# Add functions from MDL
for func in ast['functions']:
ns = p.namespace(func.namespace)
ns.function(func.name, *func.commands)
# Add additional functions via Python API
ns = p.namespace("python")
ns.function("python_func", "say Created via Python API!")
return p
Best Practices
1. Organize by Namespace
def create_organized_pack():
p = Pack("Organized Pack", "Well-organized datapack", 82)
# Core systems
core = p.namespace("core")
core.function("init", "say Initializing...")
core.function("tick", "say Tick...")
# Feature modules
combat = p.namespace("combat")
ui = p.namespace("ui")
data = p.namespace("data")
# Each namespace handles its own functionality
return p
2. Use Function Composition
def create_composable_pack():
p = Pack("Composable Pack", "Uses function composition", 82)
ns = p.namespace("example")
# Small, focused functions
ns.function("check_player", "execute if entity @s[type=minecraft:player]")
ns.function("give_effect", "effect give @s minecraft:speed 10 1")
ns.function("send_message", "tellraw @s {\"text\":\"Effect applied!\",\"color\":\"green\"}")
# Compose functions
ns.function("player_effects",
"function example:check_player run function example:give_effect",
"function example:check_player run function example:send_message"
)
return p
3. Error Handling
def create_robust_pack():
p = Pack("Robust Pack", "Handles errors gracefully", 82)
ns = p.namespace("robust")
# Always check conditions before operations
ns.function("safe_operation",
"execute if entity @a run say Players found",
"execute unless entity @a run say No players found",
"execute if entity @a run effect give @a minecraft:speed 5 1"
)
return p
Complete Example
Here’s a complete example that demonstrates all features including the new explicit scope system:
from minecraft_datapack_language import Pack
def create_complete_pack():
"""Create a complete datapack demonstrating all features."""
# Create the pack
p = Pack("Complete Example", "Demonstrates all MDL features", 82)
# Core namespace
core = p.namespace("core")
core.function("init",
"var num gameState scope<global> = 0",
"var num playerLevel = 1",
"gameState<global> = 0",
"playerLevel<@s> = 1",
"say [core:init] Initializing Complete Example...",
"tellraw @a {\"text\":\"Complete Example loaded!\",\"color\":\"green\"}",
"scoreboard objectives add example_counter dummy \"Example Counter\""
)
core.function("tick",
"gameState<global> = gameState<global> + 1",
"say [core:tick] Core systems running... Game state: $gameState$",
"execute as @a run particle minecraft:end_rod ~ ~ ~ 0.1 0.1 0.1 0.01 1"
)
# Combat namespace
combat = p.namespace("combat")
combat.function("weapon_effects",
"execute as @a[nbt={SelectedItem:{id:\"minecraft:diamond_sword\"}}] run effect give @s minecraft:strength 1 0 true",
"execute as @a[nbt={SelectedItem:{id:\"minecraft:golden_sword\"}}] run effect give @s minecraft:speed 1 0 true"
)
combat.function("update_combat",
"function core:tick",
"function combat:weapon_effects"
)
# UI namespace
ui = p.namespace("ui")
ui.function("hud",
"title @a actionbar {\"text\":\"Complete Example Active - Level: $playerLevel$\",\"color\":\"gold\"}"
)
ui.function("update_ui",
"function ui:hud",
"function combat:update_combat"
)
# Data namespace
data = p.namespace("data")
data.function("setup_data",
"say Setting up data..."
)
# Lifecycle hooks
p.on_load("core:init")
p.on_tick("ui:update_ui")
# Function tags
p.tag("function", "minecraft:load", values=["core:init"])
p.tag("function", "minecraft:tick", values=["ui:update_ui"])
# Data tags
p.tag("item", "example:swords", values=[
"minecraft:diamond_sword",
"minecraft:netherite_sword"
])
p.tag("block", "example:glassy", values=[
"minecraft:glass",
"minecraft:tinted_glass"
])
return p
# Create and build the pack
if __name__ == "__main__":
pack = create_complete_pack()
pack.build("dist")
print("Complete example pack built successfully!")
The Python API provides a powerful, flexible way to create Minecraft datapacks with full support for the JavaScript-style MDL language features including the new explicit scope system.