feat(R1-P6): root-motion Frame seam + dead-API removal — R1 COMPLETE
- Advance(dt, Frame? rootMotionFrame) overload: retail's actual root- motion contract (CSequence::update(quantum, Frame*) 0x00525b80) — every crossed frame's pos_frame combines into the caller's Frame plus the sequence velocity/omega via apply_physics. This is the seam R6's retail per-tick order (CPartArray.Update -> adjust_offset -> Frame.combine) consumes. - DELETED: ConsumeRootMotionDelta + the dead adapter accumulator fields (zero external callers; gap-map API-migration table). - Root-motion test now asserts REAL accumulation through the wired Frame path (replaces the P5 inert-stub pin). - Phase R plan: R1 stage marked SHIPPED with its commit trail. Full suite green (3346). R1 done: P0 research/pins -> P1 node -> P2 container -> P3 physics -> P4 advance core -> P5 adapter cutover -> P6 wiring. Next: R2 (GetObjectSequence + MotionTableManager; extraction workflow already running). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
9147344a6f
commit
a987cad182
3 changed files with 46 additions and 67 deletions
|
|
@ -997,29 +997,17 @@ public sealed class AnimationSequencerTests
|
|||
Assert.Contains(hooks, h => h is SoundHook sh && (uint)sh.Id == 0x0A000005u);
|
||||
}
|
||||
|
||||
// ── PosFrames root motion (Phase E.1; retired R1-P5) ─────────────────────
|
||||
// ── PosFrames root motion (R1-P6: the wired Frame path, gap map G7) ───────
|
||||
|
||||
[Fact]
|
||||
public void ConsumeRootMotionDelta_AlwaysZero_AccumulatorUnwiredPendingP6()
|
||||
public void Advance_WithRootMotionFrame_AccumulatesPosFrameDeltas()
|
||||
{
|
||||
// R1-P5 (2026-07-02): pre-cutover, Advance's own hand-rolled
|
||||
// per-frame-crossing loop wrote _rootMotionPos/_rootMotionRot
|
||||
// directly from Animation.PosFrames (AFrame.Combine/Subtract). That
|
||||
// loop is DELETED — frame advance now runs entirely inside
|
||||
// CSequence.Update, and root motion in retail flows through
|
||||
// CSequence.apply_physics(Frame*, ...) (0x00524ab0), which needs an
|
||||
// actual target Frame passed into Update. This adapter's Advance
|
||||
// passes null (gap map G7: "R1-P6 wires it"), so PosFrames deltas
|
||||
// are computed by the core's UpdateInternal but have nowhere to
|
||||
// land — ConsumeRootMotionDelta has zero live writers post-cutover
|
||||
// (confirmed: also zero external callers pre-cutover, per the R1
|
||||
// gap map API-migration table).
|
||||
//
|
||||
// This test pins that ConsumeRootMotionDelta is a safe, inert stub
|
||||
// until P6 wires a real Frame through Advance/Update — NOT that
|
||||
// root motion doesn't work. When P6 lands, this test should be
|
||||
// replaced with one asserting real accumulation through the wired
|
||||
// Frame path.
|
||||
// R1-P6 (2026-07-02): root motion flows through retail's actual
|
||||
// contract — CSequence::update(quantum, Frame*) (0x00525b80):
|
||||
// every crossed integer frame combines the node's pos_frame into
|
||||
// the caller-supplied Frame (update_internal 0x005255d0). The old
|
||||
// adapter-side accumulator (ConsumeRootMotionDelta) is DELETED —
|
||||
// this is the seam R6's per-tick order consumes.
|
||||
const uint Style = 0x003Du;
|
||||
const uint Motion = 0x0003u;
|
||||
const uint AnimId = 0x03000110u;
|
||||
|
|
@ -1043,15 +1031,14 @@ public sealed class AnimationSequencerTests
|
|||
|
||||
var seq = new AnimationSequencer(setup, mt, loader);
|
||||
seq.SetCycle(Style, Motion);
|
||||
seq.ConsumeRootMotionDelta(); // clear
|
||||
|
||||
// Advance 0.25s → 2.5 frames → 2 crossings (0→1, 1→2). Pre-cutover
|
||||
// this would have accumulated ~2.0 on X; post-cutover it's inert.
|
||||
seq.Advance(0.25f);
|
||||
var (pos, rot) = seq.ConsumeRootMotionDelta();
|
||||
// Advance 0.25s @10fps → 2.5 frames → 2 crossings (0→1, 1→2), each
|
||||
// combining +1 X of pos_frame origin into the supplied Frame.
|
||||
var rootFrame = new Frame { Origin = Vector3.Zero, Orientation = Quaternion.Identity };
|
||||
seq.Advance(0.25f, rootFrame);
|
||||
|
||||
Assert.Equal(Vector3.Zero, pos);
|
||||
Assert.Equal(Quaternion.Identity, rot);
|
||||
Assert.True(rootFrame.Origin.X >= 1.8f && rootFrame.Origin.X <= 2.2f,
|
||||
$"Expected ~2.0 root motion X after 2 crossings via the wired Frame, got {rootFrame.Origin.X}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue