Improved the performance and intelligence of resource harvesting by
refactoring the Harvesters' pathfinding. Now they in first place assess which is the closest resource inside their search area and then a path is calculated Changed the way harvesters find resources by always trying to find the closest resource to their refinery. Changed the strategy of finding to find resources in Annulus.
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
@@ -58,91 +57,108 @@ namespace OpenRA.Mods.Common.Activities
|
||||
if (harv.IsFull)
|
||||
return Util.SequenceActivities(deliver, NextActivity);
|
||||
|
||||
var closestHarvestablePosition = ClosestHarvestablePos(self);
|
||||
|
||||
// If no harvestable position could be found, either deliver the remaining resources
|
||||
// or get out of the way and do not disturb.
|
||||
if (!closestHarvestablePosition.HasValue)
|
||||
{
|
||||
if (!harv.IsEmpty)
|
||||
return deliver;
|
||||
|
||||
var cachedPosition = self.Location;
|
||||
harv.UnblockRefinery(self);
|
||||
|
||||
// Only do this if UnblockRefinery did nothing.
|
||||
if (self.Location == cachedPosition)
|
||||
{
|
||||
var unblockCell = harv.LastHarvestedCell ?? (self.Location + new CVec(0, 4));
|
||||
var moveTo = mobile.NearestMoveableCell(unblockCell, 2, 5);
|
||||
self.QueueActivity(mobile.MoveTo(moveTo, 1));
|
||||
self.SetTargetLine(Target.FromCell(self.World, moveTo), Color.Gray, false);
|
||||
}
|
||||
|
||||
var randFrames = self.World.SharedRandom.Next(100, 175);
|
||||
return Util.SequenceActivities(NextActivity, new Wait(randFrames), this);
|
||||
}
|
||||
else
|
||||
{
|
||||
var next = this;
|
||||
|
||||
// Attempt to claim a resource as ours
|
||||
if (territory != null)
|
||||
{
|
||||
if (!territory.ClaimResource(self, closestHarvestablePosition.Value))
|
||||
return Util.SequenceActivities(new Wait(25), next);
|
||||
}
|
||||
|
||||
// If not given a direct order, assume ordered to the first resource location we find:
|
||||
if (!harv.LastOrderLocation.HasValue)
|
||||
harv.LastOrderLocation = closestHarvestablePosition;
|
||||
|
||||
self.SetTargetLine(Target.FromCell(self.World, closestHarvestablePosition.Value), Color.Red, false);
|
||||
|
||||
var notify = self.TraitsImplementing<INotifyHarvesterAction>();
|
||||
|
||||
foreach (var n in notify)
|
||||
n.MovingToResources(self, closestHarvestablePosition.Value, next);
|
||||
|
||||
return Util.SequenceActivities(mobile.MoveTo(closestHarvestablePosition.Value, 1), new HarvestResource(self), next);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsHarvestable(Actor self, CPos pos)
|
||||
{
|
||||
var resType = resLayer.GetResource(pos);
|
||||
if (resType == null)
|
||||
return false;
|
||||
|
||||
// Can the harvester collect this kind of resource?
|
||||
if (!harvInfo.Resources.Contains(resType.Info.Name))
|
||||
return false;
|
||||
|
||||
if (territory != null)
|
||||
{
|
||||
// Another harvester has claimed this resource:
|
||||
ResourceClaim claim;
|
||||
if (territory.IsClaimedByAnyoneElse(self as Actor, pos, out claim))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the closest harvestable pos between the current position of the harvester
|
||||
/// and the last order location
|
||||
/// </summary>
|
||||
CPos? ClosestHarvestablePos(Actor self)
|
||||
{
|
||||
// Determine where to search from and how far to search:
|
||||
var searchFromLoc = harv.LastOrderLocation ?? (harv.LastLinkedProc ?? harv.LinkedProc ?? self).Location;
|
||||
var searchRadius = harv.LastOrderLocation.HasValue ? harvInfo.SearchFromOrderRadius : harvInfo.SearchFromProcRadius;
|
||||
var searchRadiusSquared = searchRadius * searchRadius;
|
||||
|
||||
// Find harvestable resources nearby:
|
||||
var path = pathFinder.FindPath(
|
||||
PathSearch.Search(self.World, mobileInfo, self, true)
|
||||
.WithHeuristic(loc =>
|
||||
{
|
||||
// Avoid this cell:
|
||||
if (avoidCell.HasValue && loc == avoidCell.Value)
|
||||
return EstimateDistance(loc, searchFromLoc) + Constants.CellCost;
|
||||
|
||||
// Don't harvest out of range:
|
||||
var distSquared = (loc - searchFromLoc).LengthSquared;
|
||||
if (distSquared > searchRadiusSquared)
|
||||
return EstimateDistance(loc, searchFromLoc) + Constants.CellCost * 2;
|
||||
|
||||
// Get the resource at this location:
|
||||
var resType = resLayer.GetResource(loc);
|
||||
if (resType == null)
|
||||
return EstimateDistance(loc, searchFromLoc) + Constants.CellCost;
|
||||
|
||||
// Can the harvester collect this kind of resource?
|
||||
if (!harvInfo.Resources.Contains(resType.Info.Name))
|
||||
return EstimateDistance(loc, searchFromLoc) + Constants.CellCost;
|
||||
|
||||
if (territory != null)
|
||||
{
|
||||
// Another harvester has claimed this resource:
|
||||
ResourceClaim claim;
|
||||
if (territory.IsClaimedByAnyoneElse(self, loc, out claim))
|
||||
return EstimateDistance(loc, searchFromLoc) + Constants.CellCost;
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
.FromPoint(self.Location));
|
||||
|
||||
var next = this;
|
||||
|
||||
if (path.Count == 0)
|
||||
{
|
||||
if (!harv.IsEmpty)
|
||||
return deliver;
|
||||
else
|
||||
var search = PathSearch.Search(self.World, mobileInfo, self, true,
|
||||
loc => IsHarvestable(self, loc))
|
||||
.WithCustomCost(loc =>
|
||||
{
|
||||
// Get out of the way if we are:
|
||||
harv.UnblockRefinery(self);
|
||||
var randFrames = self.World.SharedRandom.Next(90, 160);
|
||||
if (NextActivity != null)
|
||||
return Util.SequenceActivities(NextActivity, new Wait(randFrames), next);
|
||||
else
|
||||
return Util.SequenceActivities(new Wait(randFrames), next);
|
||||
}
|
||||
}
|
||||
if ((avoidCell.HasValue && loc == avoidCell.Value) ||
|
||||
(loc - self.Location).LengthSquared > searchRadiusSquared)
|
||||
return int.MaxValue;
|
||||
|
||||
// Attempt to claim a resource as ours:
|
||||
if (territory != null)
|
||||
{
|
||||
if (!territory.ClaimResource(self, path[0]))
|
||||
return Util.SequenceActivities(new Wait(25), next);
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.FromPoint(self.Location)
|
||||
.FromPoint(searchFromLoc);
|
||||
|
||||
// If not given a direct order, assume ordered to the first resource location we find:
|
||||
if (harv.LastOrderLocation == null)
|
||||
harv.LastOrderLocation = path[0];
|
||||
// Find any harvestable resources:
|
||||
var path = pathFinder.FindPath(search);
|
||||
|
||||
self.SetTargetLine(Target.FromCell(self.World, path[0]), Color.Red, false);
|
||||
if (path.Count > 0)
|
||||
return path[0];
|
||||
|
||||
var notify = self.TraitsImplementing<INotifyHarvesterAction>();
|
||||
foreach (var n in notify)
|
||||
n.MovingToResources(self, path[0], next);
|
||||
|
||||
return Util.SequenceActivities(mobile.MoveTo(path[0], 1), new HarvestResource(self), next);
|
||||
}
|
||||
|
||||
// Diagonal distance heuristic
|
||||
static int EstimateDistance(CPos here, CPos destination)
|
||||
{
|
||||
var diag = Math.Min(Math.Abs(here.X - destination.X), Math.Abs(here.Y - destination.Y));
|
||||
var straight = Math.Abs(here.X - destination.X) + Math.Abs(here.Y - destination.Y);
|
||||
|
||||
return Constants.CellCost * straight + (Constants.DiagonalCellCost - 2 * Constants.CellCost) * diag;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IEnumerable<Target> GetTargets(Actor self)
|
||||
|
||||
Reference in New Issue
Block a user