-
-
Notifications
You must be signed in to change notification settings - Fork 4
Feature: Chunk Send and Request Management
This feature set controls chunk pipeline pressure with explicit budgets, fair per-player sends, outbound pressure checks, and stale-request cleanup.
Main patch:
patches/VintagestoryLib/Vintagestory.Server/ServerSystemSendChunks.cs.patch
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.
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));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:
FairSchedulingEnabledFairWindowMillisecondsNearRingRadiusChunks
The report shows near/far sends as:
Fairness: lastNearFar=... totalNearFar=...
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.
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:
OutboundPressurePendingSendsSoftLimitOutboundPressurePendingSendsHardLimitOutboundPressurePendingBytesSoftLimitOutboundPressurePendingBytesHardLimitOutboundPressureScaleOutboundPressureMinimumClientBudget
The report shows skipped sends as:
skippedClient=... skippedServer=... skippedPressure=...
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.EnabledPrioritizeMovingDirectionForwardPredictionBlocks > 0- movement speed is above
MinimumMovementSpeed
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++;
}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
patches/VintagestoryLib/Vintagestory.Server/ServerSystemSendChunks.cs.patchpatches/VintagestoryLib/Vintagestory.Server.Network/TcpNetConnection.cs.patch-
sources/VintagestoryLib/Vintagestory.Server/StratumConfig.cs(Performance.ChunkSending,ChunkGeneration,ChunkRequestManagement) wiki/Performance.md