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>
80 lines
3.3 KiB
C#
80 lines
3.3 KiB
C#
using System.Numerics;
|
|
|
|
namespace AcDream.Core.Physics.Motion;
|
|
|
|
/// <summary>
|
|
/// Mutable stand-in for retail's <c>Frame</c> when it is used as the per-tick
|
|
/// <b>delta accumulator</b> that <c>PositionManager::adjust_offset</c> and its
|
|
/// three sub-managers (Interpolation / Sticky / Constraint) write into
|
|
/// (retail arg2, e.g. <c>StickyManager::adjust_offset</c> 0x00555430,
|
|
/// <c>ConstraintManager::adjust_offset</c> 0x00556180). acdream's
|
|
/// <see cref="CellFrame"/> is an immutable record — retail's per-tick math
|
|
/// mutates <c>m_fOrigin</c> in place across the interp→sticky→constraint chain
|
|
/// (each sub-manager composes on top of the previous one's write), so the
|
|
/// accumulator needs a mutable shape.
|
|
///
|
|
/// <para><see cref="Origin"/> = retail <c>m_fOrigin</c> (the accumulated
|
|
/// position delta, in the mover's LOCAL frame after
|
|
/// <c>Position::globaltolocalvec</c>). <see cref="Orientation"/> is the full
|
|
/// relative quaternion carried by retail <c>Frame</c>; the heading accessors
|
|
/// are narrow helpers for managers that explicitly call
|
|
/// <c>Frame::set_heading</c>.</para>
|
|
/// </summary>
|
|
public sealed class MotionDeltaFrame
|
|
{
|
|
/// <summary>Retail <c>m_fOrigin</c> — the accumulated per-tick position
|
|
/// delta (mover-local frame).</summary>
|
|
public Vector3 Origin;
|
|
|
|
/// <summary>Retail <c>Frame</c>'s complete relative rotation.</summary>
|
|
public Quaternion Orientation = Quaternion.Identity;
|
|
|
|
/// <summary>
|
|
/// Restore retail's identity <c>Frame</c>: zero translation and identity
|
|
/// orientation. Object ticks reuse these accumulators to avoid allocating
|
|
/// one transform per entity per render frame.
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
Origin = Vector3.Zero;
|
|
Orientation = Quaternion.Identity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retail <c>Frame::combine</c> (0x005122E0), specialized for the mutable
|
|
/// per-tick delta frame. The incoming translation is expressed in this
|
|
/// frame's local coordinates, so the current orientation rotates it before
|
|
/// addition; the incoming orientation is then post-multiplied. Translation
|
|
/// scaling is the separate <c>m_scale</c> operation performed by
|
|
/// <c>CPhysicsObj::UpdatePositionInternal</c>.
|
|
/// </summary>
|
|
public void Combine(
|
|
Vector3 localOrigin,
|
|
Quaternion localOrientation,
|
|
float originScale = 1f)
|
|
{
|
|
Origin += Vector3.Transform(localOrigin * originScale, Orientation);
|
|
Orientation = FrameOps.SetRotate(
|
|
Origin,
|
|
Orientation,
|
|
Orientation * localOrientation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compose another complete delta frame using retail
|
|
/// <c>Frame::combine</c> semantics.
|
|
/// </summary>
|
|
public void Combine(MotionDeltaFrame delta, float originScale = 1f)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(delta);
|
|
Combine(delta.Origin, delta.Orientation, originScale);
|
|
}
|
|
|
|
/// <summary>Retail <c>Frame::get_heading</c> (P5 compass degrees).</summary>
|
|
public float GetHeading() => MoveToMath.GetHeading(Orientation);
|
|
|
|
/// <summary>Retail <c>Frame::set_heading(headingDeg)</c> — pure
|
|
/// yaw-about-Z setter (P5 compass degrees).</summary>
|
|
public void SetHeading(float headingDeg) =>
|
|
Orientation = MoveToMath.SetHeading(Orientation, headingDeg);
|
|
}
|