Front end: LocalConsole marshal + single-binary loop (timed stop, relaunch)
The in-process console that replaces the operator for solo play: it owns
the mission clock and ends the race at the chosen length, then relaunches
to the setup menu -- the arcade launcher behavior in one binary.
- engine/APPMGR: gPerFrameHook -- a per-frame observer called on the game
thread in RunMissions (the marshal's engine-safe tick site).
- btl4console.{hpp,cpp}: BTLocalConsole_Install/MissionCompleted -- the
marshal watches for RunningMission, starts the clock, and dispatches
Application::StopMissionMessage at expiry (BT_MISSION_SECONDS overrides
for testing). Confirmed: StopMission cleanly ends the mission and
RunMissions returns.
- btl4fe: expose BTFrontEnd_LastMissionSeconds; Enter=LAUNCH / Esc=quit in
the menu loop; BT_FE_AUTOLAUNCH quick-launch (skips the menu).
- btl4main WinMain: front-end mode runs menu -> arms marshal -> mission;
when the marshal ends it, RELAUNCH a fresh instance (arcade launcher
model) -> lands back on the menu. This sidesteps BT's in-process
re-init fragility: a second mission in-process AV'd on stale gBT*
per-mission entity globals (gBTTerrainEntity et al., cdb-traced to
MakeEntityRenderables); a fresh process has none.
Verified: menu LAUNCH -> mission runs -> marshal stops it at the set
length -> RunMissions returns -> relaunch (3 distinct PIDs across a
multi-cycle run, no crash).
Remaining in Phase 5: the results screen (kills/deaths at stop).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,11 @@ HWND ghWnd = 0;
|
||||
// front end / lobby member path (Phase 5/6).
|
||||
Logical gConsoleLossEndsMission = False;
|
||||
|
||||
// BT412: a per-frame observer called each frame in RunMissions while an
|
||||
// application is live (the in-process LocalConsole marshal hangs off this to
|
||||
// own the mission clock). NULL when unregistered.
|
||||
void (*gPerFrameHook)() = NULL;
|
||||
|
||||
ApplicationManager* ApplicationManager::CurrentAppManager = NULL;
|
||||
|
||||
ApplicationManager::ApplicationManager(HINSTANCE hInstance, HWND hWnd, Scalar frame_rate) : Node(ApplicationManagerClassID), runningApplications(this)
|
||||
@@ -81,6 +86,15 @@ Start_Of_Frame:
|
||||
{
|
||||
Check(application);
|
||||
foregroundTasksRun++;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// BT412: give the per-frame observer a slice while 'application' is
|
||||
// live (the loop condition NULLs the global on exit). The
|
||||
// single-player LocalConsole marshal hangs off this; NULL otherwise.
|
||||
//------------------------------------------------------------------
|
||||
if (gPerFrameHook != NULL)
|
||||
(*gPerFrameHook)();
|
||||
|
||||
if (!application->ExecuteForeground(end_of_frame, frameDuration))
|
||||
{
|
||||
if (!application->Shutdown(current_application.GetSize()))
|
||||
|
||||
Reference in New Issue
Block a user