Skip to content

Feature: Chunk Send and Request Management

Tsu edited this page Jun 9, 2026 · 3 revisions

This feature set controls chunk pipeline pressure with explicit budgets, fair per-player sends, outbound pressure checks, 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();

When ChunkSending.FairSchedulingEnabled is on, Stratum also sorts that rotated list by recent chunks sent in the current fairness window. Players with fewer recent sends go first, then lower current chunk radius wins ties. This is mainly for events, server opens, and mass travel where several players are requesting chunks at once.

Config:

  • FairSchedulingEnabled
  • FairWindowMilliseconds
  • NearRingRadiusChunks

The report shows near/far sends as:

Fairness: lastNearFar=... totalNearFar=...

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.

Outbound Pressure Checks

Stratum tracks pending TCP sends on TcpNetConnection:

public int PendingSendCount => Volatile.Read(ref pendingSendCount);
public long PendingSendBytes => Interlocked.Read(ref pendingSendBytes);

If a client is already backed up, ChunkSending.OutboundPressureEnabled can reduce that client's chunk budget for the tick. This is per client, not global, so one slow connection should not force everyone else down.

Config:

  • OutboundPressurePendingSendsSoftLimit
  • OutboundPressurePendingSendsHardLimit
  • OutboundPressurePendingBytesSoftLimit
  • OutboundPressurePendingBytesHardLimit
  • OutboundPressureScale
  • OutboundPressureMinimumClientBudget

The report shows skipped sends as:

skippedClient=... skippedServer=... skippedPressure=...

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 and who still wants them:

request.MarkWanted(client.Id, distanceRing, nowMs);
request.State = state;

Each tracked request keeps:

  • chunk column position
  • first requested time
  • last wanted time
  • requesting client ids
  • approximate distance ring per requester
  • state such as deferred, queued, worker-owned, loaded/sent, or cancelled

The stale-cancel path checks the recorded requesters first. If another connected player still has that column within view range plus MaxDistanceBeyondViewChunks, the request stays queued.

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 includes:

  • last and total chunks sent
  • deferred clients
  • client-cap skips
  • server-cap skips
  • outbound-pressure skips
  • near/far sends
  • tracked wanted columns
  • wanted-by links
  • shared column requests
  • worker-owned tracked requests

Source of Truth

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

Clone this wiki locally