Re-implement parallel for pathfinding crumbs (#12355)
This commit is contained in:
@@ -13,6 +13,11 @@ public sealed class GridPathfindingChunk
|
||||
|
||||
public readonly List<PathPoly>[] Polygons = new List<PathPoly>[SharedPathfindingSystem.ChunkSize * SharedPathfindingSystem.ChunkSize];
|
||||
|
||||
/// <summary>
|
||||
/// Store the recalculated polygons to know what needs changing.
|
||||
/// </summary>
|
||||
internal readonly List<PathPoly>[] BufferPolygons = new List<PathPoly>[SharedPathfindingSystem.ChunkSize * SharedPathfindingSystem.ChunkSize];
|
||||
|
||||
/// <summary>
|
||||
/// The relevant polygon for this chunk's portals
|
||||
/// </summary>
|
||||
@@ -28,6 +33,7 @@ public sealed class GridPathfindingChunk
|
||||
for (var x = 0; x < Polygons.Length; x++)
|
||||
{
|
||||
Polygons[x] = new List<PathPoly>();
|
||||
BufferPolygons[x] = new List<PathPoly>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@ public sealed partial class PathfindingSystem
|
||||
var updateCount = 0;
|
||||
#endif
|
||||
_stopwatch.Restart();
|
||||
var options = new ParallelOptions()
|
||||
{
|
||||
MaxDegreeOfParallelism = _parallel.ParallelProcessCount,
|
||||
};
|
||||
|
||||
// We defer chunk updates because rebuilding a navmesh is hella costly
|
||||
// If we're paused then NPCs can't run anyway.
|
||||
@@ -132,7 +136,7 @@ public sealed partial class PathfindingSystem
|
||||
// This is for map <> grid pathfinding
|
||||
|
||||
// Without parallel this is roughly 3x slower on my desktop.
|
||||
for (var i = 0; i < dirt.Length; i++)
|
||||
Parallel.For(0, dirt.Length, options, i =>
|
||||
{
|
||||
// Doing the queries per task seems faster.
|
||||
var accessQuery = GetEntityQuery<AccessReaderComponent>();
|
||||
@@ -141,8 +145,9 @@ public sealed partial class PathfindingSystem
|
||||
var fixturesQuery = GetEntityQuery<FixturesComponent>();
|
||||
var physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
BuildBreadcrumbs(dirt[i], mapGridComp, accessQuery, destructibleQuery, doorQuery, fixturesQuery, physicsQuery, xformQuery);
|
||||
}
|
||||
BuildBreadcrumbs(dirt[i], mapGridComp, accessQuery, destructibleQuery, doorQuery, fixturesQuery,
|
||||
physicsQuery, xformQuery);
|
||||
});
|
||||
|
||||
const int Division = 4;
|
||||
|
||||
@@ -159,7 +164,7 @@ public sealed partial class PathfindingSystem
|
||||
{
|
||||
var it1 = it;
|
||||
|
||||
Parallel.For(0, dirt.Length, j =>
|
||||
Parallel.For(0, dirt.Length, options, j =>
|
||||
{
|
||||
var chunk = dirt[j];
|
||||
// Check if the chunk is safe on this iteration.
|
||||
@@ -375,13 +380,11 @@ public sealed partial class PathfindingSystem
|
||||
var points = chunk.Points;
|
||||
var gridOrigin = chunk.Origin * ChunkSize;
|
||||
var tileEntities = new ValueList<EntityUid>();
|
||||
|
||||
// TODO: Pool this or something
|
||||
var chunkPolys = new List<PathPoly>[ChunkSize * ChunkSize];
|
||||
var chunkPolys = chunk.BufferPolygons;
|
||||
|
||||
for (var i = 0; i < chunkPolys.Length; i++)
|
||||
{
|
||||
chunkPolys[i] = new List<PathPoly>();
|
||||
chunkPolys[i].Clear();
|
||||
}
|
||||
|
||||
var tilePolys = new ValueList<Box2i>(SubStep);
|
||||
@@ -577,43 +580,6 @@ public sealed partial class PathfindingSystem
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the tiles match
|
||||
for (var x = 0; x < ChunkSize; x++)
|
||||
{
|
||||
for (var y = 0; y < ChunkSize; y++)
|
||||
{
|
||||
var index = x * ChunkSize + y;
|
||||
var polys = chunkPolys[index];
|
||||
var existing = chunk.Polygons[index];
|
||||
|
||||
var isEquivalent = true;
|
||||
|
||||
if (polys.Count == existing.Count)
|
||||
{
|
||||
// May want to update damage or the likes if it's different but not invalidate the ref.
|
||||
for (var i = 0; i < existing.Count; i++)
|
||||
{
|
||||
var ePoly = existing[i];
|
||||
var poly = polys[i];
|
||||
|
||||
if (!ePoly.IsEquivalent(poly))
|
||||
{
|
||||
isEquivalent = false;
|
||||
break;
|
||||
}
|
||||
|
||||
ePoly.Data.Damage = poly.Data.Damage;
|
||||
}
|
||||
|
||||
if (isEquivalent)
|
||||
continue;
|
||||
}
|
||||
|
||||
ClearTilePolys(existing);
|
||||
existing.AddRange(polys);
|
||||
}
|
||||
}
|
||||
|
||||
// _sawmill.Debug($"Built breadcrumbs in {sw.Elapsed.TotalMilliseconds}ms");
|
||||
SendBreadcrumbs(chunk, grid.GridEntityId);
|
||||
}
|
||||
@@ -650,7 +616,48 @@ public sealed partial class PathfindingSystem
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
// After the breadcrumbs step need to determine which polygons need rebuilding. Can't do this above
|
||||
// as we are tampering with neighbor nodes.
|
||||
var chunkPolys = chunk.Polygons;
|
||||
var bufferPolygons = chunk.BufferPolygons;
|
||||
|
||||
for (var x = 0; x < ChunkSize; x++)
|
||||
{
|
||||
for (var y = 0; y < ChunkSize; y++)
|
||||
{
|
||||
var index = x * ChunkSize + y;
|
||||
var polys = bufferPolygons[index];
|
||||
var existing = chunkPolys[index];
|
||||
|
||||
var isEquivalent = true;
|
||||
|
||||
if (polys.Count == existing.Count)
|
||||
{
|
||||
// May want to update damage or the likes if it's different but not invalidate the ref.
|
||||
for (var i = 0; i < existing.Count; i++)
|
||||
{
|
||||
var ePoly = existing[i];
|
||||
var poly = polys[i];
|
||||
|
||||
if (!ePoly.IsEquivalent(poly))
|
||||
{
|
||||
isEquivalent = false;
|
||||
break;
|
||||
}
|
||||
|
||||
ePoly.Data.Damage = poly.Data.Damage;
|
||||
}
|
||||
|
||||
if (isEquivalent)
|
||||
continue;
|
||||
}
|
||||
|
||||
ClearTilePolys(existing);
|
||||
existing.AddRange(polys);
|
||||
}
|
||||
}
|
||||
|
||||
component.Chunks.TryGetValue(chunk.Origin + new Vector2i(-1, 0), out var leftChunk);
|
||||
component.Chunks.TryGetValue(chunk.Origin + new Vector2i(0, -1), out var bottomChunk);
|
||||
component.Chunks.TryGetValue(chunk.Origin + new Vector2i(1, 0), out var rightChunk);
|
||||
|
||||
@@ -15,6 +15,7 @@ using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Threading;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -37,6 +38,7 @@ namespace Content.Server.NPC.Pathfinding
|
||||
|
||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IParallelManager _parallel = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly DestructibleSystem _destructible = default!;
|
||||
|
||||
Reference in New Issue
Block a user