diff --git a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs index 1e8a611385..55f6ad28c9 100644 --- a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs +++ b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs @@ -42,8 +42,11 @@ namespace OpenRA.Traits public bool Visible = true; public bool Shrouded { get; private set; } - public bool NeedRenderables { get; private set; } - public bool IsRendering { get; private set; } + public bool NeedRenderables { get; set; } + public IRenderable[] Renderables = NoRenderables; + static readonly IRenderable[] NoRenderables = new IRenderable[0]; + + int flashTicks; public FrozenActor(Actor self, PPos[] footprint, Shroud shroud, bool startsRevealed) { @@ -69,11 +72,6 @@ namespace OpenRA.Traits public ActorInfo Info { get { return actor.Info; } } public Actor Actor { get { return !actor.IsDead ? actor : null; } } - static readonly IRenderable[] NoRenderables = new IRenderable[0]; - - int flashTicks; - IRenderable[] renderables = NoRenderables; - public void Tick() { UpdateVisibility(); @@ -103,8 +101,7 @@ namespace OpenRA.Traits Shrouded = false; } - if (Visible && !wasVisible) - NeedRenderables = true; + NeedRenderables = Visible && !wasVisible; } public void Flash() @@ -114,31 +111,20 @@ namespace OpenRA.Traits public IEnumerable Render(WorldRenderer wr) { - if (NeedRenderables) - { - NeedRenderables = false; - if (!actor.Disposed) - { - IsRendering = true; - renderables = actor.Render(wr).ToArray(); - IsRendering = false; - } - } - if (Shrouded) return NoRenderables; if (flashTicks > 0 && flashTicks % 2 == 0) { var highlight = wr.Palette("highlight"); - return renderables.Concat(renderables.Where(r => !r.IsDecoration) + return Renderables.Concat(Renderables.Where(r => !r.IsDecoration) .Select(r => r.WithPalette(highlight))); } - return renderables; + return Renderables; } - public bool HasRenderables { get { return !Shrouded && renderables.Any(); } } + public bool HasRenderables { get { return !Shrouded && Renderables.Any(); } } public bool ShouldBeRemoved(Player owner) { diff --git a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs index d1bb72ee2d..0017a7e605 100644 --- a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs @@ -27,7 +27,7 @@ namespace OpenRA.Mods.Common.Traits public object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); } } - public class FrozenUnderFog : IRenderModifier, IDefaultVisibility, ITick, ISync + public class FrozenUnderFog : IRenderModifier, IDefaultVisibility, ITick, ITickRender, ISync { [Sync] public int VisibilityHash; @@ -41,6 +41,7 @@ namespace OpenRA.Mods.Common.Traits ITooltip tooltip; Health health; bool initialized; + bool isRendering; class FrozenState { @@ -143,11 +144,35 @@ namespace OpenRA.Mods.Common.Traits initialized = true; } + public void TickRender(WorldRenderer wr, Actor self) + { + if (!initialized) + return; + + IRenderable[] renderables = null; + foreach (var player in self.World.Players) + { + var frozen = stateByPlayer[player].FrozenActor; + if (!frozen.NeedRenderables) + continue; + + if (renderables == null) + { + isRendering = true; + renderables = self.Render(wr).ToArray(); + isRendering = false; + } + + frozen.NeedRenderables = false; + frozen.Renderables = renderables; + } + } + public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) { return IsVisible(self, self.World.RenderPlayer) || - (initialized && stateByPlayer[self.World.RenderPlayer].FrozenActor.IsRendering) ? + (initialized && isRendering) ? r : SpriteRenderable.None; } } diff --git a/OpenRA.Mods.RA/Effects/GpsDot.cs b/OpenRA.Mods.RA/Effects/GpsDot.cs index d8515b5380..1ff8497ef9 100644 --- a/OpenRA.Mods.RA/Effects/GpsDot.cs +++ b/OpenRA.Mods.RA/Effects/GpsDot.cs @@ -37,14 +37,23 @@ namespace OpenRA.Mods.RA.Effects readonly GpsDotInfo info; readonly Animation anim; - readonly Dictionary showToPlayer = new Dictionary(); + readonly Dictionary stateByPlayer = new Dictionary(); + readonly Lazy huf; + readonly Lazy fuf; + readonly Lazy disguise; + readonly Lazy cloak; + readonly Cache frozen; - Lazy huf; - Lazy fuf; - Lazy disguise; - Lazy cloak; - Cache watcher; - Cache frozen; + class DotState + { + public readonly GpsWatcher Gps; + public bool IsTargetable; + public bool ShouldRender; + public DotState(GpsWatcher gps) + { + Gps = gps; + } + } public GpsDot(Actor self, GpsDotInfo info) { @@ -60,19 +69,20 @@ namespace OpenRA.Mods.RA.Effects disguise = Exts.Lazy(() => self.TraitOrDefault()); cloak = Exts.Lazy(() => self.TraitOrDefault()); - watcher = new Cache(p => p.PlayerActor.Trait()); frozen = new Cache(p => p.PlayerActor.Trait()); - showToPlayer = self.World.Players.ToDictionary(x => x, x => false); + stateByPlayer = self.World.Players.ToDictionary(p => p, p => new DotState(p.PlayerActor.Trait())); } public bool IsDotVisible(Player toPlayer) { - return showToPlayer[toPlayer]; + return stateByPlayer[toPlayer].IsTargetable; } - bool ShouldShowIndicator(Player toPlayer) + bool IsTargetableBy(Player toPlayer, out bool shouldRenderIndicator) { + shouldRenderIndicator = false; + if (cloak.Value != null && cloak.Value.Cloaked) return false; @@ -81,19 +91,27 @@ namespace OpenRA.Mods.RA.Effects if (huf.Value != null && !huf.Value.IsVisible(self, toPlayer) && toPlayer.Shroud.IsExplored(self.CenterPosition)) + { + var f1 = FrozenActorForPlayer(toPlayer); + shouldRenderIndicator = f1 == null || !f1.HasRenderables; return true; + } if (fuf.Value == null) return false; - var f = frozen[toPlayer].FromID(self.ActorID); - if (f == null) + var f2 = FrozenActorForPlayer(toPlayer); + if (f2 == null) return false; - if (f.HasRenderables || f.NeedRenderables) - return false; + shouldRenderIndicator = !f2.HasRenderables; - return f.Visible && !f.Shrouded; + return f2.Visible && !f2.Shrouded; + } + + FrozenActor FrozenActorForPlayer(Player player) + { + return frozen[player].FromID(self.ActorID); } public void Tick(World world) @@ -106,14 +124,17 @@ namespace OpenRA.Mods.RA.Effects foreach (var player in self.World.Players) { - var gps = watcher[player]; - showToPlayer[player] = (gps.Granted || gps.GrantedAllies) && ShouldShowIndicator(player); + var state = stateByPlayer[player]; + var shouldRender = false; + var targetable = (state.Gps.Granted || state.Gps.GrantedAllies) && IsTargetableBy(player, out shouldRender); + state.IsTargetable = targetable; + state.ShouldRender = targetable && shouldRender; } } public IEnumerable Render(WorldRenderer wr) { - if (self.World.RenderPlayer == null || !showToPlayer[self.World.RenderPlayer] || self.Disposed) + if (self.World.RenderPlayer == null || !stateByPlayer[self.World.RenderPlayer].ShouldRender || self.Disposed) return SpriteRenderable.None; var palette = wr.Palette(info.IndicatorPalettePrefix + self.Owner.InternalName); diff --git a/OpenRA.Mods.RA/Traits/SupportPowers/GpsPower.cs b/OpenRA.Mods.RA/Traits/SupportPowers/GpsPower.cs index 16ca4eb1ea..5d411145e0 100644 --- a/OpenRA.Mods.RA/Traits/SupportPowers/GpsPower.cs +++ b/OpenRA.Mods.RA/Traits/SupportPowers/GpsPower.cs @@ -63,7 +63,7 @@ namespace OpenRA.Mods.RA.Traits foreach (var i in atek.World.ActorsWithTrait()) i.Trait.RefreshGranted(); - if ((Granted || GrantedAllies) && atek.Owner.IsAlliedWith(atek.World.RenderPlayer)) + if ((Granted || GrantedAllies) && atek.Owner.IsAlliedWith(Owner)) atek.Owner.Shroud.ExploreAll(atek.World); }