Network sync: rollback / lockstep (deterministic)

Synchronises peers by inputs only: they run the same deterministic simulation, either predicting remote inputs and re-simulating on a misprediction (rollback) or waiting for every input of a frame (lockstep).

Source: module-kits:kits/net_rollback/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs net-rollbackMCP tool: gripforge_docs { "topic": "net-rollback" }

Network sync: rollback / lockstep (deterministic) (net.rollback) #

What it is for #

Synchronises peers by inputs only: they run the same deterministic simulation, either predicting remote inputs and re-simulating on a misprediction (rollback) or waiting for every input of a frame (lockstep).

It needs net.transport, input.actions, game.engine; installing it brings them in.

Turn it on #

Install the kit in a project, then change a setting (the values shown are its defaults):

gripforge_gamekit_install   { project_id: "gkp_…", id: "net.rollback" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "net.rollback",
                              config: { "mode": "rollback", "players": 2 } }

First example #

<!-- test: kits/net_rollback/tests/net_rollback.rs::input_actions_feed_the_arena_bits_when_no_input_is_set --> This is the body of the passing test input_actions_feed_the_arena_bits_when_no_input_is_set; the helper functions it calls are defined at the top of the same test file.

#[test]
fn input_actions_feed_the_arena_bits_when_no_input_is_set() {
    let mut s = online(json!({}));
    commands(&mut s);
    s.apply(&json!({ "op": "key", "code": "Space", "down": true }))
        .unwrap();
    step(&mut s, 1);
    let sent = inputs(&mut s);
    assert_eq!(
        sent[0]["v"].as_u64().unwrap() & 16,
        16,
        "jump is bit 16: {sent:?}"
    );
    s.apply(&json!({ "op": "key", "code": "Space", "down": false }))
        .unwrap();
    step(&mut s, 1);
    assert_eq!(
        inputs(&mut s).last().unwrap()["v"].as_u64().unwrap() & 16,
        0
    );
}

Settings and defaults #

Descriptions come from the kit manifest and stay in English.

SettingTypeDefaultRange or valuesMeaning
modestring"rollback"rollback, locksteprollback = predict + re-simulate; lockstep = wait for every input.
playersinteger21–8Slots of a match; it starts when all are filled.
frameHzinteger6010–120Simulation frames per second.
inputDelayinteger20–30Local inputs apply this many frames later (hides latency, fewer rollbacks).
maxRollbackinteger80–30Never predict further than this past the last confirmed frame (stall instead).
maxBehindFramesinteger301–600A peer more than this many frames behind the match clock catches up without rendering the frames in between.
hashEveryinteger600–6000Frames between state hash checks (0 = off).
maxPendingHashesinteger641–4096State hashes waiting for comparison per peer.
hashWindowFramesinteger60060–100000Relay: frames of state hashes kept for comparison.
inputLogFramesinteger36000600–1000000Relay: frames of input kept for resumed peers.
maxAheadFramesinteger12010–6000Relay: inputs further ahead of the match clock are refused.
relayMsinteger505–1000Relay: resend period of unacknowledged inputs.
orderResendMsinteger305–1000Peer: pending orders are batched and sent at most every max(2 frames, orderResendMs) (orders ride the reliable channel).
resyncGapMsinteger2000100–60000A peer that received nothing for this long asks the relay for a resync.
seedinteger00–2147483647Match seed (0 = random).
gamestring"arena"arena, physicsThe deterministic game every peer runs inside the core: the integer arena, or the net.physics arena (needs physics: shared).
physicsstring"none"none, sharednone, or shared = net.physics (engine physics is not deterministic across machines, so native is not offered).
inputTimeoutMsinteger00–600000Relay: a connected player that sends no input for this long is declared left and disconnected (0 = off).
ordersbooleantrueRelay: offer the structured orders channel (RTS commands, r.ord); gfnet-core peers only.
maxOrderBytesinteger102464–1024Largest order (canonical JSON bytes).
maxOrdersPerFrameinteger41–32Orders per player and per frame.
orderDelayinteger00–120Orders apply at least this many frames ahead (never earlier than inputDelay).
turnMs0Turn-based lockstep (RTS style): turn length in ms (typically 100–200; 50–1000), 0 = off.
turnDelayinteger21–10Turns between issuing an order and running it.
adaptiveTurnbooleanfalseRelay: stretch the turn to the slowest round trip (never below turnMs, at most adaptiveTurnMaxMs).
adaptiveTurnMaxMsinteger50050–2000Adaptive turns never grow past this (ms).
adaptiveTurnPeriodMsinteger1000100–60000Relay: the adaptive turn is re-evaluated this often.
adaptiveTurnRttFactornumber1.21–4Relay: the adaptive turn covers the slowest round trip × this.

Services, events, variables #

  • Service net.sync: The project replication model (one per project: the net.* sync kits conflict with each other).
  • Service net.rollback: register(game), setInput(bits), state(), frame(); rollback / desync events.
  • Service net.lockstep: The same session in strict lockstep (mode: lockstep).
  • Events emitted:
    • net.match_started (slot, players, seed) — All slots filled; frame 0 starts.
    • net.desync (frame) — State hashes differ between peers (non-deterministic game code).
    • net.slot_left (slot, frame) — A player left; its input is neutral from frame.
    • net.connected (id, resumed, transport) — Welcome received on a session reopened by register(game) (the first session reports it through the shared session mirror, as net.transport declares).
    • net.peer (id, on) — Another peer joined or left a session reopened by register(game).
    • net.refused (code, msg) — 1.4: the handshake of a session reopened by register(game) was refused (the core's code; mods: the server runs other mods, net.transport 1.3).
  • Variables:
    • net.status (string) — Network status
    • net.rtt (number) — Ping (ms)
    • net.peers (number) — Players online
    • net.frame (number) — Frame
    • net.rollbacks (number) — Rollbacks

Hooks and modding #

This kit declares no hook and no collection to mod.

Engines #

Declared targets: web, godot, unity, unreal. gripforge kit api net.rollback lists the exact settings and services of your version.

Versions #

Kit version 1.4.0.