feat: ChunkStreamer dirty set with cardinal-neighbor remesh on load
This commit is contained in:
@@ -82,7 +82,7 @@ public class ChunkStreamerTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tick_PlayerMoves_LoadsNewChunksOnly()
|
||||
public void Tick_PlayerMoves_LoadsNewChunks()
|
||||
{
|
||||
var cfg = new Configuration
|
||||
{
|
||||
@@ -94,10 +94,24 @@ public class ChunkStreamerTests
|
||||
var (streamer, world, created) = CreateStreamer(cfg);
|
||||
|
||||
streamer.Tick(new Vector3i(0, 0, 0)); // loads 9
|
||||
int firstWave = created.Count;
|
||||
streamer.Tick(new Vector3i(1, 0, 0)); // loads only the 3 new column to +x
|
||||
|
||||
Assert.Equal(firstWave + 3, created.Count);
|
||||
// After the second tick the 3 new x=2 chunks must be ready.
|
||||
// Cardinal-neighbor dirty-marking may also produce remesh renderers, so
|
||||
// we assert on world state rather than an exact renderer count.
|
||||
streamer.Tick(new Vector3i(1, 0, 0));
|
||||
|
||||
for (int z = -1; z <= 1; z++)
|
||||
{
|
||||
var newPos = new Vector3i(2, 0, z);
|
||||
Assert.NotNull(world.GetChunk(newPos));
|
||||
Assert.True(streamer.IsReady(newPos));
|
||||
}
|
||||
// x=-1 column must be unloaded
|
||||
for (int z = -1; z <= 1; z++)
|
||||
{
|
||||
Assert.Null(world.GetChunk(new Vector3i(-1, 0, z)));
|
||||
Assert.False(streamer.IsReady(new Vector3i(-1, 0, z)));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -240,4 +254,67 @@ public class ChunkStreamerTests
|
||||
for (int i = 0; i < 9; i++) streamer.Tick(new Vector3i(0, 0, 0));
|
||||
Assert.True(streamer.SpawnReady);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MarkDirty_RemeshesChunkOnNextTick()
|
||||
{
|
||||
var cfg = new Configuration
|
||||
{
|
||||
RenderDistanceHorizontal = 0,
|
||||
RenderDistanceVertical = 0,
|
||||
MaxGenerateJobsInFlight = 100,
|
||||
MaxMeshUploadsPerFrame = 100,
|
||||
};
|
||||
var (streamer, _, created) = CreateStreamer(cfg);
|
||||
|
||||
streamer.Tick(new Vector3i(0, 0, 0));
|
||||
Assert.Single(created);
|
||||
var initialRenderer = created[0];
|
||||
|
||||
streamer.MarkDirty(new Vector3i(0, 0, 0));
|
||||
streamer.Tick(new Vector3i(0, 0, 0)); // same chunk, but a remesh is queued
|
||||
|
||||
// Two renderers exist over the lifetime — old disposed, new live.
|
||||
Assert.Equal(2, created.Count);
|
||||
Assert.True(initialRenderer.Disposed);
|
||||
Assert.False(created[1].Disposed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tick_LoadingChunk_MarksReadyCardinalNeighborsDirty()
|
||||
{
|
||||
var cfg = new Configuration
|
||||
{
|
||||
RenderDistanceHorizontal = 1,
|
||||
RenderDistanceVertical = 0,
|
||||
MaxGenerateJobsInFlight = 100,
|
||||
MaxMeshUploadsPerFrame = 100,
|
||||
};
|
||||
var (streamer, _, created) = CreateStreamer(cfg);
|
||||
|
||||
streamer.Tick(new Vector3i(0, 0, 0)); // load initial 3×3
|
||||
int firstWave = created.Count; // 9 chunks
|
||||
|
||||
// Move so we load a new x=2 column. The new chunks become ready and
|
||||
// mark their cardinal neighbors (x=1 column) dirty during Drain.
|
||||
streamer.Tick(new Vector3i(1, 0, 0)); // dispatch + drain new loads → dirty marks set
|
||||
streamer.Tick(new Vector3i(1, 0, 0)); // dispatch the queued remeshes → drain them
|
||||
|
||||
// Should have: 3 new loads + at least 3 remeshes of the x=1 column.
|
||||
Assert.True(created.Count > firstWave + 3,
|
||||
$"Expected remeshes beyond the 3 new loads; got {created.Count - firstWave}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MarkDirty_OnUntrackedChunk_IsNoOp()
|
||||
{
|
||||
var cfg = new Configuration { RenderDistanceHorizontal = 0, RenderDistanceVertical = 0 };
|
||||
var (streamer, _, created) = CreateStreamer(cfg);
|
||||
|
||||
streamer.MarkDirty(new Vector3i(99, 0, 99));
|
||||
streamer.Tick(new Vector3i(0, 0, 0));
|
||||
|
||||
// Only the chunk in the load box was created; no spurious remesh.
|
||||
Assert.Single(created);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user