From df858e06d6e84305d31a3022970da35e4dd3f6fa Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Thu, 11 Aug 2022 20:25:24 +0100 Subject: [PATCH] Fix HierarchicalPathFinder failing to consider multiple source locations. When asked to find a path from multiple source locations, the abstract search is used to determine which source locations are viable. Source locations that cannot be reached on the abstract graph are excluded from the local path search. As we know the locations are unreachable, this prevents the local path search from expanding over the entire search space in an attempt to find these unreachable locations, preventing wasted effort. In order to determine these reachable locations, the abstract search is expanded successively trying to reach each source location each time. However, this failed to account for a property of the ExpandToTarget for which a comment is now added. If the location was found previously, then expanding to try and find it again will fail. If the source locations were close together, it was likely that the initial expansions of the search space would have included them, and thus they would not be found on a later expansion. This would mean these locations would incorrectly be thought unreachable. To fix this, we check if the location has already been explored (has CellStatus.Closed in the graph). If so we can check the cost to determine if it is reachable. --- .../Pathfinder/HierarchicalPathFinder.cs | 20 ++++++++++++++----- OpenRA.Mods.Common/Pathfinder/PathSearch.cs | 5 +++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/OpenRA.Mods.Common/Pathfinder/HierarchicalPathFinder.cs b/OpenRA.Mods.Common/Pathfinder/HierarchicalPathFinder.cs index d0333449d7..ba066942cc 100644 --- a/OpenRA.Mods.Common/Pathfinder/HierarchicalPathFinder.cs +++ b/OpenRA.Mods.Common/Pathfinder/HierarchicalPathFinder.cs @@ -629,9 +629,19 @@ namespace OpenRA.Mods.Common.Pathfinder var sourcesWithPathableNodes = new List(sourcesWithReachableNodes.Count); foreach (var source in sourcesWithReachableNodes) { - reverseAbstractSearch.TargetPredicate = cell => cell == source; - if (reverseAbstractSearch.ExpandToTarget()) - sourcesWithPathableNodes.Add(source); + // Check if we have already found a route to this node before we attempt to expand the search. + var sourceStatus = reverseAbstractSearch.Graph[source]; + if (sourceStatus.Status == CellStatus.Closed) + { + if (sourceStatus.CostSoFar != PathGraph.PathCostForInvalidPath) + sourcesWithPathableNodes.Add(source); + } + else + { + reverseAbstractSearch.TargetPredicate = cell => cell == source; + if (reverseAbstractSearch.ExpandToTarget()) + sourcesWithPathableNodes.Add(source); + } } if (sourcesWithPathableNodes.Count == 0) @@ -900,8 +910,8 @@ namespace OpenRA.Mods.Common.Pathfinder var abstractCell = gridInfo.AbstractCellForLocalCell(cell).Value; var info = graph[abstractCell]; - // Expand the abstract search if we have not visited the abstract cell. - if (info.Status == CellStatus.Unvisited) + // Expand the abstract search only if we have yet to get a route to the abstract cell. + if (info.Status != CellStatus.Closed) { abstractSearch.TargetPredicate = c => c == abstractCell; if (!abstractSearch.ExpandToTarget()) diff --git a/OpenRA.Mods.Common/Pathfinder/PathSearch.cs b/OpenRA.Mods.Common/Pathfinder/PathSearch.cs index e8459b928b..e127192856 100644 --- a/OpenRA.Mods.Common/Pathfinder/PathSearch.cs +++ b/OpenRA.Mods.Common/Pathfinder/PathSearch.cs @@ -241,6 +241,11 @@ namespace OpenRA.Mods.Common.Pathfinder /// /// Expands the path search until a path is found, and returns whether a path is found successfully. /// + /// + /// If the path search has previously been expanded it will only return true if a path can be found during + /// *this* expansion of the search. If the search was expanded previously and the target is already + /// then this method will return false. + /// public bool ExpandToTarget() { while (CanExpand())