diff --git a/OpenRA.Mods.Common/Pathfinder/PathSearch.cs b/OpenRA.Mods.Common/Pathfinder/PathSearch.cs index e127192856..9a57aa007c 100644 --- a/OpenRA.Mods.Common/Pathfinder/PathSearch.cs +++ b/OpenRA.Mods.Common/Pathfinder/PathSearch.cs @@ -48,7 +48,7 @@ namespace OpenRA.Mods.Common.Pathfinder foreach (var sl in froms) if (world.Map.Contains(sl)) - search.AddInitialCell(sl); + search.AddInitialCell(sl, customCost); return search; } @@ -75,7 +75,7 @@ namespace OpenRA.Mods.Common.Pathfinder foreach (var sl in froms) if (world.Map.Contains(sl)) - search.AddInitialCell(sl); + search.AddInitialCell(sl, customCost); return search; } @@ -87,7 +87,7 @@ namespace OpenRA.Mods.Common.Pathfinder var graph = new SparsePathGraph(edges, estimatedSearchSize); var search = new PathSearch(graph, DefaultCostEstimator(locomotor, target), 100, loc => loc == target, recorder); - search.AddInitialCell(from); + search.AddInitialCell(from, null); return search; } @@ -162,10 +162,18 @@ namespace OpenRA.Mods.Common.Pathfinder openQueue = new PriorityQueue(GraphConnection.ConnectionCostComparer); } - void AddInitialCell(CPos location) + void AddInitialCell(CPos location, Func customCost) { + var initialCost = 0; + if (customCost != null) + { + initialCost = customCost(location); + if (initialCost == PathGraph.PathCostForInvalidPath) + return; + } + var estimatedCost = heuristic(location) * heuristicWeightPercentage / 100; - Graph[location] = new CellInfo(CellStatus.Open, 0, estimatedCost, location); + Graph[location] = new CellInfo(CellStatus.Open, initialCost, initialCost + estimatedCost, location); var connection = new GraphConnection(location, estimatedCost); openQueue.Add(connection); } diff --git a/OpenRA.Mods.Common/Traits/Harvester.cs b/OpenRA.Mods.Common/Traits/Harvester.cs index 163421cc52..3fbe209927 100644 --- a/OpenRA.Mods.Common/Traits/Harvester.cs +++ b/OpenRA.Mods.Common/Traits/Harvester.cs @@ -15,7 +15,6 @@ using System.Collections.ObjectModel; using System.Linq; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; -using OpenRA.Mods.Common.Pathfinder; using OpenRA.Primitives; using OpenRA.Traits; @@ -183,6 +182,7 @@ namespace OpenRA.Mods.Common.Traits public Actor ClosestProc(Actor self, Actor ignore) { // Find all refineries and their occupancy count: + // Exclude refineries with too many harvesters clogging the delivery location. var refineries = self.World.ActorsWithTrait() .Where(r => r.Actor != ignore && r.Actor.Owner == self.Owner && IsAcceptableProcType(r.Actor)) .Select(r => new @@ -190,28 +190,28 @@ namespace OpenRA.Mods.Common.Traits Location = r.Actor.Location + r.Trait.DeliveryOffset, Actor = r.Actor, Occupancy = self.World.ActorsHavingTrait(h => h.LinkedProc == r.Actor).Count() - }).ToLookup(r => r.Location); + }) + .Where(r => r.Occupancy < Info.MaxUnloadQueue) + .ToDictionary(r => r.Location); + + if (refineries.Count == 0) + return null; // Start a search from each refinery's delivery location: var path = mobile.PathFinder.FindPathToTargetCell( self, refineries.Select(r => r.Key), self.Location, BlockedByActor.None, location => { - if (!refineries.Contains(location)) + if (!refineries.ContainsKey(location)) return 0; - var occupancy = refineries[location].First().Occupancy; - - // Too many harvesters clogs up the refinery's delivery location: - if (occupancy >= Info.MaxUnloadQueue) - return PathGraph.PathCostForInvalidPath; - // Prefer refineries with less occupancy (multiplier is to offset distance cost): + var occupancy = refineries[location].Occupancy; return occupancy * Info.UnloadQueueCostModifier; }); if (path.Count > 0) - return refineries[path.Last()].First().Actor; + return refineries[path.Last()].Actor; return null; } diff --git a/OpenRA.Mods.Common/Traits/World/PathFinder.cs b/OpenRA.Mods.Common/Traits/World/PathFinder.cs index 7a699fb0ec..d3e18ba674 100644 --- a/OpenRA.Mods.Common/Traits/World/PathFinder.cs +++ b/OpenRA.Mods.Common/Traits/World/PathFinder.cs @@ -102,7 +102,9 @@ namespace OpenRA.Mods.Common.Traits // For adjacent cells on the same layer, we can return the path without invoking a full search. if (source.Layer == target.Layer && (source - target).LengthSquared < 3) { - if (!world.Map.Contains(source)) + // If the source cell is inaccessible, there is no path. + if (!world.Map.Contains(source) || + (customCost != null && customCost(source) == PathGraph.PathCostForInvalidPath)) return NoPath; return new List(2) { target, source }; }