diff --git a/OpenRA.Mods.Common/Pathfinder/HierarchicalPathFinder.cs b/OpenRA.Mods.Common/Pathfinder/HierarchicalPathFinder.cs
index 31959e36d7..4521944d3f 100644
--- a/OpenRA.Mods.Common/Pathfinder/HierarchicalPathFinder.cs
+++ b/OpenRA.Mods.Common/Pathfinder/HierarchicalPathFinder.cs
@@ -146,12 +146,21 @@ namespace OpenRA.Mods.Common.Pathfinder
///
/// Maps a local cell to a abstract node in the graph.
/// Returns null when the local cell is unreachable.
+ /// Pass a null to skip cost checks if the caller already checked.
///
- public CPos? AbstractCellForLocalCell(CPos localCell)
+ public CPos? AbstractCellForLocalCell(CPos localCell, HierarchicalPathFinder hpf)
{
var abstractCell = singleAbstractCellForLayer[localCell.Layer];
if (abstractCell != null)
+ {
+ // All reachable cells in the grid are joined together so only a single abstract cell was needed,
+ // but there may be unreachable cells in the grid which we must exclude.
+ if (hpf != null && !hpf.CellIsAccessible(localCell))
+ return null;
return abstractCell;
+ }
+
+ // Only reachable cells would be populated in the lookup, so no need to check their cost.
if (localCellToAbstractCell.TryGetValue(localCell, out var abstractCellFromMap))
return abstractCellFromMap;
return null;
@@ -461,13 +470,11 @@ namespace OpenRA.Mods.Common.Pathfinder
if (!MovementAllowedBetweenCells(cell, candidateCell))
return;
- var gridInfo = gridInfos[GridIndex(cell)];
- var abstractCell = gridInfo.AbstractCellForLocalCell(cell);
+ var abstractCell = AbstractCellForLocalCellNoAccessibleCheck(cell);
if (abstractCell == null)
return;
- var gridInfoAdjacent = gridInfos[GridIndex(candidateCell)];
- var abstractCellAdjacent = gridInfoAdjacent.AbstractCellForLocalCell(candidateCell);
+ var abstractCellAdjacent = AbstractCellForLocalCellNoAccessibleCheck(candidateCell);
if (abstractCellAdjacent == null)
return;
@@ -877,12 +884,10 @@ namespace OpenRA.Mods.Common.Pathfinder
RebuildDomains();
- var sourceGridInfo = gridInfos[GridIndex(source)];
- var targetGridInfo = gridInfos[GridIndex(target)];
- var abstractSource = sourceGridInfo.AbstractCellForLocalCell(source);
+ var abstractSource = AbstractCellForLocalCell(source);
if (abstractSource == null)
return false;
- var abstractTarget = targetGridInfo.AbstractCellForLocalCell(target);
+ var abstractTarget = AbstractCellForLocalCell(target);
if (abstractTarget == null)
return false;
var sourceDomain = abstractDomains[abstractSource.Value];
@@ -999,11 +1004,22 @@ namespace OpenRA.Mods.Common.Pathfinder
}
///
- /// Maps a local cell to a abstract node in the graph.
- /// Returns null when the local cell is unreachable.
+ /// Maps a local cell to a abstract node in the graph. Returns null when the local cell is unreachable.
///
- CPos? AbstractCellForLocalCell(CPos localCell) =>
- gridInfos[GridIndex(localCell)].AbstractCellForLocalCell(localCell);
+ CPos? AbstractCellForLocalCell(CPos localCell)
+ {
+ return gridInfos[GridIndex(localCell)].AbstractCellForLocalCell(localCell, this);
+ }
+
+ ///
+ /// Maps a local cell to a abstract node in the graph. Returns null when the local cell is unreachable.
+ /// Skips the check, if it has already been performed.
+ /// If an accessible check has not been performed, call instead.
+ ///
+ CPos? AbstractCellForLocalCellNoAccessibleCheck(CPos localCell)
+ {
+ return gridInfos[GridIndex(localCell)].AbstractCellForLocalCell(localCell, null);
+ }
///
/// Creates a from the to the .
@@ -1035,8 +1051,7 @@ namespace OpenRA.Mods.Common.Pathfinder
// If the exceptions here do fire, they indicate a bug. The abstract graph is considering a cell to be
// unreachable, but the local pathfinder thinks it is reachable. We must fix the abstract graph to also
// consider the cell to be reachable.
- var gridInfo = gridInfos[GridIndex(cell)];
- var maybeAbstractCell = gridInfo.AbstractCellForLocalCell(cell);
+ var maybeAbstractCell = AbstractCellForLocalCellNoAccessibleCheck(cell);
if (maybeAbstractCell == null)
throw new Exception(
"The abstract path should never be searched for an unreachable point. " +