Files
RP412/docs/RP412-ROADMAP.md
CydandClaude Fable 5 9f79508257 LocalConsole: the in-process marshal that ends missions
Domain correction from playtest: hand-fed eggs are a developer shortcut
- a mission only ends on a console command, so the clock hits 00:00 and
counts up forever. Even single-player games need a console marshal.

RPL4CONSOLE is that console. Like the real one it lives on its own
thread: it owns the mission clock and raises the stop request at the
selected length; the app-manager per-frame hook (new gPerFrameHook seam
in APPMGR, called while the application global is live - the loop
condition NULLs it on exit, which ate the first attempt) executes the
engine-safe part, dispatching the same StopMissionMessage TeslaConsole
sent. Final scores flow in through a new RP-layer sink
(gConsoleScoreSink in RPCNSL): RPPlayer feeds it the same score it
sends a real console at mission end.

It also inherits the launcher role: the application tears down after a
stop (arcade pods were relaunched per mission by TeslaLauncher), so
WinMain respawns the process when the console ended the mission,
landing back on the race-setup screen. L4NetworkManager grows
FeedLocalEgg (the single-user egg-inject path, callable mid-session)
for the future in-process loop.

Verified end to end: menu -> 3:00 race -> stop dispatched exactly on
time -> final score collected (host 1 = 4113) -> process respawned with
the front end up. -egg runs stay unmarshaled (the dev shortcut).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 18:10:02 -05:00

9.9 KiB
Raw Permalink Blame History

RP 4.12 Roadmap — Steam + Internet Multiplayer

Working plan for turning the 4.11 arcade/cockpit build into a consumer Steam title. Status: initial assessment (2026-07-12). Items marked [investigate] need code archaeology before they become concrete tasks.

Where 4.11 stands

  • Game: rpl4opt.exe, 32-bit Win32, DirectX 9, VS2005/2008-era .vcproj projects (BUILD.md). Builds clean on VC++ 2008 Express.
  • Networking: the engine has a real multiplayer layer — MUNGA/NETWORK.cpp, MUNGA/SOCKET.cpp, MUNGA/HOSTMGR.cpp, interest management (MUNGA/INTEREST.cpp), bound to WinSock2 in MUNGA_L4/L4NET.CPP (TCP; the 2007 WinSock port of the 1995 code). It was built for pods on a dedicated LAN.
  • Input/output: the pod's controls are a RIO serial board (buttons, five analog axes, lamps) and a plasma display (128×32 dot-matrix on COM2, driven by MUNGA_L4/L4PLASMA.CPP). No cockpit, no controls.
  • Session control: races are configured and launched from the outside by TeslaConsole over the Munga control protocol (TCP 1501, via Munga Net.dll), with TeslaLauncher (TCP 53290) handling app lifecycle on each pod.

Workstream A — Play without the cockpit (from vRIO)

vRIO already solved the "no hardware" problem once, from the outside: it speaks the RIO serial protocol as the device, with a complete keyboard + XInput bindings model (deflect/rate/deadzone/invert per axis, bindings file), and vPLASMA renders the display's recovered command grammar (VPlasma.Core/Protocol/PlasmaProtocol.cs, grammar recovered from L4PLASMA.CPP itself). For 4.12 that logic moves inside the game:

