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

Introduce MoveCooldownHelper to prevent lag spikes from failed pathfinding #21391

Open
wants to merge 1 commit into
base: bleed
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions OpenRA.Mods.Cnc/Activities/LeapAttack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class LeapAttack : Activity, IActivityNotifyStanceChanged
readonly bool allowMovement;
readonly bool forceAttack;
readonly Color? targetLineColor;
readonly MoveCooldownHelper moveCooldownHelper;

Target target;
Target lastVisibleTarget;
Expand All @@ -47,6 +48,7 @@ public LeapAttack(Actor self, in Target target, bool allowMovement, bool forceAt
this.allowMovement = allowMovement;
this.forceAttack = forceAttack;
mobile = self.Trait<Mobile>();
moveCooldownHelper = new MoveCooldownHelper(self.World, mobile);

// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
Expand Down Expand Up @@ -92,6 +94,10 @@ public override bool Tick(Actor self)

useLastVisibleTarget = targetIsHiddenActor || !target.IsValidFor(self);

var result = moveCooldownHelper.Tick(targetIsHiddenActor);
if (result != null)
return result.Value;

// Target is hidden or dead, and we don't have a fallback position to move towards
if (useLastVisibleTarget && !lastVisibleTarget.IsValidFor(self))
return true;
Expand All @@ -104,6 +110,7 @@ public override bool Tick(Actor self)
if (!allowMovement || lastVisibleMaxRange == WDist.Zero || lastVisibleMaxRange < lastVisibleMinRange)
return true;

moveCooldownHelper.NotifyMoveQueued();
QueueChild(mobile.MoveWithinRange(target, lastVisibleMinRange, lastVisibleMaxRange, checkTarget.CenterPosition, Color.Red));
return false;
}
Expand Down
19 changes: 9 additions & 10 deletions OpenRA.Mods.Common/Activities/Attack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ protected enum AttackStatus { UnableToAttack, NeedsToTurn, NeedsToMove, Attackin
readonly IPositionable positionable;
readonly bool forceAttack;
readonly Color? targetLineColor;
readonly MoveCooldownHelper moveCooldownHelper;

protected Target target;
Target lastVisibleTarget;
WDist lastVisibleMaximumRange;
BitSet<TargetableType> lastVisibleTargetTypes;
Player lastVisibleOwner;
bool useLastVisibleTarget;
bool wasMovingWithinRange;

WDist minRange;
WDist maxRange;
Expand All @@ -61,6 +61,8 @@ public Attack(Actor self, in Target target, bool allowMovement, bool forceAttack
mobile = iMove as Mobile;
move = allowMovement ? iMove : null;

moveCooldownHelper = new MoveCooldownHelper(self.World, mobile);

// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
Expand Down Expand Up @@ -114,16 +116,14 @@ public override bool Tick(Actor self)

useLastVisibleTarget = targetIsHiddenActor || !target.IsValidFor(self);

// If we are ticking again after previously sequencing a MoveWithRange then that move must have completed
// Either we are in range and can see the target, or we've lost track of it and should give up
if (wasMovingWithinRange && targetIsHiddenActor)
return true;
var result = moveCooldownHelper.Tick(targetIsHiddenActor);
if (result != null)
return result.Value;

// Target is hidden or dead, and we don't have a fallback position to move towards
if (useLastVisibleTarget && !lastVisibleTarget.IsValidFor(self))
return true;

wasMovingWithinRange = false;
var pos = self.CenterPosition;
var checkTarget = useLastVisibleTarget ? lastVisibleTarget : target;

Expand All @@ -135,7 +135,7 @@ public override bool Tick(Actor self)
return true;

// Move towards the last known position
wasMovingWithinRange = true;
moveCooldownHelper.NotifyMoveQueued();
QueueChild(move.MoveWithinRange(target, WDist.Zero, lastVisibleMaximumRange, checkTarget.CenterPosition, Color.Red));
return false;
}
Expand All @@ -148,9 +148,6 @@ public override bool Tick(Actor self)
attack.IsAiming = status == AttackStatus.Attacking || status == AttackStatus.NeedsToTurn;
}

if (attackStatus.HasFlag(AttackStatus.NeedsToMove))
wasMovingWithinRange = true;

