diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index e1e3e1b..e2b62d9 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -5133,6 +5133,7 @@ public sealed class GameWindow : IDisposable Position = e.Position + worldOffset, Rotation = e.Rotation, MeshRefs = meshRefs, + IsBuildingShell = e.IsBuildingShell, // Phase A8: preserve dat-level tag }; hydrated.Add(entity); } diff --git a/src/AcDream.Core/World/LandblockLoader.cs b/src/AcDream.Core/World/LandblockLoader.cs index b18608a..c685496 100644 --- a/src/AcDream.Core/World/LandblockLoader.cs +++ b/src/AcDream.Core/World/LandblockLoader.cs @@ -82,6 +82,7 @@ public static class LandblockLoader Position = building.Frame.Origin, Rotation = building.Frame.Orientation, MeshRefs = Array.Empty(), + IsBuildingShell = true, // Phase A8: tag at source array boundary }; buildingEntity.RefreshAabb(); // A.5 T18: populate cached AABB at construction result.Add(buildingEntity); diff --git a/src/AcDream.Core/World/WorldEntity.cs b/src/AcDream.Core/World/WorldEntity.cs index 20643d3..0a70d81 100644 --- a/src/AcDream.Core/World/WorldEntity.cs +++ b/src/AcDream.Core/World/WorldEntity.cs @@ -44,6 +44,25 @@ public sealed class WorldEntity /// public uint? ParentCellId { get; init; } + /// + /// True when this entity originates from LandBlockInfo.Buildings[] + /// (the dat array that carries building shells: cottage walls, smithy walls, + /// inn walls — every solid building enclosure). False for entities from + /// LandBlockInfo.Objects[] (rocks, fences, lampposts, tree clusters — + /// outdoor scenery placeholders). The two arrays are conflated through + /// hydration today but the dat itself carries the distinction; retail + /// (CLandBlock::init_buildings) and WorldBuilder + /// (SceneryInstance.IsBuilding) both preserve it. + /// + /// + /// Read at draw time by WbDrawDispatcher's IndoorPass + /// partition so building shells render unconditionally when the camera + /// is inside their building (they ARE the indoor walls), not stencil-gated + /// as outdoor scenery would be. + /// + /// + public bool IsBuildingShell { get; init; } + /// /// Uniform scale applied to this entity's mesh by the scenery pipeline. /// For scenery objects this is spawn.Scale (typically 0.8–1.3). For stabs diff --git a/tests/AcDream.Core.Tests/World/LandblockLoaderTests.cs b/tests/AcDream.Core.Tests/World/LandblockLoaderTests.cs index d1d24b8..21096dd 100644 --- a/tests/AcDream.Core.Tests/World/LandblockLoaderTests.cs +++ b/tests/AcDream.Core.Tests/World/LandblockLoaderTests.cs @@ -162,4 +162,54 @@ public class LandblockLoaderTests Assert.Single(entities); Assert.Equal(1u, entities[0].Id); } + + [Fact] + public void BuildEntitiesFromInfo_TagsBuildingsWithIsBuildingShellTrue() + { + var info = new LandBlockInfo + { + Buildings = + { + new BuildingInfo + { + ModelId = 0x02000123u, // Setup id + Frame = new Frame + { + Origin = new Vector3(10f, 20f, 30f), + Orientation = Quaternion.Identity, + }, + }, + }, + }; + + var entities = LandblockLoader.BuildEntitiesFromInfo(info); + + Assert.Single(entities); + Assert.True(entities[0].IsBuildingShell); + } + + [Fact] + public void BuildEntitiesFromInfo_TagsObjectsWithIsBuildingShellFalse() + { + var info = new LandBlockInfo + { + Objects = + { + new Stab + { + Id = 0x01000123u, // GfxObj id + Frame = new Frame + { + Origin = new Vector3(10f, 20f, 30f), + Orientation = Quaternion.Identity, + }, + }, + }, + }; + + var entities = LandblockLoader.BuildEntitiesFromInfo(info); + + Assert.Single(entities); + Assert.False(entities[0].IsBuildingShell); + } }