Commit Graph
9 Commits
Author SHA1 Message Date
CydandClaude Fable 5 c66cb00a7e Network races: the local console marshals remote pods over the wire
The lobby-owner-as-console architecture, in-engine. RPL4CONSOLE gains
RPL4LocalConsole_InstallNetworkRace: the owner pod switches to network
mode and meshes like any pod (egg fed locally via FeedLocalEgg, which
now opens the ConsoleOnly state gate), while the console tick also
marshals REMOTE pods over NetTransport speaking the exact arcade
protocol - egg chunks with 5s-retry-until-ACK, 1Hz state polling,
RunMission once every pod stages at WaitingForLaunch, StopMission at
expiry (remotes first, local pod holds until their EndMission scores
land), score intake labeled with [pilots]-order names on the results
screen.

The front end builds the multi-pilot egg: RP412HOSTPODS lists member
console channels (lobby stand-in; the Steam lobby feeds the same
path), RP412HOSTPORT/RP412HOSTADDR set the owner side.

Winsock Connect now redials with a fresh socket per attempt (a refused
TCP socket is dead; the old loop reused it) bounded at 120s - needed
whenever a peer boots after the caller, which is the normal Steam
lobby launch order.

Verified on loopback: member pod in -net, owner hosting from its menu;
mesh completed both sides, 30s race, remote score collected over the
wire (host 3), local stop after the drain, results screen shows both
pilots by name in one process that returns to the menu.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 21:08:18 -05:00
CydandClaude Fable 5 ff6ec8c56a SteamNetTransport: the Steam wire is implemented and live
Steamworks SDK 1.64 vendored at extern/steamworks_sdk_164 (headers +
win32 redistributables only; .gitignore trims the rest). Both projects
build with RP412_STEAM; activation stays behind the RP412STEAM=1
environment switch, so plain desktop runs never touch Steam.

L4STEAMTRANSPORT.cpp implements NetTransport on ISteamNetworkingSockets
with FakeIP: SteamNetTransport_Install brings up SteamAPI, relay
network access, and a two-port FakeIP identity (fake port 0 = console
channel, 1 = game mesh), then swaps the process wire; any failure logs
the reason and the game carries on over TCP. Addressing keeps the
engine untouched: all pods share the -net port convention, eggs carry
fakeip:engineport, and the transport alone translates engine ports to
Steam fake ports via the lobby-fed peer table (RegisterPeer). Connect
mirrors the TCP retry-while-refused loop; Receive normalizes message
lanes back into the stream semantics CheckBuffers expects.

Runtime verified on this box: RP412STEAM=1 under AppID 480 came up as
169.254.59.52 (fake ports 32256/32257); without Steam credentials it
falls back to TCP cleanly; default boot logs no Steam lines at all.
steam_api.dll ships in the dist.

Next: the lobby layer (ISteamMatchmaking member data -> RegisterPeer +
egg build + RPL4CONSOLE marshal), which needs a second account to test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 20:34:07 -05:00
CydandClaude Fable 5 8d7373974f Results screen between race and menu
After a console-marshaled race ends, the race loop now shows a RACE
RESULTS screen (place / pilot / final score, sorted descending, with a
CONTINUE button) before returning to the setup menu. Scores come from
the local console's intake; single-player rows carry the pilot's own
name, additional pods show their host number until the Steam roster
maps IDs to personas.

The setup menu also keeps the player's selections and pilot name across
races now instead of resetting to defaults each cycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 19:05:55 -05:00
CydandClaude Fable 5 570eb3aceb Single-binary race loop: menu -> race -> menu in one process
WinMain now wraps the engine block in a loop: when a front-end-launched
mission ends under the local console, the setup screen comes back in the
same process instead of exiting (the arcade relaunch-per-mission model).
Replaces the CreateProcess self-respawn - required for Steam, where the
lobby and sockets must survive across races.

Second-cycle re-init crash fixed: d3d_OBJECT kept a static texture cache
keyed by filename, so race 2 got IDirect3DTexture9 pointers created on
race 1 destroyed device and died at first draw (DrawMesh AV). The cache
is now flushed in ~DPLRenderer before the device is released, and
ParticleEngine::Initialize drops particles left over from the previous
mission. Verified: three consecutive 30s races in one PID, each stopped
on time by the console with final scores collected.

Also: L4CONSOLELEN env override for test-length races, and the console
exposes MissionCompleted() for the loop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 18:48:56 -05:00
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
CydandClaude Fable 5 58eb25a792 In-game front end: race setup menu builds the mission egg locally
Starting without -egg, -net, or -mr now boots a race-setup screen
(RP_L4/RPL4FE.cpp) instead of aborting: track / vehicle / color / badge
/ time-of-day / weather / race length plus pilot name, populated from
TeslaConsole''s RPConfig.xml catalog (Death Race scenario). LAUNCH
builds the egg exactly as the console did - the RPMission.ToEggString
port, including the pilot name pre-rendered to 1bpp plasma bitmaps
(128x32 + 64x16) via GDI with the console''s auto-shrink font logic and
the verbatim ordinal graphics - writes frontend.egg, and injects it
into the standard egg-load path (new L4Application::
SetEggNotationFileName).

The menu is a GDI child of the main window (pod green-on-black, double
buffered, mouse driven, EDIT control for the name) running a modal loop
before engine init; closing the window exits cleanly. Found and fixed
along the way: the empty egg CString holds a NULL representation
(operator! is the safe emptiness test), and the modal loop needed a
queue nudge for launch clicks delivered via SendMessage.

Verified end to end: boot -> menu -> LAUNCH -> generated egg (7.5KB) ->
racing in the 1080p cockpit with score and mission clock running.
start-windowed.bat now boots into the front end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 16:20:05 -05:00
CydandClaude Fable 5 aa24968c3d Assemble the whole cockpit in a single window
The main game window becomes the cockpit shell (enlarged, clipping
children); every display folds in as a chrome-less child pane in the
pod interior arrangement:

  [ MFD UL ] [ MFD UC ] [ MFD UR ]
  [ plasma (reduced) ][ viewscreen (centered) ]
  [ MFD LL ] [   Map  ] [ MFD LR ]

The 3D scene presents into a black STATIC viewscreen child via
Present's hDestWindowOverride (new gMainPresentWindow global) - no
swap-chain changes, and STATIC's transparent hit-testing keeps mouse
input over the 3D view flowing to the game window. MFDSplitView gains a
parent/child mode; PlasmaScreen::Position reparents the glass into the
shell. Main window class background goes black for the cockpit gaps.

Verified by screenshot: live green gauges (LIFT CUT / BOOST / CHUTE /
trigger-program screens) with their red button strips, the 3D canyon in
the centered viewscreen, plasma score glass at its left, map with lit
amber preset lamps - one window, 976x1132 client at 50% scale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 14:52:26 -05:00
CydandClaude Fable 5 c1990d0ffa Hide the mouse cursor only in fullscreen
The arcade startup hid the cursor unconditionally in release builds -
correct for a pod, but desktop windowed play needs the mouse for the
on-screen cockpit buttons and the cursor vanished over every display
window. Hide (and restore) it only when running fullscreen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 14:26:14 -05:00
CydandClaude Opus 4.8 4abbf8879f Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:

- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies

Removed stale Subversion metadata and added .gitignore/.gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 07:59:51 -05:00