Fix FrozenUnderFog / FrozenActor visibility consistency.

This fixes cases where both objects return visible / not
when queried at the wrong time during a tick.
This commit is contained in:
Paul Chote
2019-01-26 18:43:58 +00:00
committed by reaperrr
parent dc40a973e3
commit d6d1f3a06d
2 changed files with 30 additions and 3 deletions

View File

@@ -18,6 +18,11 @@ using OpenRA.Primitives;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {
public interface ICreatesFrozenActors
{
void OnVisibilityChanged(FrozenActor frozen);
}
[Desc("Required for FrozenUnderFog to work. Attach this to the player actor.")] [Desc("Required for FrozenUnderFog to work. Attach this to the player actor.")]
public class FrozenActorLayerInfo : Requires<ShroudInfo>, ITraitInfo public class FrozenActorLayerInfo : Requires<ShroudInfo>, ITraitInfo
{ {
@@ -32,6 +37,7 @@ namespace OpenRA.Traits
public readonly PPos[] Footprint; public readonly PPos[] Footprint;
public readonly WPos CenterPosition; public readonly WPos CenterPosition;
readonly Actor actor; readonly Actor actor;
readonly ICreatesFrozenActors frozenTrait;
readonly Player viewer; readonly Player viewer;
readonly Shroud shroud; readonly Shroud shroud;
@@ -70,9 +76,10 @@ namespace OpenRA.Traits
int flashTicks; int flashTicks;
public FrozenActor(Actor actor, PPos[] footprint, Player viewer, bool startsRevealed) public FrozenActor(Actor actor, ICreatesFrozenActors frozenTrait, PPos[] footprint, Player viewer, bool startsRevealed)
{ {
this.actor = actor; this.actor = actor;
this.frozenTrait = frozenTrait;
this.viewer = viewer; this.viewer = viewer;
shroud = viewer.Shroud; shroud = viewer.Shroud;
NeedRenderables = startsRevealed; NeedRenderables = startsRevealed;
@@ -153,6 +160,11 @@ namespace OpenRA.Traits
Shrouded = false; Shrouded = false;
} }
// Force the backing trait to update so other actors can't
// query inconsistent state (both hidden or both visible)
if (Visible != wasVisible)
frozenTrait.OnVisibilityChanged(this);
NeedRenderables |= Visible && !wasVisible; NeedRenderables |= Visible && !wasVisible;
} }

View File

@@ -9,6 +9,7 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
@@ -27,7 +28,7 @@ namespace OpenRA.Mods.Common.Traits
public object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); } public object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); }
} }
public class FrozenUnderFog : IRenderModifier, IDefaultVisibility, ITick, ITickRender, ISync, INotifyCreated public class FrozenUnderFog : ICreatesFrozenActors, IRenderModifier, IDefaultVisibility, ITick, ITickRender, ISync, INotifyCreated
{ {
[Sync] public int VisibilityHash; [Sync] public int VisibilityHash;
@@ -37,6 +38,7 @@ namespace OpenRA.Mods.Common.Traits
PlayerDictionary<FrozenState> frozenStates; PlayerDictionary<FrozenState> frozenStates;
bool isRendering; bool isRendering;
bool created;
class FrozenState class FrozenState
{ {
@@ -67,7 +69,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
frozenStates = new PlayerDictionary<FrozenState>(self.World, (player, playerIndex) => frozenStates = new PlayerDictionary<FrozenState>(self.World, (player, playerIndex) =>
{ {
var frozenActor = new FrozenActor(self, footprint, player, startsRevealed); var frozenActor = new FrozenActor(self, this, footprint, player, startsRevealed);
player.PlayerActor.Trait<FrozenActorLayer>().Add(frozenActor); player.PlayerActor.Trait<FrozenActorLayer>().Add(frozenActor);
return new FrozenState(frozenActor) { IsVisible = startsRevealed }; return new FrozenState(frozenActor) { IsVisible = startsRevealed };
}); });
@@ -75,6 +77,8 @@ namespace OpenRA.Mods.Common.Traits
if (startsRevealed) if (startsRevealed)
for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++) for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++)
UpdateFrozenActor(self, frozenStates[playerIndex].FrozenActor, playerIndex); UpdateFrozenActor(self, frozenStates[playerIndex].FrozenActor, playerIndex);
created = true;
} }
void UpdateFrozenActor(Actor self, FrozenActor frozenActor, int playerIndex) void UpdateFrozenActor(Actor self, FrozenActor frozenActor, int playerIndex)
@@ -83,6 +87,17 @@ namespace OpenRA.Mods.Common.Traits
frozenActor.RefreshState(); frozenActor.RefreshState();
} }
void ICreatesFrozenActors.OnVisibilityChanged(FrozenActor frozen)
{
// Ignore callbacks during initial setup
if (!created)
return;
// Update state visibility to match the frozen actor to ensure consistency within the tick
// The rest of the state will be updated by ITick.Tick below
frozenStates[frozen.Viewer].IsVisible = !frozen.Visible;
}
bool IsVisibleInner(Actor self, Player byPlayer) bool IsVisibleInner(Actor self, Player byPlayer)
{ {
// If fog is disabled visibility is determined by shroud // If fog is disabled visibility is determined by shroud