--- id: steam-networking title: "Steam networking — the BT_STEAM wire (transport + lobby)" status: living source_sections: "docs/GLASS_COCKPIT.md §4; docs/STEAM_TEST.md; commits e79e8fa/48ede2f/f703bb1" related_topics: [glass-cockpit, multiplayer] key_terms: [PadRIO, miniconsole] open_questions: ["live 2-account cross-machine session (docs/STEAM_TEST.md) — the step-4 exit criterion"] --- # Steam networking — the BT_STEAM wire Internet MP for the glass cockpit (dev tooling; gate `BT_STEAM`, requires `BT_GLASS`). **Status: CODE COMPLETE 2026-07-18; single-machine verified; live 2-machine test pending.** ## The three layers 1. **The wire seam** (`L4NET.CPP`, always compiled): file-local `BTNetSend/Recv/Accept/Close` wrappers around the 9 raw Winsock sites — pure code motion when OFF; under `BT_STEAM` each offers the op to the transport first. Est. delegates: `CheckSocket` (peer address), `OpenConnection` TCP_OPEN head, `GetMyAddress` (self token). 2. **The transport** (`engine/MUNGA_L4/L4STEAMNET.*`, gated): `ISteamNetworkingSockets` pseudo-SOCKETs (`0x5EA0xxxx`); engine TCP byte stream over reliable-NoNagle messages with per-connection reassembly rings (recv: empty→`WSAEWOULDBLOCK`, closed→0); listen channels console=0 / game=1 (`CreateListenSocketP2P`); install on env `BT_STEAM_NET=1`; degrades to Winsock at every failure. Pump = `SteamAPI_RunCallbacks` AND sockets `RunCallbacks` (the general dispatch carries the async results — sockets-only pumping stalls). 3. **The lobby** (`game/glass/btl4lobby.*`, gated): ISteamMatchmaking room (`btl4=1` list filter); pilots publish name/mech/color; the host's GO mints the roster and signals. ## THE TOKEN MODEL (the FakeIP lesson) [T2] FakeIP does NOT survive the per-mission process relaunch (live-disproven prior-art assumption: menu and mission processes got different FakeIPs; the pod timed out dialing its own stale address). Roster addresses are therefore **opaque ipv4-shaped tokens** — `169.254.77.N`, port 1501=console / 1502=game — minted by the HOST at GO and mapped to **Steam identities**; connections ride `ConnectP2P(identity, channel)`. Handoff to mission processes via env: `BT_FE_MYFAKE` (own token → `GetMyAddress` self-match) + `BT_FE_STEAMMAP` (`ip=steamid64;...`). The engine's roster matching, Waterloo swap logic, and self-identification all run UNCHANGED on tokens. ## Testing Single-machine (verified): lobby-of-1 GO → token map → egg roster token → mission runs over the stock console ladder. Live 2-machine procedure + checklist: `docs/STEAM_TEST.md`. AppID 480 (Spacewar) via auto-written gitignored `content/steam_appid.txt`. ## Key Relationships - Rides: [[glass-cockpit]] miniconsole (marshal has a Steam-wire branch) · Extends: [[multiplayer]] (the arcade mesh, unchanged above the seam)