if (attackStatus >= AttackStatus.NeedsToTurn)
return false;

Expand Down Expand Up @@ -185,6 +182,7 @@ protected virtual AttackStatus TickAttack(Actor self, AttackFrontal attack)
var sightRange = rs != null ? rs.Range : WDist.FromCells(2);

attackStatus |= AttackStatus.NeedsToMove;
moveCooldownHelper.NotifyMoveQueued();
QueueChild(move.MoveWithinRange(target, sightRange, target.CenterPosition, Color.Red));
return AttackStatus.NeedsToMove;
}
Expand Down Expand Up @@ -218,6 +216,7 @@ protected virtual AttackStatus TickAttack(Actor self, AttackFrontal attack)
return AttackStatus.UnableToAttack;

attackStatus |= AttackStatus.NeedsToMove;
moveCooldownHelper.NotifyMoveQueued();
var checkTarget = useLastVisibleTarget ? lastVisibleTarget : target;
QueueChild(move.MoveWithinRange(target, minRange, maxRange, checkTarget.CenterPosition, Color.Red));
return AttackStatus.NeedsToMove;
Expand Down
9 changes: 9 additions & 0 deletions OpenRA.Mods.Common/Activities/Enter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum EnterState { Approaching, Entering, Exiting, Finished }

readonly IMove move;
readonly Color? targetLineColor;
readonly MoveCooldownHelper moveCooldownHelper;

Target target;
Target lastVisibleTarget;
Expand All @@ -37,6 +38,7 @@ protected Enter(Actor self, in Target target, Color? targetLineColor = null)
this.target = target;
this.targetLineColor = targetLineColor;
ChildHasPriority = false;
moveCooldownHelper = new MoveCooldownHelper(self.World, move as Mobile) { RetryIfDestinationBlocked = true };
}

/// <summary>
Expand Down Expand Up @@ -72,6 +74,10 @@ public override bool Tick(Actor self)
if (!IsCanceling && useLastVisibleTarget && lastState == EnterState.Entering)
Cancel(self, true);

var result = moveCooldownHelper.Tick(targetIsHiddenActor);
if (result != null)
return result.Value;

TickInner(self, target, useLastVisibleTarget);

