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
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.Physics.Motion;
|
||||
using Xunit;
|
||||
|
||||
namespace AcDream.Core.Tests.Physics;
|
||||
|
|
@ -27,6 +28,164 @@ public sealed class InterpolationManagerTests
|
|||
|
||||
private static InterpolationManager Make() => new InterpolationManager();
|
||||
|
||||
[Fact]
|
||||
public void AdjustOffset_CompleteFrame_ReplacesOriginAndNonCommutingOrientation()
|
||||
{
|
||||
var manager = Make();
|
||||
Quaternion current = Quaternion.CreateFromAxisAngle(Vector3.UnitX, 1.1f);
|
||||
Quaternion target = Quaternion.CreateFromAxisAngle(Vector3.UnitY, -0.9f);
|
||||
manager.Enqueue(
|
||||
new Vector3(10f, 0f, 0f),
|
||||
target,
|
||||
isMovingTo: false,
|
||||
currentBodyPosition: Vector3.Zero);
|
||||
var offset = new MotionDeltaFrame
|
||||
{
|
||||
Origin = new Vector3(7f, 8f, 9f),
|
||||
Orientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, 0.4f),
|
||||
};
|
||||
|
||||
bool overwritten = manager.AdjustOffset(
|
||||
dt: 0.1,
|
||||
currentBodyPosition: Vector3.Zero,
|
||||
currentBodyOrientation: current,
|
||||
maxSpeedFromMinterp: 4f,
|
||||
offset);
|
||||
|
||||
Assert.True(overwritten);
|
||||
Vector3 expectedLocalOrigin = MoveToMath.GlobalToLocalVec(
|
||||
current,
|
||||
new Vector3(0.8f, 0f, 0f));
|
||||
Assert.Equal(expectedLocalOrigin.X, offset.Origin.X, 5);
|
||||
Assert.Equal(expectedLocalOrigin.Y, offset.Origin.Y, 5);
|
||||
Assert.Equal(expectedLocalOrigin.Z, offset.Origin.Z, 5);
|
||||
Quaternion expectedOrientation = Quaternion.Normalize(
|
||||
Quaternion.Inverse(current) * target);
|
||||
Assert.InRange(
|
||||
MathF.Abs(Quaternion.Dot(
|
||||
expectedOrientation,
|
||||
Quaternion.Normalize(offset.Orientation))),
|
||||
0.99999f,
|
||||
1.00001f);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdjustOffset_MoveToNode_KeepsCurrentHeading()
|
||||
{
|
||||
var manager = Make();
|
||||
manager.Enqueue(
|
||||
new Vector3(10f, 0f, 0f),
|
||||
Quaternion.CreateFromAxisAngle(Vector3.UnitY, -0.9f),
|
||||
isMovingTo: true,
|
||||
currentBodyPosition: Vector3.Zero);
|
||||
var offset = new MotionDeltaFrame
|
||||
{
|
||||
Orientation = Quaternion.CreateFromAxisAngle(Vector3.UnitX, 0.6f),
|
||||
};
|
||||
|
||||
Assert.True(manager.AdjustOffset(
|
||||
0.1,
|
||||
Vector3.Zero,
|
||||
Quaternion.CreateFromAxisAngle(Vector3.UnitZ, 0.2f),
|
||||
4f,
|
||||
offset));
|
||||
|
||||
Assert.Equal(Quaternion.Identity, offset.Orientation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdjustOffset_UsesManagerWideLatestKeepHeadingFlag()
|
||||
{
|
||||
var manager = Make();
|
||||
Quaternion current = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, 0.2f);
|
||||
manager.Enqueue(
|
||||
new Vector3(10f, 0f, 0f),
|
||||
Quaternion.CreateFromAxisAngle(Vector3.UnitY, 0.7f),
|
||||
isMovingTo: false,
|
||||
currentBodyPosition: Vector3.Zero,
|
||||
currentBodyOrientation: current);
|
||||
manager.Enqueue(
|
||||
new Vector3(20f, 0f, 0f),
|
||||
Quaternion.CreateFromAxisAngle(Vector3.UnitX, -0.6f),
|
||||
isMovingTo: true,
|
||||
currentBodyPosition: Vector3.Zero,
|
||||
currentBodyOrientation: current);
|
||||
var offset = new MotionDeltaFrame();
|
||||
|
||||
Assert.True(manager.AdjustOffset(
|
||||
0.1,
|
||||
Vector3.Zero,
|
||||
current,
|
||||
4f,
|
||||
offset));
|
||||
|
||||
// keep_heading is an InterpolationManager field in retail, not a
|
||||
// property of each queued node. The latest near enqueue therefore
|
||||
// controls the current head as well.
|
||||
Assert.Equal(Quaternion.Identity, offset.Orientation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdjustOffset_WithoutContact_LeavesFrameAndQueueUntouched()
|
||||
{
|
||||
var manager = Make();
|
||||
manager.Enqueue(
|
||||
FarTarget,
|
||||
Quaternion.CreateFromAxisAngle(Vector3.UnitY, 0.7f),
|
||||
isMovingTo: false,
|
||||
currentBodyPosition: BodyOrigin);
|
||||
var offset = new MotionDeltaFrame
|
||||
{
|
||||
Origin = new Vector3(1f, 2f, 3f),
|
||||
Orientation = Quaternion.CreateFromAxisAngle(Vector3.UnitX, 0.4f),
|
||||
};
|
||||
Vector3 originalOrigin = offset.Origin;
|
||||
Quaternion originalOrientation = offset.Orientation;
|
||||
|
||||
bool overwritten = manager.AdjustOffset(
|
||||
0.1,
|
||||
BodyOrigin,
|
||||
Quaternion.Identity,
|
||||
4f,
|
||||
offset,
|
||||
inContact: false);
|
||||
|
||||
Assert.False(overwritten);
|
||||
Assert.Equal(originalOrigin, offset.Origin);
|
||||
Assert.Equal(originalOrientation, offset.Orientation);
|
||||
Assert.True(manager.IsActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Enqueue_AlreadyClose_InstallsOnlyTargetHeading()
|
||||
{
|
||||
var manager = Make();
|
||||
Quaternion target = Quaternion.Normalize(
|
||||
Quaternion.CreateFromAxisAngle(Vector3.UnitX, 0.8f)
|
||||
* Quaternion.CreateFromAxisAngle(Vector3.UnitZ, -0.6f));
|
||||
|
||||
Quaternion? immediate = manager.Enqueue(
|
||||
new Vector3(0.01f, 0f, 0f),
|
||||
target,
|
||||
isMovingTo: false,
|
||||
currentBodyPosition: Vector3.Zero);
|
||||
|
||||
Assert.NotNull(immediate);
|
||||
Quaternion expected = MoveToMath.SetHeading(
|
||||
target,
|
||||
MoveToMath.GetHeading(target));
|
||||
Assert.InRange(
|
||||
MathF.Abs(Quaternion.Dot(
|
||||
Quaternion.Normalize(expected),
|
||||
Quaternion.Normalize(immediate!.Value))),
|
||||
0.99999f,
|
||||
1.00001f);
|
||||
Assert.True(MathF.Abs(Quaternion.Dot(
|
||||
Quaternion.Normalize(target),
|
||||
Quaternion.Normalize(immediate.Value))) < 0.999f);
|
||||
Assert.False(manager.IsActive);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Queue mechanics
|
||||
// =========================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue