Skip to content

Feature: Chunk Send and Request Management

Tsu edited this page May 31, 2026 · 3 revisions

This feature set controls chunk pipeline pressure with explicit budgets, fairness rotation, and stale-request cleanup.

Where It Lives

Main patch:

  • patches/VintagestoryLib/Vintagestory.Server/ServerSystemSendChunks.cs.patch

Server-Tick Budgets

At the top of OnServerTick, Stratum reads three config slices and derives per-tick budgets:

StratumChunkSendingConfig stratumChunkSending = StratumRuntime.Config.Performance.ChunkSending;
StratumChunkGenerationConfig stratumChunkGeneration = StratumRuntime.Config.Performance.ChunkGeneration;
StratumChunkRequestManagementConfig stratumChunkRequestManagement = StratumRuntime.Config.Performance.ChunkRequestManagement;

int stratumChunkBudget = stratumBudgetEnabled ? Math.Max(1, stratumChunkSending.MaxChunksPerServerTick) : int.MaxValue;
int stratumColumnRequestBudget = stratumGenerationBudgetEnabled ? Math.Max(1, stratumChunkGeneration.MaxColumnRequestsPerServerTick) : int.MaxValue;

Those budgets are consumed as each connected client is processed.

Fairness Rotation Across Clients

Client order is rotated each tick so one client does not permanently go first:

int offset = stratumClientBudgetRotation % count;
stratumClientBudgetRotation = (stratumClientBudgetRotation + 1) % count;
...
clients.Reverse(0, offset);
clients.Reverse(offset, count - offset);
clients.Reverse();

Per-Client Budget Application

Per-client chunk budget and generation budget are clamped when enabled:

num2 = Math.Min(num2, Math.Max(1, stratumChunkSending.MaxChunksPerClientTick));
num2 = Math.Min(num2, Math.Max(0, stratumChunkBudget));

columnRequestBudget = Math.Min(columnRequestBudget, Math.Max(1, stratumChunkGeneration.MaxColumnRequestsPerClientTick));
columnRequestBudget = Math.Min(columnRequestBudget, Math.Max(0, stratumColumnRequestBudget));

When the request budget is exhausted and a new column would be needed, the tick records deferred generation.

Movement-Aware Chunk Candidate Priority

Chunk candidates can be sorted toward projected movement direction:

double projectedChunkX = (position.X + position.Motion.X * inverseHorizontalSpeed * config.ForwardPredictionBlocks) / MagicNum.ServerChunkSize;
double projectedChunkZ = (position.Z + position.Motion.Z * inverseHorizontalSpeed * config.ForwardPredictionBlocks) / MagicNum.ServerChunkSize;
Array.Sort(octagonPoints, (left, right) => GetStratumProjectedChunkDistance(left, projectedChunkX, projectedChunkZ).CompareTo(GetStratumProjectedChunkDistance(right, projectedChunkX, projectedChunkZ)));

This only activates when:

  • ChunkRequestManagement.Enabled
  • PrioritizeMovingDirection
  • ForwardPredictionBlocks > 0
  • movement speed is above MinimumMovementSpeed

Tracked Pending Requests and Stale Cancellation

Stratum tracks chunk-column requests it enqueues:

stratumTrackedChunkColumnRequests[mapChunkIndex] = new StratumTrackedChunkColumnRequest(chunkX, chunkZ, server.ElapsedMilliseconds);

Cleanup runs on an interval and can cancel requests that are old and no longer near any connected player:

if (nowMs - request.RequestedAtMilliseconds < config.MinimumPendingAgeSeconds * 1000L)
{
    continue;
}

if (cancelledRequests >= config.MaxCancelledRequestsPerCleanup || IsStratumChunkColumnStillWanted(request, config))
{
    continue;
}

if (RemovePendingStratumChunkColumnRequest(mapChunkIndex))
{
    cancelledRequests++;
}

Timing and Stats Hooks

chunk.pipeline and chunk.serialize timings are recorded, and chunk pipeline counters are sent to StratumPerformanceStats via RecordChunkSendTick(...).

Related Files

  • patches/VintagestoryLib/Vintagestory.Server/ServerSystemSendChunks.cs.patch
  • sources/VintagestoryLib/Vintagestory/Server/StratumConfig.cs (Performance.ChunkSending, ChunkGeneration, ChunkRequestManagement)
  • wiki/Performance.md

Clone this wiki locally