// We need to wait for movement to finish before transitioning to
Expand All @@ -97,6 +103,7 @@ public override bool Tick(Actor self)
if (target.Type != TargetType.Invalid && !move.CanEnterTargetNow(self, target))
{
// Target lines are managed by this trait, so we do not pass targetLineColor
moveCooldownHelper.NotifyMoveQueued();
var initialTargetPosition = (useLastVisibleTarget ? lastVisibleTarget : target).CenterPosition;
QueueChild(move.MoveToTarget(self, target, initialTargetPosition));
return false;
Expand All @@ -110,6 +117,7 @@ public override bool Tick(Actor self)
// Are we ready to move into the target?
if (TryStartEnter(self, target.Actor))
{
moveCooldownHelper.NotifyMoveQueued();
lastState = EnterState.Entering;
QueueChild(move.MoveIntoTarget(self, target));
return false;
Expand All @@ -136,6 +144,7 @@ public override bool Tick(Actor self)

case EnterState.Exiting:
{
moveCooldownHelper.NotifyMoveQueued();
QueueChild(move.ReturnToCell(self));
lastState = EnterState.Finished;
return false;
Expand Down
7 changes: 7 additions & 0 deletions OpenRA.Mods.Common/Activities/HarvestResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class HarvestResource : Activity
readonly IMove move;
readonly CPos targetCell;
readonly INotifyHarvestAction[] notifyHarvestActions;
readonly MoveCooldownHelper moveCooldownHelper;

public HarvestResource(Actor self, CPos targetCell)
{
Expand All @@ -40,6 +41,7 @@ public HarvestResource(Actor self, CPos targetCell)
resourceLayer = self.World.WorldActor.Trait<IResourceLayer>();
this.targetCell = targetCell;
notifyHarvestActions = self.TraitsImplementing<INotifyHarvestAction>().ToArray();
moveCooldownHelper = new MoveCooldownHelper(self.World, move as Mobile);
}

protected override void OnFirstRun(Actor self)
Expand All @@ -58,12 +60,17 @@ public override bool Tick(Actor self)
if (IsCanceling || harv.IsFull)
return true;

var result = moveCooldownHelper.Tick(false);
if (result != null)
return result.Value;

// Move towards the target cell
if (self.Location != targetCell)
{
foreach (var n in notifyHarvestActions)
n.MovingToResources(self, targetCell);

moveCooldownHelper.NotifyMoveQueued();
QueueChild(move.MoveTo(targetCell, 0));
return false;
}
Expand Down
8 changes: 8 additions & 0 deletions OpenRA.Mods.Common/Activities/LayMines.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class LayMines : Activity
readonly IMove movement;
readonly IMoveInfo moveInfo;
readonly RearmableInfo rearmableInfo;
readonly MoveCooldownHelper moveCooldownHelper;

List<CPos> minefield;
bool returnToBase;
Expand All @@ -39,6 +40,7 @@ public LayMines(Actor self, List<CPos> minefield = null)
movement = self.Trait<IMove>();
moveInfo = self.Info.TraitInfo<IMoveInfo>();
rearmableInfo = self.Info.TraitInfoOrDefault<RearmableInfo>();
moveCooldownHelper = new MoveCooldownHelper(self.World, movement as Mobile);
this.minefield = minefield;
}

Expand Down Expand Up @@ -70,6 +72,10 @@ public override bool Tick(Actor self)
return true;
}

var result = moveCooldownHelper.Tick(false);
if (result != null)
return result.Value;

if (layingMine)
{
layingMine = false;
Expand Down Expand Up @@ -98,6 +104,7 @@ public override bool Tick(Actor self)
return true;

// Add a CloseEnough range of 512 to the Rearm/Repair activities in order to ensure that we're at the host actor
moveCooldownHelper.NotifyMoveQueued();
QueueChild(new MoveAdjacentTo(self, Target.FromActor(rearmTarget)));
QueueChild(movement.MoveTo(self.World.Map.CellContaining(rearmTarget.CenterPosition), ignoreActor: rearmTarget));
QueueChild(new Resupply(self, rearmTarget, new WDist(512)));
Expand Down Expand Up @@ -125,6 +132,7 @@ public override bool Tick(Actor self)
var nextCell = NextValidCell(self);
if (nextCell != null)
{
moveCooldownHelper.NotifyMoveQueued();
QueueChild(movement.MoveTo(nextCell.Value, 0));
return false;
}
Expand Down
14 changes: 6 additions & 8 deletions OpenRA.Mods.Common/Activities/Move/Follow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public class Follow : Activity
readonly WDist maxRange;
readonly IMove move;
readonly Color? targetLineColor;
readonly MoveCooldownHelper moveCooldownHelper;
Target target;
Target lastVisibleTarget;
bool useLastVisibleTarget;
bool wasMovingWithinRange;

public Follow(Actor self, in Target target, WDist minRange, WDist maxRange,
WPos? initialTargetPosition, Color? targetLineColor = null)
Expand All @@ -36,6 +36,7 @@ public class Follow : Activity
this.maxRange = maxRange;
this.targetLineColor = targetLineColor;
move = self.Trait<IMove>();
moveCooldownHelper = new MoveCooldownHelper(self.World, move as Mobile) { RetryIfDestinationBlocked = true };

// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
Expand All @@ -57,12 +58,9 @@ public override bool Tick(Actor self)

useLastVisibleTarget = targetIsHiddenActor || !target.IsValidFor(self);

// If we are ticking again after previously sequencing a MoveWithRange then that move must have completed
// Either we are in range and can see the target, or we've lost track of it and should give up
if (wasMovingWithinRange && targetIsHiddenActor)
return true;

wasMovingWithinRange = false;
var result = moveCooldownHelper.Tick(targetIsHiddenActor);
if (result != null)
return result.Value;

// Target is hidden or dead, and we don't have a fallback position to move towards
if (useLastVisibleTarget && !lastVisibleTarget.IsValidFor(self))
Expand All @@ -77,7 +75,7 @@ public override bool Tick(Actor self)
return useLastVisibleTarget;

// Move into range
wasMovingWithinRange = true;
moveCooldownHelper.NotifyMoveQueued();
QueueChild(move.MoveWithinRange(target, minRange, maxRange, checkTarget.CenterPosition, targetLineColor));
return false;
}
Expand Down