# RP412 Front End & Steam Multiplayer — Design Notes Findings from reading TeslaConsole's Red Planet control code (`TeslaSuite/Console/TeslaConsole.RedPlanet/`) against the game side (`MUNGA_L4/L4NET.CPP`, `MUNGA/NETWORK.cpp`), and how a Steam front end maps onto it. Written 2026-07-12 for the implement-decision. ## 1. What the console actually does TeslaConsole is four things, and RP412's front end must absorb all four: ### a) Pod control channel (`Munga.Net`, TCP console port) Per-pod state machine (`RPGame.cs`): take **ownership** of a pod, watch its app state, and drive the lifecycle: ``` WaitingForEgg --egg chunks--> (ACK, 5s retry) WaitingForLaunch --RunMissionMessage--> RunningMission --telemetry--> EndMission (final scores) --AbortMissionMessage--> reset ``` The egg is sent as `EggFileMessage` chunks of 1000 bytes with an `AcknowledgeEggFileMessage` reply from the pod. ### b) The mission egg (the ENTIRE mission definition) A NotationFile-format text file (`RPMission.ToEggString()`), newline→NUL: ```ini [mission] adventure=Red Planet, scenario, map, time, weather, temperature, compression, length (seconds) [pilots] ordered pilot= list (players, then cameras) [
] per participant: hostType, dropzone, name, bitmapindex, loadzones, vehicle, color, badge (+ team/position in football) [largebitmap] player names PRE-RENDERED as 1bpp bitmaps for the plasma [smallbitmap] glass (128x32 and 64x16), generated by the console [ordinals] 1st-4th place plasma graphics (hardcoded art) ``` The game already loads a local egg with `-egg ` (standalone mode) — the same text format. **Building an egg locally = the whole single-player front end problem.** ### c) The catalog (`RedPlanet/RPConfig.xml`) Two scenarios — **Martian Death Race** and **Martian Football** (2-color teams, crusher/blocker/runner positions) — 11 maps, ~30 vehicles (sharing a handful of models), 9 colors, 11 badges, day/night, 3 weather levels, with per-scenario exclusion lists. Clean data file; reusable as-is. ### d) Results & telemetry During the mission the pods stream `VTVBooster/Damaged/Killed/Scored/ ScoreUpdate` and `EndMission(finalScore)` to the console host, which records them (`RPMissionRecorder`) into `RPMissionResults` and prints score sheets. The consumer version wants this as a post-race results screen (and, later, Steam leaderboards/achievements fed from the same events). ## 2. How the pods network with each other (the key finding) The console does NOT relay gameplay. Every pod receives the *same* egg, and `L4NetworkManager::StartConnecting` builds a **deterministic full TCP mesh** from the ordered `[pilots]` list: - Resolve each address (`ip[:port]`, default = game port). - Entries **before your own**: open a TCP connection to them. - Entries **after your own**: listen for their incoming connection. - No entry matching a local address → single-user mode, immediate load. - Egg-from-network (`SlaveMode`) → ACK the egg, wait for mesh completion. So the "lobby protocol" is simply: *agree on an ordered participant list, then everyone meshes*. This is an exceptionally good fit for Steam. ## 3. Steam mapping (plan) | Arcade concept | Steam concept | |---|---| | TeslaConsole operator | **Lobby owner** (host player) | | Pod list / Site Management | `ISteamMatchmaking` lobby members | | Pilot config dialog | In-lobby cockpit UI; member data (name/vehicle/color/badge) via lobby member data | | Egg delivery + ACK | Owner builds the canonical egg, distributes via lobby data or reliable P2P channel; same ACK semantics | | `[pilots]` host addresses | **Ordered SteamID list** — same list, different address type | | TCP mesh (`StartConnecting`) | `ISteamNetworkingSockets` P2P mesh over SDR: ConnectP2P to earlier entries, accept later ones — the connect/listen ordering ports 1:1 | | Console telemetry sink | Lobby owner doubles as the console host (results collection); results screen replaces the printout | | Site network / fixed IPs | NAT traversal + IP privacy for free via Steam Datagram Relay | Transport seam: mirror the `RIOBase` pattern at the L4NET layer — a `NetTransport` interface with the existing WinSock TCP implementation (LAN/dev, keeps working today) and a Steam-sockets implementation (retail). `L4Host` keeps its identity/queue role; only connect/listen/send/recv move behind the interface. ## 4. Implementation options (decide here) **A. In-engine front end (recommended).** Port the egg builder (~300 lines: `RPMission/RPPlayer.ToEggString` + the plasma name-bitmap generator) to C++ inside RP_L4. New application state before `WaitingForEgg`: a menu that renders on the cockpit displays we just built — scenario/map/weather/length on the viewscreen, selections driven by the MFD buttons and map presets (the cockpit IS the menu — maximally pod-authentic). Single player works immediately: build egg → hand to the existing egg-load path. Multiplayer then layers the Steam lobby under the same UI (owner builds the egg, distributes, mesh over Steam sockets). **B. Standalone launcher app** (C#, reuse TeslaConsole code nearly verbatim, drive the game via `-net` + console port like the arcade). Fastest to stand up, but a second process, not cockpit-feel, and awkward under Steam (overlay, launch flow, no in-game rejoin). Useful as a dev tool, not the product. **C. Hybrid:** in-engine UI, but mission/egg logic in a small shared C++ library so a dev console tool and the game share one egg builder. ### Open decisions 1. Front end location — Option A (in-engine, cockpit-rendered) confirmed? 2. v1 scenario scope — Death Race only, or Football (needs teams UI) too? 3. Results screen — post-race on the cockpit displays (replaces printout)? 4. Steam model — lobby-owner-as-console confirmed? (Implies owner migration handling later; the egg re-issue path makes host migration plausible.) 5. Pilot identity — Steam persona as pilot name; vehicle/color/badge persisted per player (Steam Cloud later)?