Variables & Types
Declaring Variables
Use let for mutable variables and const for constants:
let health: int = 20;
let name: string = "Steve";
const MAX_PLAYERS: int = 16;const values cannot be reassigned:
const PI: fixed = 3.14;
PI = 3.15; // Error: cannot reassign constantNegative literals work in const declarations:
const MIN_SCORE: int = -50;
const DEPTH: int = -64; // e.g. Minecraft bedrock levelTypes
RedScript has a small set of primitive types plus a few Minecraft-facing value categories that show up constantly in real datapacks:
| Type | Description | Example |
|---|---|---|
int | Integer (scoreboard, 32-bit) | 42, -7, 0 |
fixed | Fixed-point decimal, stored at scale ×10000 | 1.0, 1.5 |
double | IEEE 754 double (NBT-backed) | x as double |
string | Text | "hello", "Steve" |
bool | Boolean | true, false |
selector | Minecraft entity/player selector | @s, @a[tag=runner] |
T[] | Array of one element type | int[], string[] |
Option<T> | Value that may be absent | Some(42), None |
v2.5.0 note:
floathas been renamed tofixed. Any existing code usingfloatwill trigger a deprecation warning and should be migrated tofixed. Thedoubletype is new.
Integers
let score: int = 0;
let negative: int = -10;
score = score + 1;Fixed-point (fixed)
fixed represents decimal values on scoreboards as integers scaled by ×10000. This is the language-level fixed-point representation for fractional math in datapacks.
let speed: fixed = 1.5; // stored as int 15000
let half: fixed = 0.5; // stored as int 5000
let one: fixed = 1.0; // stored as int 10000Key rules:
- Decimal literals are scaled for storage:
1.0→10000,1.5→15000,0.0→0 fixedarithmetic is scale-aware:a * banda / bare lowered by the compiler with×10000compensation.- Raw integer literals are
int; useas fixedto convert fromintordouble.
let x: int = 5;
let xf: fixed = x as fixed; // 5 * 10000 = 50000
let d: double = 3.14 as double;
let df: fixed = d as fixed; // floor(3.14 * 10000) = 31400Note:
stdlib/math.mcrsstill exposes legacy scale-specific helpers such assin_fixed,cos_fixed,sqrt_fixed,mulfix, anddivfix, which are×1000integer helpers. These are not replacements for languagefixedoperators.
Double (double)
double stores an IEEE 754 double-precision value in NBT storage (rs:d). It is used when integer or fixed-point precision is insufficient — e.g. for high-precision trig, physics simulation, or values that span a very wide range.
let pi: double = 3 as double; // start from int 3
// ... use math_hp functions to refineConversion:
let n: int = 42;
let d: double = n as double; // 42.0
let f: fixed = 1.5;
let d2: double = f as double; // 1.5 (divided by 10000 automatically)
let d3: double = /* some double */;
let back: fixed = d3 as fixed; // floor(d3 * 10000)
let back_int: int = d3 as int; // floor(d3)NBT storage:
doublevalues live inrs:d __dp0(and__dp1,__dp2, …). Direct assignment usesdata modify storage. Use functions fromstdlib/math_hp.mcrsfor arithmetic.
Explicit as casting
Starting in v2.5.0, numeric type conversions require an explicit as cast. Implicit coercion no longer works between int, fixed, and double.
// ✅ Correct — explicit cast
let n: int = 5;
let f: fixed = n as fixed; // 50000
// ❌ Error — implicit coercion removed
let f2: fixed = n; // compiler error: expected fixed, got intStrings
Use canonical f-strings (f"...{expr}...") for interpolation:
let player: string = "Alex";
let msg: string = f"Hello, {player}!";
say(msg); // Hello, Alex!Booleans
let alive: bool = true;
let creative: bool = false;Selectors
selector is the type used by commands that target entities or players. It is not stored like an int; it compiles into Minecraft selector syntax and execute context.
let nearest: selector = @p;
give(nearest, "minecraft:apple", 1);
foreach (player in @a[tag=runner]) {
actionbar(player, "Keep running!");
}Use @s when the current execute context matters, especially inside trigger/event handlers and foreach loops.
Arrays
Arrays hold multiple values of the same type:
let scores: int[] = [10, 20, 30];
let names: string[] = ["Alice", "Bob"];Access elements by index:
let first: int = scores[0]; // 10Arrays are homogeneous: every element must have the same type. Use for value in array to iterate values, or for i in 0..array.len when you need indexes.
Optional Values
Option<T> represents a value that might be missing. Use Some(value) when the value exists and None when it does not.
let maybe_score: Option<int> = Some(10);
let missing_score: Option<int> = None;
if let Some(score) = maybe_score {
say(f"Score: {score}");
}if let Some(x) = option { ... } is the supported unwrap pattern. Do not assume Rust-style helpers like .unwrap() or .unwrap_or() exist.
Type Inference
RedScript can infer the type when the value is obvious:
let health = 20; // inferred as int
let name = "Steve"; // inferred as string
let alive = true; // inferred as bool
let speed = 1.5; // inferred as fixedThis also works for const — the type annotation is optional:
const MAX_PLAYERS = 16; // inferred as int
const PREFIX = "[Game]"; // inferred as string
const RATE = 0.5; // inferred as fixedExplicit types are recommended for clarity, but optional.
Global Variables
Variables declared at the top level are global and accessible from any function:
let score: int = 0;
@throttle(ticks=20)
fn update() {
score = score + 1;
actionbar(@a, f"Score: {score}");
}
fn reset() {
score = 0;
}Global variables are stored as Minecraft scoreboard objectives.
Next Steps
- Functions — Define reusable logic
- Structs & Enums — Custom data types