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
|
|
@ -110,9 +110,8 @@ public readonly struct PartTransform
|
|||
/// var seq = new AnimationSequencer(setup, motionTable, dats);
|
||||
/// seq.SetCycle(style, motion, speedMod);
|
||||
/// // each frame:
|
||||
/// var transforms = seq.Advance(dt);
|
||||
/// var transforms = seq.Advance(dt, rootMotionFrame); // root motion lands in the Frame
|
||||
/// var hooks = seq.ConsumePendingHooks(); // fire audio / VFX / damage
|
||||
/// var root = seq.ConsumeRootMotionDelta(); // add to AFrame if desired
|
||||
/// </code>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
|
|
@ -223,16 +222,9 @@ public sealed class AnimationSequencer
|
|||
// AdapterHookQueue seam below); drained via ConsumePendingHooks.
|
||||
private readonly List<AnimationHook> _pendingHooks = new();
|
||||
|
||||
// Root motion (PosFrames) delta accumulated during Advance. Drained via
|
||||
// ConsumeRootMotionDelta. R1-P6 NOTE (gap map G7): the accumulation
|
||||
// sites that used to write these fields are gone with the deleted
|
||||
// legacy advance loop — root motion now flows ONLY through the core's
|
||||
// CSequence.Update(frame) path, which R1-P6 wires to an actual Frame.
|
||||
// ConsumeRootMotionDelta has zero callers today (confirmed at cutover)
|
||||
// so it's kept as a no-op-returning stub for API compatibility until
|
||||
// P6 retires or rewires it.
|
||||
private Vector3 _rootMotionPos;
|
||||
private Quaternion _rootMotionRot = Quaternion.Identity;
|
||||
// R1-P6: root motion flows through the Advance(dt, Frame) overload
|
||||
// (retail CSequence::update(Frame*), 0x00525b80) — the old adapter
|
||||
// accumulator fields are gone with ConsumeRootMotionDelta.
|
||||
|
||||
// ── Diagnostics (Commit A 2026-05-03) ───────────────────────────────────
|
||||
// Throttle clock for the [SCFAST] / [SCFULL] / [SCNULLFALLBACK] log lines
|
||||
|
|
@ -704,19 +696,35 @@ public sealed class AnimationSequencer
|
|||
/// If no animation is loaded, all parts get identity transforms.
|
||||
/// </returns>
|
||||
public IReadOnlyList<PartTransform> Advance(float dt)
|
||||
=> Advance(dt, rootMotionFrame: null);
|
||||
|
||||
/// <summary>
|
||||
/// R1-P6 (gap map G7): the root-motion overload. When
|
||||
/// <paramref name="rootMotionFrame"/> is supplied, the core's
|
||||
/// <c>update</c>/<c>update_internal</c> apply BOTH root-motion sources
|
||||
/// into it exactly as retail's <c>CPartArray::Update</c> path does —
|
||||
/// the per-crossed-frame <c>PosFrames</c> combine/subtract AND the
|
||||
/// sequence velocity/omega via <c>apply_physics</c> (0x00524ab0). This
|
||||
/// is the seam R6's retail per-tick order consumes
|
||||
/// (<c>UpdatePositionInternal → CPartArray.Update → adjust_offset →
|
||||
/// Frame.combine</c>).
|
||||
/// </summary>
|
||||
public IReadOnlyList<PartTransform> Advance(float dt, Frame? rootMotionFrame)
|
||||
{
|
||||
int partCount = _setup.Parts.Count;
|
||||
|
||||
if (_core.CurrAnim == null || dt <= 0f)
|
||||
if (_core.CurrAnim == null && rootMotionFrame is null)
|
||||
return BuildIdentityFrame(partCount);
|
||||
if (dt <= 0f)
|
||||
return _core.CurrAnim == null
|
||||
? BuildIdentityFrame(partCount)
|
||||
: BuildBlendedFrame();
|
||||
|
||||
// R1-P6 wires a real Frame* through here for root-motion output
|
||||
// (gap map G7). Until then, pass null — the core still advances
|
||||
// frame_number, fires hooks, and steps nodes; it just skips the
|
||||
// apply_physics/pos-frame combine calls that need a target Frame.
|
||||
_core.Update(dt, null);
|
||||
_core.Update(dt, rootMotionFrame);
|
||||
|
||||
return BuildBlendedFrame();
|
||||
return _core.CurrAnim == null
|
||||
? BuildIdentityFrame(partCount)
|
||||
: BuildBlendedFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -734,24 +742,10 @@ public sealed class AnimationSequencer
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve and clear the root-motion displacement accumulated from
|
||||
/// <see cref="Animation.PosFrames"/> during the last <see cref="Advance"/>
|
||||
/// calls. Returns (Zero, Identity) — see the R1-P5 note on
|
||||
/// <see cref="_rootMotionPos"/>: this accumulator has zero live writers
|
||||
/// after the cutover (root motion now flows only through
|
||||
/// <see cref="CSequence.Update"/>'s Frame* argument, unwired until P6;
|
||||
/// gap map G7). Kept for API compatibility; P6 either wires a real
|
||||
/// accumulation path or deletes this method (it already has zero
|
||||
/// external callers).
|
||||
/// </summary>
|
||||
public (Vector3 Position, Quaternion Rotation) ConsumeRootMotionDelta()
|
||||
{
|
||||
var result = (_rootMotionPos, _rootMotionRot);
|
||||
_rootMotionPos = Vector3.Zero;
|
||||
_rootMotionRot = Quaternion.Identity;
|
||||
return result;
|
||||
}
|
||||
// R1-P6: ConsumeRootMotionDelta DELETED (zero external callers; gap map
|
||||
// API-migration table). Root motion flows through the
|
||||
// Advance(dt, Frame) overload — retail's CSequence::update(Frame*)
|
||||
// contract — for R6's per-tick wiring.
|
||||
|
||||
/// <summary>
|
||||
/// Play a one-shot action/modifier motion (Jump, emote, attack, etc.)
|
||||
|
|
@ -895,8 +889,6 @@ public sealed class AnimationSequencer
|
|||
{
|
||||
_core.Clear();
|
||||
_pendingHooks.Clear();
|
||||
_rootMotionPos = Vector3.Zero;
|
||||
_rootMotionRot = Quaternion.Identity;
|
||||
CurrentStyle = 0;
|
||||
CurrentMotion = 0;
|
||||
CurrentSpeedMod = 1f;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue