diff --git a/CLAUDE.md b/CLAUDE.md index 0e02b6d..469b95c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -552,17 +552,14 @@ via `PlayerMovementController.ApplyServerRunRate`) or from diagnostics (`[UM_RAW]`, `[SCFAST]`, `[SCFULL]`, `[SETCYCLE]`, `[FWD_WIRE]`, `[OMEGA_DIAG]`, `[SEQSTATE]`, `[PARTSDIAG]`, `[VEL_DIAG]`, `[UPCYCLE]`). Heavy. -- ⚠️ `ACDREAM_INTERP_MANAGER=1` — **DO NOT ENABLE.** This was an - experimental rewrite (e94e791) of the per-tick remote motion path. - It's regressed: the env-var path drops the per-tick collision sweep - (`ResolveWithTransition`) that the default path retains, causing a - visible "staircase" pattern when remotes run up/down slopes (body - Z stays flat between UPs, snaps at each one) plus position blips - during steady-state motion. Default (env-var unset) uses the - working retail-port chain. The PositionManager class itself is - fine and retail-faithful; only the integration into per-tick was - wrong. To be re-done in a future L.3 follow-up phase as additive - refinement on top of the working chain. +- *(retired 2026-05-05 by L.3 M2/M3)* `ACDREAM_INTERP_MANAGER` was an + env-var gate on an experimental per-tick remote motion path. L.3 M2 + (commit 40d88b9) replaced both gates (`OnLivePositionUpdated` + + `TickAnimations`) with `IsPlayerGuid(...)` so player remotes use the + retail-faithful queue routing (InterpolationManager queue catch-up + + PositionManager combiner) unconditionally. NPCs and airborne player + remotes still flow through the legacy `apply_current_movement` + + `ResolveWithTransition` path. The env-var no longer toggles anything. ### Outbound motion wire format (acdream → ACE) diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 0c1c15e..08a8a05 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -295,11 +295,6 @@ public sealed class GameWindow : IDisposable /// public double LastMoveToPacketTime; /// - /// Legacy field — no longer used for slerp (retail hard-snaps - /// per FUN_00514b90 set_frame). Kept to avoid churn. - /// - public System.Numerics.Quaternion TargetOrientation = System.Numerics.Quaternion.Identity; - /// /// Angular velocity seeded from UpdateMotion TurnCommand/TurnSpeed /// (π/2 × turnSpeed, signed). Applied per tick to body orientation /// via manual integration (bypassing PhysicsBody.update_object's @@ -334,34 +329,21 @@ public sealed class GameWindow : IDisposable /// /// Per-remote position-waypoint queue + catch-up math (retail's /// CPhysicsObj::InterpolateTo + InterpolationManager::adjust_offset). - /// Replaces the hard-snap-then-Euler-extrapolate path when - /// ACDREAM_INTERP_MANAGER=1 — see Phase L.3.1 spec at - /// docs/superpowers/specs/2026-05-02-l3-remote-entity-motion-design.md. - /// Field exists from Task 3 onwards; consumed in Tasks 4 + 5. + /// Drives per-tick body translation for grounded player remotes + /// via . /// public AcDream.Core.Physics.InterpolationManager Interp { get; } = new AcDream.Core.Physics.InterpolationManager(); /// /// Per-frame combiner for animation root motion + InterpolationManager - /// correction (Phase L.3.2). Consumed in TickAnimations to compute the - /// per-frame body.Position delta. + /// correction. Mirrors retail UpdatePositionInternal @ 0x00512c30: + /// queue catch-up REPLACES anim when active; anim stands when queue + /// is idle. /// public AcDream.Core.Physics.PositionManager Position { get; } = new AcDream.Core.Physics.PositionManager(); - /// - /// Most recent server-broadcast Z coordinate from any UpdatePosition - /// (including mid-arc airborne UPs). Used by the - /// ACDREAM_INTERP_MANAGER=1 per-tick path as a landing-fallback - /// floor: if gravity drags the body's Z below this value while - /// is still set, force-land locally because - /// the server has effectively told us where the ground is even if - /// it never sent an IsGrounded=true UP. Initialized to NaN so the - /// fallback is a no-op until the first UP arrives. - /// - public float LastServerZ = float.NaN; - /// /// Diagnostic-only (gated on ACDREAM_REMOTE_VEL_DIAG=1): the /// previous UpdatePosition's world position + timestamp. The per-tick @@ -3444,30 +3426,12 @@ public sealed class GameWindow : IDisposable // from ServerVelocity / ServerMoveTo which the legacy path // already handles correctly. // - // Was previously gated on ACDREAM_INTERP_MANAGER=1; the env-var - // path's per-tick TickAnimations counterpart is regressed - // (issue #40). M2 keeps the OnLivePositionUpdated half (which - // is correct) and rewrites the per-tick half — see TickAnimations. if (IsPlayerGuid(update.Guid)) { // Orientation always snaps on receipt — InterpolationManager walks // position only; heading would otherwise lag the queue. rmState.Body.Orientation = rot; - // Track the most recent GROUNDED server-broadcast Z. Read by - // the per-tick landing-fallback in TickAnimations: if gravity - // drags the body more than 0.5 m below this floor while still - // airborne, we force-land locally even when the server never - // sent an IsGrounded=true UP for the actual landing frame. - // - // Only updated for grounded UPs — mid-arc airborne UPs would - // raise this value to the player's peak Z, then the body's - // descent would cross (peak - 0.5) and trigger a force-land - // mid-air, producing the user-reported "small landing in the - // air before landing on the ground" when jumping while moving. - if (update.IsGrounded) - rmState.LastServerZ = worldPos.Z; - // Diagnostic (ACDREAM_REMOTE_VEL_DIAG=1): roll the previous // server-pos snapshot forward AND print the per-UP comparison // between the max sequencer speed observed since last UP and @@ -3643,7 +3607,6 @@ public sealed class GameWindow : IDisposable // a halved "observed" rate → visible slow-start. Formula-only // is stable and simple; hard-snap fixes any drift. rmState.Body.Orientation = rot; - rmState.TargetOrientation = rot; rmState.LastServerPos = worldPos; rmState.LastServerPosTime = nowSec; // Align the body's physics clock with our clock so update_object