feat(R4-V4): REMOTE cutover - per-remote MoveToManager; RemoteMoveToDriver + PlanMoveToStart DELETED (closes M1-remote, M4/M5/M6/M8-remote; retires AD-8, AD-9, AP-8, AP-9)

Every remote's server-directed movement now runs the verbatim retail
MoveToManager. EnsureRemoteMotionBindings constructs it per remote with
the full V2 seam set (position/heading/velocity providers, the P4
TargetTracker adapter via setTarget/clearTarget storing the tracked
guid on RemoteMotion) and binds InterruptCurrentMovement ->
CancelMoveTo(0x36) - the retail interrupt chain (TS-36 remote side).

UM routing is retail's unpack_movement dispatch (0x00524440): the
head-interrupt + unstick fire for EVERY movement type, then mt 6/7
build MovementParameters.FromWire(raw bitfield - now surfaced by the
parser) + a MovementStruct (mt 6 resolves the target guid against the
entity table, degrading to MoveToPosition at the wire origin per the
plan's 2f; my_run_rate written from MoveToRunRate per @300603) ->
MoveTo.PerformMovement; mt 8/9 likewise via FromWireTurnTo; ONLY mt 0
flows through the interpreted funnel (the PlanMoveToStart seed is
DELETED - retail never routes MoveTo types through the interpreted
state copy).

Per tick: the P4 tracker feeds HandleUpdateTarget(Ok/ExitWorld) from
the live entity table, then UseTime runs the manager's steering/
arrival/fail handlers, then apply_current_movement recomputes velocity
- the same shape ordinary locomotion uses. The legacy driver branches,
the stale-destination timer, and the ClampApproachVelocity band-aid
are gone; arrival now uses retail cylinder distance (watch melee-range
stop distance in the visual pass).

DELETED: RemoteMoveToDriver.cs + its tests (OriginToWorld relocated
verbatim to MoveToMath; the B.6 auto-walk's two surviving constants
inlined into PlayerMovementController, dying with it in V5);
ServerControlledLocomotion.PlanMoveToStart + tests (PlanFromVelocity
survives - new AP-80 row); the RemoteMotion MoveTo capture fields.
Registers: AD-8/AD-9/AP-8/AP-9 retired; AP-79 (TargetTracker adapter,
retire R5) + AP-80 added.

Full suite green: 3,948 passed. Live smoke launched - NPC
chase/wander behavior pending user verification (recorded in the
session handoff).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-03 12:18:05 +02:00
parent a144e87318
commit 7016b26ce7
10 changed files with 248 additions and 883 deletions

View file

@ -200,6 +200,12 @@ public sealed class PlayerMovementController
private bool _prevRunHeld;
private int _prevAutoWalkTurnDir;
// R4-V4: relocated from the DELETED RemoteMoveToDriver — B.6 auto-walk's
// last two dependencies on it. Both die with auto-walk in R4-V5.
private const float AutoWalkArrivalEpsilon = 0.05f;
private static float AutoWalkTurnRateFor(bool running)
=> running ? (MathF.PI / 2.0f) * 1.5f : (MathF.PI / 2.0f); // BaseTurnRate x RunTurnFactor
// Heartbeat timer.
// Cadence is 1.0 sec to match holtburger's
// AUTONOMOUS_POSITION_HEARTBEAT_INTERVAL and the retail trace
@ -533,10 +539,10 @@ public sealed class PlayerMovementController
/// for the rest of <see cref="Update"/> to consume.
///
/// <para>
/// Heading correction matches <see cref="RemoteMoveToDriver.Drive"/>
/// — ±<see cref="RemoteMoveToDriver.HeadingSnapToleranceRad"/>
/// Heading correction matches the deleted RemoteMoveToDriver.Drive
/// — ±its 20-degree HeadingSnapTolerance
/// snap-on-aligned, otherwise rotate at
/// <see cref="RemoteMoveToDriver.TurnRateRadPerSec"/>. Arrival
/// pi/2 rad/s. Arrival
/// predicate matches retail's
/// <c>MoveToManager::HandleMoveToPosition</c>: chase arrives at
/// <c>distanceToObject</c>; flee arrives at <c>minDistance</c>.
@ -618,7 +624,7 @@ public sealed class PlayerMovementController
(_autoWalkMoveTowards
&& dist <= arrivalThreshold)
|| (!_autoWalkMoveTowards
&& dist >= arrivalThreshold + RemoteMoveToDriver.ArrivalEpsilon);
&& dist >= arrivalThreshold + AutoWalkArrivalEpsilon);
// Step Yaw toward target. Convention from Update line 364:
// _body.Orientation = Quaternion.CreateFromAxisAngle(Z, Yaw - π/2),
@ -655,7 +661,7 @@ public sealed class PlayerMovementController
// run/walk decision (one-shot at chain start) drives the
// turn rate: running rotation is 50% faster per
// run_turn_factor at retail 0x007c8914.
float maxStep = RemoteMoveToDriver.TurnRateFor(_autoWalkInitiallyRunning) * dt;
float maxStep = AutoWalkTurnRateFor(_autoWalkInitiallyRunning) * dt;
float yawStep = MathF.Sign(delta) * MathF.Min(MathF.Abs(delta), maxStep);
Yaw += yawStep;
while (Yaw > MathF.PI) Yaw -= 2f * MathF.PI;
@ -1011,7 +1017,7 @@ public sealed class PlayerMovementController
if (!autoWalkConsumedMotion
&& _motion.InterpretedState.TurnCommand == MotionCommand.TurnRight)
{
Yaw -= RemoteMoveToDriver.BaseTurnRateRadPerSec
Yaw -= (MathF.PI / 2.0f) // BaseTurnRateRadPerSec (AP-9), ex-RemoteMoveToDriver
* _motion.InterpretedState.TurnSpeed * dt;
}
Yaw -= input.MouseDeltaX * MouseTurnSensitivity;