#108 forensics block (pre-717): ghost detector + IDs + field envs
The night-11 instrumentation that makes the next ghost/K-D report diagnosable instead of anecdotal: - UNGATED [ghost] stale-replicant detector: ReadUpdateRecord stamps every applied record; the death-handler tick logs ONE line per starvation episode (>600 frames, unburied) with entity id + mode + last position, plus a GHOST matchlog record. Verified both ways: zero false positives on a healthy 2-node session; fires on both nodes at frame 601 after a mid-session relay kill. - Entity IDs on the render forensics (MakeMechRenderables / RemakeEntity / wreck-swap fallbacks) and the replicant un-wreck line un-gated -- ghost triage no longer needs players to set envs. - players/*.bat (steam + both joins): BT_MATCHLOG/BT_SCORE_LOG/BT_DEATH_LOG on for every field session. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c38377a6d2
commit
81dda84e9b
@@ -1193,8 +1193,20 @@ extern void BTSpawnDamageEffect(Mech *mech, int effect_resource, int segment_ind
|
||||
// unported "RemakeEntity" render state). Entity* param -> Mech* binds fine.
|
||||
extern void BTRemakeMechModel(Entity *entity);
|
||||
|
||||
//
|
||||
// #108 bridge: Mech::ReadUpdateRecord (mech.cpp, incomplete-type TU for the
|
||||
// handler) stamps the ghost detector through this.
|
||||
//
|
||||
void
|
||||
BTMechNoteUpdateApplied(void *mech_v)
|
||||
{
|
||||
Mech *m = (Mech *)mech_v;
|
||||
if (m != 0 && m->DeathHandlerPtr() != 0)
|
||||
((MechDeathHandler *)m->DeathHandlerPtr())->NoteUpdateApplied();
|
||||
}
|
||||
|
||||
MechDeathHandler::MechDeathHandler(Mech *mech) // @0042a984
|
||||
: owner(mech), prevMode(0)
|
||||
: owner(mech), prevMode(0), ghostFrames(0), ghostLogged(0)
|
||||
{
|
||||
// per-zone last-damage cache, zeroed (binary this[0x10], size mech+0x11c).
|
||||
int count = (mech != 0 && mech->damageZoneCount > 0) ? mech->damageZoneCount : 0;
|
||||
@@ -1217,6 +1229,35 @@ void
|
||||
if (owner == 0)
|
||||
return;
|
||||
|
||||
// #108 GHOST DETECTOR (PORT, ungated -- the night-9 forensic): a visible
|
||||
// REPLICANT that stops receiving update records is exactly what "everyone
|
||||
// shoots thin air" looks like from the other side. ReadUpdateRecord
|
||||
// stamps arrivals (NoteUpdateApplied); ~20s of silence on an unburied
|
||||
// replicant logs ONE [ghost] line per episode with the identity + last
|
||||
// position, then re-arms when records resume. Frame-counted (Tick has no
|
||||
// dt); 600 frames ~ 10-20s at field rates.
|
||||
if (owner->GetInstance() == Entity::ReplicantInstance)
|
||||
{
|
||||
++ghostFrames;
|
||||
if (ghostFrames > 600 && !ghostLogged
|
||||
&& !owner->WreckBuried()) // buried wrecks are expected-silent
|
||||
{
|
||||
ghostLogged = 1;
|
||||
DEBUG_STREAM << "[ghost] replicant " << owner->GetEntityID()
|
||||
<< " has received NO update records for " << ghostFrames
|
||||
<< " frames (mode " << (int)owner->MovementMode()
|
||||
<< ") last pos (" << owner->localOrigin.linearPosition.x
|
||||
<< "," << owner->localOrigin.linearPosition.z
|
||||
<< ") -- stale-replicant / ghost signature (#108)\n" << std::flush;
|
||||
if (BTMatchLogActive())
|
||||
BTMatchLog("GHOST", "mech=%d:%d frames=%d mode=%d x=%.1f z=%.1f",
|
||||
BTMatchHostOf(owner->GetEntityID()), (int)owner->GetEntityID(),
|
||||
ghostFrames, (int)owner->MovementMode(),
|
||||
(float)owner->localOrigin.linearPosition.x,
|
||||
(float)owner->localOrigin.linearPosition.z);
|
||||
}
|
||||
}
|
||||
|
||||
// REPLICANT UN-WRECK (#94): fire on the DEATH-STATE EXIT edge of the
|
||||
// replicated SimulationState dial (MovementMode 9/2 are the death modes;
|
||||
// they never revert except through Mech::Reset, whose SetMovementMode(0)
|
||||
@@ -1251,11 +1292,13 @@ void
|
||||
BTStartWarpEffect((float)owner->localOrigin.linearPosition.x,
|
||||
(float)owner->localOrigin.linearPosition.y,
|
||||
(float)owner->localOrigin.linearPosition.z);
|
||||
if (getenv("BT_DEATH_LOG"))
|
||||
DEBUG_STREAM << "[respawn] replicant un-wrecked + warp (mode "
|
||||
<< oldMode << "->" << mode << ") at ("
|
||||
<< owner->localOrigin.linearPosition.x << ","
|
||||
<< owner->localOrigin.linearPosition.z << ")\n" << std::flush;
|
||||
// #108 forensics: UNGATED -- one line per peer respawn; a field
|
||||
// night's ghost triage needs these without asking players for envs.
|
||||
DEBUG_STREAM << "[respawn] replicant " << owner->GetEntityID()
|
||||
<< " un-wrecked + warp (mode "
|
||||
<< oldMode << "->" << mode << ") at ("
|
||||
<< owner->localOrigin.linearPosition.x << ","
|
||||
<< owner->localOrigin.linearPosition.z << ")\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user