feat(app): stage live entities before runtime placement

This commit is contained in:
Erik 2026-08-01 18:43:23 +02:00
parent 3f800a4aec
commit 74103f75b5
2 changed files with 187 additions and 3 deletions

View file

@ -202,6 +202,131 @@ public sealed class LiveEntityRuntimeTests
Assert.Equal(new[] { false, true }, visibilityEdges);
}
[Fact]
public void RuntimePlacementPendingMaterialization_OwnsResourcesWithoutPublishingResidence()
{
const uint guid = 0x70000081u;
const uint cell = 0x01010001u;
var spatial = new GpuWorldState();
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
var resources = new CallbackResources();
LiveEntityRuntime runtime = LiveEntityRuntimeFixture.Create(
spatial,
resources);
LiveEntityRegistrationResult registration = runtime.RegisterLiveEntity(
Spawn(guid, instance: 1, positionSequence: 1, cell));
RuntimeEntityRecord canonical = Assert.IsType<RuntimeEntityRecord>(
registration.Canonical);
uint acceptedCell = canonical.FullCellId;
ulong spatialAuthority = canonical.SpatialAuthorityVersion;
ulong placementCommit = canonical.PlacementCommitVersion;
ulong clockEpoch = canonical.ObjectClockEpoch;
bool clockActive = canonical.ObjectClock.IsActive;
RuntimePhysicsOwnershipSnapshot physicsOwnership =
runtime.Physics.CaptureOwnership();
var visibilityEdges = new List<bool>();
runtime.ProjectionVisibilityChanged += (_, visible) =>
visibilityEdges.Add(visible);
resources.OnRegister = entity =>
{
Assert.False(entity.IsDrawVisible);
Assert.True(runtime.TryGetRecord(guid, out LiveEntityRecord current));
Assert.False(current.IsSpatiallyProjected);
Assert.False(current.IsSpatiallyVisible);
Assert.False(runtime.RebucketLiveEntity(guid, cell));
};
WorldEntity entity = Assert.IsType<WorldEntity>(
runtime.MaterializeLiveEntity(
canonical,
cell,
id => Entity(id, guid),
LiveEntityProjectionKind.World,
initializeProjection: null,
out LiveEntityRecord? record,
LiveEntityMaterializationResidence.AwaitRuntimePlacement));
Assert.NotNull(record);
Assert.Same(entity, record!.WorldEntity);
Assert.True(record.ResourcesRegistered);
Assert.False(record.IsSpatiallyProjected);
Assert.False(record.IsSpatiallyVisible);
Assert.False(entity.IsDrawVisible);
Assert.Equal(acceptedCell, canonical.FullCellId);
Assert.Equal(spatialAuthority, canonical.SpatialAuthorityVersion);
Assert.Equal(placementCommit, canonical.PlacementCommitVersion);
Assert.Equal(clockEpoch, canonical.ObjectClockEpoch);
Assert.Equal(clockActive, canonical.ObjectClock.IsActive);
Assert.Equal(physicsOwnership, runtime.Physics.CaptureOwnership());
Assert.Equal(0, runtime.SpatialRootObjectCount);
Assert.Equal(1, resources.RegisterCount);
Assert.Empty(spatial.Entities);
Assert.Empty(runtime.VisibleRecords);
Assert.Empty(visibilityEdges);
WorldEntity retained = Assert.IsType<WorldEntity>(
runtime.MaterializeLiveEntity(
canonical,
cell,
id => Entity(id, guid),
LiveEntityProjectionKind.World,
initializeProjection: null,
out LiveEntityRecord? retainedRecord,
LiveEntityMaterializationResidence.AwaitRuntimePlacement));
Assert.Same(entity, retained);
Assert.Same(record, retainedRecord);
Assert.Equal(1, resources.RegisterCount);
Assert.False(runtime.RebucketLiveEntity(guid, cell));
Assert.Throws<InvalidOperationException>(() =>
runtime.MaterializeLiveEntity(
canonical,
cell,
id => Entity(id, guid),
LiveEntityProjectionKind.World,
initializeProjection: null,
out _,
LiveEntityMaterializationResidence.LegacyImmediate));
Assert.Empty(spatial.Entities);
}
[Fact]
public void LegacyMaterialization_CannotSwitchToRuntimePlacementResidence()
{
const uint guid = 0x70000082u;
const uint cell = 0x01010001u;
var spatial = new GpuWorldState();
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
var resources = new RecordingResources();
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
RuntimeEntityRecord canonical = Assert.IsType<RuntimeEntityRecord>(
runtime.RegisterLiveEntity(
Spawn(guid, instance: 1, positionSequence: 1, cell)).Canonical);
WorldEntity entity = Assert.IsType<WorldEntity>(
runtime.MaterializeLiveEntity(
canonical,
cell,
id => Entity(id, guid),
LiveEntityProjectionKind.World,
initializeProjection: null,
out LiveEntityRecord? record));
Assert.Throws<InvalidOperationException>(() =>
runtime.MaterializeLiveEntity(
canonical,
cell,
id => Entity(id, guid),
LiveEntityProjectionKind.World,
initializeProjection: null,
out _,
LiveEntityMaterializationResidence.AwaitRuntimePlacement));
Assert.True(record!.IsSpatiallyProjected);
Assert.True(record.IsSpatiallyVisible);
Assert.True(entity.IsDrawVisible);
Assert.Single(spatial.Entities);
Assert.Equal(1, resources.RegisterCount);
}
[Fact]
public void StaticRootCommit_HiddenObjectUpdatesPoseWithoutRestoringShadow()
{