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>