-
-
Notifications
You must be signed in to change notification settings - Fork 6
Feature: Async Pathfinding Workers and Queue Bound
This feature expands pathfinding throughput with additional async workers and bounded queue cleanup.
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:
AsyncWorkerThreadsMaxQueuedMaxTaskAgeMs
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.
- Pathfinding stays async.
- The number of worker threads can scale above one.
- Queue growth can be capped without spending worker time on stale requests.
-
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)