Speed up AutoTarget.ChooseTarget among groups of allied units.

Most auto target scans will be conducted among groups of allied units unable to target each other because they are allied and their weapons only target enemies. Since they cannot target each other, the scan will be repeated constantly. Realising this, we can significantly reduce the performance impact of auto target scanning by bailing early in this scenario to avoid carrying out expensive targeting checks on friendly units which we know will fail anyway.
This commit is contained in:
RoosterDragon
2016-01-03 00:12:37 +00:00
parent 7acd71cd7d
commit adc7e902e3
2 changed files with 27 additions and 3 deletions

View File

@@ -287,6 +287,17 @@ namespace OpenRA.Mods.Common.Traits
&& (target.IsInRange(self.CenterPosition, GetMaximumRange()) || (allowMove && self.Info.HasTraitInfo<IMoveInfo>()));
}
public Stance UnforcedAttackTargetStances()
{
// PERF: Avoid LINQ.
var stances = Stance.None;
foreach (var armament in Armaments)
if (!armament.IsTraitDisabled)
stances |= armament.Info.TargetStances;
return stances;
}
class AttackOrderTargeter : IOrderTargeter
{
readonly AttackBase ab;

View File

@@ -140,8 +140,14 @@ namespace OpenRA.Mods.Common.Traits
if (nextScanTime <= 0)
{
nextScanTime = self.World.SharedRandom.Next(info.MinimumScanTimeInterval, info.MaximumScanTimeInterval);
var range = info.ScanRadius > 0 ? WDist.FromCells(info.ScanRadius) : attack.GetMaximumRange();
return ChooseTarget(self, range, allowMove);
// If we can't attack right now, there's no need to try and find a target.
var attackStances = attack.UnforcedAttackTargetStances();
if (attackStances != OpenRA.Traits.Stance.None)
{
var range = info.ScanRadius > 0 ? WDist.FromCells(info.ScanRadius) : attack.GetMaximumRange();
return ChooseTarget(self, attackStances, range, allowMove);
}
}
return null;
@@ -162,12 +168,19 @@ namespace OpenRA.Mods.Common.Traits
attack.AttackTarget(target, false, allowMove);
}
Actor ChooseTarget(Actor self, WDist range, bool allowMove)
Actor ChooseTarget(Actor self, Stance attackStances, WDist range, bool allowMove)
{
var actorsByArmament = new Dictionary<Armament, List<Actor>>();
var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, range);
foreach (var actor in actorsInRange)
{
// PERF: Most units can only attack enemy units. If this is the case but the target is not an enemy, we
// can bail early and avoid the more expensive targeting checks and armament selection. For groups of
// allied units, this helps significantly reduce the cost of auto target scans. This is important as
// these groups will continuously rescan their allies until an enemy finally comes into range.
if (attackStances == OpenRA.Traits.Stance.Enemy && !actor.AppearsHostileTo(self))
continue;
if (PreventsAutoTarget(self, actor) || !self.Owner.CanTargetActor(actor))
continue;