Remote operator control channel + THE teardown crash root-caused and fixed

REMOTE OPERATORS (dev-channel ask): the relay grows a control TCP
listener (console port + 7) speaking a line protocol -- AUTH <secret>
(auto-generated content\operator_secret.txt), then launch / stop /
ping / get mission / set key=value;...  The relay's timestamped log
stream tees to the authenticated operator (bounded per-conn buffers --
a stalled operator can NEVER stall the relay; overflow = drop), with a
400-line history replay on connect so mid-session operators see
current state.  One operator at a time; a new AUTH displaces the old.
stdin commands unchanged (rigs/GUI local mode untouched).

The operator GUI gains a 'Relay host' field: blank = today's local
flow byte-for-byte (child relay dies with the window); a hostname =
drive that machine's relay remotely (launch/stop/apply-settings over
the wire, roster rebuilt from the teed log, local-instance joins point
at the remote relay).  Only the relay host needs port forwarding.

Scripted protocol test: auth reject/accept, takeover, get/set, ping,
history replay, and a FULL 2-node mission launched and stopped
entirely over the socket.

CRASH FIX (the layout-shifting heisenbug -- and almost certainly issue
#35): the new crash self-report finally captured its 24-frame stack:
InterestManager::OrphanInterestOrigin -> RemoveUninterestingEntity ->
DestroyEntityAudioObjects -> {Static,Dynamic}3DPatchSource::
IsAudioSourceClipped, AV reading NULL+0x38 -- the unguarded chain
GetMissionPlayer()->GetPlayerVehicle()->GetSimulationState() (the
authentic burning-mech death-silence check) hit a NULL vehicle during
MP teardown windows.  Both sites now null-guard; burning semantics
preserved whenever the vehicle exists.  Also live-confirms that
interest-based entity teardown RUNS in MP (the #38 paint mechanism).
Regression: full combat round + control-channel drive, zero crashes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-24 12:41:51 -05:00
co-authored by Claude Opus 4.8
parent b710a848c2
commit 210bdb05ee
3 changed files with 525 additions and 17 deletions
+44 -8
View File
@@ -1189,13 +1189,31 @@ Dynamic3DPatchSource::Dynamic3DPatchSource(
Logical
Dynamic3DPatchSource::IsAudioSourceClipped(AudioHead *audio_head)
{
if (AudioSource::IsAudioSourceClipped(audio_head) || l4_application->GetMissionPlayer()->GetPlayerVehicle()->GetSimulationState() == VTV::BurningState)
if (AudioSource::IsAudioSourceClipped(audio_head))
{
return true;
} else
{
return false;
}
//
// NULL-GUARD (2026-07-24, the layout-shifting teardown crash finally
// stack-captured: InterestManager::OrphanInterestOrigin ->
// RemoveUninterestingEntity -> DestroyEntityAudioObjects -> here, AV
// reading NULL+0x38). The binary could assume the mission player
// always has a vehicle (in a pod you always do); the port's MP join/
// teardown/respawn windows briefly leave it NULL. The burning check
// (death-silence: your burning mech clips world audio) keeps its
// authentic behavior whenever the vehicle exists.
//
{
Player *mission_player = l4_application->GetMissionPlayer();
if (mission_player != 0
&& mission_player->GetPlayerVehicle() != 0
&& mission_player->GetPlayerVehicle()->GetSimulationState()
== VTV::BurningState)
{
return true;
}
}
return false;
}
//
@@ -1593,13 +1611,31 @@ Static3DPatchSource::Static3DPatchSource(
Logical Static3DPatchSource::IsAudioSourceClipped(AudioHead *audio_head)
{
if (AudioSource::IsAudioSourceClipped(audio_head) || l4_application->GetMissionPlayer()->GetPlayerVehicle()->GetSimulationState() == VTV::BurningState)
if (AudioSource::IsAudioSourceClipped(audio_head))
{
return true;
} else
{
return false;
}
//
// NULL-GUARD (2026-07-24, the layout-shifting teardown crash finally
// stack-captured: InterestManager::OrphanInterestOrigin ->
// RemoveUninterestingEntity -> DestroyEntityAudioObjects -> here, AV
// reading NULL+0x38). The binary could assume the mission player
// always has a vehicle (in a pod you always do); the port's MP join/
// teardown/respawn windows briefly leave it NULL. The burning check
// (death-silence: your burning mech clips world audio) keeps its
// authentic behavior whenever the vehicle exists.
//
{
Player *mission_player = l4_application->GetMissionPlayer();
if (mission_player != 0
&& mission_player->GetPlayerVehicle() != 0
&& mission_player->GetPlayerVehicle()->GetSimulationState()
== VTV::BurningState)
{
return true;
}
}
return false;
}
//