feat(physics): port retail complete object frame pipeline
Restore the named-retail object update order across local, remote, static, projectile, animation, shadow, teleport, and effect lifetimes. Separate authoritative root commits from spatial rebucketing, preserve per-owner hook/FIFO ordering, and remove update-path allocations with exact lifecycle and residency gates. Add deterministic conformance, adversarial lifetime, GUID-reuse, pending-cell, quaternion, timestamp, and allocation coverage. Release build is warning-free and all 6,446 tests pass with five intentional skips; retail, architecture, and adversarial reviews are clean. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
31a0889f08
commit
f961d70023
77 changed files with 12513 additions and 1871 deletions
|
|
@ -142,15 +142,16 @@ public sealed class AnimationSequencer
|
|||
/// <para>
|
||||
/// Crucially this is **not** per-node: while a link animation plays, the
|
||||
/// surfaced velocity is still the cycle's velocity (the cycle was added
|
||||
/// last, so SetVelocity's latest call wins). Remote entity dead-reckoning
|
||||
/// reads this to integrate position without gapping during stance
|
||||
/// transitions.
|
||||
/// last, so SetVelocity's latest call wins). <c>CSequence::apply_physics</c>
|
||||
/// contributes it directly to the complete root Frame; no separate body-
|
||||
/// velocity reconstruction is performed from this accessor.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public Vector3 CurrentVelocity => _core.Velocity;
|
||||
|
||||
/// <summary>
|
||||
/// Sequence-wide omega, matching <see cref="CurrentVelocity"/>'s semantics.
|
||||
/// Sequence-wide omega. <c>CSequence::apply_physics</c> rotates the same
|
||||
/// complete root Frame that carries PosFrames and sequence velocity.
|
||||
/// </summary>
|
||||
public Vector3 CurrentOmega => _core.Omega;
|
||||
|
||||
|
|
@ -283,6 +284,12 @@ public sealed class AnimationSequencer
|
|||
_table = new CMotionTable(motionTable);
|
||||
_state = new MotionState();
|
||||
_manager = new MotionTableManager(_table, _state, _core, new ForwardingMotionDoneSink(this));
|
||||
|
||||
// CPartArray::InitDefaults (0x00518980) runs for every setup-backed
|
||||
// PartArray, before CPhysicsObj::InitDefaults installs its motion
|
||||
// table. Static is only a later workset-membership decision; it does
|
||||
// not gate installation of Setup.DefaultAnimation itself.
|
||||
InitializeSetupDefaultAnimation((uint)setup.DefaultAnimation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -399,38 +406,9 @@ public sealed class AnimationSequencer
|
|||
if (dispatchResult != MotionTableManagerError.Success)
|
||||
return;
|
||||
|
||||
// ── Synthesize CurrentOmega for turn cycles ───────────────────────
|
||||
// Humanoid turn MotionData often ships without HasOmega. Until the
|
||||
// remaining R6 rotation path consumes CSequence's complete Frame
|
||||
// orientation, the remote ObservedOmega seam needs the retail
|
||||
// turn-rate fallback. Decompile references:
|
||||
// FUN_00529210 apply_current_movement (writes Omega)
|
||||
// chunk_00520000.c TurnRate globals (~π/2 rad/s for speed=1)
|
||||
// The ACE port uses `omega.z = ±(π/2) × turnSpeed` for right/left
|
||||
// turns (holtburger confirms the same via motion_resolution.rs).
|
||||
if (_core.Omega.LengthSquared() < 1e-9f)
|
||||
{
|
||||
float zomega = 0f;
|
||||
uint low = motion & 0xFFu;
|
||||
switch (low)
|
||||
{
|
||||
case 0x0D: // TurnRight — clockwise from above = -Z in right-handed.
|
||||
zomega = -(MathF.PI / 2f) * adjustedSpeed;
|
||||
break;
|
||||
case 0x0E: // TurnLeft — counter-clockwise = +Z.
|
||||
// adjust_motion above ALREADY remapped 0x0E → 0x0D
|
||||
// with adjustedSpeed = -speedMod, so the same
|
||||
// formula as 0x0D applied to the negated speed
|
||||
// produces the correct +Z (CCW) result. Using a
|
||||
// different sign here would double-negate and
|
||||
// animate a left turn as a right turn — that was
|
||||
// the bug observed before this fix (commit follows).
|
||||
zomega = -(MathF.PI / 2f) * adjustedSpeed;
|
||||
break;
|
||||
}
|
||||
if (zomega != 0f)
|
||||
_core.SetOmega(new Vector3(0f, 0f, zomega));
|
||||
}
|
||||
// Rotation stays DAT-authored. Retail MotionData::add_motion
|
||||
// (0x005224B0) contributes the entry's literal omega to CSequence;
|
||||
// CSequence::apply_physics emits it through the complete Frame.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -453,6 +431,36 @@ public sealed class AnimationSequencer
|
|||
/// </summary>
|
||||
public void InitializeState() => EnsureInitialized();
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>CPartArray::InitDefaults</c> (0x00518980): a Setup
|
||||
/// <c>DefaultAnimation</c> bypasses the MotionTable, clears the sequence,
|
||||
/// and appends one direct animation over frames <c>0..-1</c> at 30 fps.
|
||||
/// Installation is unconditional for every setup-backed PartArray.
|
||||
/// <c>CPhysicsObj::InitDefaults</c> separately decides whether a Static
|
||||
/// owner enters <c>CPhysics::static_animating_objects</c>; ordinary motion
|
||||
/// table initialization may subsequently replace this direct sequence.
|
||||
/// </summary>
|
||||
public bool InitializeSetupDefaultAnimation(uint animationId)
|
||||
{
|
||||
if (animationId == 0)
|
||||
return false;
|
||||
|
||||
// CPartArray::InitDefaults (0x00518980) calls only
|
||||
// CSequence::clear_animations (0x00524DC0). Sequence velocity,
|
||||
// omega, and placement state belong to the surrounding PartArray
|
||||
// lifetime and survive replacement of the animation list.
|
||||
_core.ClearAnimations();
|
||||
_pendingHooks.Clear();
|
||||
_core.AppendAnimation(new AnimData
|
||||
{
|
||||
AnimId = (QualifiedDataId<Animation>)animationId,
|
||||
LowFrame = 0,
|
||||
HighFrame = -1,
|
||||
Framerate = 30f,
|
||||
});
|
||||
return _core.CurrAnim is not null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// R2-Q5: the single dispatch entry — lazy initialize_state, then
|
||||
/// <see cref="MotionTableManager.PerformMovement"/>. The resulting
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue