using System.Numerics; using AcDream.App.Rendering.Wb; using AcDream.Core.World; using DatReaderWriter.DBObjs; namespace AcDream.App.Tests.Rendering.Wb; public sealed class LandblockSpawnAdapterReadinessTests { [Fact] public void RenderReady_WaitsForStaticAndEnvCellMeshes() { var meshes = new ReadinessMeshAdapter(); var adapter = new LandblockSpawnAdapter(meshes); var entity = new WorldEntity { Id = 1, ServerGuid = 0, SourceGfxObjOrSetupId = 0x01000010u, Position = Vector3.Zero, Rotation = Quaternion.Identity, MeshRefs = [new MeshRef(0x01000010u, Matrix4x4.Identity)], }; var landblock = new LoadedLandblock( 0x1234FFFFu, new LandBlock(), new[] { entity }); const ulong envCellGeometryId = 0x2_0000_1234ul; adapter.OnLandblockLoaded(landblock, new[] { envCellGeometryId }); Assert.False(adapter.IsLandblockRenderReady(landblock.LandblockId)); meshes.ReadyIds.Add(0x01000010ul); Assert.False(adapter.IsLandblockRenderReady(landblock.LandblockId)); meshes.ReadyIds.Add(envCellGeometryId); Assert.True(adapter.IsLandblockRenderReady(landblock.LandblockId)); } [Fact] public void RenderReady_EmptyPublishedLandblockIsReadyUntilUnload() { var meshes = new ReadinessMeshAdapter(); var adapter = new LandblockSpawnAdapter(meshes); var landblock = new LoadedLandblock( 0x1234FFFFu, new LandBlock(), Array.Empty()); adapter.OnLandblockLoaded(landblock); Assert.True(adapter.IsLandblockRenderReady(landblock.LandblockId)); adapter.OnLandblockUnloaded(landblock.LandblockId); Assert.False(adapter.IsLandblockRenderReady(landblock.LandblockId)); } [Fact] public void SharedEnvCellGeometry_IsPinnedPerLandblockAndReleasedSymmetrically() { const ulong sharedGeometryId = 0x2_0000_1234ul; var meshes = new ReadinessMeshAdapter(); var adapter = new LandblockSpawnAdapter(meshes); var first = new LoadedLandblock( 0x1234FFFFu, new LandBlock(), Array.Empty()); var second = new LoadedLandblock( 0x1235FFFFu, new LandBlock(), Array.Empty()); adapter.OnLandblockLoaded(first, new[] { sharedGeometryId, sharedGeometryId }); adapter.OnLandblockLoaded(second, new[] { sharedGeometryId }); Assert.Equal(2, meshes.ReferenceCounts[sharedGeometryId]); Assert.Equal(2, meshes.PreparedPinCalls.Count); adapter.OnLandblockUnloaded(first.LandblockId); Assert.Equal(1, meshes.ReferenceCounts[sharedGeometryId]); adapter.OnLandblockUnloaded(second.LandblockId); Assert.DoesNotContain(sharedGeometryId, meshes.ReferenceCounts); } private sealed class ReadinessMeshAdapter : IWbMeshAdapter { public HashSet ReadyIds { get; } = new(); public Dictionary ReferenceCounts { get; } = new(); public List PreparedPinCalls { get; } = new(); public void IncrementRefCount(ulong id) => ReferenceCounts[id] = ReferenceCounts.GetValueOrDefault(id) + 1; public void PinPreparedRenderData(ulong id) { PreparedPinCalls.Add(id); IncrementRefCount(id); } public void DecrementRefCount(ulong id) { int count = ReferenceCounts[id] - 1; if (count == 0) ReferenceCounts.Remove(id); else ReferenceCounts[id] = count; } public bool IsRenderDataReady(ulong id) => ReadyIds.Contains(id); } }