RedScript 2.6: stdlib Expansion, Event System, and MC Integration Testing
Today I added five modules to RedScript’s standard library in one go, and then did something I had been postponing: adding an event system to Minecraft.
- GitHub: bkmashiro/redscript
Major stdlib expansion
RedScript always had a basic math library, but lacked support for more advanced algorithms. v2.6 fills that gap with five new modules at once.
graph.mcrs — adjacency lists + graph algorithms
Player and entity relations in Minecraft are naturally graph-structured. graph.mcrs implements:
- adjacency lists (simulated with scoreboards)
- BFS / DFS traversal
- Dijkstra shortest paths
Implementing Dijkstra under scoreboard-integer constraints is interesting: no floating-point arithmetic, so all weights must be integers, but the core idea remains the same.
ode.mcrs — RK4 numerical integration
A Runge-Kutta 4th-order ODE solver written in RedScript. It may look odd at first: why solve differential equations in Minecraft?
It turns out to be useful for physical simulation (ballistics, projectile motion), fluid approximation, and economic models. Because scoreboard precision is limited, this is fixed-point RK4, and under those constraints the precision is already sufficient.
linalg.mcrs — vectors, matrices, Cramer’s rule
A linear algebra module with double precision represented as scaled fixed-point numbers:
let v1: Vec3 = Vec3(1, 2, 3);
let v2: Vec3 = Vec3(4, 5, 6);
let dot: int = dot(v1, v2); // 32
let cross: Vec3 = cross(v1, v2);
Matrix inversion uses Cramer’s rule; for Minecraft precision requirements, 3×3 matrices are enough.
Debugging exposed an interesting cast bug: implicit conversion from integer to fixed-point overflows in some edge cases. I fixed it over the course of one morning.
fft.mcrs — DFT + @coroutine
A discrete Fourier transform executed with @coroutine frame-splitting.
The hardest part was trigonometric functions. Minecraft has no native sin/cos, so:
- Precompute sin/cos lookup tables at compile time (LUT), stored in NBT storage
math:tables. - Use table lookup at runtime, with interpolation good enough for practical precision.
@coroutine splits each DFT frequency component into separate game ticks, avoiding frame timeouts.
@coroutine
fn compute_spectrum(signal: int[]) {
// Auto-slicing by frames to avoid server lag
...
}
In the first test, the DC component was always zero. Tracing it showed an angle bug: 3600000 had been written as 360, a LUT precision issue. After fixing two places, it passed.
ecs.mcrs — Entity Component System
A lightweight ECS using scoreboards to simulate component storage:
@component
struct Health { value: int; }
@component
struct Speed { value: int; }
@system
fn move_system(e: Entity) {
if has_component(e, Speed) {
// ...
}
}
Entity IDs are stored in scoreboards, and component data hangs on each entity’s scores. @system generates iteration logic.
Event system: @on(EventType)
This is the most important new feature in v2.6.
Before this, RedScript had no way to react to game events (player join, death, block break, etc.). This added a compile-time statically registered event system:
@on(PlayerJoin)
fn greet(p: Player) {
tellraw(p, "欢迎!");
rs.joined += 1;
}
@on(PlayerDeath)
fn on_death(p: Player) {
rs.deaths += 1;
}
Architecture:
@on(EventType)registers handlers statically at compile time.- Generates
events.mcrsto poll and dispatch each tick. - Uses Minecraft’s native advancement mechanism to trigger events (e.g.
minecraft:adventure/rootchecks join).
BlockBreak design tradeoff
The initial design was two-argument BlockBreak(p: Player, blockType: BlockType), but Minecraft cannot pass the broken block type into mcfunction at runtime. It was ultimately changed to a single argument (p: Player)—if a specific block type needs counting, pre-record it in a scoreboard.
MC integration testing
To validate the event system, I ran integration tests on a local Minecraft server (~/mc-test-server):
- Start server and load datapack.
- Player joins ->
rs.joinedscoreboard increments by 1. - Player dies ->
rs.deathsscoreboard increments by 1. - Read scoreboards and verify values.
During debugging I found a scoreboard_get/set Player-parameter bug: the ident fallback in exprToCommandArg did not correctly point to @s, so generated command targets were wrong. After fixing, all 440 tests passed.
Reflection
What was most interesting today was not any one algorithm, but API design under Minecraft constraints. There is no floating-point arithmetic, no dynamic arrays, no deep recursion (call-chain limits can freeze the server)—every language feature has to be considered by what command it will compile into.
ECS components in scoreboards, FFT lookup-table trigonometry, fixed-point ODEs—those constraints create a strange kind of elegance.
The full v2.6 changelog is in CHANGELOG.md.