Network: asynchronous multiplayer (ghosts, replays, async PvP, boards)

Supports asynchronous multiplayer with nobody online at the same time: record a run, upload it, and let other players race it as a ghost, replay it or compete on boards.

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

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

Network: asynchronous multiplayer (ghosts, replays, async PvP, boards) (net.async) #

What it is for #

Supports asynchronous multiplayer with nobody online at the same time: record a run, upload it, and let other players race it as a ghost, replay it or compete on boards.

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.async" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "net.async",
                              config: { "preset": "none", "game": "arena" } }

First example #

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

#[test]
fn a_server_in_the_transport_makes_the_session_connect() {
    let mut s = session(
        &[
            ("net.transport", json!({ "url": "ws://127.0.0.1:9" })),
            (KIT, json!({})),
        ],
        true,
    );
    let sessions = call(&mut s, "probe.core", "sessions", json!([]));
    assert_eq!(sessions[0]["config"]["model"], "async");
    assert_eq!(
        sessions[0]["config"]["transport"]["url"],
        "ws://127.0.0.1:9"
    );
    assert!(commands(&mut s).iter().any(|c| c["c"] == "connect"));
}

Settings and defaults #

Descriptions come from the kit manifest and stay in English.

SettingTypeDefaultRange or valuesMeaning
presetstring"none"none, ghost-race, async-pvp, daily-challengeReady-made option set applied between the defaults and this config (defaults ← preset ← your keys, merged key by key; rules too):…
gamestring"arena"arena / physics = deterministic games of the core (replayable, verified by server replay); any other name = your engine game…
physicsstring"none"none, native, sharedshared = the game physics (net.physics) inside the core; native = your engine physics, recorded as samples (game must then be…
recordstring"both"inputs, samples, bothWhat a run stores: input streams (net.rollback format), transform samples, or both.
playersinteger11–8Slots of the recorded game (2+ for async PvP).
slotinteger00–7The recording player's slot (< players).
opponentSlotinteger-1-1–7Async PvP: slot played by the loaded opponent run (< players, ≠ slot; -1 = auto: the first slot other than slot when an opponent…
frameHzinteger6010–120Frames per second of a run.
sampleHzinteger101–60Transform samples per second.
maxFramesinteger3600060–216000Longest recording (frames); recording stops there.
clockstring"core"core, hostcore = frames advance with time; host = on step() (your fixed update drives the run).
boardstring""Board / challenge key of the runs (daily-YYYY-MM-DD for daily challenges).
orderstring"desc"desc, ascBoards: higher (desc) or lower (asc) scores first.
appstring""Application id written in runs (the wrappers fill it from net.transport app).
playerstring""Player name written in runs.
enginestring""Engine tag written in runs (web, godot, unity, unreal; set by the wrappers).
apiUrlstring""Run API up to /api/v1/async (GripForge: https://<host>/api/v1/async; self-hosted: gf-async-server).
apiKeystring""x-api-key for the GripForge API.
rulesobject{"minFrames": 1, "maxSpeed": 0, "speedSlack":…Server checks of a submitted run (merged key by key over the preset's).
maxRunsinteger10001–100000Async gfnet server (gf-net-server --model async): runs kept in memory.
maxRunBytesinteger2621441024–1048576Largest run accepted (bytes).
uploadChunksPerSecondnumber61–60Client: run upload rate (chunks of 32000 base64 characters per second).
maxPartialUploadsPerPeerinteger21–64Server: uploads in progress per peer.
boardRowsinteger1001–1000Largest board / run list a query or a client asks for.
boardDefaultRowsinteger101–1000Rows of a board / run list when the query does not say.

Services, events, variables #

  • Service net.async: recordStart / recordStop / export, loadGhost / play / ghost, submit / fetch / board / daily (HTTP), verify (local).
  • Service net.replay: Compact recordings of a run (inputs + samples), replayed bit-exactly for the deterministic games.
  • Events emitted:
    • net.async.recorded (id, bytes, frames, score) — A recording stopped; export() returns it.
    • net.async.submitted (ok, id, score, rank) — The server verified (or refused) a run.
    • net.async.ghost_end (ghost, id) — A ghost reached the end of its run.
    • net.refused (code, msg) — 1.2: the server of the session path refused the handshake (version, app, model, full…; mods: it runs other mods than this game,…
  • Variables:
    • net.async.frame (number) — Run frame
    • net.async.score (number) — Run score
    • net.async.recording (boolean) — Recording

Hooks and modding #

This kit declares no hook and no collection to mod.

Engines #

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

Versions #

Kit version 1.2.0.