From 0555ce932137b53c83d71cda7dce4cc25e8d04a4 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Sat, 17 Mar 2018 14:18:40 +0000 Subject: [PATCH] Reduce allocations in AutoTarget.ChooseTarget. - Cache active target query. - Prefer .Count == 0 over Any when working with Lists. - Use helper for GetEnabledTargetTypes. - Don't declare target variable until actually needed. --- OpenRA.Mods.Common/Traits/AutoTarget.cs | 29 ++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/AutoTarget.cs b/OpenRA.Mods.Common/Traits/AutoTarget.cs index 4ef49b737b..c82193f055 100644 --- a/OpenRA.Mods.Common/Traits/AutoTarget.cs +++ b/OpenRA.Mods.Common/Traits/AutoTarget.cs @@ -98,7 +98,7 @@ namespace OpenRA.Mods.Common.Traits UnitStance stance; ConditionManager conditionManager; - AutoTargetPriority[] targetPriorities; + IEnumerable activeTargetPriorities; int conditionToken = ConditionManager.InvalidConditionToken; public void SetStance(Actor self, UnitStance value) @@ -140,8 +140,14 @@ namespace OpenRA.Mods.Common.Traits void INotifyCreated.Created(Actor self) { + // AutoTargetPriority and their Priorities are fixed - so we can safely cache them with ToArray. + // IsTraitEnabled can change over time, and so must appear after the ToArray so it gets re-evaluated each time. + activeTargetPriorities = + self.TraitsImplementing() + .OrderByDescending(ati => ati.Info.Priority).ToArray() + .Where(Exts.IsTraitEnabled).Select(atp => atp.Info); + conditionManager = self.TraitOrDefault(); - targetPriorities = self.TraitsImplementing().ToArray(); ApplyStanceCondition(self); } @@ -263,12 +269,8 @@ namespace OpenRA.Mods.Common.Traits var chosenTargetPriority = int.MinValue; int chosenTargetRange = 0; - var activePriorities = targetPriorities.Where(Exts.IsTraitEnabled) - .Select(at => at.Info) - .OrderByDescending(ati => ati.Priority) - .ToList(); - - if (!activePriorities.Any()) + var activePriorities = activeTargetPriorities.ToList(); + if (activePriorities.Count == 0) return null; var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, scanRange); @@ -282,11 +284,7 @@ namespace OpenRA.Mods.Common.Traits continue; // Check whether we can auto-target this actor - var targetTypes = actor.TraitsImplementing() - .Where(Exts.IsTraitEnabled).SelectMany(t => t.TargetTypes) - .ToHashSet(); - - var target = Target.FromActor(actor); + var targetTypes = actor.GetEnabledTargetTypes().ToArray(); var validPriorities = activePriorities.Where(ati => { // Already have a higher priority target @@ -294,16 +292,17 @@ namespace OpenRA.Mods.Common.Traits return false; // Incompatible target types - if (!targetTypes.Overlaps(ati.ValidTargets) || targetTypes.Overlaps(ati.InvalidTargets)) + if (!ati.ValidTargets.Overlaps(targetTypes) || ati.InvalidTargets.Overlaps(targetTypes)) return false; return true; }).ToList(); - if (!validPriorities.Any() || PreventsAutoTarget(self, actor) || !actor.CanBeViewedByPlayer(self.Owner)) + if (validPriorities.Count == 0 || PreventsAutoTarget(self, actor) || !actor.CanBeViewedByPlayer(self.Owner)) continue; // Make sure that we can actually fire on the actor + var target = Target.FromActor(actor); var armaments = ab.ChooseArmamentsForTarget(target, false); if (!allowMove) armaments = armaments.Where(arm =>