Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abstract docking from Refinery & Harvester #20636

Merged
merged 4 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
96 changes: 0 additions & 96 deletions OpenRA.Mods.Common/Activities/DeliverResources.cs

This file was deleted.

90 changes: 44 additions & 46 deletions OpenRA.Mods.Common/Activities/FindAndDeliverResources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ public class FindAndDeliverResources : Activity
readonly HarvesterInfo harvInfo;
readonly Mobile mobile;
readonly ResourceClaimLayer claimLayer;

Actor deliverActor;
CPos? orderLocation;
CPos? lastHarvestedCell;
bool hasDeliveredLoad;
Expand All @@ -34,19 +32,14 @@ public class FindAndDeliverResources : Activity

public bool LastSearchFailed { get; private set; }

public FindAndDeliverResources(Actor self, Actor deliverActor = null)
public FindAndDeliverResources(Actor self, CPos? orderLocation = null)
{
harv = self.Trait<Harvester>();
harvInfo = self.Info.TraitInfo<HarvesterInfo>();
mobile = self.Trait<Mobile>();
claimLayer = self.World.WorldActor.Trait<ResourceClaimLayer>();
this.deliverActor = deliverActor;
}

public FindAndDeliverResources(Actor self, CPos orderLocation)
: this(self, null)
{
this.orderLocation = orderLocation;
if (orderLocation.HasValue)
this.orderLocation = orderLocation.Value;
}

protected override void OnFirstRun(Actor self)
Expand All @@ -61,15 +54,7 @@ protected override void OnFirstRun(Actor self)
// We have to make sure the actual "harvest" order is not skipped if a third order is queued,
// so we keep deliveredLoad false.
if (harv.IsFull)
QueueChild(new DeliverResources(self));
}

// If an explicit "deliver" order is given, the harvester goes immediately to the refinery.
if (deliverActor != null)
{
QueueChild(new DeliverResources(self, deliverActor));
hasDeliveredLoad = true;
deliverActor = null;
QueueChild(new MoveToDock(self));
}
}

Expand All @@ -92,9 +77,12 @@ public override bool Tick(Actor self)
// Are we full or have nothing more to gather? Deliver resources.
if (harv.IsFull || (!harv.IsEmpty && LastSearchFailed))
{
QueueChild(new DeliverResources(self));
// If we are reserved it means docking was already initiated and we should wait.
if (harv.DockClientManager.ReservedHost != null)
return false;

QueueChild(new MoveToDock(self));
hasDeliveredLoad = true;
return false;
}

// After a failed search, wait and sit still for a bit before searching again.
Expand Down Expand Up @@ -128,13 +116,13 @@ public override bool Tick(Actor self)
// of the refinery entrance.
if (LastSearchFailed)
{
var lastproc = harv.LastLinkedProc ?? harv.LinkedProc;
if (lastproc != null && !lastproc.Disposed)
var lastproc = harv.DockClientManager.LastReservedHost;
if (lastproc != null)
{
var deliveryLoc = lastproc.Trait<IAcceptResources>().DeliveryPosition;
if (self.CenterPosition == deliveryLoc && harv.IsEmpty)
var deliveryLoc = self.World.Map.CellContaining(lastproc.DockPosition);
if (self.Location == deliveryLoc && harv.IsEmpty)
{
var unblockCell = self.World.Map.CellContaining(deliveryLoc) + harv.Info.UnblockCell;
var unblockCell = deliveryLoc + harv.Info.UnblockCell;
var moveTo = mobile.NearestMoveableCell(unblockCell, 1, 5);
QueueChild(mobile.MoveTo(moveTo, 1));
}
Expand Down Expand Up @@ -171,14 +159,31 @@ public override bool Tick(Actor self)
}

// Determine where to search from and how far to search:
var procLoc = GetSearchFromProcLocation();
var searchFromLoc = lastHarvestedCell ?? procLoc ?? self.Location;
var searchRadius = lastHarvestedCell.HasValue ? harvInfo.SearchFromHarvesterRadius : harvInfo.SearchFromProcRadius;
// Prioritise search by these locations in this order: lastHarvestedCell -> lastLinkedDock -> self.
CPos searchFromLoc;
int searchRadius;
WPos? dockPos = null;
if (lastHarvestedCell.HasValue)
{
searchRadius = harvInfo.SearchFromHarvesterRadius;
searchFromLoc = lastHarvestedCell.Value;
}
else
{
searchRadius = harvInfo.SearchFromProcRadius;
var dock = harv.DockClientManager.LastReservedHost;
if (dock != null)
{
dockPos = dock.DockPosition;
searchFromLoc = self.World.Map.CellContaining(dockPos.Value);
}
else
searchFromLoc = self.Location;
}

var searchRadiusSquared = searchRadius * searchRadius;

var map = self.World.Map;
var procPos = procLoc.HasValue ? (WPos?)map.CenterOfCell(procLoc.Value) : null;
var harvPos = self.CenterPosition;

// Find any harvestable resources:
Expand All @@ -196,19 +201,19 @@ public override bool Tick(Actor self)

// Add a cost modifier to harvestable cells to prefer resources that are closer to the refinery.
// This reduces the tendency for harvesters to move in straight lines
if (procPos.HasValue && harvInfo.ResourceRefineryDirectionPenalty > 0 && harv.CanHarvestCell(loc))
if (dockPos.HasValue && harvInfo.ResourceRefineryDirectionPenalty > 0 && harv.CanHarvestCell(loc))
{
var pos = map.CenterOfCell(loc);

// Calculate harv-cell-refinery angle (cosine rule)
var b = pos - procPos.Value;
var b = pos - dockPos.Value;

if (b != WVec.Zero)
{
var c = pos - harvPos;
if (c != WVec.Zero)
{
var a = harvPos - procPos.Value;
var a = harvPos - dockPos.Value;
var cosA = (int)(512 * (b.LengthSquared + c.LengthSquared - a.LengthSquared) / b.Length / c.Length);

// Cost modifier varies between 0 and ResourceRefineryDirectionPenalty
Expand Down Expand Up @@ -239,19 +244,12 @@ public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)

if (orderLocation != null)
yield return new TargetLineNode(Target.FromCell(self.World, orderLocation.Value), harvInfo.HarvestLineColor);
else if (deliverActor != null)
yield return new TargetLineNode(Target.FromActor(deliverActor), harvInfo.DeliverLineColor);
}

CPos? GetSearchFromProcLocation()
{
if (harv.LastLinkedProc != null && !harv.LastLinkedProc.IsDead && harv.LastLinkedProc.IsInWorld)
return harv.LastLinkedProc.World.Map.CellContaining(harv.LastLinkedProc.Trait<IAcceptResources>().DeliveryPosition);

if (harv.LinkedProc != null && !harv.LinkedProc.IsDead && harv.LinkedProc.IsInWorld)
return harv.LinkedProc.World.Map.CellContaining(harv.LinkedProc.Trait<IAcceptResources>().DeliveryPosition);

return null;
else
{
var manager = harv.DockClientManager;
if (manager.ReservedHostActor != null)
yield return new TargetLineNode(Target.FromActor(manager.ReservedHostActor), manager.DockLineColor);
}
}
}
}