Getting Started
MDL (Minecraft Datapack Language) is a simple language that compiles to Minecraft datapack .mcfunction
files.
Installation
Install MDL using pipx:
pipx install minecraft-datapack-language
Quick Start
Create your first MDL file:
// hello.mdl
pack "hello" "My first datapack" 82;
namespace "hello";
function "main" {
say Hello, Minecraft!;
tellraw @a {"text":"Welcome to my datapack!","color":"green"};
}
on_load "hello:main";
Compile it:
mdl build --mdl hello.mdl -o dist
The compiled datapack will be in the dist
folder. Copy it to your Minecraft world’s datapacks
folder and run /reload
in-game.
Basic Concepts
Variables
Variables store numbers and can be scoped to different entities. MDL uses an explicit scope system where you must specify the scope each time you access a variable:
// Player-specific variable (default)
var num playerScore = 0;
// Server-wide variable
var num globalCounter scope<global> = 0;
// Team-specific variable
var num teamScore scope<@a[team=red]> = 0;
// Access variables with explicit scopes
playerScore<@s> = 42; // Player scope
globalCounter<global> = 100; // Global scope
teamScore<@a[team=red]> = 5; // Team scope
Variable Substitution
Use $variable$
to read variable values. Variables automatically resolve to their declared scopes:
say Your score: $playerScore$;
tellraw @a {"text":"Global counter: $globalCounter$","color":"gold"};
if "$playerScore$ > 100" {
say High score!;
}
Functions
Functions contain Minecraft commands:
function "my_function" {
say This is my function!;
effect give @s minecraft:speed 10 1;
}
// Call a function
function "hello:my_function";
// Call a function for all players
function "hello:my_function<@a>";
Control Structures
MDL supports real if/else statements and while loops:
// If statement
if "$playerScore$ > 50" {
say Great job!;
} else {
say Keep trying!;
}
// While loop
while "$counter$ < 5" {
say Counter: $counter$;
counter = counter + 1;
}
Explicit Scopes in Conditions
You can override variable scopes in conditions using explicit scope selectors:
// Check current player's score
if "$playerScore<@s>$ > 50" {
say "Your score is high!";
}
// Check global counter
if "$globalCounter<global>$ > 100" {
say "Global milestone reached!";
}
// Check another player's score
if "$playerScore<@p[name=Steve]>$ > 20" {
say "Steve has a good score!";
}
// Check team score
if "$teamScore<@a[team=red]>$ > 50" {
say "Red team is winning!";
}
This allows you to check variables across different scopes without changing their declared scope.
Hooks
Automatically run functions:
on_load "hello:init"; // Runs when datapack loads
on_tick "hello:update"; // Runs every tick
Complete Example
Here’s a complete example that demonstrates all the basic features:
pack "example" "Complete example" 82;
namespace "example";
// Variables
var num playerScore = 0; // Defaults to player-specific scope
var num globalTimer scope<global> = 0;
// Initialize function
function "init" {
playerScore<@s> = 0;
globalTimer<global> = 0;
say Game initialized!;
}
// Update function
function "update" {
globalTimer<global> = globalTimer<global> + 1;
if "$playerScore$ > 100" {
say High score!;
tellraw @a {"text":"Player has a high score!","color":"gold"};
}
if "$globalTimer$ >= 1200" { // 60 seconds
globalTimer<global> = 0;
say Time's up!;
}
}
// Score function
function "add_score" {
playerScore<@s> = playerScore<@s> + 10;
say Score: $playerScore$;
}
// Hooks
on_load "example:init";
on_tick "example:update";
Building and Testing
Single File
mdl build --mdl myfile.mdl -o dist
Multiple Files
mdl build --mdl "file1.mdl file2.mdl" -o dist
Directory
mdl build --mdl myproject/ -o dist
Testing
- Copy the
dist
folder to your Minecraft world’sdatapacks
folder - Run
/reload
in-game - Test your functions with
/function namespace:function_name
Next Steps
- Read the Language Reference for complete syntax
- Check out Examples for more complex examples
- Learn about Multi-file Projects for larger datapacks