From 0b4a54ab548f507c2f994fe5dd1a38621c2ceeab Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Fri, 5 May 2023 19:10:05 +0100 Subject: [PATCH] TechTree.GatherOwnedPrerequisites performance improvements. - Consuming methods cared only about the count and not the actual actors, so only counts the actors rather that creating lists. - ProvidesPrerequisites implementations return cached objects rather then allocating new enumerables on each call. --- .../GrantPrerequisiteChargeDrainPower.cs | 13 +++------- .../Traits/Player/ProvidesPrerequisite.cs | 22 ++++++----------- .../Traits/Player/ProvidesTechPrerequisite.cs | 5 ++-- OpenRA.Mods.Common/Traits/Player/TechTree.cs | 24 +++++++++++-------- 4 files changed, 26 insertions(+), 38 deletions(-) diff --git a/OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs b/OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs index 091c379104..553c005495 100644 --- a/OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs +++ b/OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs @@ -43,6 +43,7 @@ namespace OpenRA.Mods.Cnc.Traits public class GrantPrerequisiteChargeDrainPower : SupportPower, ITechTreePrerequisite, INotifyOwnerChanged { readonly GrantPrerequisiteChargeDrainPowerInfo info; + readonly string[] prerequisites; TechTree techTree; bool active; @@ -50,6 +51,7 @@ namespace OpenRA.Mods.Cnc.Traits : base(self, info) { this.info = info; + prerequisites = new[] { info.Prerequisite }; } protected override void Created(Actor self) @@ -82,16 +84,7 @@ namespace OpenRA.Mods.Cnc.Traits techTree.ActorChanged(self); } - IEnumerable ITechTreePrerequisite.ProvidesPrerequisites - { - get - { - if (!active) - yield break; - - yield return info.Prerequisite; - } - } + IEnumerable ITechTreePrerequisite.ProvidesPrerequisites => active ? prerequisites : Enumerable.Empty(); public class DischargeableSupportPowerInstance : SupportPowerInstance { diff --git a/OpenRA.Mods.Common/Traits/Player/ProvidesPrerequisite.cs b/OpenRA.Mods.Common/Traits/Player/ProvidesPrerequisite.cs index f407c7cb91..edf60d03c3 100644 --- a/OpenRA.Mods.Common/Traits/Player/ProvidesPrerequisite.cs +++ b/OpenRA.Mods.Common/Traits/Player/ProvidesPrerequisite.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -39,7 +40,7 @@ namespace OpenRA.Mods.Common.Traits public class ProvidesPrerequisite : ConditionalTrait, ITechTreePrerequisite, INotifyOwnerChanged, INotifyCreated { - readonly string prerequisite; + readonly string[] prerequisites; bool enabled; TechTree techTree; @@ -48,24 +49,15 @@ namespace OpenRA.Mods.Common.Traits public ProvidesPrerequisite(ActorInitializer init, ProvidesPrerequisiteInfo info) : base(info) { - prerequisite = info.Prerequisite; - - if (string.IsNullOrEmpty(prerequisite)) - prerequisite = init.Self.Info.Name; + if (string.IsNullOrEmpty(info.Prerequisite)) + prerequisites = new[] { init.Self.Info.Name }; + else + prerequisites = new[] { info.Prerequisite }; faction = init.GetValue(init.Self.Owner.Faction.InternalName); } - public IEnumerable ProvidesPrerequisites - { - get - { - if (!enabled) - yield break; - - yield return prerequisite; - } - } + public IEnumerable ProvidesPrerequisites => enabled ? prerequisites : Enumerable.Empty(); protected override void Created(Actor self) { diff --git a/OpenRA.Mods.Common/Traits/Player/ProvidesTechPrerequisite.cs b/OpenRA.Mods.Common/Traits/Player/ProvidesTechPrerequisite.cs index d87ac184f3..bf98673ea7 100644 --- a/OpenRA.Mods.Common/Traits/Player/ProvidesTechPrerequisite.cs +++ b/OpenRA.Mods.Common/Traits/Player/ProvidesTechPrerequisite.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -38,11 +39,9 @@ namespace OpenRA.Mods.Common.Traits readonly ProvidesTechPrerequisiteInfo info; readonly bool enabled; - static readonly string[] NoPrerequisites = Array.Empty(); - public string Name => info.Name; - public IEnumerable ProvidesPrerequisites => enabled ? info.Prerequisites : NoPrerequisites; + public IEnumerable ProvidesPrerequisites => enabled ? info.Prerequisites : Enumerable.Empty(); public ProvidesTechPrerequisite(ProvidesTechPrerequisiteInfo info, ActorInitializer init) { diff --git a/OpenRA.Mods.Common/Traits/Player/TechTree.cs b/OpenRA.Mods.Common/Traits/Player/TechTree.cs index ad54f110a0..81c0095b52 100644 --- a/OpenRA.Mods.Common/Traits/Player/TechTree.cs +++ b/OpenRA.Mods.Common/Traits/Player/TechTree.cs @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -71,9 +70,9 @@ namespace OpenRA.Mods.Common.Traits ^ !ownedPrereqs.ContainsKey(p.Replace("!", "").Replace("~", "")))); } - static Cache> GatherOwnedPrerequisites(Player player) + static Dictionary GatherOwnedPrerequisites(Player player) { - var ret = new Cache>(x => new List()); + var ret = new Dictionary(); if (player == null) return ret; @@ -89,7 +88,8 @@ namespace OpenRA.Mods.Common.Traits if (p == null) continue; - ret[p].Add(b.Actor); + ret.TryGetValue(p, out var count); + ret[p] = count + 1; } } @@ -103,7 +103,11 @@ namespace OpenRA.Mods.Common.Traits a.Actor.Info.TraitInfo().BuildLimit > 0); foreach (var buildable in buildables) - ret[buildable.Actor.Info.Name].Add(buildable.Actor); + { + var name = buildable.Actor.Info.Name; + ret.TryGetValue(name, out var count); + ret[name] = count + 1; + } return ret; } @@ -132,7 +136,7 @@ namespace OpenRA.Mods.Common.Traits hidden = false; } - bool HasPrerequisites(Cache> ownedPrerequisites) + bool HasPrerequisites(Dictionary ownedPrerequisites) { // PERF: Avoid LINQ. foreach (var prereq in prerequisites) @@ -145,7 +149,7 @@ namespace OpenRA.Mods.Common.Traits return true; } - bool IsHidden(Cache> ownedPrerequisites) + bool IsHidden(Dictionary ownedPrerequisites) { // PERF: Avoid LINQ. foreach (var prereq in prerequisites) @@ -160,12 +164,12 @@ namespace OpenRA.Mods.Common.Traits return false; } - public void Update(Cache> ownedPrerequisites) + public void Update(Dictionary ownedPrerequisites) { - var hasReachedLimit = limit > 0 && ownedPrerequisites.ContainsKey(Key) && ownedPrerequisites[Key].Count >= limit; + var hasReachedLimit = limit > 0 && ownedPrerequisites.TryGetValue(Key, out var count) && count >= limit; // The '!' annotation inverts prerequisites: "I'm buildable if this prerequisite *isn't* met" - var nowHasPrerequisites = HasPrerequisites(ownedPrerequisites) && !hasReachedLimit; + var nowHasPrerequisites = !hasReachedLimit && HasPrerequisites(ownedPrerequisites); var nowHidden = IsHidden(ownedPrerequisites); if (initialized == false)