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
|
|
@ -44,6 +44,7 @@ public sealed class RemoteTeleportControllerTests
|
|||
public Vector3 LastServerPosition { get; set; }
|
||||
public double LastServerPositionTime { get; set; }
|
||||
public Vector3 LastShadowSyncPosition { get; set; }
|
||||
public Quaternion LastShadowSyncOrientation { get; set; }
|
||||
public void BindCanonicalCell(Func<uint> read, Action<uint> write)
|
||||
{
|
||||
_readCell = read;
|
||||
|
|
@ -64,6 +65,7 @@ public sealed class RemoteTeleportControllerTests
|
|||
public Vector3 LastServerPosition { get; set; }
|
||||
public double LastServerPositionTime { get; set; }
|
||||
public Vector3 LastShadowSyncPosition { get; set; }
|
||||
public Quaternion LastShadowSyncOrientation { get; set; }
|
||||
public void BindCanonicalCell(Func<uint> read, Action<uint> write) { }
|
||||
public void HitGround() { }
|
||||
public void LeaveGround() { }
|
||||
|
|
@ -921,6 +923,165 @@ public sealed class RemoteTeleportControllerTests
|
|||
Assert.Equal(1, fixture.Engine.ShadowObjects.TotalRegistered);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolverAcceptsNewerPosition_OlderPlacementReturnsSuperseded()
|
||||
{
|
||||
const uint guid = 0x70000060u;
|
||||
const uint sourceCell = 0xA9B40039u;
|
||||
const uint destinationCell = 0xAAB40001u;
|
||||
var fixture = CreateLoadedRemoteFixture(guid, sourceCell);
|
||||
Assert.True(fixture.Live.TryApplyPosition(
|
||||
PositionUpdate(guid, destinationCell, x: 1f, sequence: 2),
|
||||
isLocalPlayer: false,
|
||||
forcePositionRotation: null,
|
||||
currentLocalVelocity: null,
|
||||
out _,
|
||||
out _,
|
||||
out _));
|
||||
Assert.True(fixture.Live.RebucketLiveEntity(guid, destinationCell));
|
||||
Assert.True(fixture.Live.TryGetRecord(guid, out LiveEntityRecord record));
|
||||
ulong outerPositionAuthority = record.PositionAuthorityVersion;
|
||||
ulong outerVelocityAuthority = record.VelocityAuthorityVersion;
|
||||
Vector3 newerWorldPosition = new(195f, 10f, 50f);
|
||||
RemoteTeleportController? controller = null;
|
||||
RemoteTeleportController.Result nestedResult = default;
|
||||
bool nested = false;
|
||||
controller = new RemoteTeleportController(
|
||||
fixture.Engine,
|
||||
fixture.Live,
|
||||
(_, _) => (0.48f, 1.835f),
|
||||
CellLocal,
|
||||
(_, _, _) => { },
|
||||
(_, _, _) => { },
|
||||
(_, _) => { },
|
||||
resolvePlacement: (position, cell, _, _, _, _) =>
|
||||
{
|
||||
if (!nested)
|
||||
{
|
||||
nested = true;
|
||||
Assert.True(fixture.Live.TryApplyPosition(
|
||||
PositionUpdate(guid, destinationCell, x: 3f, sequence: 3),
|
||||
isLocalPlayer: false,
|
||||
forcePositionRotation: null,
|
||||
currentLocalVelocity: null,
|
||||
out _,
|
||||
out _,
|
||||
out _));
|
||||
Assert.True(fixture.Live.TryGetRecord(guid, out var current));
|
||||
nestedResult = controller!.TryApply(
|
||||
current,
|
||||
current.PositionAuthorityVersion,
|
||||
current.VelocityAuthorityVersion,
|
||||
fixture.Remote,
|
||||
fixture.Entity,
|
||||
newerWorldPosition,
|
||||
destinationCell,
|
||||
new Vector3(3f, 10f, 50f),
|
||||
Quaternion.Identity,
|
||||
gameTime: 6.0,
|
||||
destinationProjectionVisible: true,
|
||||
generation: 1,
|
||||
positionSequence: 3);
|
||||
}
|
||||
|
||||
return SuccessfulPlacement(position, cell);
|
||||
});
|
||||
|
||||
RemoteTeleportController.Result outerResult = controller.TryApply(
|
||||
record,
|
||||
outerPositionAuthority,
|
||||
outerVelocityAuthority,
|
||||
fixture.Remote,
|
||||
fixture.Entity,
|
||||
new Vector3(193f, 10f, 50f),
|
||||
destinationCell,
|
||||
new Vector3(1f, 10f, 50f),
|
||||
Quaternion.Identity,
|
||||
gameTime: 5.0,
|
||||
destinationProjectionVisible: true,
|
||||
generation: 1,
|
||||
positionSequence: 2);
|
||||
|
||||
Assert.True(nestedResult.Applied);
|
||||
Assert.True(nestedResult.ContactResolved);
|
||||
Assert.True(outerResult.Superseded);
|
||||
Assert.False(outerResult.Applied);
|
||||
Assert.Equal(newerWorldPosition, fixture.Remote.Body.Position);
|
||||
Assert.Equal(newerWorldPosition, fixture.Entity.Position);
|
||||
controller.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolverAcceptsIndependentState_PositionPlacementStillCommits()
|
||||
{
|
||||
const uint guid = 0x70000061u;
|
||||
const uint sourceCell = 0xA9B40039u;
|
||||
const uint destinationCell = 0xAAB40001u;
|
||||
var fixture = CreateLoadedRemoteFixture(guid, sourceCell);
|
||||
Assert.True(fixture.Live.TryApplyPosition(
|
||||
PositionUpdate(guid, destinationCell, x: 1f, sequence: 2),
|
||||
isLocalPlayer: false,
|
||||
forcePositionRotation: null,
|
||||
currentLocalVelocity: null,
|
||||
out _,
|
||||
out _,
|
||||
out _));
|
||||
Assert.True(fixture.Live.RebucketLiveEntity(guid, destinationCell));
|
||||
Assert.True(fixture.Live.TryGetRecord(guid, out LiveEntityRecord record));
|
||||
ulong positionAuthority = record.PositionAuthorityVersion;
|
||||
ulong velocityAuthority = record.VelocityAuthorityVersion;
|
||||
bool stateAccepted = false;
|
||||
using var controller = new RemoteTeleportController(
|
||||
fixture.Engine,
|
||||
fixture.Live,
|
||||
(_, _) => (0.48f, 1.835f),
|
||||
CellLocal,
|
||||
(_, _, _) => { },
|
||||
(_, _, _) => { },
|
||||
(_, _) => { },
|
||||
resolvePlacement: (position, cell, _, _, _, _) =>
|
||||
{
|
||||
if (!stateAccepted)
|
||||
{
|
||||
stateAccepted = true;
|
||||
Assert.True(fixture.Live.TryApplyState(
|
||||
new SetState.Parsed(
|
||||
guid,
|
||||
(uint)(PhysicsStateFlags.Hidden
|
||||
| PhysicsStateFlags.ReportCollisions),
|
||||
1,
|
||||
2),
|
||||
out _));
|
||||
}
|
||||
return SuccessfulPlacement(position, cell);
|
||||
});
|
||||
Vector3 destination = new(193f, 10f, 50f);
|
||||
|
||||
RemoteTeleportController.Result result = controller.TryApply(
|
||||
record,
|
||||
positionAuthority,
|
||||
velocityAuthority,
|
||||
fixture.Remote,
|
||||
fixture.Entity,
|
||||
destination,
|
||||
destinationCell,
|
||||
new Vector3(1f, 10f, 50f),
|
||||
Quaternion.Identity,
|
||||
gameTime: 5.0,
|
||||
destinationProjectionVisible: true,
|
||||
generation: 1,
|
||||
positionSequence: 2);
|
||||
|
||||
Assert.True(stateAccepted);
|
||||
Assert.True(result.Applied);
|
||||
Assert.True(result.ContactResolved);
|
||||
Assert.False(result.Superseded);
|
||||
Assert.Equal(destination, fixture.Remote.Body.Position);
|
||||
Assert.Equal(destination, fixture.Entity.Position);
|
||||
Assert.True(record.FinalPhysicsState.HasFlag(PhysicsStateFlags.Hidden));
|
||||
Assert.Equal(record.FinalPhysicsState, fixture.Remote.Body.State);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TeardownCallbackFailure_StillForgetsPendingBeforeGuidReuse()
|
||||
{
|
||||
|
|
@ -1009,6 +1170,75 @@ public sealed class RemoteTeleportControllerTests
|
|||
return engine;
|
||||
}
|
||||
|
||||
private static LoadedRemoteFixture CreateLoadedRemoteFixture(
|
||||
uint guid,
|
||||
uint sourceCell)
|
||||
{
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0xA9B4FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0xAAB4FFFFu));
|
||||
var live = new LiveEntityRuntime(spatial, new Resources());
|
||||
live.RegisterLiveEntity(Spawn(guid, sourceCell));
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
sourceCell,
|
||||
id => new WorldEntity
|
||||
{
|
||||
Id = id,
|
||||
ServerGuid = guid,
|
||||
SourceGfxObjOrSetupId = 0x02000001u,
|
||||
Position = new Vector3(191f, 10f, 50f),
|
||||
Rotation = Quaternion.Identity,
|
||||
MeshRefs = Array.Empty<MeshRef>(),
|
||||
})!;
|
||||
var remote = new GameWindow.RemoteMotion();
|
||||
remote.Body.SnapToCell(sourceCell, entity.Position, entity.Position);
|
||||
live.SetRemoteMotionRuntime(guid, remote);
|
||||
return new LoadedRemoteFixture(
|
||||
live,
|
||||
entity,
|
||||
remote,
|
||||
BuildEngine(includeDestination: true));
|
||||
}
|
||||
|
||||
private static WorldSession.EntityPositionUpdate PositionUpdate(
|
||||
uint guid,
|
||||
uint cell,
|
||||
float x,
|
||||
ushort sequence) => new(
|
||||
guid,
|
||||
new CreateObject.ServerPosition(
|
||||
cell,
|
||||
x,
|
||||
10f,
|
||||
50f,
|
||||
1f,
|
||||
0f,
|
||||
0f,
|
||||
0f),
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
1,
|
||||
sequence,
|
||||
0,
|
||||
0);
|
||||
|
||||
private static ResolveResult SuccessfulPlacement(Vector3 position, uint cell) => new(
|
||||
position,
|
||||
cell,
|
||||
IsOnGround: true,
|
||||
InContact: true,
|
||||
OnWalkable: true,
|
||||
ContactPlane: new Plane(Vector3.UnitZ, 0f),
|
||||
ContactPlaneCellId: cell);
|
||||
|
||||
private readonly record struct LoadedRemoteFixture(
|
||||
LiveEntityRuntime Live,
|
||||
WorldEntity Entity,
|
||||
GameWindow.RemoteMotion Remote,
|
||||
PhysicsEngine Engine);
|
||||
|
||||
private static void AddDestination(PhysicsEngine engine) =>
|
||||
engine.AddLandblock(
|
||||
0xAAB4FFFFu,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue