From dd2ae9fe5e4506f2f2f94572d66d5b63f55dd826 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Fri, 15 Dec 2017 19:26:09 +0000 Subject: [PATCH] Avoid LINQ in some Tick methods. As Tick is called often, avoiding allocation overhead in these methods is useful. --- OpenRA.Game/Traits/Player/PlayerResources.cs | 8 ++++--- .../Player/ConquestVictoryConditions.cs | 16 +++++++++---- OpenRA.Mods.Common/Traits/Player/TechTree.cs | 23 ++++++++++++++++--- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/OpenRA.Game/Traits/Player/PlayerResources.cs b/OpenRA.Game/Traits/Player/PlayerResources.cs index eb92af6214..06f3b91249 100644 --- a/OpenRA.Game/Traits/Player/PlayerResources.cs +++ b/OpenRA.Game/Traits/Player/PlayerResources.cs @@ -172,9 +172,11 @@ namespace OpenRA.Traits void ITick.Tick(Actor self) { - ResourceCapacity = self.World.ActorsWithTrait() - .Where(a => a.Actor.Owner == owner) - .Sum(a => a.Trait.Capacity); + // PERF: Avoid LINQ. + ResourceCapacity = 0; + foreach (var tp in self.World.ActorsWithTrait()) + if (tp.Actor.Owner == owner) + ResourceCapacity += tp.Trait.Capacity; if (Resources > ResourceCapacity) Resources = ResourceCapacity; diff --git a/OpenRA.Mods.Common/Traits/Player/ConquestVictoryConditions.cs b/OpenRA.Mods.Common/Traits/Player/ConquestVictoryConditions.cs index 973f5a0958..5e83e51e3a 100644 --- a/OpenRA.Mods.Common/Traits/Player/ConquestVictoryConditions.cs +++ b/OpenRA.Mods.Common/Traits/Player/ConquestVictoryConditions.cs @@ -33,6 +33,7 @@ namespace OpenRA.Mods.Common.Traits { readonly ConquestVictoryConditionsInfo info; readonly MissionObjectives mo; + Player[] otherPlayers; int objectiveID = -1; public ConquestVictoryConditions(Actor self, ConquestVictoryConditionsInfo cvcInfo) @@ -51,13 +52,18 @@ namespace OpenRA.Mods.Common.Traits if (!self.Owner.NonCombatant && self.Owner.HasNoRequiredUnits()) mo.MarkFailed(self.Owner, objectiveID); - var others = self.World.Players.Where(p => !p.NonCombatant - && !p.IsAlliedWith(self.Owner)); + // Players, NonCombatants, and IsAlliedWith are all fixed once the game starts, so we can cache the result. + if (otherPlayers == null) + otherPlayers = self.World.Players.Where(p => !p.NonCombatant && !p.IsAlliedWith(self.Owner)).ToArray(); - if (!others.Any()) return; + if (otherPlayers.Length == 0) return; - if (others.All(p => p.WinState == WinState.Lost)) - mo.MarkCompleted(self.Owner, objectiveID); + // PERF: Avoid LINQ. + foreach (var otherPlayer in otherPlayers) + if (otherPlayer.WinState != WinState.Lost) + return; + + mo.MarkCompleted(self.Owner, objectiveID); } public void OnPlayerLost(Player player) diff --git a/OpenRA.Mods.Common/Traits/Player/TechTree.cs b/OpenRA.Mods.Common/Traits/Player/TechTree.cs index fc15e076ce..a95830432a 100644 --- a/OpenRA.Mods.Common/Traits/Player/TechTree.cs +++ b/OpenRA.Mods.Common/Traits/Player/TechTree.cs @@ -130,13 +130,30 @@ namespace OpenRA.Mods.Common.Traits bool HasPrerequisites(Cache> ownedPrerequisites) { - return prerequisites.All(p => !(p.Replace("~", "").StartsWith("!") ^ !ownedPrerequisites.ContainsKey(p.Replace("!", "").Replace("~", "")))); + // PERF: Avoid LINQ. + foreach (var prereq in prerequisites) + { + var withoutTilde = prereq.Replace("~", ""); + if (withoutTilde.StartsWith("!") ^ !ownedPrerequisites.ContainsKey(withoutTilde.Replace("!", ""))) + return false; + } + + return true; } bool IsHidden(Cache> ownedPrerequisites) { - return prerequisites.Any(prereq => prereq.StartsWith("~") && - (prereq.Replace("~", "").StartsWith("!") ^ !ownedPrerequisites.ContainsKey(prereq.Replace("~", "").Replace("!", "")))); + // PERF: Avoid LINQ. + foreach (var prereq in prerequisites) + { + if (!prereq.StartsWith("~")) + continue; + var withoutTilde = prereq.Replace("~", ""); + if (withoutTilde.StartsWith("!") ^ !ownedPrerequisites.ContainsKey(withoutTilde.Replace("!", ""))) + return true; + } + + return false; } public void Update(Cache> ownedPrerequisites)