Launch pend counter: no timeout, no queue entry (mid-load launch crash 2)

The take-1 deferral (re-post at +1s, capped at 120) turned a SLOW load
into a crash: loads on a busy operator box measure 1-2+ minutes, the
cap expired, and the original "Not ready to run" Fail/abort fired
(field report: sound after ~1 min, crash ~2 min later; the log shows
exactly 120 deferrals all in LoadingMission).

A mid-load RunMission now just bumps gBTRunMissionPendCount -- nothing
enters the event queue and there is NO timeout to outlive -- and
CheckLoadMessageHandler drains the counter immediately after advancing
LoadingMission -> WaitingForLaunch, re-posting that many stack
RunMissionMessages (the engine's own no-console launch pattern at the
same site, which also demonstrates Post spools stack messages safely).

Verified (two-round rig, round 1): both relay launches pended through
the load, fired at load completion, the requested mech spawned and the
scene went live.  Round reset + round-2 rejoin remain verified from the
prior run; why loads take 1-2+ min on a busy box is left as an open
perf question.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-22 19:11:03 -05:00
co-authored by Claude Opus 4.8
parent 3a9b35fc06
commit 53c86fa1dd
3 changed files with 60 additions and 25 deletions
+36 -25
View File
@@ -564,6 +564,23 @@ Entity*
return viewing_entity;
}
//
// Pended mid-load operator launches (see the handler's default case).
// APP.cpp CheckLoadMessageHandler drains the count the moment the state
// reaches WaitingForLaunch and re-posts that many RunMissions.
//
int gBTRunMissionPendCount = 0;
int BTTakePendingRunMissions(void)
{
int pended = gBTRunMissionPendCount;
gBTRunMissionPendCount = 0;
if (pended > 0)
DEBUG_STREAM << "[launch] load complete -- firing " << pended
<< " pended RunMission(s)" << std::endl << std::flush;
return pended;
}
//
//#############################################################################
// RunMissionMessageHandler
@@ -611,31 +628,25 @@ void
default:
//
// LAUNCH/LOAD RACE (2026-07-22): the relay sends the RunMission pair
// a fixed settle after the egg ACK, but a long mission load (glass +
// dev gauges on a busy box) can still be in LoadingMission when it
// lands -- the 1995 console never hit this state (the operator
// launched much later), so it Fail()ed = the "silent crash at
// mission launch" (c0000409 abort; 3/3 reproduced under cdb).
// DEFER instead: re-post the message to ourselves at +1s until the
// ladder reaches WaitingForLaunch (the VehicleDead re-post pattern).
// Bounded so a truly wedged load still surfaces the original Fail.
{
static int s_launch_deferrals = 0;
if (++s_launch_deferrals <= 120)
{
DEBUG_STREAM << "[launch] RunMission arrived in state "
<< (int)GetApplicationState()
<< " (still loading) -- deferred +1s ("
<< s_launch_deferrals << ")" << std::endl << std::flush;
Time when = Now();
when += 1.0f;
Post(HighEventPriority, this, message, when);
return; // base handler runs when ready
}
}
Fail("Application::RunMissionMessageHandler - Not ready to run!\n");
break;
// LAUNCH/LOAD RACE, take 2 (2026-07-22): the relay's RunMission pair
// can land while the pod is still in LoadingMission (long loads; the
// 1995 console launched operator-paced, so this state Fail()ed = the
// silent c0000409 crash). Take 1 re-posted the message at +1s --
// but the LoadingMission -> WaitingForLaunch transition
// (APP.cpp CheckLoadMessageHandler) requires
// IsPriorityEmpty(MinEventPriority), so the pending deferred launch
// KEPT THE QUEUE NON-EMPTY and blocked the very transition it waited
// for (livelock -> 120 x 1s cap -> the same abort; field-reported).
// Now a mid-load launch just bumps a COUNTER -- nothing enters the
// event queue -- and CheckLoadMessageHandler re-posts the launches
// (the engine's own no-console stack-message pattern) right after it
// advances the state.
++gBTRunMissionPendCount;
DEBUG_STREAM << "[launch] RunMission arrived in state "
<< (int)GetApplicationState()
<< " (still loading) -- pended until the load completes ("
<< gBTRunMissionPendCount << ")" << std::endl << std::flush;
return;
}
//