diff --git a/OpenRA.Game/Exts.cs b/OpenRA.Game/Exts.cs index da09d912a4..aa9015ab20 100644 --- a/OpenRA.Game/Exts.cs +++ b/OpenRA.Game/Exts.cs @@ -538,6 +538,26 @@ namespace OpenRA return default; } + public static T FirstEnabledConditionalTraitOrDefault(this IEnumerable ts) where T : IDisabledTrait + { + // PERF: Avoid LINQ. + foreach (var t in ts) + if (!t.IsTraitDisabled) + return t; + + return default(T); + } + + public static T FirstEnabledConditionalTraitOrDefault(this T[] ts) where T : IDisabledTrait + { + // PERF: Avoid LINQ. + foreach (var t in ts) + if (!t.IsTraitDisabled) + return t; + + return default(T); + } + public static LineSplitEnumerator SplitLines(this string str, char separator) { return new LineSplitEnumerator(str.AsSpan(), separator); diff --git a/OpenRA.Mods.Cnc/Scripting/Properties/ChronosphereProperties.cs b/OpenRA.Mods.Cnc/Scripting/Properties/ChronosphereProperties.cs index df2b621d31..5064cdaf2b 100644 --- a/OpenRA.Mods.Cnc/Scripting/Properties/ChronosphereProperties.cs +++ b/OpenRA.Mods.Cnc/Scripting/Properties/ChronosphereProperties.cs @@ -37,7 +37,7 @@ namespace OpenRA.Mods.Cnc.Scripting } var cs = actor.TraitsImplementing() - .FirstEnabledTraitOrDefault(); + .FirstEnabledConditionalTraitOrDefault(); if (cs != null && cs.CanChronoshiftTo(actor, cell)) cs.Teleport(actor, cell, duration, killCargo, Self); diff --git a/OpenRA.Mods.Cnc/Traits/SupportPowers/ChronoshiftPower.cs b/OpenRA.Mods.Cnc/Traits/SupportPowers/ChronoshiftPower.cs index 25178791ea..40abca1cef 100644 --- a/OpenRA.Mods.Cnc/Traits/SupportPowers/ChronoshiftPower.cs +++ b/OpenRA.Mods.Cnc/Traits/SupportPowers/ChronoshiftPower.cs @@ -90,7 +90,7 @@ namespace OpenRA.Mods.Cnc.Traits foreach (var target in UnitsInRange(order.ExtraLocation)) { var cs = target.TraitsImplementing() - .FirstEnabledTraitOrDefault(); + .FirstEnabledConditionalTraitOrDefault(); if (cs == null) continue; diff --git a/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs index 683f29a677..60d6efa283 100644 --- a/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs +++ b/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs @@ -32,7 +32,7 @@ namespace OpenRA.Mods.Common.Scripting public void Demolish(Actor target) { // NB: Scripted actions get no visible targetlines. - var demolition = demolitions.FirstEnabledTraitOrDefault(); + var demolition = demolitions.FirstEnabledConditionalTraitOrDefault(); if (demolition != null) Self.QueueActivity(demolition.GetDemolishActivity(Self, Target.FromActor(target), null)); } diff --git a/OpenRA.Mods.Common/Scripting/Properties/GeneralProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/GeneralProperties.cs index beab188023..c18770297a 100644 --- a/OpenRA.Mods.Common/Scripting/Properties/GeneralProperties.cs +++ b/OpenRA.Mods.Common/Scripting/Properties/GeneralProperties.cs @@ -185,7 +185,7 @@ namespace OpenRA.Mods.Common.Scripting { get { - var tooltip = tooltips.FirstEnabledTraitOrDefault(); + var tooltip = tooltips.FirstEnabledConditionalTraitOrDefault(); return tooltip?.Info.Name; } diff --git a/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs b/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs index 9a393ef65a..8c93cee761 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs @@ -62,7 +62,7 @@ namespace OpenRA.Mods.Common.Traits.Render if (token == Actor.InvalidConditionToken) token = self.GrantCondition(info.Condition); - var wsb = wsbs.FirstEnabledTraitOrDefault(); + var wsb = wsbs.FirstEnabledConditionalTraitOrDefault(); if (wsb == null) return; @@ -88,7 +88,7 @@ namespace OpenRA.Mods.Common.Traits.Render if (token == Actor.InvalidConditionToken) token = self.GrantCondition(info.Condition); - var wsb = wsbs.FirstEnabledTraitOrDefault(); + var wsb = wsbs.FirstEnabledConditionalTraitOrDefault(); if (wsb == null) return; @@ -117,7 +117,7 @@ namespace OpenRA.Mods.Common.Traits.Render // (sell/transform/etc) runs. This causes visual glitches that we attempt to minimize // by forcing the animation to frame 0 and regranting the make condition. // These workarounds will break the actor if the followup activity doesn't dispose it! - wsbs.FirstEnabledTraitOrDefault()?.DefaultAnimation.PlayFetchIndex(info.Sequence, () => 0); + wsbs.FirstEnabledConditionalTraitOrDefault()?.DefaultAnimation.PlayFetchIndex(info.Sequence, () => 0); token = self.GrantCondition(info.Condition);