#141 sweep: every hand-composed segment->world now goes through the engine accessor
Finishing the audit the #141 fix implied. The unfaithful pattern
mw.Multiply(seg->GetSegmentToEntity(), mech->localToWorld);
appeared at FOUR sites, not one. GetSegmentToEntity only recomputes when
segmentModified is already set (SEGMENT.cpp:262); the thing that sets it is the
binary's FUN_00424da8 == JointedMover::GetSegmentToWorld, which tests
AreJointsModified() and marks the whole segment table dirty. Compose by hand
and you read whatever cache is there -- fresh on the local mech (the render pass
refreshes it every frame), BIND POSE on any replicant.
Swept (the muzzle path was fixed in f01de8c):
* BTResolveWeaponMuzzle -- weapon muzzle (already done)
* BTGetMechSegmentWorldPos @1066 -- generic segment->world bridge
* damage-effect anchor @2148 -- peer effects anchored to the bind pose
* energy-beam gun port @8916 -- SAME exposure as the missile launch:
a peer's BEAM would originate from the
untwisted gun port too
Repo-wide grep now shows exactly one GetSegmentToEntity call outside
SEGMENT.cpp -- JMOVER.cpp:153, which is inside GetSegmentToWorld itself, after
the refresh. That is the correct one.
No regression (scratchpad/night13/missileframe.sh):
master n=165 max 2.1719 mean 1.2781 >0.1rad 100%
REPLICANT n=165 max 2.0907 mean 0.8201 >0.1rad 64%
and the peer failures remain a clean PREFIX with zero interleaved cases --
i.e. only the window before the peer has any replicated twist to carry, which
is correct behaviour, not a miss.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SgmXGNMXavXiafKXf9MDC
This commit is contained in:
co-authored by
Claude Opus 5
parent
f01de8cbfa
commit
e6c5ac951e
@@ -1062,8 +1062,13 @@ int
|
||||
{
|
||||
if (seg->GetIndex() == seg_index)
|
||||
{
|
||||
AffineMatrix mw;
|
||||
mw.Multiply(seg->GetSegmentToEntity(), m->localToWorld);
|
||||
// #141 sweep: go through the engine accessor, which is the
|
||||
// binary's FUN_00424da8 (the joints->segments refresh). A hand
|
||||
// composed GetSegmentToEntity() x localToWorld reads a STALE
|
||||
// cache on any mech whose segments were not refreshed this frame
|
||||
// -- i.e. every REPLICANT. See BTResolveWeaponMuzzle.
|
||||
LinearMatrix mw;
|
||||
m->GetSegmentToWorld(*seg, &mw);
|
||||
p = mw; // Point3D = matrix translation
|
||||
break;
|
||||
}
|
||||
@@ -2144,8 +2149,11 @@ void
|
||||
{
|
||||
if (seg->GetIndex() == segment_index)
|
||||
{
|
||||
AffineMatrix mw;
|
||||
mw.Multiply(seg->GetSegmentToEntity(), mech->localToWorld);
|
||||
// #141 sweep: engine accessor (== the binary's FUN_00424da8),
|
||||
// not a hand-composed product -- otherwise a peer's damage
|
||||
// effect anchors to the BIND-POSE segment.
|
||||
LinearMatrix mw;
|
||||
mech->GetSegmentToWorld(*seg, &mw);
|
||||
fxPos = mw; // Point3D = matrix translation
|
||||
break;
|
||||
}
|
||||
@@ -8912,9 +8920,12 @@ void
|
||||
}
|
||||
if (s_portCache[energyOrdinal] != 0)
|
||||
{
|
||||
AffineMatrix mw;
|
||||
mw.Multiply(s_portCache[energyOrdinal]->GetSegmentToEntity(),
|
||||
localToWorld);
|
||||
// #141 sweep: engine accessor (== the binary's FUN_00424da8).
|
||||
// This is the BEAM muzzle -- the same stale-cache exposure the
|
||||
// missile launch had, so a peer's beam would also originate
|
||||
// from the bind-pose gun port instead of the twisted torso.
|
||||
LinearMatrix mw;
|
||||
GetSegmentToWorld(*s_portCache[energyOrdinal], &mw);
|
||||
mz = mw; // Point3D = matrix translation
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user