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:
co-authored by
Claude Opus 4.8
parent
b710a848c2
commit
210bdb05ee
@@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user