# 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): ```text 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 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. ```rust #[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. | Setting | Type | Default | Range or values | Meaning | |---|---|---|---|---| | `preset` | string | `"none"` | `none`, `ghost-race`, `async-pvp`, `daily-challenge` | Ready-made option set applied between the defaults and this config (defaults ← preset ← your keys, merged key by key; rules too):… | | `game` | string | `"arena"` | | arena / physics = deterministic games of the core (replayable, verified by server replay); any other name = your engine game… | | `physics` | string | `"none"` | `none`, `native`, `shared` | shared = the game physics (net.physics) inside the core; native = your engine physics, recorded as samples (game must then be… | | `record` | string | `"both"` | `inputs`, `samples`, `both` | What a run stores: input streams (net.rollback format), transform samples, or both. | | `players` | integer | `1` | 1–8 | Slots of the recorded game (2+ for async PvP). | | `slot` | integer | `0` | 0–7 | The recording player's slot (< players). | | `opponentSlot` | integer | `-1` | -1–7 | Async PvP: slot played by the loaded opponent run (< players, ≠ slot; -1 = auto: the first slot other than slot when an opponent… | | `frameHz` | integer | `60` | 10–120 | Frames per second of a run. | | `sampleHz` | integer | `10` | 1–60 | Transform samples per second. | | `maxFrames` | integer | `36000` | 60–216000 | Longest recording (frames); recording stops there. | | `clock` | string | `"core"` | `core`, `host` | core = frames advance with time; host = on step() (your fixed update drives the run). | | `board` | string | `""` | | Board / challenge key of the runs (daily-YYYY-MM-DD for daily challenges). | | `order` | string | `"desc"` | `desc`, `asc` | Boards: higher (desc) or lower (asc) scores first. | | `app` | string | `""` | | Application id written in runs (the wrappers fill it from net.transport app). | | `player` | string | `""` | | Player name written in runs. | | `engine` | string | `""` | | Engine tag written in runs (web, godot, unity, unreal; set by the wrappers). | | `apiUrl` | string | `""` | | Run API up to /api/v1/async (GripForge: https:///api/v1/async; self-hosted: gf-async-server). | | `apiKey` | string | `""` | | x-api-key for the GripForge API. | | `rules` | object | `{"minFrames": 1, "maxSpeed": 0, "speedSlack":…` | | Server checks of a submitted run (merged key by key over the preset's). | | `maxRuns` | integer | `1000` | 1–100000 | Async gfnet server (gf-net-server --model async): runs kept in memory. | | `maxRunBytes` | integer | `262144` | 1024–1048576 | Largest run accepted (bytes). | | `uploadChunksPerSecond` | number | `6` | 1–60 | Client: run upload rate (chunks of 32000 base64 characters per second). | | `maxPartialUploadsPerPeer` | integer | `2` | 1–64 | Server: uploads in progress per peer. | | `boardRows` | integer | `100` | 1–1000 | Largest board / run list a query or a client asks for. | | `boardDefaultRows` | integer | `10` | 1–1000 | Rows 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.