From 3f691cacb3184aa45fad1eb77f7c454dc32885b9 Mon Sep 17 00:00:00 2001 From: Cyd Date: Mon, 13 Jul 2026 00:02:54 -0500 Subject: [PATCH] Departed-pod resilience: collision guard + console loss ends the race Round six raced all three machines (staging fix confirmed) and then exposed what happens when a pod leaves mid-mission - which arcade pods never did. The B crash dump named it exactly: VTV::TakeDamageMessageHandler resolved message->inflictingEntity to NULL (the entity belonged to the departed owner) and dereferenced it - Verify is compiled out in release. Collision damage from an entity that no longer exists is now ignored. And the race B and C were left in was a zombie: the owner (console) had aborted, so the mission clock would count up forever and the death/respawn flow hung with nobody to arbitrate. Lobby-member races now set gConsoleLossEndsMission: losing the console mid-mission posts StopMission locally, the pod tears down, and lands back in the lobby room. Arcade -net pods keep the re-listen-and-wait behavior. Loopback hosted race still green. For the drivers: the ampersand key is the arcade mission-abort - that was every crash-on-keypress so far; and a sleeping Bluetooth pad wakes on the Xbox button and hot-connects within 3 seconds (PadRIO re-probes). Co-Authored-By: Claude Fable 5 --- MUNGA/APPMGR.cpp | 3 +++ MUNGA/APPMGR.h | 6 ++++++ MUNGA_L4/L4NET.CPP | 16 ++++++++++++++++ RP/VTV.cpp | 10 ++++++++++ RP_L4/RPL4.CPP | 6 +++++- 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/MUNGA/APPMGR.cpp b/MUNGA/APPMGR.cpp index 390aae2..6dbad56 100644 --- a/MUNGA/APPMGR.cpp +++ b/MUNGA/APPMGR.cpp @@ -12,6 +12,9 @@ void (*gPerFrameHook)() = NULL; // an in-process console owns the launch (hosted network races) Logical gConsoleMarshalsLaunch = False; +// losing the console mid-mission ends it (lobby-member races) +Logical gConsoleLossEndsMission = False; + ApplicationManager* ApplicationManager::CurrentAppManager = NULL; ApplicationManager::ApplicationManager(HINSTANCE hInstance, HWND hWnd, Scalar frame_rate) : Node(ApplicationManagerClassID), runningApplications(this) diff --git a/MUNGA/APPMGR.h b/MUNGA/APPMGR.h index eac4952..ac52fdc 100644 --- a/MUNGA/APPMGR.h +++ b/MUNGA/APPMGR.h @@ -14,6 +14,12 @@ extern void (*gPerFrameHook)(); // single player leaves it False and auto-runs exactly as always. extern Logical gConsoleMarshalsLaunch; +// True for lobby-member races: losing the console mid-mission ends the +// mission (the owner left - without a console the timer counts up +// forever). Arcade -net pods leave it False and re-listen for their +// console to return, exactly as always. +extern Logical gConsoleLossEndsMission; + class ApplicationManager : public Node { public: diff --git a/MUNGA_L4/L4NET.CPP b/MUNGA_L4/L4NET.CPP index 2d1c5ef..996cf4c 100644 --- a/MUNGA_L4/L4NET.CPP +++ b/MUNGA_L4/L4NET.CPP @@ -20,6 +20,8 @@ #include "l4host.h" #include "l4net.h" #include "l4nettransport.h" +#include "..\munga\appmgr.h" +#include "..\munga\appmsg.h" #include "..\munga\mission.h" #include "..\munga\notation.h" //#include @@ -1000,6 +1002,20 @@ void L4NetworkManager::HostDisconnectedMessageHandler(HostDisconnectedMessage* H #else myConsoleHost = 0; #endif + // + // Lobby-member races: the departed console was the race + // owner - without a console the mission clock counts up + // forever, so end the mission and get back to the lobby + // room. (Arcade pods keep the listen above and wait for + // their console to return.) + // + if (gConsoleLossEndsMission && + application->GetApplicationState() == Application::RunningMission) + { + DEBUG_STREAM << "Console lost mid-race - ending the mission\n" << std::flush; + Application::StopMissionMessage stop_message(0); + application->Post(DefaultEventPriority, application, &stop_message); + } break; } default: diff --git a/RP/VTV.cpp b/RP/VTV.cpp index 2d4eea9..d94e49f 100644 --- a/RP/VTV.cpp +++ b/RP/VTV.cpp @@ -179,6 +179,16 @@ void Check(host); Mover *mover = (Mover*)host->GetEntityPointer(message->inflictingEntity); + if (mover == NULL) + { + // + // The inflicting entity is gone - its pod left the race + // mid-mission (consumer multiplayer; arcade pods never + // left). Nothing to bounce against. + // + Check_Fpu(); + return; + } Verify(mover->IsDerivedFrom(Mover::GetClassDerivations())); Vector3D v; diff --git a/RP_L4/RPL4.CPP b/RP_L4/RPL4.CPP index 1048cdd..a0ca74b 100644 --- a/RP_L4/RPL4.CPP +++ b/RP_L4/RPL4.CPP @@ -298,12 +298,16 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // // Lobby member: enter the race as a network pod. The // owner's console connects over the wire, feeds the egg, - // and marshals us - no local egg, no local console. + // and marshals us - no local egg, no local console. If + // the owner leaves mid-race the mission ends (a race + // with no console never stops on its own). // L4Application::SetNetworkCommonFlatAddress(1501); + gConsoleLossEndsMission = True; } else { + gConsoleLossEndsMission = False; L4Application::SetEggNotationFileName(frontend_egg); // Front-end games are marshaled by the in-process console: