From e201e410f405455c4e507f6c804a83a924214643 Mon Sep 17 00:00:00 2001 From: Vapre Date: Fri, 16 Jul 2021 01:41:17 +0200 Subject: [PATCH] PathGraph, skip closed cells early. In path finding GetConnections considers connections to already closed cells and calculates the cost for them. The caller afterwards ignores them. These are 15% of all connections. --- OpenRA.Mods.Common/Pathfinder/PathGraph.cs | 30 ++++++++++++------- .../Traits/World/SubterraneanActorLayer.cs | 3 +- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/OpenRA.Mods.Common/Pathfinder/PathGraph.cs b/OpenRA.Mods.Common/Pathfinder/PathGraph.cs index b61a729af1..70abc3c0f8 100644 --- a/OpenRA.Mods.Common/Pathfinder/PathGraph.cs +++ b/OpenRA.Mods.Common/Pathfinder/PathGraph.cs @@ -100,11 +100,11 @@ namespace OpenRA.Mods.Common.Pathfinder groundInfo = pooledLayer.GetLayer(); var locomotorInfo = locomotor.Info; this.locomotor = locomotor; - var layers = world.GetCustomMovementLayers().Values - .Where(cml => cml.EnabledForActor(actor.Info, locomotorInfo)); - foreach (var cml in layers) - customLayerInfo[cml.Index] = (cml, pooledLayer.GetLayer()); + // PERF: Avoid LINQ + foreach (var cml in world.GetCustomMovementLayers().Values) + if (cml.EnabledForActor(actor.Info, locomotorInfo)) + customLayerInfo[cml.Index] = (cml, pooledLayer.GetLayer()); World = world; Actor = actor; @@ -133,7 +133,8 @@ namespace OpenRA.Mods.Common.Pathfinder public List GetConnections(CPos position) { - var info = position.Layer == 0 ? groundInfo : customLayerInfo[position.Layer].Info; + var posLayer = position.Layer; + var info = posLayer == 0 ? groundInfo : customLayerInfo[posLayer].Info; var previousPos = info[position].PreviousPos; var dx = position.X - previousPos.X; @@ -141,16 +142,22 @@ namespace OpenRA.Mods.Common.Pathfinder var index = dy * 3 + dx + 4; var directions = DirectedNeighbors[index]; - var validNeighbors = new List(directions.Length); + var validNeighbors = new List(directions.Length + (posLayer == 0 ? customLayerInfo.Count : 1)); for (var i = 0; i < directions.Length; i++) { - var neighbor = position + directions[i]; - var movementCost = GetCostToNode(neighbor, directions[i]); + var dir = directions[i]; + var neighbor = position + dir; + + // PERF: Skip closed cells already, 15% of all cells + if (info[neighbor].Status == CellStatus.Closed) + continue; + + var movementCost = GetCostToNode(neighbor, dir); if (movementCost != CostForInvalidCell) validNeighbors.Add(new GraphConnection(neighbor, movementCost)); } - if (position.Layer == 0) + if (posLayer == 0) { foreach (var cli in customLayerInfo.Values) { @@ -163,7 +170,7 @@ namespace OpenRA.Mods.Common.Pathfinder else { var layerPosition = new CPos(position.X, position.Y, 0); - var exitCost = customLayerInfo[position.Layer].Layer.ExitMovementCost(Actor.Info, locomotor.Info, layerPosition); + var exitCost = customLayerInfo[posLayer].Layer.ExitMovementCost(Actor.Info, locomotor.Info, layerPosition); if (exitCost != CostForInvalidCell) validNeighbors.Add(new GraphConnection(layerPosition, exitCost)); } @@ -199,8 +206,9 @@ namespace OpenRA.Mods.Common.Pathfinder // Prevent units from jumping over height discontinuities if (checkTerrainHeight && neighborCPos.Layer == 0) { + var heightLayer = World.Map.Height; var from = neighborCPos - direction; - if (Math.Abs(World.Map.Height[neighborCPos] - World.Map.Height[from]) > 1) + if (Math.Abs(heightLayer[neighborCPos] - heightLayer[from]) > 1) return CostForInvalidCell; } diff --git a/OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs b/OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs index bf37579db2..1fa36ea276 100644 --- a/OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs @@ -72,10 +72,9 @@ namespace OpenRA.Mods.Common.Traits return pos + new WVec(0, 0, height[cell] - pos.Z); } - bool ValidTransitionCell(CPos cell, LocomotorInfo li) + bool ValidTransitionCell(CPos cell, SubterraneanLocomotorInfo sli) { var terrainType = map.GetTerrainInfo(cell).Type; - var sli = (SubterraneanLocomotorInfo)li; if (!sli.SubterraneanTransitionTerrainTypes.Contains(terrainType) && sli.SubterraneanTransitionTerrainTypes.Any()) return false;