Yuzhe's Blog

yuzhes

RedScript v3.0 — match Expressions, For-Each Iteration, and Major stdlib Expansion

RedScript v3.0 — match Expressions, For-Each Iteration, and Major stdlib Expansion

RedScript v3.0 is officially released. This release focuses on making code feel more natural—less boilerplate and clearer intent expression.


match expressions

Say goodbye to long if/else chains. match makes branch logic immediately readable:

match player_state {
    STATE_IDLE    => { start_walking(p) }
    STATE_WALKING => { check_destination(p) }
    STATE_COMBAT  => { update_combat(p) }
    _             => { }
}

Wildcard _ handles all unlisted cases, and the compiler will prompt you if branches are missing.

match also supports parenthesized form, and match (v) { } is fully equivalent to match v { }—choose whichever style you prefer.

Option pattern matching

Together with if let, handling possibly empty values becomes clean:

let opt: Option<int> = find_target(p)
if let Some(target_id) = opt {
    attack(p, target_id)
}

No more manual checks for -1 or magic sentinel values.


for item in array

v3.0 supports direct iteration over array elements without manual indexing:

// Old style
for i in 0..items.len() {
    process(items[i])
}

// New style
for item in items {
    process(item)
}

It is shorter and less prone to out-of-bounds mistakes.


Three new stdlib modules

state.mcrs — player state machine

Use integers to bind player states; state storage is managed uniformly by stdlib:

set_state(p, STATE_COMBAT)
let s: Option<int> = get_state(p)

get_state returns Option<int> and is None when unset; it pairs best with if let.

dialog.mcrs — dialog and UI

Three lines to set up dungeon intro prompts:

dialog_say(p, "Welcome to the dungeon!")
dialog_title(p, "Chapter 1", "City of the Lost")
dialog_actionbar(p, "§eHP: 100 / 100")

dialog_say uses chat, dialog_title uses title + subtitle, and dialog_actionbar uses action bar, covering three MC UI channels.

scheduler.mcrs — delayed task scheduling

No need to maintain custom timer scoreboards anymore:

task_schedule(p, 0, 100)  // trigger task 0 after 100 ticks

// Check in @tick function
if (task_ready(p, 0) == 1) {
    spawn_boss(p)
}

Each player can schedule multiple tasks independently (distinguished by task ID), and scheduler_tick() advances timing.


Combined example: dungeon opening sequence

Putting the three modules together, a dungeon intro with a waiting state only needs:

import "stdlib/state"
import "stdlib/dialog"
import "stdlib/scheduler"

const STATE_WAITING:  int = 0
const STATE_STARTING: int = 1
const STATE_ACTIVE:   int = 2

@on(PlayerJoin)
fn on_join(p: Player) {
    set_state(p, STATE_WAITING)
    dialog_title(p, "§6Doom Dungeon", "§7Waiting for more players...")
}

@tick
fn game_tick() {
    scheduler_tick()
}

Player joins → sets waiting state → displays title. Later, game_tick can check player count, and once threshold is reached call task_schedule for countdown start, then dispatch phase logic with match—no extra scoreboard scaffolding needed.


Upgrade guide

Upgrading from v2.x to v3.0 is non-breaking; existing code works directly. New features are fully backward compatible:


📖 Full docs: redscript-docs.pages.dev

Previous: RedScript 2.6: stdlib expansion, event system, and MC integration testing