-
-
Notifications
You must be signed in to change notification settings - Fork 4
Feature: Async Pathfinding Workers and Queue Bound
This feature expands pathfinding throughput with additional async workers, bounded queue cleanup, queue priority, and short failure cooldowns.
Main patch:
patches/VSEssentials/Entity/Pathfinding/PathfindingAsync.cs.patch
The patch adds PathfindingAsyncWorker, each with its own AStar instance:
internal class PathfindingAsyncWorker : IAsyncServerSystem
{
private readonly PathfindingAsync owner;
public AStar Astar;
public void OnSeparateThreadTick()
{
owner.ProcessQueue(Astar, 100);
}
}PathfindingAsync still registers the built-in thread:
api.Server.AddServerThread("ai-pathfinding", this);Then Stratum may add more:
for (int i = 0; i < extra; i++)
{
var worker = new PathfindingAsyncWorker(this, api);
stratumExtraWorkers.Add(worker);
api.Server.AddServerThread("ai-pathfinding-" + (i + 2), worker);
}The patch reflectively reads Stratum config from VintagestoryLib to avoid hard compile-time coupling from VSEssentials:
Assembly libAsm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == "VintagestoryLib");
Type runtimeT = libAsm?.GetType("Vintagestory.Server.StratumRuntime");
object cfg = runtimeT?.GetProperty("Config", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null);From Performance.Pathfinding, it reads:
AsyncWorkerThreadsMaxQueuedMaxTaskAgeMsPriorityEnabledPriorityQueueThresholdFarTaskDistanceBlocksDropFarTasksUnderPressureFailureCooldownAfterFailuresFailureCooldownMs
If WorkerThreads <= 0, it falls back to:
workers = Math.Max(2, Environment.ProcessorCount / 2);When MaxQueued > 0, Stratum prunes the queue before enqueueing more work. It drops obsolete work first:
- tasks already marked finished
- tasks older than
MaxTaskAgeMs - tasks whose source entity is gone, dead, inactive, or marked for despawn
Only after stale work is removed does it drop oldest remaining useful work to make room.
if (stratumMaxQueued > 0 && PathfinderTasks.Count >= stratumMaxQueued)
{
StratumPrunePathfinderQueue(forceOneFreeSlot: true);
}
PathfinderTasks.Enqueue(task);Workers also skip obsolete tasks when dequeueing:
while (PathfinderTasks.TryDequeue(out PathfinderTask task))
{
if (!StratumIsObsoleteTask(task, out _))
{
return task;
}
StratumMarkDropped(task);
}Pathfinder tasks carry the owning entity id and enqueue time so this cleanup can be precise.
When PriorityEnabled is on and the queue is at or above PriorityQueueThreshold, Stratum gives nearby owner tasks first shot at worker time. Far tasks can be dropped under pressure when:
-
DropFarTasksUnderPressureis enabled -
FarTaskDistanceBlocksis greater than 0 - the task owner is farther than that distance from players
This keeps active nearby mobs from waiting behind far or stale path work.
PathfinderTask carries Stratum metadata for this:
SourceEntityIdEnqueuedMillisecondsStratumNearestPlayerDistanceSqStratumDropWhenFarUnderPressure
WaypointsTraverser cancels an older queued async goal when the same traverser starts a new one. This avoids spending worker time on a path the entity already stopped needing.
After repeated no-path results, WaypointsTraverser can wait briefly before queueing the same kind of work again:
FailureCooldownAfterFailuresFailureCooldownMs
This is meant for mobs stuck against the same impossible route. A short cooldown cuts queue churn without making normal movement feel delayed.
- Pathfinding stays async.
- The number of worker threads can scale above one.
- Queue growth can be capped without spending worker time on stale requests.
- Nearby work gets priority when the queue is backed up.
- Far path work can be dropped under pressure.
- Repeated failed goals can cool down briefly before retrying.
-
MaxTaskAgeMs = 0disables age-based staleness while leaving owner/finished checks active.
patches/VSEssentials/Entity/Pathfinding/PathfindingAsync.cs.patchpatches/VSEssentials/Entity/Pathfinding/Astar/WaypointsTraverser.cs.patchpatches/VintagestoryApi/Server/PathfinderTask.cs.patchVSEssentials/Entity/Pathfinding/PathfindingAsync.cs-
sources/VintagestoryLib/Vintagestory.Server/StratumConfig.cs(Performance.Pathfinding)