Fix PathFinder.FindPathToTargetCells.

When this hits the case that "As both ends are accessible, we can freely swap them." - we must note that we are reversing the path search and pass the information into the HierarchicalPathFinder. When a normal path search occurs, the actor trying to pathfind will never check its own location - and thus never gets blocked by itself. When a search is reversed, the search will check the actors location. If we inform the search it is doing done in reverse, it will special case this scenario and avoid the actor blocking itself. But if it is not told about this scenario, then this special case is not applied and no path will be found when in fact a path is possible.
This commit is contained in:
RoosterDragon
2024-07-06 10:26:21 +01:00
committed by Gustas
parent c24913ea24
commit 1cd3e1bf3f
2 changed files with 25 additions and 21 deletions

View File

@@ -414,7 +414,7 @@ namespace OpenRA.Mods.Common.Pathfinder
{ {
var src = accessibleCells.First(); var src = accessibleCells.First();
using (var search = GetLocalPathSearch( using (var search = GetLocalPathSearch(
null, new[] { src }, src, customCost, null, BlockedByActor.None, false, grid, 100)) null, new[] { src }, src, customCost, null, BlockedByActor.None, false, grid, 100, null, false, null))
{ {
var localCellsInRegion = search.ExpandAll(); var localCellsInRegion = search.ExpandAll();
var abstractCell = AbstractCellForLocalCells(localCellsInRegion, gridLayer); var abstractCell = AbstractCellForLocalCells(localCellsInRegion, gridLayer);
@@ -725,7 +725,7 @@ namespace OpenRA.Mods.Common.Pathfinder
/// </summary> /// </summary>
public List<CPos> FindPath(Actor self, IReadOnlyCollection<CPos> sources, CPos target, public List<CPos> FindPath(Actor self, IReadOnlyCollection<CPos> sources, CPos target,
BlockedByActor check, int heuristicWeightPercentage, Func<CPos, int> customCost, BlockedByActor check, int heuristicWeightPercentage, Func<CPos, int> customCost,
Actor ignoreActor, bool laneBias, PathFinderOverlay pathFinderOverlay) Actor ignoreActor, bool inReverse, bool laneBias, PathFinderOverlay pathFinderOverlay)
{ {
if (costEstimator == null) if (costEstimator == null)
return PathFinder.NoPath; return PathFinder.NoPath;
@@ -812,8 +812,9 @@ namespace OpenRA.Mods.Common.Pathfinder
{ {
using (var fromSrc = GetLocalPathSearch( using (var fromSrc = GetLocalPathSearch(
self, sourcesWithPathableNodes, target, customCost, ignoreActor, check, laneBias, null, heuristicWeightPercentage, self, sourcesWithPathableNodes, target, customCost, ignoreActor, check, laneBias, null, heuristicWeightPercentage,
heuristic: Heuristic(reverseAbstractSearch, estimatedSearchSize, sourcesWithPathableNodes, unpathableNodes), Heuristic(reverseAbstractSearch, estimatedSearchSize, sourcesWithPathableNodes, unpathableNodes),
recorder: pathFinderOverlay?.RecordLocalEdges(self))) inReverse,
pathFinderOverlay?.RecordLocalEdges(self)))
return fromSrc.FindPath(); return fromSrc.FindPath();
} }
} }
@@ -825,7 +826,7 @@ namespace OpenRA.Mods.Common.Pathfinder
/// </summary> /// </summary>
public List<CPos> FindPath(Actor self, CPos source, CPos target, public List<CPos> FindPath(Actor self, CPos source, CPos target,
BlockedByActor check, int heuristicWeightPercentage, Func<CPos, int> customCost, BlockedByActor check, int heuristicWeightPercentage, Func<CPos, int> customCost,
Actor ignoreActor, bool laneBias, PathFinderOverlay pathFinderOverlay) Actor ignoreActor, bool inReverse, bool laneBias, PathFinderOverlay pathFinderOverlay)
{ {
if (costEstimator == null) if (costEstimator == null)
return PathFinder.NoPath; return PathFinder.NoPath;
@@ -851,7 +852,9 @@ namespace OpenRA.Mods.Common.Pathfinder
List<CPos> localPath; List<CPos> localPath;
using (var search = GetLocalPathSearch( using (var search = GetLocalPathSearch(
self, new[] { source }, target, customCost, ignoreActor, check, laneBias, gridToSearch, heuristicWeightPercentage, self, new[] { source }, target, customCost, ignoreActor, check, laneBias, gridToSearch, heuristicWeightPercentage,
recorder: pathFinderOverlay?.RecordLocalEdges(self))) null,
inReverse,
pathFinderOverlay?.RecordLocalEdges(self)))
localPath = search.FindPath(); localPath = search.FindPath();
if (localPath.Count > 0) if (localPath.Count > 0)
@@ -872,7 +875,7 @@ namespace OpenRA.Mods.Common.Pathfinder
// Call the other overload which can handle this scenario. // Call the other overload which can handle this scenario.
var sourceAbstractCell = AbstractCellForLocalCell(source); var sourceAbstractCell = AbstractCellForLocalCell(source);
if (sourceAbstractCell == null) if (sourceAbstractCell == null)
return FindPath(self, new[] { source }, target, check, heuristicWeightPercentage, customCost, ignoreActor, laneBias, pathFinderOverlay); return FindPath(self, new[] { source }, target, check, heuristicWeightPercentage, customCost, ignoreActor, inReverse, laneBias, pathFinderOverlay);
// If the source and target belong to different domains, there is no path. // If the source and target belong to different domains, there is no path.
RebuildDomains(); RebuildDomains();
@@ -903,13 +906,14 @@ namespace OpenRA.Mods.Common.Pathfinder
using (var fromSrc = GetLocalPathSearch( using (var fromSrc = GetLocalPathSearch(
self, new[] { source }, target, customCost, ignoreActor, check, laneBias, null, heuristicWeightPercentage, self, new[] { source }, target, customCost, ignoreActor, check, laneBias, null, heuristicWeightPercentage,
heuristic: Heuristic(reverseAbstractSearch, estimatedSearchSize, null, null), Heuristic(reverseAbstractSearch, estimatedSearchSize, null, null),
recorder: pathFinderOverlay?.RecordLocalEdges(self))) inReverse,
pathFinderOverlay?.RecordLocalEdges(self)))
using (var fromDest = GetLocalPathSearch( using (var fromDest = GetLocalPathSearch(
self, new[] { target }, source, customCost, ignoreActor, check, laneBias, null, heuristicWeightPercentage, self, new[] { target }, source, customCost, ignoreActor, check, laneBias, null, heuristicWeightPercentage,
heuristic: Heuristic(forwardAbstractSearch, estimatedSearchSize, null, null), Heuristic(forwardAbstractSearch, estimatedSearchSize, null, null),
inReverse: true, !inReverse,
recorder: pathFinderOverlay?.RecordLocalEdges(self))) pathFinderOverlay?.RecordLocalEdges(self)))
return PathSearch.FindBidiPath(fromDest, fromSrc); return PathSearch.FindBidiPath(fromDest, fromSrc);
} }
} }
@@ -1258,9 +1262,9 @@ namespace OpenRA.Mods.Common.Pathfinder
PathSearch GetLocalPathSearch( PathSearch GetLocalPathSearch(
Actor self, IEnumerable<CPos> srcs, CPos dst, Func<CPos, int> customCost, Actor self, IEnumerable<CPos> srcs, CPos dst, Func<CPos, int> customCost,
Actor ignoreActor, BlockedByActor check, bool laneBias, Grid? grid, int heuristicWeightPercentage, Actor ignoreActor, BlockedByActor check, bool laneBias, Grid? grid, int heuristicWeightPercentage,
Func<CPos, bool, int> heuristic = null, Func<CPos, bool, int> heuristic,
bool inReverse = false, bool inReverse,
PathSearch.IRecorder recorder = null) PathSearch.IRecorder recorder)
{ {
return PathSearch.ToTargetCell( return PathSearch.ToTargetCell(
world, locomotor, self, srcs, dst, check, heuristicWeightPercentage, world, locomotor, self, srcs, dst, check, heuristicWeightPercentage,

View File

@@ -94,7 +94,7 @@ namespace OpenRA.Mods.Common.Traits
Actor ignoreActor = null, Actor ignoreActor = null,
bool laneBias = true) bool laneBias = true)
{ {
return FindPathToTarget(self, sources.ToList(), target, check, customCost, ignoreActor, laneBias); return FindPathToTarget(self, sources.ToList(), target, check, customCost, ignoreActor, false, laneBias);
} }
/// <summary> /// <summary>
@@ -149,7 +149,7 @@ namespace OpenRA.Mods.Common.Traits
if (sourceIsAccessible) if (sourceIsAccessible)
{ {
// As both ends are accessible, we can freely swap them. // As both ends are accessible, we can freely swap them.
path = FindPathToTarget(self, targetsList, source, check, customCost, ignoreActor, laneBias); path = FindPathToTarget(self, targetsList, source, check, customCost, ignoreActor, true, laneBias);
} }
else else
{ {
@@ -171,7 +171,7 @@ namespace OpenRA.Mods.Common.Traits
List<CPos> FindPathToTarget( List<CPos> FindPathToTarget(
Actor self, List<CPos> sources, CPos target, BlockedByActor check, Actor self, List<CPos> sources, CPos target, BlockedByActor check,
Func<CPos, int> customCost, Actor ignoreActor, bool laneBias) Func<CPos, int> customCost, Actor ignoreActor, bool inReverse, bool laneBias)
{ {
if (sources.Count == 0) if (sources.Count == 0)
return NoPath; return NoPath;
@@ -181,7 +181,7 @@ namespace OpenRA.Mods.Common.Traits
// If the target cell is inaccessible, bail early. // If the target cell is inaccessible, bail early.
// The destination cell must allow movement and also have a reachable movement cost. // The destination cell must allow movement and also have a reachable movement cost.
if (!PathSearch.CellAllowsMovement(self.World, locomotor, target, customCost) if (!PathSearch.CellAllowsMovement(self.World, locomotor, target, customCost)
|| locomotor.MovementCostToEnterCell(self, target, check, ignoreActor) == PathGraph.MovementCostForUnreachableCell) || locomotor.MovementCostToEnterCell(self, target, check, ignoreActor, inReverse) == PathGraph.MovementCostForUnreachableCell)
return NoPath; return NoPath;
// When searching from only one source cell, some optimizations are possible. // When searching from only one source cell, some optimizations are possible.
@@ -201,12 +201,12 @@ namespace OpenRA.Mods.Common.Traits
// Use a hierarchical path search, which performs a guided bidirectional search. // Use a hierarchical path search, which performs a guided bidirectional search.
return GetHierarchicalPathFinder(locomotor, check, ignoreActor).FindPath( return GetHierarchicalPathFinder(locomotor, check, ignoreActor).FindPath(
self, source, target, check, DefaultHeuristicWeightPercentage, customCost, ignoreActor, laneBias, pathFinderOverlay); self, source, target, check, DefaultHeuristicWeightPercentage, customCost, ignoreActor, inReverse, laneBias, pathFinderOverlay);
} }
// Use a hierarchical path search, which performs a guided unidirectional search. // Use a hierarchical path search, which performs a guided unidirectional search.
return GetHierarchicalPathFinder(locomotor, check, ignoreActor).FindPath( return GetHierarchicalPathFinder(locomotor, check, ignoreActor).FindPath(
self, sources, target, check, DefaultHeuristicWeightPercentage, customCost, ignoreActor, laneBias, pathFinderOverlay); self, sources, target, check, DefaultHeuristicWeightPercentage, customCost, ignoreActor, inReverse, laneBias, pathFinderOverlay);
} }
HierarchicalPathFinder GetHierarchicalPathFinder(Locomotor locomotor, BlockedByActor check, Actor ignoreActor) HierarchicalPathFinder GetHierarchicalPathFinder(Locomotor locomotor, BlockedByActor check, Actor ignoreActor)