Skip to content

Feature: Chunk Send and Request Management

Tsu edited this page Jun 5, 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 ? GetStratumAdaptiveChunkSendBudget(stratumChunkSending, serverBudget: true) : int.MaxValue;
int stratumColumnRequestBudget = stratumGenerationBudgetEnabled ? GetStratumAdaptiveChunkGenerationBudget(stratumChunkGeneration, serverBudget: true) : int.MaxValue;

Those budgets are consumed as each connected client is processed.

Adaptive Overload Scaling

Chunk sending and chunk generation can scale down when the recent average server tick exceeds OverloadTickMs.

ChunkSending defaults:

AdaptiveUnderOverload = true;
OverloadTickMs = 45;
OverloadScale = 0.5f;
OverloadFloorServerTick = 64;
OverloadFloorClientTick = 8;

ChunkGeneration defaults:

AdaptiveUnderOverload = true;
OverloadTickMs = 45;
OverloadScale = 0.5f;
OverloadFloorServerTick = 4;
OverloadFloorClientTick = 1;

The helper keeps budgets within a bounded range:

int scaled = (int)Math.Floor(baseBudget * config.OverloadScale);
return Math.Min(baseBudget, Math.Max(floor, scaled));

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, GetStratumAdaptiveChunkSendBudget(stratumChunkSending, serverBudget: false));
num2 = Math.Min(num2, Math.Max(0, stratumChunkBudget));

columnRequestBudget = Math.Min(columnRequestBudget, GetStratumAdaptiveChunkGenerationBudget(stratumChunkGeneration, serverBudget: false));
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(...). The performance report also prints whether adaptive chunk send/generation scaling is enabled and the overload threshold/scale.

Source of Truth

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

Clone this wiki locally