SplitScript reference / Language / state

state

declaration

state "game.exe" { ... } | state ["game.exe", "demo.exe"] { ... } | state Provider { ... }

Declares process attachment and persistent watched state.

A native string is an exact host process identity. The current Windows host reports executable filenames including .exe, so a Windows candidate must include that extension. An array tries alternate executable names in order; it does not attach to several processes at once. A named standard-library provider selects a typed memory model. Unity binds managed image schemas while GBA, PS1, PS2, SMS, Genesis, GCN, and Wii expose emulator-specific read roots and accept original console addresses in state fields. Put build-specific memory shapes in named layout blocks instead of duplicating ASL-style state declarations. With attachment-wide layout dimensions, conditional state fields may use an if / else if / else chain; later branches cover the exact layout combinations left unmatched by earlier branches. Every state expression has one implicit fallible boundary (T!): internal postfix ? and a fallible final call propagate into that same boundary. Use an ordinary value block when address discovery or decoding needs several local steps; its final expression supplies the field value without requiring a helper function. A field may use another field from the same active layout by name, including as the base of an at path. Declaration order is irrelevant: the compiler evaluates dependencies first and rejects cycles. Initialization requires all required fields to succeed in one poll and seeds old and current equally without running lifecycle actions. Later, failed fields retain their accepted values while successful independent fields advance; a dependent field is not evaluated when one of its dependencies fails. Deliberately optional reads can discard their error into T? with discardError.

Examples

Read state from a native process

state "game.exe" {
    score = process.read<i32>(0x1000);
}

Compose fallible address discovery with a read

state "game.exe" {
    score: i32 = {
        let address = process.follow(0x1000, [0x20])?
        process.read(address)
    };
}

Try alternate executable names

state ["game.exe", "game-demo.exe"] {
    score: i32 at 0x1000;
}

Support multiple game builds

state "game.exe" {
    layout Steam {
        level: u32 at 0x1000;
        checkpoint: u8 at 0x1100;
    },

    layout GOG {
        level: u32 at 0x2000;
        checkpoint: u16 at 0x2100;
    },
}

onAttach {
    let module = await process.mainModule()
    if module.size == 10_000 {
        return StateLayout.Steam
    }
    if module.size == 20_000 {
        return StateLayout.GOG
    }
    await process.closed()
}

whileAttached {
    setVariable("Level", current.level)
    setVariable("Checkpoint", match layout {
        StateLayout.Steam => current.checkpoint as u16,
        StateLayout.GOG => current.checkpoint,
    })
}

Read state from a GBA emulator

state GBA {
    room: u8 at 0x03000010;
}

Read state from a PlayStation emulator

state PS1 {
    health: u16 at 0x80012346;
}

Read state from a PlayStation 2 emulator

state PS2 {
    health: u16 at 0x00123456;
}

Read state from a Master System emulator

state SMS {
    lives: u8 at 0xc010;
}

Read state from a Sega Genesis emulator

state Genesis {
    score: u32 at 0x1200;
}

Read state from a GameCube emulator

state GCN {
    room: u16 at 0x80001000;
}

Read state from a Wii emulator

state Wii {
    room: u16 at 0x80001000;
}