using System.Collections.Generic; using System.Numerics; using AcDream.App.Rendering.Wb; using DatReaderWriter.DBObjs; using DatReaderWriter.Types; using Xunit; namespace AcDream.App.Tests.Rendering.Wb; public class BuildingLoaderTests { // Helper: build a minimal LandBlockInfo with one BuildingInfo per supplied tuple. // OtherCellId values are 16-bit cell-local ids (low word of full cell id). private static LandBlockInfo MakeInfo(params (uint modelId, uint[] portalOtherCellIds)[] buildings) { var bls = new List(); foreach (var (modelId, portals) in buildings) { var portalList = new List(); foreach (var ocid in portals) { portalList.Add(new BuildingPortal { OtherCellId = (ushort)(ocid & 0xFFFFu), Flags = 0, OtherPortalId = 0, StabList = new List(), }); } bls.Add(new BuildingInfo { ModelId = modelId, Frame = new Frame { Origin = Vector3.Zero, Orientation = Quaternion.Identity }, Portals = portalList, }); } return new LandBlockInfo { Objects = new List(), Buildings = bls, }; } [Fact] public void Empty_NoBuildings_EmptyRegistry() { var info = new LandBlockInfo { Objects = new List(), Buildings = new List() }; var reg = BuildingLoader.Build(info, landblockId: 0xA9B40000u, cellsByCellId: new Dictionary()); Assert.Equal(0, reg.Count); } [Fact] public void OneBuilding_OnePortal_MapsToOneCell() { // Building points to cell 0x0150 in landblock 0xA9B40000 → full cell id 0xA9B40150 var info = MakeInfo((modelId: 0x02000123u, portalOtherCellIds: new[] { 0x0150u })); // Pass an empty cell dict — loader seeds from BuildingInfo.Portals only var reg = BuildingLoader.Build(info, landblockId: 0xA9B40000u, cellsByCellId: new Dictionary()); Assert.Equal(1, reg.Count); var building = System.Linq.Enumerable.First(reg.All()); Assert.Contains(0xA9B40150u, building.EnvCellIds); } [Fact] public void OneBuilding_MultiplePortals_MapsToMultipleCells() { var info = MakeInfo((0x02000123u, new[] { 0x0150u, 0x0151u, 0x0152u })); var reg = BuildingLoader.Build(info, 0xA9B40000u, new Dictionary()); var building = System.Linq.Enumerable.First(reg.All()); Assert.Equal(3, building.EnvCellIds.Count); Assert.Contains(0xA9B40150u, building.EnvCellIds); Assert.Contains(0xA9B40151u, building.EnvCellIds); Assert.Contains(0xA9B40152u, building.EnvCellIds); } [Fact] public void TwoBuildings_AllocateSequentialIds() { var info = MakeInfo( (0x02000001u, new[] { 0x0150u }), (0x02000002u, new[] { 0x0160u })); var reg = BuildingLoader.Build(info, 0xA9B40000u, new Dictionary()); Assert.Equal(2, reg.Count); var ids = new SortedSet(); foreach (var b in reg.All()) ids.Add(b.BuildingId); Assert.Equal(new SortedSet { 1, 2 }, ids); // sequential 1, 2 } [Fact] public void Build_StampsLoadedCellBuildingId() { // Fixture: minimal LoadedCell instances representing 2 cottage cells. var cell150 = new AcDream.App.Rendering.LoadedCell { CellId = 0xA9B40150u, Portals = new List(), PortalPolygons = new List(), WorldTransform = Matrix4x4.Identity, InverseWorldTransform = Matrix4x4.Identity, LocalBoundsMin = new Vector3(-5, -5, -5), LocalBoundsMax = new Vector3(5, 5, 5), ClipPlanes = new List(), }; var cell151 = new AcDream.App.Rendering.LoadedCell { CellId = 0xA9B40151u, Portals = new List(), PortalPolygons = new List(), WorldTransform = Matrix4x4.Identity, InverseWorldTransform = Matrix4x4.Identity, LocalBoundsMin = new Vector3(-5, -5, -5), LocalBoundsMax = new Vector3(5, 5, 5), ClipPlanes = new List(), }; var cells = new Dictionary { { 0xA9B40150u, cell150 }, { 0xA9B40151u, cell151 }, }; var info = MakeInfo((0x02000123u, new[] { 0x0150u, 0x0151u })); var reg = BuildingLoader.Build(info, 0xA9B40000u, cells); Assert.Equal(1, reg.Count); var b = System.Linq.Enumerable.First(reg.All()); // Both cells stamped with the building id: Assert.Equal(b.BuildingId, cell150.BuildingId); Assert.Equal(b.BuildingId, cell151.BuildingId); } }