feat(motion): L.3 M1 — fresh InterpolationManager port + retail spec
Rewrites src/AcDream.Core/Physics/InterpolationManager.cs from the spec in docs/research/2026-05-04-l3-port/04-interp-manager.md. Public API preserved (Vector3-returning AdjustOffset, Enqueue, Clear, IsActive, Count) so PositionManager + GameWindow callers continue to compile; internals are full retail spec. Bug fixes vs prior port (audit 04-interp-manager.md § 7): #1 progress_quantum accumulates dt (sum of frame deltas), not step magnitude. Retail line 353140; the prior port's `+= step` made the secondary stall ratio meaningless. #3 Far-branch Enqueue (dist > AutonomyBlipDistance = 100m) sets _failCount = StallFailCountThreshold + 1 = 4, so the next AdjustOffset call's post-stall check fires an immediate blip-to- tail snap. Retail line 352944. Prior port silently drifted toward far targets at catch-up speed instead of teleporting. #4 Secondary stall test ports the retail formula verbatim: cumulative / progress_quantum / dt < CREATURE_FAILED_INTERPOLATION_PERCENTAGE. Audit notes the units are 1/sec (likely Turbine bug or x87 FPU misread by Binary Ninja) — mirrored byte-for-byte regardless. #5 Tail-prune is a tail-walking loop, not a single-tail compare. Multiple consecutive stale tail entries within DesiredDistance (0.05 m) of the new target collapse together. Retail line 352977. #6 Cap-eviction at the HEAD when count reaches 20 (already correct in the prior port; verified). New API: Enqueue gains an optional `currentBodyPosition` parameter so the far-branch detection can reference the body when the queue is empty. Backward-compatible (default null = pre-far-branch behavior). UseTime collapsed into AdjustOffset's tail (post-stall blip check) since acdream has no per-tick UseTime call separate from adjust_offset; identical semantic outcome. State fields renamed to retail names with sentinel values: _frameCounter, _progressQuantum, _originalDistance (init = 999999f sentinel per retail line 0x00555D30 ctor), _failCount. Tests: - 17/17 InterpolationManagerTests green. - New test Enqueue_FarBranch_PrearmsImmediateBlipOnNextAdjustOffset pins the bug #3 fix: enqueueing 150 m away triggers a same-tick blip (delta length ≈ 150 m), and the queue clears. Spec tree: 17 research docs (00–14) under docs/research/2026-05-04-l3-port/. 00-master-plan + 00-port-plan describe the 8-phase rollout. 01-per-tick, 03-up-routing, 04-interp-manager, 05-position-manager-and-partarray, 06-acdream-audit, 14-local-player-audit are the L.3 spec used by this commit and the M2 follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a3f53c2644
commit
de129bc164
18 changed files with 10721 additions and 190 deletions
|
|
@ -360,6 +360,52 @@ public sealed class InterpolationManagerTests
|
|||
"First stall window must NOT trigger a blip (would require > 3 consecutive failures).");
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Far-branch enqueue: when the new target is beyond AutonomyBlipDistance
|
||||
// (100 m outdoor) of the reference (tail or body), retail
|
||||
// InterpolationManager::InterpolateTo (acclient @ 0x00555B20 line 352944)
|
||||
// sets node_fail_counter = 4 so the very next stall-check blips to the
|
||||
// tail. Audit 04-interp-manager.md § 7 gap #3.
|
||||
//
|
||||
// Effect: the body teleports to the freshly-enqueued tail on the first
|
||||
// adjust_offset call after a far enqueue, instead of drifting toward it
|
||||
// at catch-up speed. Critical for >100 m server-side teleports / cell
|
||||
// crossings on observed remotes.
|
||||
// =========================================================================
|
||||
|
||||
[Fact]
|
||||
public void Enqueue_FarBranch_PrearmsImmediateBlipOnNextAdjustOffset()
|
||||
{
|
||||
var mgr = Make();
|
||||
// Target > AutonomyBlipDistance (100 m) from origin → far branch.
|
||||
var farTarget = new Vector3(150f, 0f, 0f);
|
||||
|
||||
mgr.Enqueue(farTarget, heading: 0f, isMovingTo: true, currentBodyPosition: BodyOrigin);
|
||||
|
||||
// Single AdjustOffset call: body still at origin, queue has 1 node,
|
||||
// node_fail_counter = 4 (set by far-branch enqueue) > 3 threshold,
|
||||
// so the very first stall-check fires a blip to the tail.
|
||||
//
|
||||
// The blip delta should be the full far distance (≈150 m), not a
|
||||
// single per-frame catch-up step.
|
||||
Vector3? blipDelta = null;
|
||||
for (int i = 0; i < InterpolationManager.StallCheckFrameInterval; i++)
|
||||
{
|
||||
var delta = mgr.AdjustOffset(dt: 0.016, currentBodyPosition: BodyOrigin, maxSpeedFromMinterp: 4f);
|
||||
// Blip fires when delta >> per-frame step. Per-frame step at
|
||||
// 4 m/s × 2 (mod) × 0.016 s = 0.128 m. Blip is 150 m.
|
||||
if (delta.Length() > 50f)
|
||||
{
|
||||
blipDelta = delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.NotNull(blipDelta);
|
||||
Assert.Equal(150f, blipDelta!.Value.X, precision: 4);
|
||||
Assert.False(mgr.IsActive, "Queue must be cleared after blip.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdjustOffset_DtZeroOrNegative_ReturnsZero()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue