acdream/tests/AcDream.App.Tests/Streaming/ResidentStreamingWindowFactTests.cs

142 lines
5.2 KiB
C#

using AcDream.App.Streaming;
using AcDream.Core.World;
using DatReaderWriter.DBObjs;
namespace AcDream.App.Tests.Streaming;
public sealed class ResidentStreamingWindowFactTests
{
[Fact]
public void CaptureUsesOnlyLargestCompleteActuallyPublishedWindow()
{
var state = new GpuWorldState();
AddSquare(state, centerX: 100, centerY: 101, radius: 1);
ResidentStreamingWindowFact first =
state.CaptureResidentStreamingWindow(100, 101);
Assert.True(first.HasPublishedCenter);
Assert.Equal(1, first.CompleteRadiusLandblocks);
Assert.Equal(192f, first.MaximumReachMeters);
// A retained outer ring with one unpublished gap is not a safe shadow
// reach even though most of its landblocks are live.
AddRing(state, 100, 101, radius: 2, skipX: 102, skipY: 101);
ResidentStreamingWindowFact incomplete =
state.CaptureResidentStreamingWindow(100, 101);
Assert.Equal(1, incomplete.CompleteRadiusLandblocks);
Assert.Equal(192f, incomplete.MaximumReachMeters);
Add(state, 102, 101);
ResidentStreamingWindowFact complete =
state.CaptureResidentStreamingWindow(100, 101);
Assert.Equal(2, complete.CompleteRadiusLandblocks);
Assert.Equal(384f, complete.MaximumReachMeters);
}
[Fact]
public void NearToFarDemotionRetainsTerrainReachAndDoesNotRepublishTheWindow()
{
var state = new GpuWorldState();
AddSquare(state, centerX: 40, centerY: 50, radius: 1);
ResidentStreamingWindowFact before =
state.CaptureResidentStreamingWindow(40, 50);
GpuLandblockRetirement? retirement = state.DetachNearLayer(
StreamingRegion.EncodeLandblockId(41, 50));
ResidentStreamingWindowFact after =
state.CaptureResidentStreamingWindow(40, 50);
Assert.NotNull(retirement);
Assert.Equal(before.Revision, after.Revision);
Assert.Equal(before.MaximumReachMeters, after.MaximumReachMeters);
Assert.Equal(before.PublishedLandblockCount, after.PublishedLandblockCount);
}
[Fact]
public void RecenterAndPortalGenerationTurnoverCannotReusePriorReach()
{
var state = new GpuWorldState();
AddSquare(state, centerX: 12, centerY: 20, radius: 2);
ResidentStreamingWindowFact oldGeneration =
state.CaptureResidentStreamingWindow(12, 20);
Assert.Equal(384f, oldGeneration.MaximumReachMeters);
_ = state.DetachAllForOriginRecenter();
ResidentStreamingWindowFact betweenGenerations =
state.CaptureResidentStreamingWindow(12, 20);
Assert.False(betweenGenerations.HasPublishedCenter);
Assert.Equal(0f, betweenGenerations.MaximumReachMeters);
Assert.True(betweenGenerations.Revision > oldGeneration.Revision);
Add(state, 220, 221);
ResidentStreamingWindowFact newGeneration =
state.CaptureResidentStreamingWindow(220, 221);
Assert.True(newGeneration.HasPublishedCenter);
Assert.Equal(0, newGeneration.CompleteRadiusLandblocks);
Assert.Equal(0f, newGeneration.MaximumReachMeters);
Assert.True(newGeneration.Revision > betweenGenerations.Revision);
Assert.False(state.CaptureResidentStreamingWindow(12, 20).HasPublishedCenter);
}
[Fact]
public void RemovingOneResidentEdgeImmediatelyShrinksTheReadOnlyReach()
{
var state = new GpuWorldState();
AddSquare(state, centerX: 80, centerY: 90, radius: 2);
ResidentStreamingWindowFact before =
state.CaptureResidentStreamingWindow(80, 90);
state.RemoveLandblock(StreamingRegion.EncodeLandblockId(82, 90));
ResidentStreamingWindowFact after =
state.CaptureResidentStreamingWindow(80, 90);
Assert.True(after.Revision > before.Revision);
Assert.Equal(1, after.CompleteRadiusLandblocks);
Assert.Equal(192f, after.MaximumReachMeters);
}
private static void AddSquare(
GpuWorldState state,
int centerX,
int centerY,
int radius)
{
for (int x = centerX - radius; x <= centerX + radius; x++)
{
for (int y = centerY - radius; y <= centerY + radius; y++)
Add(state, x, y);
}
}
private static void AddRing(
GpuWorldState state,
int centerX,
int centerY,
int radius,
int skipX,
int skipY)
{
for (int x = centerX - radius; x <= centerX + radius; x++)
{
for (int y = centerY - radius; y <= centerY + radius; y++)
{
if (Math.Max(Math.Abs(x - centerX), Math.Abs(y - centerY)) != radius
|| (x == skipX && y == skipY))
{
continue;
}
Add(state, x, y);
}
}
}
private static void Add(GpuWorldState state, int x, int y)
{
uint landblockId = StreamingRegion.EncodeLandblockId(x, y);
if (state.TryGetLandblock(landblockId, out _))
return;
state.AddLandblock(new LoadedLandblock(
landblockId,
new LandBlock(),
Array.Empty<WorldEntity>()));
}
}