diff --git a/context/steamification.md b/context/steamification.md index 575a977..ffe2ceb 100644 --- a/context/steamification.md +++ b/context/steamification.md @@ -154,7 +154,7 @@ Verified after merge: clean build; solo front-end mode; loopback MP through the - In-process **LocalConsole marshal** (`btl4console.{hpp,cpp}`): NOT a thread — it runs on the engine's per-frame hook (`gPerFrameHook`, added to `engine/MUNGA/APPMGR.*`, called on the game thread in `RunMissions`), so its `application->Dispatch(StopMissionMessage)` is - safe. Owns the mission clock and stops the race at the chosen `length=`; snapshots + safe. Owns the mission clock and stops it at the chosen `length=`; snapshots per-pilot kills/deaths at the stop (`BTResolveRosterPilot`/`BTPilotKills`/`BTPilotDeaths`). - **Score intake + results screen**: BT's own kills/deaths model (no `gConsoleScoreSink` — that is RP-layer; BT has no working mission-end wire flow, msgID 0x18 stays a stub). A @@ -163,7 +163,7 @@ Verified after merge: clean build; solo front-end mode; loopback MP through the - **Single-binary loop** = RELAUNCH per mission (`CreateProcessW` after the marshal stop), NOT an in-process `for(;;)` — in-process re-init crashes on the stale reconstructed `gBT*` globals (cdb-traced to `BTL4VideoRenderer::MakeEntityRenderables` → - `gBTTerrainEntity`). Verified: 3 distinct PIDs across the menu→race→results→menu cycle. + `gBTTerrainEntity`). Verified: 3 distinct PIDs across the menu→mission→results→menu cycle. - WinMain launch-mode branch (`BTFrontEnd_LastLaunchMode()`): 0 solo, 1 lobby host, 2 lobby member (see Phase 6). - **Phase 6 (Steam lobby) — CODE LANDED 2026-07-16; live 3-machine test DEFERRED.** @@ -171,16 +171,16 @@ Verified after merge: clean build; solo front-end mode; loopback MP through the — stubs without `BT412_STEAM`, full `ISteamMatchmaking` room under it (both configs link clean). What works: the room screen; member data (`ip`/`cp`/`gp`/`nm`/`vh`/`cl`/`bd` = FakeIP + fake console/game ports + persona + mech/color/badge); the nonced `go` launch - roster → `SteamNetTransport_RegisterPeer` for every peer; `Push`/`PullRaceResults` over + roster → `SteamNetTransport_RegisterPeer` for every peer; `Push`/`PullMissionResults` over lobby data (`res` key) rebuilding the shared score sheet via `BTLocalConsole_ClearResults`/ `InjectResult`. The menu offers HOST/JOIN when `BTLobby_Available()` (Steam transport up, installed by WinMain on `BT412STEAM` env). A host launch bakes every member into the egg's `[pilots]` (mesh `FakeIP:1502` addresses, round-robin drop zones) via `BTFrontEnd_SetHostedPilots`; a member enters as a network pod on `:1501` (`SetNetworkCommonFlatAddress` + `gConsoleLossEndsMission=True`). - **Deferred / not built:** the host→member **wire egg-feed marshal** (`InstallNetworkRace` — + **Deferred / not built:** the host→member **wire egg-feed marshal** (`InstallNetworkMission` — the owner streaming eggs + RunMission to remote pods, as `tools/btconsole.py` does). Without - it a member waits for a console connection nothing supplies, so a live host+member race + it a member waits for a console connection nothing supplies, so a live host+member mission is blocked on it. The lobby object does NOT survive the per-mission relaunch (the single-binary limitation — everyone returns to a fresh menu, not the room). `docs/STEAM-3-MACHINE-TEST.md` for BT is not yet authored. diff --git a/docs/BT412-ROADMAP.md b/docs/BT412-ROADMAP.md index a97ffb5..485f5f9 100644 --- a/docs/BT412-ROADMAP.md +++ b/docs/BT412-ROADMAP.md @@ -139,7 +139,7 @@ identical-to-baseline → take RP412's file verbatim, diverged → hand-apply th console on its own thread over NetTransport — egg chunks + ACK, RunMission ×2 (mirror btconsole.py), stays connected (fixes the console-loss listener bug for solo), owns the mission clock, StopMission at `length=` expiry, launcher-role loop, - `InstallNetworkRace` marshal for remote pods. + `InstallNetworkMission` marshal for remote pods. - **5c Score intake — genuinely new for BT** (no mission-end flow exists): a `gConsoleScoreSink` equivalent through `BTPlayer`; v1 results screen = kills/deaths per pilot from the Comm-MFD `pilotList` tally at stop. @@ -160,7 +160,7 @@ identical-to-baseline → take RP412's file verbatim, diverged → hand-apply th > `Application::StopMissionMessage` at the chosen length; it snapshots per-pilot > kills/deaths at the stop (BT's own score model — msgID 0x18 stays a stub). The > single-binary loop is a RELAUNCH per mission (`CreateProcessW`; avoids the stale -> `gBT*`-global re-init crash), showing a GDI "MISSION COMPLETE" scoreboard between races. +> `gBT*`-global re-init crash), showing a GDI "MISSION COMPLETE" scoreboard between missions. > WinMain (`game/btl4main.cpp`) wires front-end-mode detection, the marshal arm, the > results screen + relaunch, and the launch-mode branch (solo/host/member). Details in > `context/steamification.md`. @@ -170,7 +170,7 @@ identical-to-baseline → take RP412's file verbatim, diverged → hand-apply th - **`game/reconstructed/btl4lobby.cpp`** (skeleton: `RPL4LOBBY.cpp` — mechanics generic): lobby owner = console; member data = FakeIP + fake console/game ports + persona + loadout (**mech**/color/badge); nonced launch roster → `RegisterPeer` all → - owner hosts via egg+marshal, members join as network pods; Push/PullRaceResults + owner hosts via egg+marshal, members join as network pods; Push/PullMissionResults distribute the score sheet. FE gains HOST/JOIN screens. - Author `docs/STEAM-3-MACHINE-TEST.md` for BT (adapt RP412's; keep its gotchas: disable Steam Input on 480, one Steam account per machine, abort key). @@ -183,14 +183,14 @@ identical-to-baseline → take RP412's file verbatim, diverged → hand-apply th > `BT412_STEAM`, full ISteamMatchmaking room under it). Built: the room screen (green-on-black, > like the menu), member data exchange (FakeIP + fake console/game ports + persona + > mech/color/badge), the nonced "go" launch roster → `SteamNetTransport_RegisterPeer` all peers, -> and Push/PullRaceResults over lobby data. The menu shows HOST/JOIN when `BTLobby_Available()` +> and Push/PullMissionResults over lobby data. The menu shows HOST/JOIN when `BTLobby_Available()` > (Steam transport up); a launch routes through `BTFrontEnd_LastLaunchMode()`: **host** builds the > egg with every member as a `[pilots]` entry + owns the marshal clock, **member** enters as a > network pod on `:1501` (`SetNetworkCommonFlatAddress` + `gConsoleLossEndsMission`). WinMain > installs the Steam transport on `BT412STEAM` env. **Remaining / deferred:** the host→member -> **wire egg-feed marshal** (`InstallNetworkRace` — the owner streaming eggs to remote pods) is +> **wire egg-feed marshal** (`InstallNetworkMission` — the owner streaming eggs to remote pods) is > NOT built; a member currently waits for a console connection that only that marshal provides, so -> a live host+member race needs it. The lobby OBJECT does not survive the per-mission relaunch +> a live host+member mission needs it. The lobby OBJECT does not survive the per-mission relaunch > (documented single-binary limitation — everyone lands on a fresh menu, not back in the room). > `docs/STEAM-3-MACHINE-TEST.md` for BT is not yet authored. Details in `context/steamification.md`. diff --git a/game/btl4main.cpp b/game/btl4main.cpp index 8b87205..4a3dbcb 100644 --- a/game/btl4main.cpp +++ b/game/btl4main.cpp @@ -370,7 +370,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // STEAM NETWORKING (BT412_STEAM build + BT412STEAM env): bring the Steam // transport up BEFORE the front end so the lobby is available (its HOST/JOIN - // buttons appear only when a FakeIP was allocated) and the race mesh routes + // buttons appear only when a FakeIP was allocated) and the mission mesh routes // over SDR/FakeIP. Any failure silently leaves the process on Winsock TCP. #ifdef BT412_STEAM if (getenv("BT412STEAM") != NULL && atoi(getenv("BT412STEAM")) != 0) @@ -549,8 +549,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine extern void BTFrontEnd_ShowResults(); extern void BTLocalConsole_Install(int mission_seconds); extern int BTLocalConsole_MissionCompleted(); - extern void BTLobby_PushRaceResults(); - extern void BTLobby_PullRaceResults(); + extern void BTLobby_PushMissionResults(); + extern void BTLobby_PullMissionResults(); int launch_mode = 0; // 0 solo, 1 lobby host, 2 lobby member if (front_end_mode) @@ -649,15 +649,15 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // The mission ran (not the menu-closed early return) if we front-end-moded // and the window still lives (a user window-close destroys hWnd -> quit, no // relaunch). Solo/host end via the local marshal; a member ends when the - // host stops the race (console-loss), so it has no local completion flag. + // host stops the mission (console-loss), so it has no local completion flag. bool mission_ran = front_end_mode && IsWindow(hWnd) && (launch_mode == 2 || BTLocalConsole_MissionCompleted()); if (mission_ran) { // Distribute (host) or collect (member) the shared score sheet over the // lobby so every pod shows the same board; solo needs neither. - if (launch_mode == 1) BTLobby_PushRaceResults(); - else if (launch_mode == 2) BTLobby_PullRaceResults(); + if (launch_mode == 1) BTLobby_PushMissionResults(); + else if (launch_mode == 2) BTLobby_PullMissionResults(); // Scoreboard first (kills/deaths snapshotted at the stop), then relaunch. ShowWindow(hWnd, SW_HIDE); @@ -672,7 +672,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); - std::cout << "[launcher] mission ended -- relaunched for the next race" + std::cout << "[launcher] mission ended -- relaunched for the next mission" << std::endl << std::flush; } } diff --git a/game/reconstructed/btl4console.cpp b/game/reconstructed/btl4console.cpp index 0a4af5e..efd02ae 100644 --- a/game/reconstructed/btl4console.cpp +++ b/game/reconstructed/btl4console.cpp @@ -91,7 +91,7 @@ namespace (GetTickCount() - gStartTick) >= (unsigned long)(gMissionSeconds * 1000)) { // The console clock expired: snapshot the final scores (the - // game state is still live here), then stop the race exactly + // game state is still live here), then stop the mission exactly // as the arcade console did (StopMissionMessage on our pod). DEBUG_STREAM << "[marshal] time expired -- stopping mission\n" << std::flush; SnapshotResults(); @@ -114,7 +114,7 @@ void BTLocalConsole_Install(int mission_seconds) gStartTick = 0; gWatched = 0; // Marshaled: the in-process console owns the clock, so a console-loss - // (there is none locally) would end the race -- harmless for solo. + // (there is none locally) would end the mission -- harmless for solo. gConsoleLossEndsMission = True; gPerFrameHook = &ConsoleTick; DEBUG_STREAM << "[marshal] installed (length " << mission_seconds << "s)\n" << std::flush; diff --git a/game/reconstructed/btl4fe.cpp b/game/reconstructed/btl4fe.cpp index ecdeffa..39c239c 100644 --- a/game/reconstructed/btl4fe.cpp +++ b/game/reconstructed/btl4fe.cpp @@ -259,7 +259,7 @@ namespace } //---------------------------------------------------------------------------// -// Defaults: a solo race on grass, one local pilot in a Black Hawk. +// Defaults: a solo mission on grass, one local pilot in a Black Hawk. //---------------------------------------------------------------------------// void BTFeMission_Default(BTFeMission *mission) { @@ -369,7 +369,7 @@ int BTFeMission_WriteEgg(const BTFeMission *mission, const char *path) } //===========================================================================// -// THE MINICONSOLE MENU -- the in-game race setup that replaces the operator +// THE MINICONSOLE MENU -- the in-game mission setup that replaces the operator // console. A GDI-painted green-on-black terminal (RP412 RPL4FE pattern): the // catalogs render as clickable columns, a pilot-name edit box, and a LAUNCH // button; clicking LAUNCH fills a BTFeMission from the selections and writes @@ -424,8 +424,8 @@ const char *ItemName(int g, int i) { case GColor: return kMenuColors[i].name; case GTime: return kMenuTimes[i].name; case GWeather: return kMenuWeather[i].name; case GLength: return kMenuLengths[i].name; case GLaunch: return "L A U N C H"; - case GHost: return "HOST STEAM RACE"; - case GJoin: return "JOIN STEAM RACE"; + case GHost: return "HOST STEAM MISSION"; + case GJoin: return "JOIN STEAM MISSION"; } return ""; } diff --git a/game/reconstructed/btl4fe.hpp b/game/reconstructed/btl4fe.hpp index 583662c..a20a46c 100644 --- a/game/reconstructed/btl4fe.hpp +++ b/game/reconstructed/btl4fe.hpp @@ -1,7 +1,7 @@ //===========================================================================// // btl4fe.hpp -- BT412 in-game front end: local mission-egg builder. // -// Replaces the external operator console for solo / host play: a race is +// Replaces the external operator console for solo / host play: a mission is // configured from an in-process catalog and the mission egg is built LOCALLY // (the exact NotationFile the console used to stream), then fed through the // standard -egg load path (L4Application::SetEggNotationFileName). diff --git a/game/reconstructed/btl4lobby.cpp b/game/reconstructed/btl4lobby.cpp index b3e1d66..8229189 100644 --- a/game/reconstructed/btl4lobby.cpp +++ b/game/reconstructed/btl4lobby.cpp @@ -3,7 +3,7 @@ // // Ported from RP412 RPL4LOBBY: the ISteamMatchmaking room, member loadout // exchange (FakeIP + ports + persona + mech/color/badge), the launch roster, -// and the post-race score sheet. Compiled to stubs without BT412_STEAM. +// and the post-mission score sheet. Compiled to stubs without BT412_STEAM. //===========================================================================// #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0500 @@ -23,8 +23,8 @@ int BTLobby_InRoom() { return 0; } int BTLobby_Host(void *, void *) { return LobbyRoomLeft; } int BTLobby_Join(void *, void *) { return LobbyRoomLeft; } int BTLobby_Room(void *, void *) { return LobbyRoomLeft; } -void BTLobby_PushRaceResults() { } -void BTLobby_PullRaceResults() { } +void BTLobby_PushMissionResults() { } +void BTLobby_PullMissionResults() { } #else @@ -45,8 +45,8 @@ extern int BTLocalConsole_GetResult(int index, int *kills, int *deaths); extern void BTLocalConsole_ClearResults(); extern void BTLocalConsole_InjectResult(int slot, int kills, int deaths, const char *name); extern const char *BTLocalConsole_GetResultName(int slot); -// (The remote-pod network-race marshal -- collating every pod's scores over the -// wire -- is deferred; the owner publishes its local snapshot for now.) +// (The remote-pod network-mission marshal -- collating every pod's scores over +// the wire -- is deferred; the owner publishes its local snapshot for now.) namespace { @@ -160,9 +160,9 @@ namespace members[i].gamePort, members[i].id.ConvertToUint64()); } - // Owner side: prime the hosted-race env (BT412HOSTPODS/ADDR/PORT) + the + // Owner side: prime the hosted-mission env (BT412HOSTPODS/ADDR/PORT) + the // hosted-pilot loadouts the front end feeds into the egg. - void PrimeHostedRace(MemberInfo *members, int count) { + void PrimeHostedMission(MemberInfo *members, int count) { static char pods_env[512], addr_env[64], port_env[32]; CSteamID self = SteamUser()->GetSteamID(); FEHostedPilot pilots[kMaxLobbyMembers]; int pilot_count = 0; @@ -205,7 +205,7 @@ namespace FillRect(mem, &cl, (HBRUSH) GetStockObject(BLACK_BRUSH)); SetBkMode(mem, TRANSPARENT); SelectObject(mem, room->titleFont); SetTextColor(mem, kGreenBright); RECT title = cl; title.top = cl.bottom/28; title.bottom = title.top + cl.bottom/10; - DrawTextA(mem, "STEAM RACE LOBBY", -1, &title, DT_CENTER|DT_TOP|DT_SINGLELINE); + DrawTextA(mem, "STEAM MISSION LOBBY", -1, &title, DT_CENTER|DT_TOP|DT_SINGLELINE); SelectObject(mem, room->textFont); int row_h = cl.bottom/16, top = cl.bottom/4, left = cl.right/4, right = 3*cl.right/4; char text[128]; @@ -226,7 +226,7 @@ namespace :"Waiting for the host to launch...", -1, &hint, DT_CENTER|DT_VCENTER|DT_SINGLELINE); HBRUSH frame = CreateSolidBrush(kGreenBright); if (IsOwner()) { FrameRect(mem, &room->launchRect, frame); SetTextColor(mem, kGreenBright); - DrawTextA(mem, "L A U N C H R A C E", -1, &room->launchRect, DT_CENTER|DT_VCENTER|DT_SINGLELINE); } + DrawTextA(mem, "L A U N C H M I S S I O N", -1, &room->launchRect, DT_CENTER|DT_VCENTER|DT_SINGLELINE); } FrameRect(mem, &room->leaveRect, frame); SetTextColor(mem, kGreenBright); DrawTextA(mem, "LEAVE LOBBY", -1, &room->leaveRect, DT_CENTER|DT_VCENTER|DT_SINGLELINE); DeleteObject(frame); @@ -311,7 +311,7 @@ namespace } SteamMatchmaking()->SetLobbyData(gLobby, kGoKey, go); RegisterRoster(room.members, room.memberCount); - PrimeHostedRace(room.members, room.memberCount); + PrimeHostedMission(room.members, room.memberCount); outcome = LobbyLaunchHost; break; } } @@ -391,7 +391,7 @@ int BTLobby_Room(void *instance, void *main_window) { return RunRoom((HINSTANCE)instance, (HWND)main_window); } -void BTLobby_PushRaceResults() { +void BTLobby_PushMissionResults() { if (!gInLobby || !IsOwner() || BTLocalConsole_ResultCount() == 0) return; SteamAPI_RunCallbacks(); char sheet[700]; sprintf(sheet, "%d:", gLastGoNonce); @@ -405,7 +405,7 @@ void BTLobby_PushRaceResults() { gShownResultsNonce = gLastGoNonce; } -void BTLobby_PullRaceResults() { +void BTLobby_PullMissionResults() { if (!gInLobby || IsOwner() || gLastGoNonce == gShownResultsNonce) return; const char *sheet = NULL; DWORD deadline = GetTickCount() + 8000; for (;;) { diff --git a/game/reconstructed/btl4lobby.hpp b/game/reconstructed/btl4lobby.hpp index 13a3076..fb96f68 100644 --- a/game/reconstructed/btl4lobby.hpp +++ b/game/reconstructed/btl4lobby.hpp @@ -6,10 +6,10 @@ // console/game ports + persona + loadout (mech/color/badge) as lobby member // data; the lobby OWNER is the console. Launching writes a "go" roster into // lobby data -- each pod registers every peer with the Steam transport and -// enters the race: the owner through the hosted-race marshal (it builds the -// egg and marshals the members over the wire), the members as network pods -// waiting for the owner's console connection. The lobby OBJECT outlives races -// (the single-binary payoff -- after a race everyone lands back in the room). +// enters the mission: the owner through the hosted-mission marshal (it builds +// the egg and marshals the members over the wire), the members as network pods +// waiting for the owner's console connection. The lobby OBJECT outlives +// missions (the single-binary payoff -- afterward everyone lands back in the room). // // Compiled to stubs without BT412_STEAM (single-player + LAN -net unaffected). //===========================================================================// @@ -20,26 +20,26 @@ enum BTLobbyOutcome { LobbyRoomLeft = 0, // player left the lobby -> back to the menu LobbyRoomClosed, // window went away -> quit - LobbyLaunchHost, // owner launched: hosted-race path is primed - LobbyLaunchMember // owner launched: enter the race as a network pod + LobbyLaunchHost, // owner launched: hosted-mission path is primed + LobbyLaunchMember // owner launched: enter the mission as a network pod }; // True when the Steam transport is up (the lobby UI is offered in the menu). int BTLobby_Available(); -// True while we sit in a lobby (races return to the room). +// True while we sit in a lobby (missions return to the room). int BTLobby_InRoom(); // Create a lobby / find-and-join one, then run the room screen. int BTLobby_Host(void *instance, void *main_window); int BTLobby_Join(void *instance, void *main_window); -// Re-enter the room of the lobby we are already in (post-race). +// Re-enter the room of the lobby we are already in (post-mission). int BTLobby_Room(void *instance, void *main_window); -// Post-race score sheet: the owner publishes its console's results into lobby -// data; members pull them so the same results screen shows everywhere. -void BTLobby_PushRaceResults(); -void BTLobby_PullRaceResults(); +// Post-mission score sheet: the owner publishes its console's results into +// lobby data; members pull them so the same results screen shows everywhere. +void BTLobby_PushMissionResults(); +void BTLobby_PullMissionResults(); #endif // BTL4LOBBY_HPP