diff --git a/game/reconstructed/mech4.cpp b/game/reconstructed/mech4.cpp index d956306..b480375 100644 --- a/game/reconstructed/mech4.cpp +++ b/game/reconstructed/mech4.cpp @@ -1952,7 +1952,25 @@ void localToWorld.GetFromAxis(Z_Axis, &zAxR); const float fdot = -((float)wv.x * (float)zAxR.x + (float)wv.z * (float)zAxR.z); // mech faces -Z - replMppr->speedDemand = (fdot < 0.0f) ? -spd : spd; + Scalar sd = (fdot < 0.0f) ? -spd : spd; + // WALK-ENTRY FLOOR (user-reported "slides forward before it steps", + // root-caused 2026-07-14 from a per-frame [replmov] trace): the leg + // SM enters walk only when `standSpeed < commandedSpeed`, but a mech's + // forward WALK velocity == walkStrideLength which sits BELOW standSpeed + // (bhk1: walk 6.13 < stand ~6.8). The master clears the gate because + // it feeds the leg SM its COMMANDED throttle speed (>> standSpeed); the + // replicant feeds the DERIVED actual velocity, which never crosses the + // gate -- so a steadily-walking peer dead-reckons forward frozen in the + // standing pose (legState 0, legFrm pinned) until the master happens to + // accelerate past standSpeed. When the peer is clearly moving forward, + // floor the demand just past standSpeed so it enters the walk cycle at + // once; the walk case (6/7) clamps legCycleSpeed back to walkStrideLength, + // so the CADENCE still matches the actual travel (no foot-slip). Reverse + // needs no floor -- its entry gate is `commandedSpeed < ZeroSpeed`, which + // any negative demand already trips. + if (sd > walkStrideLength * 0.5f && sd < standSpeed * 1.1f) + sd = standSpeed * 1.1f; + replMppr->speedDemand = sd; // REPLICANT TURN-STEP (user-reported: a turning peer // statue-rotates while the local mech steps): the leg SM's // Standing case arms the turn-in-place "trn" clip (state 4, @@ -1997,7 +2015,11 @@ void DEBUG_STREAM << "[repltrn] yawRate=" << yawRate << " turnDemand=" << replMppr->turnDemand << " legState=" << (int)legStateAlarm.GetLevel() - << " spd=" << replMppr->speedDemand << "\n" << std::flush; + << " bodyState=" << (int)bodyStateAlarm.GetLevel() + << " legFrm=" << legAnimation.currentFrame + << " bodyFrm=" << bodyAnimation.currentFrame + << " spd=" << replMppr->speedDemand + << " tgt=" << bodyTargetSpeed << "\n" << std::flush; } } // PER-FRAME heading trace (BT_REPL_HDG, choppy-spin diagnosis): the @@ -2019,6 +2041,29 @@ void << " yawRate=" << yawRate << " dt=" << dt << "\n" << std::flush; } + // PER-FRAME travel/animation coupling probe (BT_REPL_MOV, user: + // "slides forward before it steps"): position vs the dead-reckon target + // vs the derived speed vs the leg SM state, every frame there is + // replicated motion. Reveals travel-vs-animation lag + lerp-gap jitter. + if (getenv("BT_REPL_MOV")) + { + const Scalar uvx = (Scalar)updateVelocity.linearMotion.x; + const Scalar uvz = (Scalar)updateVelocity.linearMotion.z; + const Scalar umag = (Scalar)sqrtf(uvx*uvx + uvz*uvz); + if (umag > 0.01f || replMppr->speedDemand != 0.0f) + DEBUG_STREAM << "[replmov]" + << " pos=(" << localOrigin.linearPosition.x << "," + << localOrigin.linearPosition.z << ")" + << " proj=(" << projectedOrigin.linearPosition.x << "," + << projectedOrigin.linearPosition.z << ")" + << " uvel=" << umag + << " spd=" << replMppr->speedDemand + << " legState=" << (int)legStateAlarm.GetLevel() + << " legFrm=" << legAnimation.currentFrame + << " nu-lp=" << (nextUpdate.ticks - lastPerformance.ticks) + << " dt=" << dt << "\n" << std::flush; + } + // REPLICANT BEAMS (task #51): the emitters carry live replicated // discharge state (Emitter::ReadUpdateRecord); draw them with the // same per-weapon walk the master uses. @@ -3136,6 +3181,16 @@ void localVelocity.linearMotion = Vector3D(0.0f, worldLinearVelocity.y, -fwdSpeed); localVelocity.angularMotion = Vector3D(0.0f, turn * authTurnRate, 0.0f); + // MASTER twin of [replmov]: the velocity this mech PUBLISHES vs its own + // leg state -- compare the master ramp to the replicant response. + if (getenv("BT_REPL_MOV") && (fwdSpeed > 0.01f || throttle != 0.0f)) + DEBUG_STREAM << "[mastervel] fwdSpeed=" << fwdSpeed + << " thr=" << throttle + << " legState=" << (int)legStateAlarm.GetLevel() + << " pos=(" << localOrigin.linearPosition.x << "," + << localOrigin.linearPosition.z << ")" + << " dt=" << dt << "\n" << std::flush; + // CRASH motion suppression (spec: the binary zeroes localVelocity while // crashed). While the stagger clip (legState 0x20) plays, freeze the // velocity so a knocked-down mech does not creep back into the obstacle and