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

@ -164,6 +164,113 @@ public sealed class LiveEntityPresentationControllerTests
Assert.Equal([fixture.Entity.Id], fixture.PartArrayEnterWorld);
}
[Fact]
public void StateAcceptedDuringHiddenEffect_DrainsAfterCompleteHiddenTail()
{
Fixture fixture = new(PhysicsStateFlags.ReportCollisions);
Assert.True(fixture.Controller.OnLiveEntityReady(Fixture.Guid));
bool nestedAccepted = false;
fixture.OnTypedPlay = type =>
{
if (type != LiveEntityPresentationController.HiddenScriptType
|| nestedAccepted)
{
return;
}
nestedAccepted = true;
Assert.True(fixture.Runtime.TryApplyState(
new SetState.Parsed(
Fixture.Guid,
(uint)PhysicsStateFlags.ReportCollisions,
1,
3),
out _));
Assert.True(fixture.Controller.OnStateAccepted(Fixture.Guid));
};
Assert.True(fixture.Runtime.TryApplyState(
new SetState.Parsed(
Fixture.Guid,
(uint)(PhysicsStateFlags.Hidden
| PhysicsStateFlags.ReportCollisions),
1,
2),
out _));
Assert.True(fixture.Controller.OnStateAccepted(Fixture.Guid));
Assert.True(nestedAccepted);
Assert.Equal(
[
"effect:76", "children:True", "part-array", "target",
"effect:75", "children:False", "part-array",
],
fixture.PresentationOrder);
Assert.True(fixture.Entity.IsDrawVisible);
Assert.Equal(1, fixture.Shadows.TotalRegistered);
}
[Fact]
public void DeleteAndGuidReuseDuringHiddenEffect_StopsOldTransitionTail()
{
Fixture fixture = new(PhysicsStateFlags.ReportCollisions);
Assert.True(fixture.Controller.OnLiveEntityReady(Fixture.Guid));
Assert.True(fixture.Runtime.TryGetRecord(
Fixture.Guid,
out LiveEntityRecord oldRecord));
WorldEntity? replacement = null;
fixture.OnTypedPlay = type =>
{
if (type != LiveEntityPresentationController.HiddenScriptType
|| replacement is not null)
{
return;
}
fixture.Controller.Forget(oldRecord);
fixture.Shadows.Deregister(fixture.Entity.Id);
Assert.True(fixture.Runtime.UnregisterLiveEntity(
new DeleteObject.Parsed(Fixture.Guid, 1),
isLocalPlayer: false));
fixture.Runtime.RegisterLiveEntity(Fixture.Spawn(
PhysicsStateFlags.ReportCollisions,
instanceSequence: 2));
replacement = fixture.Runtime.MaterializeLiveEntity(
Fixture.Guid,
0x01010001u,
id => new WorldEntity
{
Id = id,
ServerGuid = Fixture.Guid,
SourceGfxObjOrSetupId = 0x02000001u,
Position = new Vector3(20f, 20f, 5f),
Rotation = Quaternion.Identity,
MeshRefs = Array.Empty<MeshRef>(),
});
Assert.NotNull(replacement);
Assert.True(fixture.Controller.OnLiveEntityReady(Fixture.Guid));
};
Assert.True(fixture.Runtime.TryApplyState(
new SetState.Parsed(
Fixture.Guid,
(uint)(PhysicsStateFlags.Hidden
| PhysicsStateFlags.ReportCollisions),
1,
2),
out _));
Assert.False(fixture.Controller.OnStateAccepted(Fixture.Guid));
Assert.NotNull(replacement);
Assert.Equal(["effect:76"], fixture.PresentationOrder);
Assert.Empty(fixture.ChildNoDraw);
Assert.Empty(fixture.PartArrayEnterWorld);
Assert.Empty(fixture.InvalidTargets);
Assert.True(fixture.Runtime.TryGetRecord(Fixture.Guid, out var current));
Assert.Same(replacement, current.WorldEntity);
Assert.NotSame(oldRecord, current);
}
[Fact]
public void UnHideWhileLandblockPending_RestoresShadowWhenProjectionReturns()
{
@ -200,6 +307,285 @@ public sealed class LiveEntityPresentationControllerTests
Assert.Equal(1, fixture.Shadows.TotalRegistered);
}
[Fact]
public void VisibleOrdinaryProjectionPending_SuspendsAndHydrationRestoresShadow()
{
Fixture fixture = new(PhysicsStateFlags.ReportCollisions);
Assert.True(fixture.Controller.OnLiveEntityReady(Fixture.Guid));
Assert.Equal(1, fixture.Shadows.TotalRegistered);
Assert.True(fixture.Runtime.RebucketLiveEntity(
Fixture.Guid,
0x02020001u));
Assert.False(fixture.Runtime.WorldEntities.ContainsKey(Fixture.Guid));
Assert.Equal(0, fixture.Shadows.TotalRegistered);
Assert.Equal(1, fixture.Shadows.RetainedRegistrationCount);
Assert.Equal(1, fixture.Shadows.SuspendedRegistrationCount);
Assert.True(fixture.Controller.HasDeferredShadowRestore(Fixture.Guid));
fixture.Spatial.AddLandblock(new LoadedLandblock(
0x0202FFFFu,
new LandBlock(),
Array.Empty<WorldEntity>()));
Assert.Same(
fixture.Entity,
Assert.Single(fixture.Runtime.WorldEntities).Value);
Assert.Equal(1, fixture.Shadows.TotalRegistered);
Assert.Equal(0, fixture.Shadows.SuspendedRegistrationCount);
Assert.False(fixture.Controller.HasDeferredShadowRestore(Fixture.Guid));
}
[Fact]
public void PendingVisibilityCallback_GuidReuseCannotRestoreOldShadowOwner()
{
Fixture fixture = new(PhysicsStateFlags.ReportCollisions);
Assert.True(fixture.Controller.OnLiveEntityReady(Fixture.Guid));
Assert.True(fixture.Runtime.TryGetRecord(
Fixture.Guid,
out LiveEntityRecord oldRecord));
WorldEntity oldEntity = fixture.Entity;
WorldEntity? replacement = null;
fixture.Runtime.ProjectionVisibilityChanged += (record, visible) =>
{
if (visible
|| replacement is not null
|| !ReferenceEquals(record, oldRecord))
{
return;
}
fixture.Controller.Forget(oldRecord);
fixture.Shadows.Deregister(oldEntity.Id);
Assert.True(fixture.Runtime.UnregisterLiveEntity(
new DeleteObject.Parsed(Fixture.Guid, 1),
isLocalPlayer: false));
fixture.Runtime.RegisterLiveEntity(Fixture.Spawn(
PhysicsStateFlags.ReportCollisions,
instanceSequence: 2));
replacement = fixture.Runtime.MaterializeLiveEntity(
Fixture.Guid,
0x01010001u,
id => new WorldEntity
{
Id = id,
ServerGuid = Fixture.Guid,
SourceGfxObjOrSetupId = 0x02000001u,
Position = new Vector3(20f, 20f, 5f),
Rotation = Quaternion.Identity,
MeshRefs = Array.Empty<MeshRef>(),
});
Assert.NotNull(replacement);
fixture.Shadows.Register(
replacement.Id,
0x01000001u,
replacement.Position,
replacement.Rotation,
1f,
0f,
0f,
0x01010000u,
state: (uint)PhysicsStateFlags.ReportCollisions,
seedCellId: 0x01010001u);
Assert.True(fixture.Controller.OnLiveEntityReady(Fixture.Guid));
};
Assert.False(fixture.Runtime.RebucketLiveEntity(
Fixture.Guid,
0x02020001u));
Assert.NotNull(replacement);
Assert.True(fixture.Runtime.TryGetRecord(Fixture.Guid, out var current));
Assert.NotSame(oldRecord, current);
Assert.Same(replacement, current.WorldEntity);
Assert.Equal(1, fixture.Shadows.TotalRegistered);
Assert.Equal(1, fixture.Shadows.RetainedRegistrationCount);
Assert.Equal(0, fixture.Shadows.SuspendedRegistrationCount);
Assert.Contains(
fixture.Shadows.AllEntriesForDebug(),
entry => entry.EntityId == replacement.Id);
Assert.DoesNotContain(
fixture.Shadows.AllEntriesForDebug(),
entry => entry.EntityId == oldEntity.Id);
Assert.False(fixture.Controller.HasDeferredShadowRestore(Fixture.Guid));
}
[Fact]
public void InitialPendingProjection_ReadyBarrierSuspendsAndHydrationRestoresShadow()
{
const uint pendingCell = 0x02020001u;
var spatial = new GpuWorldState();
var shadows = new ShadowObjectRegistry();
var runtime = new LiveEntityRuntime(
spatial,
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
runtime.RegisterLiveEntity(Fixture.Spawn(
PhysicsStateFlags.ReportCollisions));
WorldEntity entity = Assert.IsType<WorldEntity>(
runtime.MaterializeLiveEntity(
Fixture.Guid,
pendingCell,
id => new WorldEntity
{
Id = id,
ServerGuid = Fixture.Guid,
SourceGfxObjOrSetupId = 0x02000001u,
Position = new Vector3(10f, 10f, 5f),
Rotation = Quaternion.Identity,
MeshRefs = Array.Empty<MeshRef>(),
ParentCellId = pendingCell,
}));
shadows.Register(
entity.Id,
0x01000001u,
entity.Position,
entity.Rotation,
1f,
0f,
0f,
0x02020000u,
state: (uint)PhysicsStateFlags.ReportCollisions,
seedCellId: pendingCell);
using var controller = new LiveEntityPresentationController(
runtime,
shadows,
(_, _, _) => true,
liveCenter: () => (2, 2));
Assert.True(controller.OnLiveEntityReady(Fixture.Guid));
Assert.Equal(0, shadows.TotalRegistered);
Assert.Equal(1, shadows.RetainedRegistrationCount);
Assert.Equal(1, shadows.SuspendedRegistrationCount);
Assert.True(controller.HasDeferredShadowRestore(Fixture.Guid));
spatial.AddLandblock(new LoadedLandblock(
0x0202FFFFu,
new LandBlock(),
Array.Empty<WorldEntity>()));
Assert.Same(entity, Assert.Single(runtime.WorldEntities).Value);
Assert.Equal(1, shadows.TotalRegistered);
Assert.Equal(0, shadows.SuspendedRegistrationCount);
Assert.False(controller.HasDeferredShadowRestore(Fixture.Guid));
}
[Fact]
public void InitialPendingHydrationCallback_GuidReuseCannotRestoreOldShadow()
{
const uint pendingCell = 0x02020001u;
var spatial = new GpuWorldState();
var shadows = new ShadowObjectRegistry();
var runtime = new LiveEntityRuntime(
spatial,
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
runtime.RegisterLiveEntity(Fixture.Spawn(
PhysicsStateFlags.ReportCollisions));
WorldEntity oldEntity = Assert.IsType<WorldEntity>(
runtime.MaterializeLiveEntity(
Fixture.Guid,
pendingCell,
id => new WorldEntity
{
Id = id,
ServerGuid = Fixture.Guid,
SourceGfxObjOrSetupId = 0x02000001u,
Position = new Vector3(10f, 10f, 5f),
Rotation = Quaternion.Identity,
MeshRefs = Array.Empty<MeshRef>(),
ParentCellId = pendingCell,
}));
Assert.True(runtime.TryGetRecord(Fixture.Guid, out LiveEntityRecord oldRecord));
shadows.Register(
oldEntity.Id,
0x01000001u,
oldEntity.Position,
oldEntity.Rotation,
1f,
0f,
0f,
0x02020000u,
state: (uint)PhysicsStateFlags.ReportCollisions,
seedCellId: pendingCell);
LiveEntityPresentationController? controller = null;
WorldEntity? replacement = null;
runtime.ProjectionVisibilityChanged += (record, visible) =>
{
if (!visible
|| replacement is not null
|| !ReferenceEquals(record, oldRecord))
{
return;
}
controller!.Forget(oldRecord);
shadows.Deregister(oldEntity.Id);
Assert.True(runtime.UnregisterLiveEntity(
new DeleteObject.Parsed(Fixture.Guid, 1),
isLocalPlayer: false));
runtime.RegisterLiveEntity(Fixture.Spawn(
PhysicsStateFlags.ReportCollisions,
instanceSequence: 2));
replacement = runtime.MaterializeLiveEntity(
Fixture.Guid,
pendingCell,
id => new WorldEntity
{
Id = id,
ServerGuid = Fixture.Guid,
SourceGfxObjOrSetupId = 0x02000001u,
Position = new Vector3(20f, 20f, 5f),
Rotation = Quaternion.Identity,
MeshRefs = Array.Empty<MeshRef>(),
ParentCellId = pendingCell,
});
Assert.NotNull(replacement);
shadows.Register(
replacement.Id,
0x01000001u,
replacement.Position,
replacement.Rotation,
1f,
0f,
0f,
0x02020000u,
state: (uint)PhysicsStateFlags.ReportCollisions,
seedCellId: pendingCell);
Assert.True(controller.OnLiveEntityReady(Fixture.Guid));
};
controller = new LiveEntityPresentationController(
runtime,
shadows,
(_, _, _) => true,
liveCenter: () => (2, 2));
Assert.True(controller.OnLiveEntityReady(Fixture.Guid));
Assert.Equal(1, shadows.SuspendedRegistrationCount);
spatial.AddLandblock(new LoadedLandblock(
0x0202FFFFu,
new LandBlock(),
Array.Empty<WorldEntity>()));
Assert.NotNull(replacement);
Assert.True(runtime.TryGetRecord(Fixture.Guid, out var current));
Assert.NotSame(oldRecord, current);
Assert.Same(replacement, current.WorldEntity);
Assert.Equal(1, shadows.TotalRegistered);
Assert.Equal(1, shadows.RetainedRegistrationCount);
Assert.Equal(0, shadows.SuspendedRegistrationCount);
Assert.Contains(
shadows.AllEntriesForDebug(),
entry => entry.EntityId == replacement.Id);
Assert.DoesNotContain(
shadows.AllEntriesForDebug(),
entry => entry.EntityId == oldEntity.Id);
Assert.False(controller.HasDeferredShadowRestore(Fixture.Guid));
controller.Dispose();
}
[Fact]
public void ActivePlacement_IsGenerationScopedAndClearsOnTeardownAndReset()
{
@ -260,6 +646,7 @@ public sealed class LiveEntityPresentationControllerTests
public ShadowObjectRegistry Shadows { get; } = new();
public WorldEntity Entity { get; }
public LiveEntityPresentationController Controller { get; }
public Action<uint>? OnTypedPlay { get; set; }
public Fixture(
PhysicsStateFlags initialState,
@ -306,6 +693,7 @@ public sealed class LiveEntityPresentationControllerTests
{
TypedPlays.Add((owner, type, intensity));
PresentationOrder.Add($"effect:{type:X2}");
OnTypedPlay?.Invoke(type);
return true;
},
(parent, noDraw) =>