--- id: multiplayer title: "Multiplayer — replication, netcode, the console" status: provisional source_sections: "PROGRESS_LOG.md §7 (Phase 7), §8 (P6); docs/HARD_PROBLEMS.md (P6)" related_topics: [wintesla-port, combat-damage, locomotion, decomp-reference] key_terms: [master, replicant, EGG, dead-reckon] open_questions: - "Cross-pod combat (damage to a replicant's master); replicant gait; pod-LAN config" --- # Multiplayer Pod-to-pod networked play. The hard infrastructure exists (WinTesla replaced DOS `NETNUB` with a WinSock2 TCP stack); the work is integrating + smoke-testing it for BT. Full detail: `docs/PROGRESS_LOG.md §7, §8`; the problem writeup: `docs/HARD_PROBLEMS.md` (P6). ## The stack (already reconstructed) - WinTesla replaced `NETNUB` with a **3446-line WinSock2 TCP** reimplementation (`MUNGA_L4/L4NET.CPP`, `SOCK_STREAM`/ReliableMode, zero SOCK_DGRAM); the master/replicant distributed-sim core (InterestManager/Entity/HostManager) is complete. So MP = integrate + smoke-test that stack (gated on P3 locomotion + P5 entity lifecycle + subsystem WAVEs). The rumored `L4NET.CPP:1853` send-size bug is DEAD CODE (`#if MESSAGE_BUFFERING`==0). [T2] ## Master / replicant model - **[[master]]** = a locally-simulated entity (your mech + dummies); drives itself + EMITS update records. - **[[replicant]]** = a peer's mech, a local proxy; DeadReckons toward the master's replicated position. MUST `SetValidFlag()` at creation or every message defers forever ([[reconstruction-gotchas]] §9). ## How a session forms `-net ` = networked mode (the pod listens on for a CONSOLE, boots ConsoleOnly; game mesh = +1). Solo (no `-net`) never touches WinSock. The mission egg's `[pilots]` section IS the roster (`pilot=ip[:port]` + a per-address page); each pod self-identifies by local-IP+game-port, connects to earlier pilots, listens for later ones — a deterministic full mesh; the mission loads when all connect. The **CONSOLE** (operator station — ABSENT from every archive) delivers the egg as chunked `ReceiveEggFileMessage` packets + the LAUNCH `RunMissionMessage`; **`tools/btconsole.py` is our console emulator** (⚠ `NotationFile::ReadText` expects NUL-SEPARATED lines). [T2] ## Verified milestones (one box, two instances) - **P6 smoke test:** two instances share a world — console egg → TCP mesh → synchronized start → bidirectional entity replication (each renders its own mech + the peer's REPLICANT), 0 crashes. - **Movement replication:** A's mech WALKS on B's screen (the replicant tracks the master to ~1.5u via dead-reckoning). The authentic mission-start ladder runs (CreatingMission→…→RunningMission via the console LAUNCH). SIX bugs fixed to get here (dead-reckoner install, replicant-motion DeadReckon, master emission threshold, emission gated on RunningMission, the console-must-LAUNCH fact, replicant validity). [T2] - **Wire-format bug class found+fixed:** MakeMessages replicate RAW over TCP, so string payload must be INLINE (`char[N]` at the binary offsets), not a `const char*` pointer (garbage cross-pod). Check EVERY MakeMessage for pointer payloads. [T2] ## Debug tooling (`BT_NET_TRACE`, permanent) `[net-tx]/[net-rx]` (L4NET), `[net-upd]` (update lookup), `[upd-repl]`, `[ent-exec]` (state ladder). Per-instance: `BT_LOG=` + `BT_AFFINITY=` (CPU pin). Update stream ≈ 60 Hz × 144-byte records per moving master. [T2] ## Remaining (P6 phase 4 / Phase 7) Cross-pod COMBAT (target a replicant + route damage to the owning master — Entity::Dispatch already reroutes); interactive 2-window driving; replicant GAIT animation (derive from replicated velocity); the pod-LAN config (real IPs, bare-IP pilot entries). See [[open-questions]]. [T3] ## Key Relationships - Base: [[wintesla-port]] (L4NET). Depends on: [[locomotion]] (update writer), [[combat-damage]] (entity lifecycle). Detail: `docs/HARD_PROBLEMS.md` (P6).