From 3026bdcea5a63d99da59d667e9a914cfbed30ca2 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Thu, 31 Dec 2015 01:38:09 +0000 Subject: [PATCH 1/5] Implement equality on TraitPair. --- OpenRA.Game/TraitDictionary.cs | 2 +- OpenRA.Game/World.cs | 21 ++++++++++++------- .../Orders/PlaceBuildingOrderGenerator.cs | 2 +- .../Traits/Player/ProductionQueue.cs | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/OpenRA.Game/TraitDictionary.cs b/OpenRA.Game/TraitDictionary.cs index a9201fc085..cad0cc5126 100644 --- a/OpenRA.Game/TraitDictionary.cs +++ b/OpenRA.Game/TraitDictionary.cs @@ -255,7 +255,7 @@ namespace OpenRA public void Reset() { index = -1; } public bool MoveNext() { return ++index < actors.Count; } - public TraitPair Current { get { return new TraitPair { Actor = actors[index], Trait = traits[index] }; } } + public TraitPair Current { get { return new TraitPair(actors[index], traits[index]); } } object System.Collections.IEnumerator.Current { get { return Current; } } public void Dispose() { } } diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 1af06e23a5..eab43ae99e 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -408,14 +408,21 @@ namespace OpenRA } } - public struct TraitPair + public struct TraitPair : IEquatable> { - public Actor Actor; - public T Trait; + public readonly Actor Actor; + public readonly T Trait; - public override string ToString() - { - return "{0}->{1}".F(Actor.Info.Name, Trait.GetType().Name); - } + public TraitPair(Actor actor, T trait) { Actor = actor; Trait = trait; } + + public static bool operator ==(TraitPair me, TraitPair other) { return me.Actor == other.Actor && Equals(me.Trait, other.Trait); } + public static bool operator !=(TraitPair me, TraitPair other) { return !(me == other); } + + public override int GetHashCode() { return Actor.GetHashCode() ^ Trait.GetHashCode(); } + + public bool Equals(TraitPair other) { return this == other; } + public override bool Equals(object obj) { return obj is TraitPair && Equals((TraitPair)obj); } + + public override string ToString() { return "{0}->{1}".F(Actor.Info.Name, Trait.GetType().Name); } } } diff --git a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs index e3a8dec8ae..a81b295f7f 100644 --- a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs @@ -236,7 +236,7 @@ namespace OpenRA.Mods.Common.Orders var blockers = allTiles.SelectMany(world.ActorMap.GetActorsAt) .Where(a => a.Owner == queue.Actor.Owner && a.IsIdle) - .Select(a => new TraitPair { Actor = a, Trait = a.TraitOrDefault() }); + .Select(a => new TraitPair(a, a.TraitOrDefault())); foreach (var blocker in blockers.Where(x => x.Trait != null)) { diff --git a/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs b/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs index b073884f95..a570446ae1 100644 --- a/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs +++ b/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs @@ -361,7 +361,7 @@ namespace OpenRA.Mods.Common.Traits public virtual TraitPair MostLikelyProducer() { var trait = self.TraitsImplementing().FirstOrDefault(p => p.Info.Produces.Contains(Info.Type)); - return new TraitPair { Actor = self, Trait = trait }; + return new TraitPair(self, trait); } // Builds a unit from the actor that holds this queue (1 queue per building) From c98df23b574986acf9bba137e6de92d1d09ed567 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Thu, 31 Dec 2015 01:40:49 +0000 Subject: [PATCH 2/5] Create FrozenActor.RefreshState method for better encapsulation and reuse of this logic. --- OpenRA.Game/Traits/Player/FrozenActorLayer.cs | 32 ++++++++++++++++--- .../Traits/Modifiers/FrozenUnderFog.cs | 20 +----------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs index 0cae87a5ee..002c65feb6 100644 --- a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs +++ b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs @@ -36,13 +36,15 @@ namespace OpenRA.Traits readonly Actor actor; readonly Shroud shroud; - public Player Owner; + public Player Owner { get; private set; } - public ITooltipInfo TooltipInfo; - public Player TooltipOwner; + public ITooltipInfo TooltipInfo { get; private set; } + public Player TooltipOwner { get; private set; } + readonly ITooltip tooltip; - public int HP; - public DamageState DamageState; + public int HP { get; private set; } + public DamageState DamageState { get; private set; } + readonly IHealth health; public bool Visible = true; public bool Shrouded { get; private set; } @@ -68,6 +70,9 @@ namespace OpenRA.Traits Bounds = self.Bounds; TargetTypes = self.GetEnabledTargetTypes().ToHashSet(); + tooltip = self.TraitsImplementing().FirstOrDefault(); + health = self.TraitOrDefault(); + UpdateVisibility(); } @@ -76,6 +81,23 @@ namespace OpenRA.Traits public ActorInfo Info { get { return actor.Info; } } public Actor Actor { get { return !actor.IsDead ? actor : null; } } + public void RefreshState() + { + Owner = actor.Owner; + + if (health != null) + { + HP = health.HP; + DamageState = health.DamageState; + } + + if (tooltip != null) + { + TooltipInfo = tooltip.TooltipInfo; + TooltipOwner = tooltip.Owner; + } + } + public void Tick() { if (flashTicks > 0) diff --git a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs index 131edee0d0..969a644c5b 100644 --- a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs @@ -37,8 +37,6 @@ namespace OpenRA.Mods.Common.Traits readonly PPos[] footprint; PlayerDictionary frozenStates; - ITooltip tooltip; - Health health; bool isRendering; class FrozenState @@ -65,9 +63,6 @@ namespace OpenRA.Mods.Common.Traits public void Created(Actor self) { - tooltip = self.TraitsImplementing().FirstOrDefault(); - health = self.TraitOrDefault(); - frozenStates = new PlayerDictionary(self.World, (player, playerIndex) => { var frozenActor = new FrozenActor(self, footprint, player.Shroud, startsRevealed); @@ -81,20 +76,7 @@ namespace OpenRA.Mods.Common.Traits void UpdateFrozenActor(Actor self, FrozenActor frozenActor, int playerIndex) { VisibilityHash |= 1 << (playerIndex % 32); - - frozenActor.Owner = self.Owner; - - if (health != null) - { - frozenActor.HP = health.HP; - frozenActor.DamageState = health.DamageState; - } - - if (tooltip != null) - { - frozenActor.TooltipInfo = tooltip.TooltipInfo; - frozenActor.TooltipOwner = tooltip.Owner; - } + frozenActor.RefreshState(); } bool IsVisibleInner(Actor self, Player byPlayer) From a232eff7fdeb25350d8cea23a6e541a7f36f412f Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Thu, 31 Dec 2015 01:42:19 +0000 Subject: [PATCH 3/5] Replace IRemoveFrozenActor with FrozenActorLayer.Remove. The IRemoveFrozenActor interface is replaced with a Remove method on FrozenActorLayer. IRemoveFrozenActor is a performance problem for FrozenActorLayer.Tick as it incurs a large cache miss penalty in order to load and enumerate the array of these interfaces for every frozen actor. Instead, we invert control and allow traits to remove frozen actors directly which eliminates the performance penalty. --- OpenRA.Game/Traits/Player/FrozenActorLayer.cs | 35 ++++-------- OpenRA.Game/Traits/TraitsInterfaces.cs | 5 -- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 - OpenRA.Mods.RA/Traits/GpsRemoveFrozenActor.cs | 55 ------------------- mods/ra/rules/defaults.yaml | 2 - 5 files changed, 12 insertions(+), 86 deletions(-) delete mode 100644 OpenRA.Mods.RA/Traits/GpsRemoveFrozenActor.cs diff --git a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs index 002c65feb6..5a142312f8 100644 --- a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs +++ b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs @@ -32,7 +32,6 @@ namespace OpenRA.Traits public readonly WPos CenterPosition; public readonly Rectangle Bounds; public readonly HashSet TargetTypes; - readonly IRemoveFrozenActor[] removeFrozenActors; readonly Actor actor; readonly Shroud shroud; @@ -59,7 +58,6 @@ namespace OpenRA.Traits actor = self; this.shroud = shroud; NeedRenderables = startsRevealed; - removeFrozenActors = self.TraitsImplementing().ToArray(); // Consider all cells inside the map area (ignoring the current map bounds) Footprint = footprint @@ -149,16 +147,6 @@ namespace OpenRA.Traits public bool HasRenderables { get { return !Shrouded && Renderables.Any(); } } - public bool ShouldBeRemoved(Player owner) - { - // PERF: Avoid LINQ. - foreach (var rfa in removeFrozenActors) - if (rfa.RemoveActor(actor, owner)) - return true; - - return false; - } - public override string ToString() { return "{0} {1}{2}".F(Info.Name, ID, IsValid ? "" : " (invalid)"); @@ -211,6 +199,13 @@ namespace OpenRA.Traits partitionedFrozenActorIds.Add(fa.ID, FootprintBounds(fa)); } + public void Remove(FrozenActor fa) + { + partitionedFrozenActorIds.Remove(fa.ID); + world.ScreenMap.Remove(owner, fa); + frozenActorsById.Remove(fa.ID); + } + Rectangle FootprintBounds(FrozenActor fa) { var p1 = fa.Footprint[0]; @@ -238,7 +233,7 @@ namespace OpenRA.Traits { UpdateDirtyFrozenActorsFromDirtyBins(); - var idsToRemove = new List(); + var frozenActorsToRemove = new List(); VisibilityHash = 0; FrozenHash = 0; @@ -253,22 +248,16 @@ namespace OpenRA.Traits if (dirtyFrozenActorIds.Contains(id)) frozenActor.UpdateVisibility(); - if (frozenActor.ShouldBeRemoved(owner)) - idsToRemove.Add(id); - else if (frozenActor.Visible) + if (frozenActor.Visible) VisibilityHash += hash; else if (frozenActor.Actor == null) - idsToRemove.Add(id); + frozenActorsToRemove.Add(frozenActor); } dirtyFrozenActorIds.Clear(); - foreach (var id in idsToRemove) - { - partitionedFrozenActorIds.Remove(id); - world.ScreenMap.Remove(owner, frozenActorsById[id]); - frozenActorsById.Remove(id); - } + foreach (var fa in frozenActorsToRemove) + Remove(fa); } void UpdateDirtyFrozenActorsFromDirtyBins() diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 5ac5d3feb2..ffa931225a 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -388,11 +388,6 @@ namespace OpenRA.Traits void DoImpact(Target target, Actor firedBy, IEnumerable damageModifiers); } - public interface IRemoveFrozenActor - { - bool RemoveActor(Actor self, Player owner); - } - public interface IRulesetLoaded { void RulesetLoaded(Ruleset rules, TInfo info); } public interface IRulesetLoaded : IRulesetLoaded, ITraitInfoInterface { } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index b0998d18f0..c35badf4cf 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -90,7 +90,6 @@ - diff --git a/OpenRA.Mods.RA/Traits/GpsRemoveFrozenActor.cs b/OpenRA.Mods.RA/Traits/GpsRemoveFrozenActor.cs deleted file mode 100644 index 3b432096ff..0000000000 --- a/OpenRA.Mods.RA/Traits/GpsRemoveFrozenActor.cs +++ /dev/null @@ -1,55 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Traits -{ - [Desc("Removes frozen actors of actors that are dead or sold," + - " when having an active GPS power.")] - public class GpsRemoveFrozenActorInfo : ITraitInfo - { - [Desc("Should this trait also affect allied players?")] - public bool GrantAllies = true; - - public object Create(ActorInitializer init) { return new GpsRemoveFrozenActor(init.Self, this); } - } - - public class GpsRemoveFrozenActor : IRemoveFrozenActor - { - readonly GpsWatcher[] watchers; - readonly GpsRemoveFrozenActorInfo info; - - public GpsRemoveFrozenActor(Actor self, GpsRemoveFrozenActorInfo info) - { - this.info = info; - watchers = self.World.ActorsWithTrait().Select(w => w.Trait).ToArray(); - } - - public bool RemoveActor(Actor self, Player owner) - { - if (!self.IsDead) - return false; - - foreach (var w in watchers) - { - if (w.Owner != owner && !(info.GrantAllies && w.Owner.IsAlliedWith(owner))) - continue; - - if (w.Launched) - return true; - } - - return false; - } - } -} diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 21a3532603..6e21894c14 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -430,7 +430,6 @@ Guardable: Range: 3c0 FrozenUnderFog: - GpsRemoveFrozenActor: Tooltip: GenericName: Structure Demolishable: @@ -500,7 +499,6 @@ SellSounds: cashturn.aud Guardable: FrozenUnderFog: - GpsRemoveFrozenActor: Health: HP: 100 Shape: Rectangle From 3c930c3ef9194eeaf7cbe2145724acf598e383fc Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Thu, 31 Dec 2015 01:47:23 +0000 Subject: [PATCH 4/5] Introduce FrozenUnderFogUpdatedByGps and IOnGpsRefreshed. This trait uses the new interface to register with the GpsWatcher to get notified when the GPS state changes. It needs to register as if the actor is destroyed, the GpsWatcher can no longer query actors in the world to get the trait. This is no good as the trait needs to perform actions after the death of its parent actor. When the GPS is enabled, the trait will track ownership changes and update the frozen actor (just like if there was only a GPS dot, it would change colour) and it will also remove frozen actors if the real actor dies or is sold. --- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 + .../Traits/FrozenUnderFogUpdatedByGps.cs | 105 ++++++++++++++++++ .../Traits/SupportPowers/GpsPower.cs | 40 +++++-- mods/ra/rules/defaults.yaml | 2 + 4 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 OpenRA.Mods.RA/Traits/FrozenUnderFogUpdatedByGps.cs diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index c35badf4cf..10da51510c 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -90,6 +90,7 @@ + diff --git a/OpenRA.Mods.RA/Traits/FrozenUnderFogUpdatedByGps.cs b/OpenRA.Mods.RA/Traits/FrozenUnderFogUpdatedByGps.cs new file mode 100644 index 0000000000..b403923e61 --- /dev/null +++ b/OpenRA.Mods.RA/Traits/FrozenUnderFogUpdatedByGps.cs @@ -0,0 +1,105 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Mods.Common.Traits; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Traits +{ + using FrozenActorAction = Action; + + [Desc("Updates frozen actors of actors that change owners, are sold or die whilst having an active GPS power.")] + public class FrozenUnderFogUpdatedByGpsInfo : ITraitInfo, Requires + { + public object Create(ActorInitializer init) { return new FrozenUnderFogUpdatedByGps(init); } + } + + public class FrozenUnderFogUpdatedByGps : INotifyOwnerChanged, INotifyActorDisposing, IOnGpsRefreshed + { + static readonly FrozenActorAction Refresh = (fufubg, fal, gps, fa) => + { + // Refreshes the visual state of the frozen actor, so ownership changes can be seen. + fa.RefreshState(); + if (fa.HasRenderables) + fa.NeedRenderables = true; + }; + static readonly FrozenActorAction Remove = (fufubg, fal, gps, fa) => + { + // Removes the frozen actor. Once done, we no longer need to track GPS updates. + fal.Remove(fa); + gps.UnregisterForOnGpsRefreshed(fufubg.self, fufubg); + }; + + class Traits + { + public readonly FrozenActorLayer FrozenActorLayer; + public readonly GpsWatcher GpsWatcher; + public Traits(Player player, FrozenUnderFogUpdatedByGps frozenUnderFogUpdatedByGps) + { + FrozenActorLayer = player.PlayerActor.TraitOrDefault(); + GpsWatcher = player.PlayerActor.TraitOrDefault(); + GpsWatcher.RegisterForOnGpsRefreshed(frozenUnderFogUpdatedByGps.self, frozenUnderFogUpdatedByGps); + } + } + + readonly PlayerDictionary traits; + readonly Actor self; + + public FrozenUnderFogUpdatedByGps(ActorInitializer init) + { + self = init.Self; + traits = new PlayerDictionary(init.World, player => new Traits(player, this)); + } + + public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) + { + ActOnFrozenActorsForAllPlayers(Refresh); + } + + public void Disposing(Actor self) + { + ActOnFrozenActorsForAllPlayers(Remove); + } + + public void OnGpsRefresh(Actor self, Player player) + { + if (self.IsDead) + ActOnFrozenActorForPlayer(player, Remove); + else + ActOnFrozenActorForPlayer(player, Refresh); + } + + void ActOnFrozenActorsForAllPlayers(FrozenActorAction action) + { + for (var playerIndex = 0; playerIndex < traits.Count; playerIndex++) + ActOnFrozenActorForTraits(traits[playerIndex], action); + } + + void ActOnFrozenActorForPlayer(Player player, FrozenActorAction action) + { + ActOnFrozenActorForTraits(traits[player], action); + } + + void ActOnFrozenActorForTraits(Traits t, FrozenActorAction action) + { + if (t.FrozenActorLayer == null || t.GpsWatcher == null || + !t.GpsWatcher.Granted || !t.GpsWatcher.GrantedAllies) + return; + + var fa = t.FrozenActorLayer.FromID(self.ActorID); + if (fa == null) + return; + + action(this, t.FrozenActorLayer, t.GpsWatcher, fa); + } + } +} diff --git a/OpenRA.Mods.RA/Traits/SupportPowers/GpsPower.cs b/OpenRA.Mods.RA/Traits/SupportPowers/GpsPower.cs index 5d411145e0..8a5930dd1b 100644 --- a/OpenRA.Mods.RA/Traits/SupportPowers/GpsPower.cs +++ b/OpenRA.Mods.RA/Traits/SupportPowers/GpsPower.cs @@ -25,12 +25,13 @@ namespace OpenRA.Mods.RA.Traits class GpsWatcher : ISync, IFogVisibilityModifier { - [Sync] public bool Launched = false; - [Sync] public bool GrantedAllies = false; - [Sync] public bool Granted = false; - public Player Owner; + [Sync] public bool Launched { get; private set; } + [Sync] public bool GrantedAllies { get; private set; } + [Sync] public bool Granted { get; private set; } + public readonly Player Owner; - List actors = new List { }; + readonly List actors = new List(); + readonly HashSet> notifyOnRefresh = new HashSet>(); public GpsWatcher(Player owner) { Owner = owner; } @@ -49,11 +50,11 @@ namespace OpenRA.Mods.RA.Traits public void Launch(Actor atek, SupportPowerInfo info) { atek.World.Add(new DelayedAction(((GpsPowerInfo)info).RevealDelay * 25, - () => - { - Launched = true; - RefreshGps(atek); - })); + () => + { + Launched = true; + RefreshGps(atek); + })); } public void RefreshGps(Actor atek) @@ -69,11 +70,18 @@ namespace OpenRA.Mods.RA.Traits void RefreshGranted() { + var wasGranted = Granted; + var wasGrantedAllies = GrantedAllies; + Granted = actors.Count > 0 && Launched; GrantedAllies = Owner.World.ActorsHavingTrait(g => g.Granted).Any(p => p.Owner.IsAlliedWith(Owner)); if (Granted || GrantedAllies) Owner.Shroud.ExploreAll(Owner.World); + + if (wasGranted != Granted || wasGrantedAllies != GrantedAllies) + foreach (var tp in notifyOnRefresh.ToList()) + tp.Trait.OnGpsRefresh(tp.Actor, Owner); } public bool HasFogVisibility() @@ -89,8 +97,20 @@ namespace OpenRA.Mods.RA.Traits return gpsDot.IsDotVisible(Owner); } + + public void RegisterForOnGpsRefreshed(Actor actor, IOnGpsRefreshed toBeNotified) + { + notifyOnRefresh.Add(new TraitPair(actor, toBeNotified)); + } + + public void UnregisterForOnGpsRefreshed(Actor actor, IOnGpsRefreshed toBeNotified) + { + notifyOnRefresh.Remove(new TraitPair(actor, toBeNotified)); + } } + interface IOnGpsRefreshed { void OnGpsRefresh(Actor self, Player player); } + class GpsPowerInfo : SupportPowerInfo { public readonly int RevealDelay = 0; diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 6e21894c14..d5cd53210c 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -430,6 +430,7 @@ Guardable: Range: 3c0 FrozenUnderFog: + FrozenUnderFogUpdatedByGps: Tooltip: GenericName: Structure Demolishable: @@ -499,6 +500,7 @@ SellSounds: cashturn.aud Guardable: FrozenUnderFog: + FrozenUnderFogUpdatedByGps: Health: HP: 100 Shape: Rectangle From dc99dbef2ab9c774cf65e054cb94e566eafad5bd Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Thu, 31 Dec 2015 01:50:24 +0000 Subject: [PATCH 5/5] Add an upgrade rule for FrozenUnderFogUpdatedByGps. --- OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 2ed1d10c62..594b30558a 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -2889,6 +2889,16 @@ namespace OpenRA.Mods.Common.UtilityCommands node.Key = "AttackSuicides"; } + // Replaced GpsRemoveFrozenActor with FrozenUnderFogUpdatedByGps + if (engineVersion < 20160117) + { + if (node.Key == "GpsRemoveFrozenActor") + { + node.Key = "FrozenUnderFogUpdatedByGps"; + node.Value.Nodes.Clear(); + } + } + UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } }