#67 torso replication, part 1: the dead-reckoning clock fix + the bug REPRODUCED on the rig
THE CLOCK FIX (landed, verified live). The replicant torso's extrapolation
window was hardwired to ZERO: both shim accessors returned the same field
(torso.hpp, the "dormant in single-player" note). The engine maintains both
clocks exactly as the binary expects -- WriteUpdateRecord stamps
lastUpdate=lastPerformance on the master, ReadUpdateRecord stamps
lastUpdate=Now() on the replicant (SIMULATE.cpp:276/296, the 1995 "HACK"
comment intact) -- so the fix is one mapping: GetCreationTime (misnamed; now
GetLastUpdateTime) reads lastUpdate. ComputeTargetTwist's
`current - lastUpdate` window is real again. Why legs always replicated
while torsos did not: Mover is ENGINE code reading these fields natively; the
Torso is our reconstruction with the collapsed shim. Rig-verified: the
copy-side log now shows distinct lastUpd/now values.
THE FIELD BUG REPRODUCED (2-pod rig, thor vs thor -- thor because the first
attempt used FOGDAY's Black Hawk, whose torso is authentically FIXED like the
Owens: hEn=0, limits +/-0.01 deg):
[torso-copy] cur=-3.31613 target=-3.31613 atUpd=-3750
The replicant renders at EXACTLY its twist limit (thor: +/-3.31613 rad)
because twistAtUpdate holds garbage (-3750) and the limit clamp slams it to
the stop -- "twisted full right but was not using TT", on demand. An earlier
run poisoned it with 2.1e-44 (= int 15 as float, suspiciously the torso's
subsystem index).
NARROWED: the tx/rx probes added here (BT_TORSO_LOG prints every torso record
both directions, header + raw payload dwords) logged ZERO records in the
poisoned runs -- Torso::Read/WriteUpdateRecord never executed. The garbage
therefore arrives OUTSIDE the torso record path: a raw state write during
mech spawn/consolidation spraying the torso's fields (stream-walker framing
or a consolidation blit). That writer is part 2's hunt; the probes and the
deterministic repro make it a short one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9bb95d8580
commit
a3329a64da
@@ -341,7 +341,7 @@ Torso::Torso(
|
||||
hitElevTop = hitElevBottom = 0; // @0x258 / @0x25C
|
||||
hitTwistLeft = hitTwistRight = 0; // @0x260 / @0x264
|
||||
recenterActive = 0; // @0x274
|
||||
lastUpdateTime = GetCreationTime(); // @0x254 = this[5]
|
||||
lastUpdateTime = GetLastUpdateTime(); // @0x254 = this[5]
|
||||
|
||||
// bring-up verification (env BT_TORSO_LOG): the gyro cross-links to
|
||||
// (Torso*)+0x1D8 (== currentTwist) at a RAW offset (mech.cpp:740), so the
|
||||
@@ -465,9 +465,9 @@ void
|
||||
Torso::ReadUpdateRecord(UpdateRecord *message)
|
||||
{
|
||||
lastUpdateTime = GetCurrentTime(); // @0x254
|
||||
if ((Scalar)(lastUpdateTime - GetCreationTime()) / MsPerSecond < MinSlewMs)
|
||||
if ((Scalar)(lastUpdateTime - GetLastUpdateTime()) / MsPerSecond < MinSlewMs)
|
||||
{
|
||||
lastUpdateTime += (lastUpdateTime - GetCreationTime()); // stretch tiny windows
|
||||
lastUpdateTime += (lastUpdateTime - GetLastUpdateTime()); // stretch tiny windows
|
||||
}
|
||||
|
||||
Subsystem::ReadUpdateRecord(message); // FUN_0041bd34
|
||||
@@ -475,6 +475,23 @@ void
|
||||
twistAtUpdate = RecordField(message, 0x10); // @0x21C
|
||||
twistVelocity = RecordField(message, 0x14); // @0x1E8
|
||||
twistRate = RecordField(message, 0x18); // @0x238
|
||||
|
||||
// #67 stream forensics (BT_TORSO_LOG): the copy received atUpd=2.1e-44
|
||||
// (= int 15 as float) on the rig -- a mis-framed record. Print the raw
|
||||
// header + payload dwords of every record this torso consumes.
|
||||
if (getenv("BT_TORSO_LOG"))
|
||||
{
|
||||
const unsigned int *raw = (const unsigned int *)message;
|
||||
DEBUG_STREAM << "[torso-rec-rx] len=" << message->recordLength
|
||||
<< " subID=" << (int)message->subsystemID
|
||||
<< " recID=" << (int)message->recordID
|
||||
<< std::hex
|
||||
<< " p10=0x" << raw[4] << " p14=0x" << raw[5]
|
||||
<< " p18=0x" << raw[6] << std::dec
|
||||
<< " -> atUpd=" << twistAtUpdate
|
||||
<< " vel=" << twistVelocity << " rate=" << twistRate
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -503,6 +520,17 @@ void
|
||||
WriteRecordField(message, 0x14, twistVelocity); // @0x1E8
|
||||
WriteRecordField(message, 0x18, twistRate); // @0x238
|
||||
twistAtUpdate = currentTwist; // @0x21C snapshot at send
|
||||
|
||||
// #67 stream forensics: what the MASTER actually serialized.
|
||||
if (getenv("BT_TORSO_LOG"))
|
||||
{
|
||||
DEBUG_STREAM << "[torso-rec-tx] len=" << message->recordLength
|
||||
<< " subID=" << (int)message->subsystemID
|
||||
<< " recID=" << (int)message->recordID
|
||||
<< " twist=" << currentTwist
|
||||
<< " vel=" << twistVelocity << " rate=" << twistRate
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -730,7 +758,7 @@ void
|
||||
}
|
||||
else
|
||||
{
|
||||
Scalar age = (Scalar)(lastUpdateTime - GetCreationTime()) / MsPerSecond;
|
||||
Scalar age = (Scalar)(lastUpdateTime - GetLastUpdateTime()) / MsPerSecond;
|
||||
currentTwist = Lerp(currentTwist, targetTwist, time_slice / (age + time_slice)); // FUN_004081e0
|
||||
}
|
||||
targetTwist = Min(targetTwist, horizontalLimitLeft); // @0x1E0
|
||||
@@ -776,12 +804,12 @@ Logical
|
||||
|
||||
if (isDamagedCopy == 0 || lastUpdateTime <= GetCurrentTime())
|
||||
{
|
||||
base = GetCurrentTime() - GetCreationTime(); // this[0x10] - this[0x14]
|
||||
base = GetCurrentTime() - GetLastUpdateTime(); // this[0x10] - this[0x14]
|
||||
slewing = False;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = lastUpdateTime - GetCreationTime(); // @0x254 - this[0x14]
|
||||
base = lastUpdateTime - GetLastUpdateTime(); // @0x254 - this[0x14]
|
||||
slewing = True;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user