fix(#170): armed moveto always ticks UseTime — the SERVERVEL branch starved the chase
The "sustain the run" residual. The handoff's "Ready stop-node backlog drains a beat slower than retail" framing was DISPROVEN: a new full-stack offline harness (RemoteChaseEndToEndHarnessTests — real MoveToManager + MotionInterpreter + AnimationSequencer + MotionTableDispatchSink + the manual omega integration, wired field-for-field like EnsureRemoteMotionBindings and ticked in TickAnimations' exact phase order) proves the Core turn/run/drain pipeline healthy: the chase turn completes in <1 s both directions, BeginMoveForward installs per arm, the run sustains across re-arms and attack swings, and pending_motions fully empties (retail cdb invariant add_to_queue == MotionDone). The real mechanism (launch-drainq.log, corrected per-guid attribution — the previous session's timeline mis-attributed [mvto] lines that fire in the network phase): funnel per chasing scamp was 16 mt-6 arms -> 11 dispatched turns -> ONE BeginMoveForward. Any NPC receiving UpdatePositions gets HasServerVelocity=true (synthesized from position deltas even when the wire carries no velocity), and the grounded per-tick branch routed those to the SERVERVEL leg, which SKIPS MoveToManager.UseTime — [npc-tick] literally logged "branch=SERVERVEL (skips UseTime) mtState=MoveToObject". The armed moveto was starved for exactly the duration of the server-side chase: legs stayed in Ready while the body glided on synthesized velocity (the #170 slide); the manager only woke in UP-silent gaps (creature stopped server-side) and its stale-heading turn was interrupted by the next UM before reaching BeginMoveForward. Retail runs MovementManager::UseTime UNCONDITIONALLY every tick (CPhysicsObj::UpdateObjectInternal 0x005156b0, call @0x00515998) and has no wire-velocity leg-driver anywhere; between UPs a moveto-driven body translates from the motion state (get_state_velocity) with UP hard-snaps correcting drift. Fix: an armed moveto (MovementTypeState != Invalid) always takes the MOVETO leg; SERVERVEL remains only as the legacy fallback for entities without a moveto (scripted paths / missiles). Register: TS-41 (the narrowed SERVERVEL stopgap), TS-42 (drain-order divergence also pinned this session: acdream drains AnimDone->MotionDone AFTER HandleTargetting/MoveTo.UseTime; retail's process_hooks @0x00512d3d runs BEFORE TargetManager/MovementManager in UpdateObjectInternal — one frame of extra latency, R6 scope). New conformance: RemoteChaseEndToEndHarnessTests (3 scenarios + theory) + RemoteChaseDrainBisectTests (the drain-chain pin; its first run also demonstrated the TS-40 InWorld=false link-strip wedge shape — harness bodies must replicate the live RemoteMotion construction). ISSUES #170 updated (awaiting user visual gate; probes stay until then); handoff doc superseded-note added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e744192361
commit
1051fc83c6
6 changed files with 811 additions and 20 deletions
|
|
@ -9957,7 +9957,34 @@ public sealed class GameWindow : IDisposable
|
|||
rm.Body.TransientState |= AcDream.Core.Physics.TransientStateFlags.Contact
|
||||
| AcDream.Core.Physics.TransientStateFlags.OnWalkable
|
||||
| AcDream.Core.Physics.TransientStateFlags.Active;
|
||||
if (!IsPlayerGuid(serverGuid) && rm.HasServerVelocity)
|
||||
// #170 residual fix (2026-07-04): an ARMED moveto always
|
||||
// takes the MOVETO branch. The old arbitration routed the
|
||||
// tick to SERVERVEL whenever UPs flowed (position-delta
|
||||
// synthesis sets HasServerVelocity=true for any moving
|
||||
// NPC), which SKIPPED MoveToManager.UseTime for exactly
|
||||
// the duration of the server-side chase — the armed
|
||||
// manager only ever ticked in UP-silent gaps (creature
|
||||
// stopped server-side), turned toward a stale heading,
|
||||
// and was interrupted by the next UM before reaching
|
||||
// BeginMoveForward. Live funnel (launch-drainq.log,
|
||||
// corrected per-guid attribution): 16 arms → 11 turns
|
||||
// dispatched → 1 run install; [npc-tick] shows
|
||||
// branch=SERVERVEL (skips UseTime) mtState=MoveToObject
|
||||
// for chasing scamps. The legs stayed in Ready while the
|
||||
// body glided on synthesized velocity — the #170 slide.
|
||||
// Retail runs MovementManager::UseTime UNCONDITIONALLY
|
||||
// per tick (CPhysicsObj::UpdateObjectInternal 0x005156b0,
|
||||
// call at 0x00515998) and has NO wire-velocity leg-driver;
|
||||
// between UPs a moveto-driven body translates from the
|
||||
// motion state (get_state_velocity) with UP hard-snaps
|
||||
// correcting drift. The SERVERVEL leg remains ONLY as the
|
||||
// legacy fallback for entities WITHOUT an armed moveto
|
||||
// (scripted-path NPCs / missiles carrying wire velocity).
|
||||
// Full-stack conformance: RemoteChaseEndToEndHarnessTests
|
||||
// (turn→run→drain sustained when the manager is ticked).
|
||||
bool moveToArmed = rm.MoveTo is
|
||||
{ MovementTypeState: not AcDream.Core.Physics.MovementType.Invalid };
|
||||
if (!IsPlayerGuid(serverGuid) && rm.HasServerVelocity && !moveToArmed)
|
||||
{
|
||||
if (Environment.GetEnvironmentVariable("ACDREAM_MVTO_DIAG") == "1")
|
||||
Console.WriteLine(System.FormattableString.Invariant(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue