diff --git a/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs b/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs index d0151dd7ec..f5ecd3645c 100644 --- a/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs +++ b/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs @@ -51,7 +51,6 @@ namespace OpenRA.Mods.Common.Traits public readonly ExternalConditionInfo Info; readonly ConditionManager conditionManager; readonly Dictionary> permanentTokens = new Dictionary>(); - readonly Dictionary> timedTokensBySource = new Dictionary>(); readonly List> timedTokensByExpiration = new List>(); public ExternalCondition(Actor self, ExternalConditionInfo info) @@ -80,12 +79,12 @@ namespace OpenRA.Mods.Common.Traits return true; } - void RemoveFromExpiration(TimedToken timedToken) + void Remove(TimedToken timedToken) { timedTokensByExpiration.RemoveAt(timedTokensByExpiration.FindIndex(p => p.Value == timedToken)); } - void AddForExpiration(TimedToken timedToken) + void Add(TimedToken timedToken) { var index = timedTokensByExpiration.FindIndex(p => p.Key >= timedToken.Expires); if (index >= 0) @@ -105,18 +104,18 @@ namespace OpenRA.Mods.Common.Traits if (duration > 0) { - var timed = timedTokensBySource.GetOrAdd(source); - // Check level caps if (Info.SourceCap > 0) { - if ((permanent != null ? permanent.Count + timed.Count : timed.Count) >= Info.SourceCap) + var timedCount = timedTokensByExpiration.Count(p => p.Value.Source == source); + if ((permanent != null ? permanent.Count + timedCount : timedCount) >= Info.SourceCap) { - var expire = timed.MinByOrDefault(t => t.Value.Expires).Value; - if (expire != null) + // Get timed token from the same source with closest expiration. + var expireIndex = timedTokensByExpiration.FindIndex(t => t.Value.Source == source); + if (expireIndex >= 0) { - timed.Remove(expire.Token); - RemoveFromExpiration(expire); + var expire = timedTokensByExpiration[expireIndex].Value; + Remove(expire); if (conditionManager.TokenValid(self, expire.Token)) conditionManager.RevokeCondition(self, expire.Token); @@ -136,15 +135,13 @@ namespace OpenRA.Mods.Common.Traits if (conditionManager.TokenValid(self, expire.Token)) conditionManager.RevokeCondition(self, expire.Token); - timedTokensBySource[expire.Source].Remove(expire.Token); - RemoveFromExpiration(expire); + Remove(expire); } } } var timedToken = new TimedToken(token, self, source, duration); - timed.Add(token, timedToken); - AddForExpiration(timedToken); + Add(timedToken); } else if (permanent == null) permanentTokens.Add(source, new HashSet { token }); @@ -169,16 +166,11 @@ namespace OpenRA.Mods.Common.Traits } else { - Dictionary timedTokensForSource; - if (timedTokensBySource.TryGetValue(source, out timedTokensForSource)) - { - TimedToken timedToken; - if (!timedTokensForSource.TryGetValue(token, out timedToken)) - return false; - - timedTokensForSource.Remove(token); - RemoveFromExpiration(timedToken); - } + var index = timedTokensByExpiration.FindIndex(p => p.Value.Token == token); + if (index >= 0 && timedTokensByExpiration[index].Value.Source == source) + timedTokensByExpiration.RemoveAt(index); + else + return false; } if (conditionManager.TokenValid(self, token)) @@ -189,26 +181,14 @@ namespace OpenRA.Mods.Common.Traits void ITick.Tick(Actor self) { - if (timedTokensByExpiration.Count == 0) - return; - // Remove expired tokens var worldTick = self.World.WorldTick; - var pair = timedTokensByExpiration[0]; - while (pair.Key < worldTick) - { - var timed = pair.Value; - var timedTokensForSource = timedTokensBySource[timed.Source]; - timedTokensForSource.Remove(timed.Token); - if (timedTokensForSource.Count == 0) - timedTokensBySource.Remove(timed.Source); + var count = 0; + while (count < timedTokensByExpiration.Count && timedTokensByExpiration[count].Key < worldTick) + count++; - timedTokensByExpiration.RemoveAt(0); - if (timedTokensByExpiration.Count == 0) - return; - - pair = timedTokensByExpiration[0]; - } + if (count > 0) + timedTokensByExpiration.RemoveRange(0, count); } } }