feat(teleport A): StreamingController priority-apply for the teleport destination LB
Adds PriorityLandblockId (uint, default 0) + _deferredApply buffer. DrainAndApply now: (1) applies up to budget from the deferred buffer, (2) when PriorityLandblockId != 0, hunts the worker outbox in chunks applying the priority LB immediately on match and buffering any non-priority items drained past it for later frames, (3) falls back to normal drain when no priority is set or not found. Extracts ApplyResult(result) + ResultLandblockId(result) helpers so both the priority and normal paths share identical side-effects. No existing behaviour changes on the non-priority path. 21 streaming tests pass (19 existing + 2 new priority-apply tests). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b869128df3
commit
1f6baa6cfc
2 changed files with 228 additions and 28 deletions
|
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.App.Streaming;
|
||||
using AcDream.Core.Terrain;
|
||||
using AcDream.Core.World;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using Xunit;
|
||||
|
||||
namespace AcDream.Core.Tests.Streaming;
|
||||
|
||||
public class StreamingControllerPriorityApplyTests
|
||||
{
|
||||
private static LandblockStreamResult.Loaded LoadedOf(uint canonicalId)
|
||||
=> new(canonicalId, LandblockStreamTier.Near,
|
||||
new LoadedLandblock(canonicalId, new LandBlock(), Array.Empty<WorldEntity>()),
|
||||
new LandblockMeshData(Array.Empty<TerrainVertex>(), Array.Empty<uint>()));
|
||||
|
||||
[Fact]
|
||||
public void PriorityLandblock_isApplied_evenWhenBeyondPerFrameCap()
|
||||
{
|
||||
uint priority = StreamingRegion.EncodeLandblockIdForTest(169, 180);
|
||||
var outbox = new Queue<LandblockStreamResult>(new LandblockStreamResult[]
|
||||
{
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 0)),
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 1)),
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 2)),
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 3)),
|
||||
LoadedOf(priority),
|
||||
});
|
||||
|
||||
var applied = new List<uint>();
|
||||
var state = new GpuWorldState();
|
||||
var ctrl = new StreamingController(
|
||||
enqueueLoad: (_, _) => { },
|
||||
enqueueUnload: _ => { },
|
||||
drainCompletions: max =>
|
||||
{
|
||||
var batch = new List<LandblockStreamResult>();
|
||||
while (batch.Count < max && outbox.Count > 0) batch.Add(outbox.Dequeue());
|
||||
return batch;
|
||||
},
|
||||
applyTerrain: (lb, _) => applied.Add(lb.LandblockId),
|
||||
state: state, nearRadius: 4, farRadius: 12)
|
||||
{ MaxCompletionsPerFrame = 4 };
|
||||
|
||||
ctrl.PriorityLandblockId = priority;
|
||||
ctrl.Tick(169, 180);
|
||||
|
||||
Assert.Contains(priority, applied); // priority applied THIS tick
|
||||
Assert.True(applied.Count <= 5); // did not blindly flush the whole outbox
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deferred_nonPriority_completions_applyOnLaterFrames_withoutLoss()
|
||||
{
|
||||
// After the priority is found, the non-priority items drained past it must
|
||||
// still be applied (over subsequent ticks), never dropped.
|
||||
uint priority = StreamingRegion.EncodeLandblockIdForTest(169, 180);
|
||||
var outbox = new Queue<LandblockStreamResult>(new LandblockStreamResult[]
|
||||
{
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 0)),
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 1)),
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 2)),
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 3)),
|
||||
LoadedOf(StreamingRegion.EncodeLandblockIdForTest(0, 4)),
|
||||
LoadedOf(priority),
|
||||
});
|
||||
var applied = new List<uint>();
|
||||
var state = new GpuWorldState();
|
||||
var ctrl = new StreamingController(
|
||||
(_, _) => { }, _ => { },
|
||||
max => { var b = new List<LandblockStreamResult>(); while (b.Count < max && outbox.Count > 0) b.Add(outbox.Dequeue()); return b; },
|
||||
(lb, _) => applied.Add(lb.LandblockId),
|
||||
state, 4, 12) { MaxCompletionsPerFrame = 4 };
|
||||
ctrl.PriorityLandblockId = priority;
|
||||
|
||||
ctrl.Tick(169, 180); // priority + some others
|
||||
ctrl.PriorityLandblockId = 0u;
|
||||
ctrl.Tick(169, 180); // drains the deferred remainder
|
||||
ctrl.Tick(169, 180);
|
||||
|
||||
Assert.Contains(priority, applied);
|
||||
Assert.Equal(6, applied.Count); // all six applied, none lost
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue