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:
Erik 2026-07-20 09:10:31 +02:00
parent 31a0889f08
commit f961d70023
77 changed files with 12513 additions and 1871 deletions

View file

@ -25,6 +25,48 @@ public static class FrameOps
/// square against |v|².</summary>
public const float FEpsilon = 0.000199999995f;
/// <summary>
/// Retail <c>Frame::set_rotate</c> (0x00535080). The candidate is
/// normalized in extended precision, then the complete frame is checked
/// by <c>Frame::IsValid</c> (0x00534ED0). If that check fails, retail
/// restores the previous quaternion instead of allowing NaNs to poison
/// the live object transform.
/// </summary>
public static Quaternion SetRotate(
Vector3 frameOrigin,
Quaternion previous,
Quaternion candidate)
{
double lengthSquared =
((double)candidate.W * candidate.W)
+ ((double)candidate.X * candidate.X)
+ ((double)candidate.Y * candidate.Y)
+ ((double)candidate.Z * candidate.Z);
double inverseLength = 1.0 / Math.Sqrt(lengthSquared);
var normalized = new Quaternion(
(float)(candidate.X * inverseLength),
(float)(candidate.Y * inverseLength),
(float)(candidate.Z * inverseLength),
(float)(candidate.W * inverseLength));
if (float.IsNaN(frameOrigin.X)
|| float.IsNaN(frameOrigin.Y)
|| float.IsNaN(frameOrigin.Z)
|| float.IsNaN(normalized.W)
|| float.IsNaN(normalized.X)
|| float.IsNaN(normalized.Y)
|| float.IsNaN(normalized.Z))
{
return previous;
}
float normalizedLengthSquared = normalized.LengthSquared();
return !float.IsNaN(normalizedLengthSquared)
&& MathF.Abs(normalizedLengthSquared - 1f) < FEpsilon * 5f
? normalized
: previous;
}
/// <summary><c>Frame::grotate</c> — incremental WORLD-space rotation.</summary>
public static void GRotate(Frame frame, Vector3 rotationGlobal)
{
@ -48,7 +90,10 @@ public static class FrameOps
rotationGlobal.Y * s * invMag,
rotationGlobal.Z * s * invMag,
c);
frame.Orientation = Quaternion.Normalize(Quaternion.Multiply(r, frame.Orientation));
frame.Orientation = SetRotate(
frame.Origin,
frame.Orientation,
Quaternion.Multiply(r, frame.Orientation));
}
/// <summary><c>Frame::rotate</c> — LOCAL rotation vector, mapped to
@ -65,7 +110,10 @@ public static class FrameOps
public static void Combine(Frame frame, Frame pos)
{
frame.Origin += Vector3.Transform(pos.Origin, frame.Orientation);
frame.Orientation = Quaternion.Normalize(frame.Orientation * pos.Orientation);
frame.Orientation = SetRotate(
frame.Origin,
frame.Orientation,
frame.Orientation * pos.Orientation);
}
/// <summary>
@ -75,7 +123,9 @@ public static class FrameOps
/// </summary>
public static void Subtract1(Frame frame, Frame pos)
{
frame.Orientation = Quaternion.Normalize(
frame.Orientation = SetRotate(
frame.Origin,
frame.Orientation,
frame.Orientation * Quaternion.Conjugate(pos.Orientation));
frame.Origin -= Vector3.Transform(pos.Origin, frame.Orientation);
}