Design principle — recreate the cockpit's feel on screen. The 4.12 screen layout places the RIO panel controls around the displays in the same physical arrangement as the pod: MFD button clusters framing the screens, board columns and keypads where they sit in the cockpit, the plasma glass in its place above. vRIO's panel layout data (VRio.Core, the five MFD clusters / four board columns / two keypads / encoder-gauge strip) is the geometry reference — it is already the faithful software copy of the physical panel. On-screen buttons light with the same lamp states the game commands, so press-feedback works like the real button field.

  • Prototype landed (2026-07-12). The seam existed: the controls manager consumes a small RIO surface (8 methods + 5 analog scalars), now split out as RIOBase. PadRIO (L4CONTROLS=PAD) implements it from XInput + the PC keyboard with vRIO's default profile — the stock VTVRIOMapper, lamps, and button field run unchanged, no serial, hot-plug supported. Verified: boots and plays with vRIO off and no COM ports.
  • Plasma display: PlasmaScreen (L4PLASMA=SCREEN) renders the same Video8BitBuffered surface into a desktop "Plasma Display" window in plasma orange — verified drawing live game content (score readout). See BUILD.md §4 for bindings and the desktop environ.ini.
  • 7-display cockpit in-engine, single window (L4MFDSPLIT=1): the five channel-packed MFDs, the portrait map, the plasma glass and the 3D viewscreen all assemble inside one cockpit window in the pod interior arrangement (MFD row / plasma+viewscreen band / MFD-map row), with each display's physical button bank around it. The 3D scene presents into the viewscreen child pane; MFDs/map render CPU-side from the gauge canvas. The external BitBlt-mirror wrapper is obsolete. Verified visually: live gauges (LIFT CUT/BOOST/CHUTE), tactical map with lit preset lamps, 3D scene in the viewscreen.
  • Cockpit buttons on the displays (2026-07-12): each split window carries its physical button bank — 4+4 red buttons per MFD, 6 amber per map side (Secondary/Screen columns; addresses per vRIO CockpitLayout, placement per the pod). Mouse presses inject into PadRIO; the game's lamp commands light them (verified: PRESET lamps lit on the map flank, aligned with the glass's own edge labels).
  • Next in A: port the full vRIO bindings-file model (deflect/rate/deadzone per axis, rebinding); pilot keypad (numpad / on-screen 4×4 → KeyEvent); Steam Input once C starts.
  • Polish pass (queued): vRIO's Dynamic Lighting RGB-keyboard mirror — lamp states glow on the physical keyboard's keys (per-key or zone-lit), blinking with the flash modes. Needs package identity for background light control (vRIO's pkg\Register-vRIO.ps1 pattern; see the vRIO README for the Settings → Dynamic Lighting steps).
  • vRIO itself stays useful as a dev harness against unmodified builds.

Workstream B — In-game sessions (from TeslaConsole)

  • Single-player front end landed (2026-07-12): starting without -egg/-net boots a race-setup menu (RP_L4/RPL4FE.cpp) — track / vehicle / color / badge / time / weather / length + pilot name from the console's catalog — which builds the mission egg locally (full RPMission.ToEggString port incl. GDI-rendered plasma name bitmaps) and feeds the standard egg-load path. Verified end to end: menu → LAUNCH → generated egg → racing in the cockpit.
  • LocalConsole marshal (RP_L4/RPL4CONSOLE.cpp): hand-fed eggs are a dev shortcut — a mission only ends on a console command, otherwise the clock rolls past 00:00 and counts up forever. Front-end games are now marshaled by an in-process console on its own thread (like the real one): it owns the mission clock, dispatches the arcade's StopMissionMessage at expiry, and collects the final scores through the same intake RPPlayer fed the real console (gConsoleScoreSink). It also plays the launcher role: after a marshaled mission end the process respawns (the arcade launcher restarted pods per mission), landing back on the setup screen. Verified: 3:00 race ends at 3:00, score collected, fresh instance boots to the menu. -egg runs stay unmarshaled (the dev shortcut, timer counts up as before). Results SCREEN (showing the collected scores) is the next brick.
  • See RP412-FRONTEND-DESIGN.md for the TeslaConsole control-code analysis and the Steam lobby mapping this builds toward (lobby owner = console, SteamID list = pilot list, Steam-sockets mesh = the egg's connect/listen ordering).

Consumer players get no operator. The create/configure/launch flow that TeslaConsole drives over TCP 1501 becomes in-game UI:

  • Front-end menus: pilot setup, race/mission select, create/join session. [investigate] how much of the mission-launch handshake lives in the game (MUNGA mission/host code) vs. in the console — TeslaSuite's Contract/ and the console's Munga-protocol client are the reference implementation.
  • vPOD (TeslaSuite) impersonates both the game client and launcher — a ready-made test double while the launch flow is being internalized.
  • TeslaLauncher's responsibilities (install, watchdog, auto-login) disappear — Steam owns install/update/launch.

Workstream C — Steam + internet multiplayer logistics

Networking

  • The engine's LAN TCP assumptions need auditing before anything else: [investigate] what HOSTMGR/NETWORK actually synchronize (state replication vs. lockstep), tick/latency assumptions, and who is authoritative. A LAN design that tolerates ~1 ms RTT may need prediction/interpolation work for 50100 ms internet RTTs; the existing interest manager is a good sign.
  • Transport: Steam Networking Sockets (ISteamNetworkingSockets) is the target — it gives NAT traversal + Steam Datagram Relay for free, hides IPs, and offers reliable + unreliable channels. Plan: introduce a transport abstraction under L4NET so raw-socket LAN play (dev) and Steam sockets (retail) coexist.
  • Topology: player-hosted (listen server / P2P over SDR) is the low-cost default for a pod-count-sized race; dedicated servers are a later option.
  • Matchmaking: Steam lobbies (ISteamMatchmaking) for create/join/invite; friends-list invites come nearly free once lobbies work.

Steamworks integration

  • Steamworks partner account + app credit (Steam Direct, $100/app), appid, depot layout via SteamPipe. The old Setup1/ installer project retires — Steam delivers files; OpenAL / libsndfile runtime DLLs ship in the depot.
  • steam_api.dll supports 32-bit Win32, so Steam does not force a 64-bit port. It does require init/callback pumping in the main loop and the overlay hooking D3D9 (works, but test early — old-engine present() paths sometimes fight the overlay).
  • Steam client requires Windows 10+ now, which frees 4.12 from the XP-era constraints that shaped the 4.11/TeslaSuite line.

Toolchain

  • Done (2026-07-12) — the solution builds on VS2022 (v143) with the Windows 11 SDK; see BUILD.md §3 for what changed and why. Runtime-verified equivalent to the VC9 baseline (including RIO init against vRIO). Remaining cleanups called out there: un-/Zp1 the Windows-header boundary, port stdext::hash_mapstd::unordered_map, single-TU the duplicated globals so /FORCE:MULTIPLE can go away.
  • The pre-existing mission-load crash (NULL-texture AddRef in d3d_OBJECT::LoadTexture) is fixed — missing textures render untextured and log. The game boots standalone to a running window (BUILD.md §4). Note for Workstream B: pod skins (player18) come from the presets / replacement-material path the console used to drive; the in-game session UI must own that.

Suggested order

  1. Toolchain upgrade to VS2022 (unblocks everything, no design risk).
  2. Workstream A input layer (makes the game playable on a desktop — also the fastest path to a demoable build).
  3. Networking audit (C), then transport abstraction + Steam sockets.
  4. Workstream B session UI, using vPOD as the test double.
  5. Steamworks bring-up (appid, overlay, lobbies), SteamPipe packaging.