Fix 2 (Gitea #12): gauge tree survives the in-session mech re-stream

The pre-launch host drop/rejoin re-stream re-creates every mech at mission
launch; the LOBBY-built gauge tree kept attribute pointers into the freed
first-stream mechs, every widget Execute AV'd, and the BT_DEV_GAUGES SEH
guard (Gauge::GuardedExecute, GAUGE.cpp:618) disabled each one PERMANENTLY
(rate=0, no rebind) -- the frozen dev-gauges window of incident #12.  The
authentic engine flow only tears the tree down at mission transitions
(Application::Shutdown -> gaugeRenderer->Shutdown() -> ShutdownImplementation
-> Remove(0), APP.cpp:787 / GAUGREND.cpp:3264); the re-stream bypassed it.

Fix: BTL4GaugeRenderer::TearDownForViewpointRestream() performs the
ENTITY-BOUND half of that same ShutdownImplementation sequence, in order
(gaugeAlarmManager->RemoveAllAlarms() -> Remove(0) -> moving/static entity
grid Clear), keeping the mission-scoped state (warehouse, graphics ports,
interpreter, controls-owned L4Lamps -- RemoveAllLamps would delete them
behind the buttonGroup's &lamp->automaticValue registrations).  Called from
BTL4Application::MakeViewpointEntity before ConfigureForModel("Init") on any
viewpoint RE-make -- that handler runs once per stream (the incident log's
[ctrlmap] installing x2) -- so the tree rebuilds bound to the NEW mech via
the renderer's existing lazy build.  Sentinel: "[gauge] viewpoint re-stream:
tearing the gauge tree down for rebuild".

Verified with the 2-instance relay harness (port 15600, MP_RELAY.EGG,
the incident sequence): join A (dev gauges) + B, kill B by exact PID at
WAITING FOR OPERATOR LAUNCH, rejoin B, operator launch.  Pod A re-streamed
(2x ctrlmap install, 4x zonebuild), logged the sentinel, and post-launch the
docked composite is fully live (mission clock/heading/radar advancing between
BT_SHOT frames) with ZERO [gauge-fault] DISABLED lines (the incident had 11).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-19 23:30:43 -05:00
co-authored by Claude Fable 5
parent 2edde29671
commit 0d032029a0
5 changed files with 124 additions and 23 deletions
+44
View File
@@ -73,6 +73,7 @@
#if !defined(L4LAMP_HPP)
# include <l4lamp.hpp>
#endif
#include <GAUGALRM.hpp> // GaugeAlarmManager (TearDownForViewpointRestream, Gitea #12)
#if !defined(L4WARE_HPP)
# include <l4ware.hpp>
#endif
@@ -269,6 +270,49 @@ Logical
return GaugeRenderer::TestInstance(); // FUN_00447b60
}
//
//#############################################################################
// TearDownForViewpointRestream (PORT FIX -- Gitea #12)
//#############################################################################
//
// The in-session mech RE-STREAM (a pre-launch host drop/rejoin re-creates all
// mechs at mission launch) frees the mech the LOBBY-built gauge tree was bound
// to; every gauge Execute then AVs on its dangling attribute pointers and the
// BT_DEV_GAUGES SEH guard (Gauge::GuardedExecute, GAUGE.cpp:618) disables each
// one PERMANENTLY (rate=0, nothing rebinds) -- the frozen dev-gauges window of
// incident #12. The AUTHENTIC engine flow only tears the tree down at mission
// transitions (Application::Shutdown -> gaugeRenderer->Shutdown() ->
// ShutdownImplementation -> Remove(0), APP.cpp:787 / GAUGREND.cpp:3264); the
// re-stream path bypasses it. This method performs the ENTITY-BOUND half of
// that same ShutdownImplementation sequence, in the same order:
// gaugeAlarmManager->RemoveAllAlarms() (alarms hold entity/subsystem ptrs)
// Remove(0) (delete every gauge, active+inactive)
// movingEntities/staticEntities.Clear() (raw Entity* grids for radar/map)
// and deliberately SKIPS the mission-scoped steps -- warehouse purge, graphics
// port destruction, lampManager->RemoveAllLamps() (the L4Lamps are owned by the
// CONTROLS layer, which registers &lamp->automaticValue into its buttonGroup --
// deleting them mid-session would dangle the button mappings; the mech-state
// "lamps" like AnimatedSubsystemLamp are Gauges and go with Remove(0)). The
// caller (MakeViewpointEntity) immediately re-runs ConfigureForModel("Init",
// <new mech>) against the still-initialized interpreter/warehouse, so the tree
// rebuilds bound to the NEW mech -- the gauge renderer builds lazily by design.
//
void
BTL4GaugeRenderer::TearDownForViewpointRestream()
{
Check(this);
if (gaugeAlarmManager != NULL)
{
Check(gaugeAlarmManager);
gaugeAlarmManager->RemoveAllAlarms();
}
Remove(0); // FUN_00447fc0(this, 0) -- all gauges
movingEntities.Clear();
staticEntities.Clear();
Check_Fpu();
}
//
//#############################################################################
// NotifyOfNewInterestingEntity