diff --git a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs index 1c4c8ee924..2420dd27e2 100644 --- a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs +++ b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs @@ -54,16 +54,18 @@ namespace OpenRA.Traits public DamageState DamageState { get; private set; } readonly IHealth health; + readonly IVisibilityModifier[] visibilityModifiers; + // The Visible flag is tied directly to the actor visibility under the fog. // If Visible is true, the actor is made invisible (via FrozenUnderFog/IDefaultVisibility) // and this FrozenActor is rendered instead. // The Hidden flag covers the edge case that occurs when the backing actor was last "seen" - // to be cloaked or otherwise not CanBeViewedByPlayer()ed. Setting Visible to true when - // the actor is hidden under the fog would leak the actors position via the tooltips and - // AutoTargetability, and keeping Visible as false would cause the actor to be rendered - // under the fog. - public bool Visible = true; - public bool Hidden = false; + // but not actually visible because a visibility modifier hid the actor. Setting Visible to + // true when the actor is hidden under the fog would leak the actors position via the + // tooltips and AutoTargetability, and keeping Visible as false would cause the actor to be + // rendered under the fog. + public bool Visible { get; private set; } = true; + public bool Hidden { get; private set; } = false; public bool Shrouded { get; private set; } public bool NeedRenderables { get; set; } @@ -108,6 +110,7 @@ namespace OpenRA.Traits tooltips = actor.TraitsImplementing().ToArray(); health = actor.TraitOrDefault(); + visibilityModifiers = actor.TraitsImplementing().ToArray(); UpdateVisibility(); } @@ -124,7 +127,6 @@ namespace OpenRA.Traits TargetTypes = actor.GetEnabledTargetTypes(); targetablePositions.Clear(); targetablePositions.AddRange(actor.GetTargetablePositions()); - Hidden = !actor.CanBeViewedByPlayer(viewer); if (health != null) { @@ -140,6 +142,19 @@ namespace OpenRA.Traits } } + public void RefreshHidden() + { + Hidden = false; + foreach (var visibilityModifier in visibilityModifiers) + { + if (!visibilityModifier.IsVisible(actor, viewer)) + { + Hidden = true; + break; + } + } + } + public void Tick() { if (flashTicks > 0) diff --git a/OpenRA.Mods.Cnc/Traits/FrozenUnderFogUpdatedByGps.cs b/OpenRA.Mods.Cnc/Traits/FrozenUnderFogUpdatedByGps.cs index 3f334dee22..4939406dfb 100644 --- a/OpenRA.Mods.Cnc/Traits/FrozenUnderFogUpdatedByGps.cs +++ b/OpenRA.Mods.Cnc/Traits/FrozenUnderFogUpdatedByGps.cs @@ -32,11 +32,7 @@ namespace OpenRA.Mods.Cnc.Traits // This only makes sense if the frozen actor has already been revealed (i.e. has renderables) if (fa.HasRenderables) { - // HACK: RefreshState updated *all* actor state, not just the owner - // This is generally bogus, and specifically breaks cursors and tooltips by setting Hidden to false - var hidden = fa.Hidden; fa.RefreshState(); - fa.Hidden = hidden; fa.NeedRenderables = true; } }; diff --git a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs index 1b86e24e97..a162b04a4b 100644 --- a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs @@ -81,13 +81,11 @@ namespace OpenRA.Mods.Common.Traits for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++) { var state = frozenStates[playerIndex]; + var frozen = state.FrozenActor; if (startsRevealed || state.IsVisible) - { - UpdateFrozenActor(state.FrozenActor, playerIndex); + UpdateFrozenActor(frozen, playerIndex); - // Needed so tooltips appear. - state.FrozenActor.Hidden = false; - } + frozen.RefreshHidden(); } }); @@ -113,6 +111,8 @@ namespace OpenRA.Mods.Common.Traits if (isVisible) UpdateFrozenActor(frozen, frozen.Viewer.World.Players.IndexOf(frozen.Viewer)); + + frozen.RefreshHidden(); } bool IsVisibleInner(Player byPlayer) @@ -176,7 +176,9 @@ namespace OpenRA.Mods.Common.Traits { // Force a state update for the old owner so the tooltip etc doesn't show them as the owner var oldOwnerIndex = self.World.Players.IndexOf(oldOwner); - UpdateFrozenActor(frozenStates[oldOwnerIndex].FrozenActor, oldOwnerIndex); + var frozen = frozenStates[oldOwnerIndex].FrozenActor; + UpdateFrozenActor(frozen, oldOwnerIndex); + frozen.RefreshHidden(); } void INotifyActorDisposing.Disposing(Actor self)