diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index e0cc610688..e8f0c5ddd5 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -504,7 +504,7 @@ - + diff --git a/OpenRA.Mods.Common/Pathfinder/BasePathSearch.cs b/OpenRA.Mods.Common/Pathfinder/BasePathSearch.cs index 57fb3c3cad..fab51285a3 100644 --- a/OpenRA.Mods.Common/Pathfinder/BasePathSearch.cs +++ b/OpenRA.Mods.Common/Pathfinder/BasePathSearch.cs @@ -18,18 +18,11 @@ namespace OpenRA.Mods.Common.Pathfinder { public interface IPathSearch { - string Id { get; } - /// /// The Graph used by the A* /// IGraph Graph { get; } - /// - /// The open queue where nodes that are worth to consider are stored by their estimator - /// - IPriorityQueue OpenQueue { get; } - /// /// Stores the analyzed nodes by the expand function /// @@ -64,6 +57,7 @@ namespace OpenRA.Mods.Common.Pathfinder /// Whether the location is a target bool IsTarget(CPos location); + bool CanExpand { get; } CPos Expand(); } @@ -71,44 +65,13 @@ namespace OpenRA.Mods.Common.Pathfinder { public IGraph Graph { get; set; } - // The Id of a Pathsearch is computed by its properties. - // So two PathSearch instances with the same parameters will - // Compute the same Id. This is used for caching purposes. - public string Id - { - get - { - if (string.IsNullOrEmpty(id)) - { - var builder = new StringBuilder(); - builder.Append(Graph.Actor.ActorID); - while (!startPoints.Empty) - { - var startpoint = startPoints.Pop(); - builder.Append(startpoint.X); - builder.Append(startpoint.Y); - builder.Append(Graph[startpoint].EstimatedTotal); - } - - builder.Append(Graph.InReverse); - if (Graph.IgnoredActor != null) builder.Append(Graph.IgnoredActor.ActorID); - builder.Append(Graph.LaneBias); - - id = builder.ToString(); - } - - return id; - } - } - - public IPriorityQueue OpenQueue { get; protected set; } + protected IPriorityQueue OpenQueue { get; private set; } public abstract IEnumerable> Considered { get; } public Player Owner { get { return Graph.Actor.Owner; } } public int MaxCost { get; protected set; } public bool Debug { get; set; } - string id; protected Func heuristic; protected Func isGoal; @@ -117,13 +80,13 @@ namespace OpenRA.Mods.Common.Pathfinder // points considered and their Heuristics to reach // the target. It pretty match identifies, in conjunction of the Actor, // a deterministic set of calculations - protected IPriorityQueue startPoints; + protected readonly IPriorityQueue StartPoints; protected BasePathSearch(IGraph graph) { Graph = graph; - OpenQueue = new PriorityQueue(new PositionComparer(Graph)); - startPoints = new PriorityQueue(new PositionComparer(Graph)); + OpenQueue = new PriorityQueue(GraphConnection.ConnectionCostComparer); + StartPoints = new PriorityQueue(GraphConnection.ConnectionCostComparer); Debug = false; MaxCost = 0; } @@ -198,6 +161,7 @@ namespace OpenRA.Mods.Common.Pathfinder return isGoal(location); } + public bool CanExpand { get { return !OpenQueue.Empty; } } public abstract CPos Expand(); } } diff --git a/OpenRA.Mods.Common/Pathfinder/CellInfo.cs b/OpenRA.Mods.Common/Pathfinder/CellInfo.cs index 57f3e9329e..a8112bc343 100644 --- a/OpenRA.Mods.Common/Pathfinder/CellInfo.cs +++ b/OpenRA.Mods.Common/Pathfinder/CellInfo.cs @@ -57,22 +57,4 @@ namespace OpenRA.Mods.Common.Pathfinder EstimatedTotal = estimatedTotal; } } - - /// - /// Compares two nodes according to their estimations - /// - public class PositionComparer : IComparer - { - readonly IGraph graph; - - public PositionComparer(IGraph graph) - { - this.graph = graph; - } - - public int Compare(CPos x, CPos y) - { - return Math.Sign(graph[x].EstimatedTotal - graph[y].EstimatedTotal); - } - } } diff --git a/OpenRA.Mods.Common/Pathfinder/PathFinderCacheDecorator.cs b/OpenRA.Mods.Common/Pathfinder/PathFinderUnitPathCacheDecorator.cs similarity index 71% rename from OpenRA.Mods.Common/Pathfinder/PathFinderCacheDecorator.cs rename to OpenRA.Mods.Common/Pathfinder/PathFinderUnitPathCacheDecorator.cs index f4fad6cf99..1aeaf768ac 100644 --- a/OpenRA.Mods.Common/Pathfinder/PathFinderCacheDecorator.cs +++ b/OpenRA.Mods.Common/Pathfinder/PathFinderUnitPathCacheDecorator.cs @@ -16,14 +16,14 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Pathfinder { /// - /// A decorator used to cache the pathfinder (Decorator design pattern) + /// A decorator used to cache FindUnitPath and FindUnitPathToRange (Decorator design pattern) /// - public class PathFinderCacheDecorator : IPathFinder + public class PathFinderUnitPathCacheDecorator : IPathFinder { readonly IPathFinder pathFinder; readonly ICacheStorage> cacheStorage; - public PathFinderCacheDecorator(IPathFinder pathFinder, ICacheStorage> cacheStorage) + public PathFinderUnitPathCacheDecorator(IPathFinder pathFinder, ICacheStorage> cacheStorage) { this.pathFinder = pathFinder; this.cacheStorage = cacheStorage; @@ -68,37 +68,13 @@ namespace OpenRA.Mods.Common.Pathfinder public List FindPath(IPathSearch search) { using (new PerfSample("Pathfinder")) - { - var key = "FindPath" + search.Id; - var cachedPath = cacheStorage.Retrieve(key); - - if (cachedPath != null) - return cachedPath; - - var pb = pathFinder.FindPath(search); - - cacheStorage.Store(key, pb); - - return pb; - } + return pathFinder.FindPath(search); } public List FindBidiPath(IPathSearch fromSrc, IPathSearch fromDest) { using (new PerfSample("Pathfinder")) - { - var key = "FindBidiPath" + fromSrc.Id + fromDest.Id; - var cachedPath = cacheStorage.Retrieve(key); - - if (cachedPath != null) - return cachedPath; - - var pb = pathFinder.FindBidiPath(fromSrc, fromDest); - - cacheStorage.Store(key, pb); - - return pb; - } + return pathFinder.FindBidiPath(fromSrc, fromDest); } } } diff --git a/OpenRA.Mods.Common/Pathfinder/PathGraph.cs b/OpenRA.Mods.Common/Pathfinder/PathGraph.cs index 3204b5282e..268e1331c2 100644 --- a/OpenRA.Mods.Common/Pathfinder/PathGraph.cs +++ b/OpenRA.Mods.Common/Pathfinder/PathGraph.cs @@ -47,6 +47,18 @@ namespace OpenRA.Mods.Common.Pathfinder public struct GraphConnection { + public static readonly CostComparer ConnectionCostComparer = CostComparer.Instance; + + public sealed class CostComparer : IComparer + { + public static readonly CostComparer Instance = new CostComparer(); + CostComparer() { } + public int Compare(GraphConnection x, GraphConnection y) + { + return x.Cost.CompareTo(y.Cost); + } + } + public readonly CPos Destination; public readonly int Cost; diff --git a/OpenRA.Mods.Common/Pathfinder/PathSearch.cs b/OpenRA.Mods.Common/Pathfinder/PathSearch.cs index 254317d030..c4f5355f7d 100644 --- a/OpenRA.Mods.Common/Pathfinder/PathSearch.cs +++ b/OpenRA.Mods.Common/Pathfinder/PathSearch.cs @@ -84,9 +84,11 @@ namespace OpenRA.Mods.Common.Pathfinder protected override void AddInitialCell(CPos location) { - Graph[location] = new CellInfo(0, heuristic(location), location, CellStatus.Open); - OpenQueue.Add(location); - startPoints.Add(location); + var cost = heuristic(location); + Graph[location] = new CellInfo(0, cost, location, CellStatus.Open); + var connection = new GraphConnection(location, cost); + OpenQueue.Add(connection); + StartPoints.Add(connection); considered.AddLast(new Pair(location, 0)); } @@ -99,7 +101,7 @@ namespace OpenRA.Mods.Common.Pathfinder /// The most promising node of the iteration public override CPos Expand() { - var currentMinNode = OpenQueue.Pop(); + var currentMinNode = OpenQueue.Pop().Destination; var currentCell = Graph[currentMinNode]; Graph[currentMinNode] = new CellInfo(currentCell.CostSoFar, currentCell.EstimatedTotal, currentCell.PreviousPos, CellStatus.Closed); @@ -128,10 +130,11 @@ namespace OpenRA.Mods.Common.Pathfinder else hCost = heuristic(neighborCPos); - Graph[neighborCPos] = new CellInfo(gCost, gCost + hCost, currentMinNode, CellStatus.Open); + var estimatedCost = gCost + hCost; + Graph[neighborCPos] = new CellInfo(gCost, estimatedCost, currentMinNode, CellStatus.Open); if (neighborCell.Status != CellStatus.Open) - OpenQueue.Add(neighborCPos); + OpenQueue.Add(new GraphConnection(neighborCPos, estimatedCost)); if (Debug) { diff --git a/OpenRA.Mods.Common/Traits/World/PathFinder.cs b/OpenRA.Mods.Common/Traits/World/PathFinder.cs index 70e71fcfc6..405f2b2a28 100644 --- a/OpenRA.Mods.Common/Traits/World/PathFinder.cs +++ b/OpenRA.Mods.Common/Traits/World/PathFinder.cs @@ -22,7 +22,7 @@ namespace OpenRA.Mods.Common.Traits { public object Create(ActorInitializer init) { - return new PathFinderCacheDecorator(new PathFinder(init.World), new PathCacheStorage(init.World)); + return new PathFinderUnitPathCacheDecorator(new PathFinder(init.World), new PathCacheStorage(init.World)); } } @@ -121,7 +121,7 @@ namespace OpenRA.Mods.Common.Traits List path = null; - while (!search.OpenQueue.Empty) + while (search.CanExpand) { var p = search.Expand(); if (search.IsTarget(p)) @@ -156,7 +156,7 @@ namespace OpenRA.Mods.Common.Traits fromDest.Debug = true; } - while (!fromSrc.OpenQueue.Empty && !fromDest.OpenQueue.Empty) + while (fromSrc.CanExpand && fromDest.CanExpand) { // make some progress on the first search var p = fromSrc.Expand();