diff --git a/OpenRA.Mods.Common/Traits/BotModules/Squads/States/GroundStates.cs b/OpenRA.Mods.Common/Traits/BotModules/Squads/States/GroundStates.cs index 82e5d4c6c2..500f5cb7f1 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/Squads/States/GroundStates.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/Squads/States/GroundStates.cs @@ -68,6 +68,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads class GroundUnitsAttackMoveState : GroundStateBase, IState { + int lastUpdatedTick; + CPos? lastLeaderLocation; + Actor lastTarget; + public void Activate(Squad owner) { } public void Tick(Squad owner) @@ -91,6 +95,27 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads if (leader == null) return; + if (leader.Location != lastLeaderLocation) + { + lastLeaderLocation = leader.Location; + lastUpdatedTick = owner.World.WorldTick; + } + + if (owner.TargetActor != lastTarget) + { + lastTarget = owner.TargetActor; + lastUpdatedTick = owner.World.WorldTick; + } + + // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds + // This works around the squad being stuck trying to attack-move to a location + // that they cannot path to, generating expensive pathfinding calls each tick. + if (owner.World.WorldTick > lastUpdatedTick + 63) + { + owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsIdleState(), true); + return; + } + var ownUnits = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.Units.Count) / 3) .Where(a => a.Owner == owner.Units.First().Owner && owner.Units.Contains(a)).ToHashSet(); @@ -126,6 +151,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads class GroundUnitsAttackState : GroundStateBase, IState { + int lastUpdatedTick; + CPos? lastLeaderLocation; + Actor lastTarget; + public void Activate(Squad owner) { } public void Tick(Squad owner) @@ -145,6 +174,28 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads } } + var leader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition); + if (leader.Location != lastLeaderLocation) + { + lastLeaderLocation = leader.Location; + lastUpdatedTick = owner.World.WorldTick; + } + + if (owner.TargetActor != lastTarget) + { + lastTarget = owner.TargetActor; + lastUpdatedTick = owner.World.WorldTick; + } + + // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds + // This works around the squad being stuck trying to attack-move to a location + // that they cannot path to, generating expensive pathfinding calls each tick. + if (owner.World.WorldTick > lastUpdatedTick + 63) + { + owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsIdleState(), true); + return; + } + foreach (var a in owner.Units) if (!BusyAttack(a)) owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false)); diff --git a/OpenRA.Mods.Common/Traits/BotModules/Squads/States/NavyStates.cs b/OpenRA.Mods.Common/Traits/BotModules/Squads/States/NavyStates.cs index 637f6b6add..bee0d32e12 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/Squads/States/NavyStates.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/Squads/States/NavyStates.cs @@ -93,6 +93,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads class NavyUnitsAttackMoveState : NavyStateBase, IState { + int lastUpdatedTick; + CPos? lastLeaderLocation; + Actor lastTarget; + public void Activate(Squad owner) { } public void Tick(Squad owner) @@ -116,6 +120,27 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads if (leader == null) return; + if (leader.Location != lastLeaderLocation) + { + lastLeaderLocation = leader.Location; + lastUpdatedTick = owner.World.WorldTick; + } + + if (owner.TargetActor != lastTarget) + { + lastTarget = owner.TargetActor; + lastUpdatedTick = owner.World.WorldTick; + } + + // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds + // This works around the squad being stuck trying to attack-move to a location + // that they cannot path to, generating expensive pathfinding calls each tick. + if (owner.World.WorldTick > lastUpdatedTick + 63) + { + owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsIdleState(), true); + return; + } + var ownUnits = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.Units.Count) / 3) .Where(a => a.Owner == owner.Units.First().Owner && owner.Units.Contains(a)).ToHashSet(); @@ -151,6 +176,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads class NavyUnitsAttackState : NavyStateBase, IState { + int lastUpdatedTick; + CPos? lastLeaderLocation; + Actor lastTarget; + public void Activate(Squad owner) { } public void Tick(Squad owner) @@ -170,6 +199,28 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads } } + var leader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition); + if (leader.Location != lastLeaderLocation) + { + lastLeaderLocation = leader.Location; + lastUpdatedTick = owner.World.WorldTick; + } + + if (owner.TargetActor != lastTarget) + { + lastTarget = owner.TargetActor; + lastUpdatedTick = owner.World.WorldTick; + } + + // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds + // This works around the squad being stuck trying to attack-move to a location + // that they cannot path to, generating expensive pathfinding calls each tick. + if (owner.World.WorldTick > lastUpdatedTick + 63) + { + owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsIdleState(), true); + return; + } + foreach (var a in owner.Units) if (!BusyAttack(a)) owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false));