Skip to content

Commit

Permalink
PathGraph, skip closed cells early.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
anvilvapre committed Jul 15, 2021
1 parent 7bfe83c commit 4e249b8
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 16 deletions.
48 changes: 34 additions & 14 deletions OpenRA.Mods.Common/Pathfinder/PathGraph.cs
Expand Up @@ -94,17 +94,27 @@ sealed class PathGraph : IGraph<CellInfo>
readonly Dictionary<byte, (ICustomMovementLayer Layer, CellLayer<CellInfo> Info)> customLayerInfo =
new Dictionary<byte, (ICustomMovementLayer, CellLayer<CellInfo>)>();

ICustomMovementLayer[] customMovementLayers;

public PathGraph(CellInfoLayerPool layerPool, Locomotor locomotor, Actor actor, World world, BlockedByActor check)
{
pooledLayer = layerPool.Get();
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());
}

// PERF: Store dictionary values as array.
customMovementLayers = new ICustomMovementLayer[customLayerInfo.Count];
var i = 0;
foreach (var cli in customLayerInfo.Values)
customMovementLayers[i++] = cli.Layer;

World = world;
Actor = actor;
Expand Down Expand Up @@ -133,37 +143,45 @@ public PathGraph(CellInfoLayerPool layerPool, Locomotor locomotor, Actor actor,

public List<GraphConnection> 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;
var dy = position.Y - previousPos.Y;
var index = dy * 3 + dx + 4;

var directions = DirectedNeighbors[index];
var validNeighbors = new List<GraphConnection>(directions.Length);
var validNeighbors = new List<GraphConnection>(directions.Length +
(posLayer == 0 ? customMovementLayers.Length : 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)
foreach (var layer in customMovementLayers)
{
var layerPosition = new CPos(position.X, position.Y, cli.Layer.Index);
var entryCost = cli.Layer.EntryMovementCost(Actor.Info, locomotor.Info, layerPosition);
var layerPosition = new CPos(position.X, position.Y, layer.Index);
var entryCost = layer.EntryMovementCost(Actor.Info, locomotor.Info, layerPosition);
if (entryCost != CostForInvalidCell)
validNeighbors.Add(new GraphConnection(layerPosition, entryCost));
}
}
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));
}
Expand Down Expand Up @@ -199,8 +217,9 @@ int CalculateCellCost(CPos neighborCPos, CVec direction, int movementCost)
// 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;
}

Expand Down Expand Up @@ -230,6 +249,7 @@ public void Dispose()
{
groundInfo = null;
customLayerInfo.Clear();
customMovementLayers = null;
pooledLayer.Dispose();
}
}
Expand Down
3 changes: 1 addition & 2 deletions OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs
Expand Up @@ -72,10 +72,9 @@ WPos ICustomMovementLayer.CenterOfCell(CPos cell)
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;

Expand Down

0 comments on commit 4e249b8

Please sign in to comment.