104 lines
3.7 KiB
C#
104 lines
3.7 KiB
C#
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<WorldEntity>());
|
|
|
|
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<WorldEntity>());
|
|
var second = new LoadedLandblock(
|
|
0x1235FFFFu,
|
|
new LandBlock(),
|
|
Array.Empty<WorldEntity>());
|
|
|
|
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<ulong> ReadyIds { get; } = new();
|
|
public Dictionary<ulong, int> ReferenceCounts { get; } = new();
|
|
public List<ulong> 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);
|
|
}
|
|
}
|