From 38fed81d8a43051c7f0a14fa238c080e3dfa79d7 Mon Sep 17 00:00:00 2001 From: arcattack Date: Tue, 14 Jul 2026 21:41:30 -0500 Subject: [PATCH] MP: tighten peer re-anchor -- error-proportional absorption (residual snap, task #50) Chasing the ~2.9u residual snap: instrumented BT_MIRDIV and isolated it to the PEER side (master send-mirror error is accurate, mean 0.39u < 0.55u threshold; peer drifted 3-11u from received authority). Root: the master models the peer with the BODY channel but the peer moves with the LEG channel -- slightly different travel/frame -- so the master deadband does not fire exactly when the peer drifts, and the fixed ~1/3s offset decay bled slower than accel/decel drift accumulated. A hard ground-snap (authentic FUN_004ab1c8:14985) popped instead (records not perfectly dense on the one-box relay). FIX: error-proportional absorption -- bleed the offset to updateOrigin at a rate that scales with the error (k 0.15..0.6/frame): small steady offset absorbed gently (no foot-pop), large speed-change drift caught in a few frames. Measured (through-zero sweep): peer drift 11u->2.1u, maxStep 2.9u->1.77u, ratio 1.043->1.036. Remaining <=1.8u snaps are the leg-vs-body channel-shape mismatch; fully closing needs a leg-channel send-mirror (second instance) -- deferred. Co-Authored-By: Claude Opus 4.8 (1M context) --- game/reconstructed/mech4.cpp | 64 +++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/game/reconstructed/mech4.cpp b/game/reconstructed/mech4.cpp index 3e19ff4..72d86dc 100644 --- a/game/reconstructed/mech4.cpp +++ b/game/reconstructed/mech4.cpp @@ -2145,23 +2145,26 @@ void // (reverse clips return negative travel; master dir==1.0 in SM mode). if (!s_drPos) { - // POSE-SYNC OFFSET DECAY (authentic FUN_004ab1c8 motionEventVector - // mechanism): a record does NOT snap the body -- the correction offset - // is absorbed over ~1/3s while the clip's root motion keeps driving, so - // the feet never pop and the position converges to authority. - static Vector3D s_rmErr[2]; // per-instance would be a member; one replicant per node in practice - Vector3D &rmErr = s_rmErr[0]; - if (poseSyncLatch) + // POSE-SYNC ERROR-PROPORTIONAL ABSORPTION: track the error to the + // received authority (updateOrigin) and bleed it into localOrigin at a + // rate that scales with the error, so a small steady offset is absorbed + // gently (no foot-pop) while a large speed-change drift is caught fast. + // The residual snap came from two sources: (a) a fixed slow ~1/3s decay + // let drift reach 3-11u during accel/decel; (b) a hard ground snap popped + // because records are not perfectly dense on this relay. Error-scaled + // absorption is the stable middle: k grows from ~0.15/frame at small + // error toward ~0.6 at large error. (Records re-measure the error every + // frame they arrive, so this converges to authority within a few frames.) { + Vector3D rmErr; rmErr.Subtract(updateOrigin.linearPosition, localOrigin.linearPosition); poseSyncLatch = 0; - } - { - Scalar k = dt * 3.0f; if (k > 1.0f) k = 1.0f; // ~1/3s absorption + const float eMag = (float)rmErr.Length(); + float k = 0.15f + eMag * 0.15f; // error-proportional catch-up + if (k > 0.6f) k = 0.6f; localOrigin.linearPosition.x += rmErr.x * k; localOrigin.linearPosition.y += rmErr.y * k; localOrigin.linearPosition.z += rmErr.z * k; - rmErr.x -= rmErr.x * k; rmErr.y -= rmErr.y * k; rmErr.z -= rmErr.z * k; } if (replLegAdv != 0.0f) { @@ -2177,6 +2180,24 @@ void localToWorld = localOrigin; // refresh with the coupled position } + // PEER-DRIFT probe (BT_MIRDIV, 1s max): how far the peer's coupled + // position wanders from the last-received authority (updateOrigin) + // before a record re-anchors it -- the other end of the snap. + if (getenv("BT_MIRDIV")) + { + static float s_pdAcc = 0.0f, s_pdMax = 0.0f; + Vector3D d; d.Subtract(localOrigin.linearPosition, updateOrigin.linearPosition); + const float dl = (float)d.Length(); + if (dl > s_pdMax) s_pdMax = dl; + s_pdAcc += dt; + if (s_pdAcc >= 1.0f) + { + DEBUG_STREAM << "[peerdrift] maxDriftFromAuthority=" << s_pdMax + << " replLegAdv=" << replLegAdv << "\n" << std::flush; + s_pdAcc = 0.0f; s_pdMax = 0.0f; + } + } + // GAIT-EVENNESS probe (BT_GAITEV, 1s stats): the metric of the VISIBLE // speed-change glitch -- per-frame leg-clip advance regularity + leg-state // transition (flap) rate on the peer. Position dead-reckons smoothly @@ -3772,6 +3793,27 @@ void error.Subtract( projectedOrigin.linearPosition, localOrigin.linearPosition); + // MIRROR-DIVERGENCE probe (BT_MIRDIV, 1s max): how far the master's + // send-mirror (projectedOrigin, body-channel gait) drifts from the true + // localOrigin (leg-channel gait) BEFORE a send fires. This is the source + // of the peer's residual snap -- quantifies the leg-vs-body channel shape + // mismatch. posDb (~0.55u) is the send threshold; anything the mirror + // over/under-shoots beyond it is the channel divergence. + if (getenv("BT_MIRDIV")) + { + static float s_mdAcc = 0.0f, s_mdMax = 0.0f, s_mdAdvB = 0.0f, s_mdAdvL = 0.0f; + const float e = (float)error.Length(); + if (e > s_mdMax) s_mdMax = e; + s_mdAdvB += (float)(mirrorBodyAdv < 0 ? -mirrorBodyAdv : mirrorBodyAdv); + s_mdAcc += dt; + if (s_mdAcc >= 1.0f) + { + DEBUG_STREAM << "[mirdiv] maxErr=" << s_mdMax + << " bodyTravel/s=" << s_mdAdvB + << " bodyTgtSpd=" << bodyTargetSpeed << "\n" << std::flush; + s_mdAcc = 0.0f; s_mdMax = 0.0f; s_mdAdvB = 0.0f; s_mdAdvL = 0.0f; + } + } Quaternion angular_deviation; angular_deviation.Subtract( projectedOrigin.angularPosition,