Skip to content

Server & slots

The server side coordinates connected clients. These builtins and events let it track who's connected, run periodic work, and move clients between shards.

Connection events

munos
event connect(client: client, handoff: u8[])   // a client joined
event disconnect(client: client)               // a client left

connect fires on a fresh connection (empty handoff) or when a client hopped in from another shard (handoff is whatever they brought). event disconnect fires on any departure — clean leave, crash, or hop away. Maintain your per-client state in both.

Slots

The runtime assigns each connected client a slot in [0, max_clients()) — the lowest free index at connect time. Slots key parallel arrays to specific clients.

munos
slot(c: client): i32      // server-only: a client's slot index
max_clients(): i32        // both roles: the shard's configured capacity

The standard per-player pattern: a client[] of handles for outbound send, an occupied[] of liveness flags, and parallel data arrays — all maintained in connect / disconnect:

munos
server {
    var clients: client[1024]
    var occupied: bool[1024]
    var playerX: u8[1024]
    var playerY: u8[1024]

    event connect(c: client, handoff: u8[]) {
        var s = slot(c)
        clients[s] = c
        occupied[s] = true
        playerX[s] = 0
        playerY[s] = 0
    }

    event disconnect(c: client) {
        occupied[slot(c)] = false
    }
}

Slot rules

  • Slots are reused. A freed slot may go to the next joiner — clear stale data on disconnect (or overwrite on the next connect).
  • Size arrays to a max, loop to max_clients(). Array sizes are compile-time constants, so allocate generously; use max_clients() for loop bounds so the script ports across differently-sized shards.
  • Pair handles with occupied[]. A client handle is valid only while its slot is occupied — calling slot() or send() on a stale handle traps. Check occupied[i] before using clients[i], like null-checking a pointer.

Server tick

munos
event tick(tick_num: i32)

tick_rate(): i32            // current rate in Hz
set_tick_rate(hz: i32)      // change it; takes effect immediately

event tick is the server heartbeat — there's no game on the server, so this is where periodic work lives (state fan-out, interest management, AI). It fires tick_rate() times per second; the default is 30 Hz. tick_num is monotonic from 0.

Fan out state from tick, not from receive — see the relay walkthrough.

munos
event tick(tick_num: i32) {
    for (var i = 0; i < max_clients(); i = i + 1) {
        if !occupied[i] { continue }
        // ...send each client what it needs...
    }
}

Moving clients between shards

A client can move to another shard, initiated from either side:

munos
hop(url: string, handoff: u8[])                      // client initiates
redirect(client: client, url: string, handoff: u8[]) // server pushes a client

Both disconnect-and-reconnect the client to url, delivering handoff to the destination's event connect. If the destination runs the same script, local client state (variables, loaded images) persists and only the server-side partner changes; if it runs a different script, the new one is fetched and instantiated and only the handoff payload carries over.

hop is client-side; redirect is server-side.

Part of the MultiNostalgia project.