using System.Numerics; using AcDream.App.Rendering.Scene; using AcDream.App.Rendering.Scene.Arch; using AcDream.App.Rendering.Walk; using AcDream.Core.Physics; using AcDream.Core.World; namespace AcDream.App.Tests.Rendering.Walk; /// /// Campaign OVERHAUL S2 chunk 5: no /// longer sweeps the scene to rebuild membership into bucket dictionaries — /// GetCellStatics/GetCellDynamics/GetOutdoorStatics/ /// GetOutdoorDynamics are borrowed, on-demand views over /// 's retail per-cell part-entry product, /// resolved back to a through /// . Every test below /// drives the REAL production path end to end — a real (bare, no-DAT) /// and a real /// — rather than a hand-fed bucket dictionary, since the resolution itself IS /// the thing under test now. /// public sealed class WalkProductionWorldDataTests { [Fact] public void BuildingShellBucketCellId_PortalLessBuildingUsesLandscapePositionCell() { const uint positionCellId = 0xF4180011u; RenderProjectionRecord record = Record( id: 0xCF418060u, position: new Vector3(53.57f, 13.874f, 160f)) with { Source = new RenderSourceMetadata() with { LocalEntityId = 0xCF418060u, SourceId = 0x01001FD3u, EffectCellId = positionCellId, BuildingShellAnchorCellId = 0, }, EntityPayload = new RenderEntityPayload() with { IsBuildingShell = true, }, }; var building = new WalkBuilding { PositionCellId = positionCellId, Portals = [], }; Assert.Equal( positionCellId, WalkProductionWorldData.BuildingShellBucketCellId(in record)); Assert.Equal( positionCellId, WalkProductionWorldData.BuildingShellBucketCellId(building)); } [Fact] public void BuildingShellBucketCellId_PortalBearingBuildingKeepsInteriorAnchor() { const uint anchorCellId = 0xF4180112u; RenderProjectionRecord record = Record( id: 0xCF41805Fu, position: new Vector3(36f, 13.8349f, 160f)) with { Source = new RenderSourceMetadata() with { LocalEntityId = 0xCF41805Fu, SourceId = 0x01001FB7u, EffectCellId = 0xF4180009u, BuildingShellAnchorCellId = anchorCellId, }, EntityPayload = new RenderEntityPayload() with { IsBuildingShell = true, }, }; var building = new WalkBuilding { PositionCellId = 0xF4180009u, Portals = [ new WalkBldPortal { OtherCellId = anchorCellId }, ], }; Assert.Equal( anchorCellId, WalkProductionWorldData.BuildingShellBucketCellId(in record)); Assert.Equal( anchorCellId, WalkProductionWorldData.BuildingShellBucketCellId(building)); } private static ShadowShape Bsp(uint gfxObjId, float radius = 1f) => ShadowShape.Bsp( gfxObjId, Vector3.Zero, Quaternion.Identity, scale: 1f, localGeometry: ShadowPartGeometry.Create( new FlatCollisionSphere(Vector3.Zero, radius), null)); private static RenderProjectionRecord IndoorStaticRecord( uint entityId, uint sourceId, uint parentCellId) => new RenderProjectionRecord() with { Id = RenderProjectionId.FromRaw(entityId), ProjectionClass = RenderProjectionClass.IndoorCellStatic, OwnerIncarnation = RenderOwnerIncarnation.FromRaw(1), Transform = new RenderTransform(Matrix4x4.Identity), PreviousTransform = new PreviousRenderTransform(Matrix4x4.Identity), Residency = new RenderSpatialResidency( RenderSpatialBucket.FromRaw(parentCellId), 0x8A020000u, parentCellId), Flags = RenderProjectionFlags.Draw, Source = new RenderSourceMetadata() with { LocalEntityId = entityId, SourceId = sourceId, ParentCellId = parentCellId, }, // Every production entity record carries its MeshRefs // (RenderProjectionRecordFactory); only an EnvCell SHELL has no // payload, and ArchRenderScene keeps shells out of the // LocalEntityId index on exactly that distinction. EntityPayload = new RenderEntityPayload() with { MeshRefs = [new MeshRef(sourceId, Matrix4x4.Identity)], }, }; private static RenderProjectionRecord DynamicRecord( uint entityId, uint sourceId, uint parentCellId) => IndoorStaticRecord(entityId, sourceId, parentCellId) with { Id = RenderProjectionId.FromRaw(0x0100_0000_0000_0000u | entityId), ProjectionClass = RenderProjectionClass.LiveDynamicRoot, }; private static RenderProjectionRecord OutdoorStaticRecord( uint entityId, uint sourceId, uint cellId, bool isBuildingShell = false) => new RenderProjectionRecord() with { Id = RenderProjectionId.FromRaw(0x0200_0000_0000_0000u | entityId), ProjectionClass = RenderProjectionClass.OutdoorStatic, OwnerIncarnation = RenderOwnerIncarnation.FromRaw(1), Transform = new RenderTransform(Matrix4x4.Identity), PreviousTransform = new PreviousRenderTransform(Matrix4x4.Identity), Residency = new RenderSpatialResidency( RenderSpatialBucket.FromRaw(cellId), cellId & 0xFFFF0000u, cellId), Flags = RenderProjectionFlags.Draw, Source = new RenderSourceMetadata() with { LocalEntityId = entityId, SourceId = sourceId, ParentCellId = cellId, }, EntityPayload = new RenderEntityPayload() with { IsBuildingShell = isBuildingShell, }, }; private static void Register( ShadowObjectRegistry shadows, uint entityId, uint seedCellId, uint landblockId) { IReadOnlyList parts = new[] { Bsp(0x01001234u) }; shadows.RegisterMultiPart( entityId, Vector3.Zero, Quaternion.Identity, parts, state: 0u, flags: EntityCollisionFlags.None, worldOffsetX: 0f, worldOffsetY: 0f, landblockId: landblockId, seedCellId: seedCellId, isStatic: true, partArray: parts); } [Fact] public void GetCellStatics_RegisteredEntityIsResolvedByLocalEntityIdAtTheRetailCell() { const uint entityId = 0x48A02001u; const uint retailCellId = 0x8A02015Fu; // A DECOY parent cell, deliberately different from the registered // retail array's cell, so the assertions below can only pass if the // per-cell view actually consulted the registry rather than the // authored parent (deleted alongside the sweep this test used to // exercise). const uint decoyParentCellId = 0x8A0201C1u; var shadows = new ShadowObjectRegistry(); Register(shadows, entityId, retailCellId, landblockId: 0x8A020000u); Assert.True(shadows.TryGetRetailCellArray(entityId, out IReadOnlyList retailCells)); Assert.Equal(new[] { retailCellId }, retailCells); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); RenderProjectionRecord projection = IndoorStaticRecord(entityId, sourceId: 0x02000001u, decoyParentCellId); scene.Apply([RenderProjectionDelta.Register(generation, 1, projection)]); var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0x8A020000u, renderCenterLbX: 0x8A, renderCenterLbY: 0x02); Assert.Contains( worldData.GetCellStatics(retailCellId).Records, record => record.Id == projection.Id); Assert.DoesNotContain( worldData.GetCellStatics(decoyParentCellId).Records, record => record.Id == projection.Id); Assert.Equal(0, worldData.UnregisteredRenderMembershipCount); } [Fact] public void GetCellStatics_RegistryAheadOfSceneContributesToNoCellAndCountsFallback() { const uint entityId = 0x48A02002u; const uint retailCellId = 0x8A02015Fu; // The registry HAS flooded this entity into its retail CELLARRAY — // exactly the streaming-window race chunk 5 keeps as the ONE // remaining fallback: the physics publisher (registry) ran before // the presentation journal applied this frame's projected record. var shadows = new ShadowObjectRegistry(); Register(shadows, entityId, retailCellId, landblockId: 0x8A020000u); Assert.True(shadows.TryGetRetailCellArray(entityId, out _)); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); // Deliberately no scene.Apply — the projected record does not exist // yet this frame. var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0x8A020000u, renderCenterLbX: 0x8A, renderCenterLbY: 0x02); Assert.Equal(0, worldData.GetCellStatics(retailCellId).Records.Count); Assert.Equal(1, worldData.UnregisteredRenderMembershipCount); } [Fact] public void GetCellStatics_UnregisteredEntityContributesToNoCellWithoutCounting() { // The OPPOSITE race: the scene has a projected record, but the // registry never registered a retail CELLARRAY for this entity at // all. Under the borrowed-view model this entity is never visited // (nothing in the registry names it), so it correctly appears in NO // cell and does not inflate the one remaining fallback counter — // that counter only tracks entities the REGISTRY has flooded. const uint entityId = 0x48A02003u; const uint parentCellId = 0x8A02015Fu; var shadows = new ShadowObjectRegistry(); Assert.False(shadows.TryGetRetailCellArray(entityId, out _)); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); RenderProjectionRecord projection = IndoorStaticRecord(entityId, sourceId: 0x02000003u, parentCellId); scene.Apply([RenderProjectionDelta.Register(generation, 1, projection)]); var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0x8A020000u, renderCenterLbX: 0x8A, renderCenterLbY: 0x02); Assert.Equal(0, worldData.GetCellStatics(parentCellId).Records.Count); Assert.Equal(0, worldData.UnregisteredRenderMembershipCount); } [Fact] public void UnregisteredRenderMembershipCount_CountsDistinctEntitiesNotCellVisits() { // One entity crossing SEVERAL cells — outdoor, since the bbox flood's // fixed outdoor expansion reliably crosses cells even against a bare // registry with no portal DAT data to cross INDOOR cells with (see // GetOutdoorStatics_UsesTheSameRegistryDrivenViewAsIndoor) — all // unresolved in the scene, must count once total, not once per cell // the registry flooded it into. const uint entityId = 0x87640002u; const uint seedCellId = 0x87640030u; IReadOnlyList parts = new[] { Bsp(0x01001234u) }; var shadows = new ShadowObjectRegistry(); shadows.RegisterMultiPart( entityId, Vector3.Zero, Quaternion.Identity, parts, state: 0u, flags: EntityCollisionFlags.None, worldOffsetX: 0f, worldOffsetY: 0f, landblockId: 0x87640000u, seedCellId: seedCellId, isStatic: true, partArray: parts); Assert.True(shadows.TryGetRetailCellArray(entityId, out IReadOnlyList cells)); Assert.True(cells.Count >= 2, "fixture must actually cross more than one cell"); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0x87640000u, renderCenterLbX: 0x87, renderCenterLbY: 0x64); foreach (uint cellId in cells) Assert.Equal(0, worldData.GetOutdoorStatics(cellId).Records.Count); Assert.Equal(1, worldData.UnregisteredRenderMembershipCount); } [Fact] public void GetCellDynamics_OnlyReturnsDynamicClassRecordsFromTheSameCell() { const uint staticEntityId = 0x48A02010u; const uint dynamicEntityId = 0x48A02011u; const uint sharedCellId = 0x8A02015Fu; var shadows = new ShadowObjectRegistry(); Register(shadows, staticEntityId, sharedCellId, landblockId: 0x8A020000u); Register(shadows, dynamicEntityId, sharedCellId, landblockId: 0x8A020000u); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); RenderProjectionRecord staticProjection = IndoorStaticRecord(staticEntityId, sourceId: 0x02000010u, sharedCellId); RenderProjectionRecord dynamicProjection = DynamicRecord(dynamicEntityId, sourceId: 0x02000011u, sharedCellId); scene.Apply([ RenderProjectionDelta.Register(generation, 1, staticProjection), RenderProjectionDelta.Register(generation, 2, dynamicProjection), ]); var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0x8A020000u, renderCenterLbX: 0x8A, renderCenterLbY: 0x02); Assert.Contains( worldData.GetCellStatics(sharedCellId).Records, record => record.Id == staticProjection.Id); Assert.DoesNotContain( worldData.GetCellStatics(sharedCellId).Records, record => record.Id == dynamicProjection.Id); Assert.Contains( worldData.GetCellDynamics(sharedCellId).Records, record => record.Id == dynamicProjection.Id); Assert.DoesNotContain( worldData.GetCellDynamics(sharedCellId).Records, record => record.Id == staticProjection.Id); } [Fact] public void GetCellStatics_ExcludesBuildingShellRecordsFromTheSameCell() { const uint shellEntityId = 0x48A02020u; const uint ordinaryEntityId = 0x48A02021u; const uint sharedCellId = 0x8A02015Fu; var shadows = new ShadowObjectRegistry(); Register(shadows, shellEntityId, sharedCellId, landblockId: 0x8A020000u); Register(shadows, ordinaryEntityId, sharedCellId, landblockId: 0x8A020000u); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); RenderProjectionRecord shellProjection = IndoorStaticRecord(shellEntityId, sourceId: 0x02000020u, sharedCellId) with { EntityPayload = new RenderEntityPayload() with { IsBuildingShell = true }, }; RenderProjectionRecord ordinaryProjection = IndoorStaticRecord(ordinaryEntityId, sourceId: 0x02000021u, sharedCellId); scene.Apply([ RenderProjectionDelta.Register(generation, 1, shellProjection), RenderProjectionDelta.Register(generation, 2, ordinaryProjection), ]); var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0x8A020000u, renderCenterLbX: 0x8A, renderCenterLbY: 0x02); Assert.DoesNotContain( worldData.GetCellStatics(sharedCellId).Records, record => record.Id == shellProjection.Id); Assert.Contains( worldData.GetCellStatics(sharedCellId).Records, record => record.Id == ordinaryProjection.Id); } [Fact] public void GetOutdoorStatics_UsesTheSameRegistryDrivenViewAsIndoor() { const uint entityId = 0x87640001u; const uint outdoorCellId = 0x87640030u; var shadows = new ShadowObjectRegistry(); Register(shadows, entityId, outdoorCellId, landblockId: 0x87640000u); Assert.True(shadows.TryGetRetailCellArray(entityId, out IReadOnlyList retailCells)); // The outdoor bbox flood's fixed expansion crosses more than the // seed cell even for a small radius; only the seed cell's own // membership matters for this test. Assert.Contains(outdoorCellId, retailCells); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); RenderProjectionRecord projection = OutdoorStaticRecord(entityId, sourceId: 0x02000030u, outdoorCellId); scene.Apply([RenderProjectionDelta.Register(generation, 1, projection)]); var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0x87640000u, renderCenterLbX: 0x87, renderCenterLbY: 0x64); Assert.Contains( worldData.GetOutdoorStatics(outdoorCellId).Records, record => record.Id == projection.Id); } [Fact] public void GetCellStatics_CachesTheResultForTheRestOfTheFrame() { const uint entityId = 0x48A02030u; const uint retailCellId = 0x8A02015Fu; var shadows = new ShadowObjectRegistry(); Register(shadows, entityId, retailCellId, landblockId: 0x8A020000u); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); RenderProjectionRecord projection = IndoorStaticRecord(entityId, sourceId: 0x02000030u, retailCellId); scene.Apply([RenderProjectionDelta.Register(generation, 1, projection)]); var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0x8A020000u, renderCenterLbX: 0x8A, renderCenterLbY: 0x02); WalkFrameStaticRecords first = worldData.GetCellStatics(retailCellId); WalkFrameStaticRecords second = worldData.GetCellStatics(retailCellId); Assert.Equal(first.Records.Array, second.Records.Array); Assert.Equal(first.Records.Offset, second.Records.Offset); Assert.Equal(first.Records.Count, second.Records.Count); } [Fact] public void StaticBucketContains_FindsARegisteredSourceIdInItsRetailCell() { const uint entityId = 0x48A02040u; const uint sourceId = 0x020009A2u; const uint retailCellId = 0xF4180112u; var shadows = new ShadowObjectRegistry(); Register(shadows, entityId, retailCellId, landblockId: 0xF4180000u); RenderSceneGeneration generation = RenderSceneGeneration.FromRaw(1); using var scene = new ArchRenderScene(generation); RenderProjectionRecord projection = IndoorStaticRecord(entityId, sourceId, retailCellId); scene.Apply([RenderProjectionDelta.Register(generation, 1, projection)]); var worldData = new WalkProductionWorldData(new WalkBuildingRegistry(), shadows); worldData.BeginFrame( scene.OpenQuery(), 0xF4180000u, renderCenterLbX: 0xF4, renderCenterLbY: 0x18); Assert.True(worldData.StaticBucketContains(retailCellId, sourceId)); Assert.False(worldData.StaticBucketContains(retailCellId, sourceId + 1)); Assert.False(worldData.StaticBucketContains(0xF4180107u, sourceId)); } private static RenderProjectionRecord Record(uint id, Vector3 position) => new RenderProjectionRecord() with { Id = RenderProjectionId.FromRaw(id), Transform = new RenderTransform(Matrix4x4.CreateTranslation(position)), Source = new RenderSourceMetadata() with { LocalEntityId = id }, }; }