Sincebbf5970bc1we update frozen actors only when required. In8339c6843ea regression was fixed where actors created in line of sight would be invisible. Here, we fix a related regression where cloaked units that are revealed, and then frozen when you move out of line of sight would lack tooltips. The fix centers around the setting of the Hidden flag. In the old code this used CanBeViewedByPlayer which checks for visibility modifiers and then uses the default visibility. The bug with this code is that when a visibility modifier was not hiding the actor, then we would report the default visibility state instead. However the frozen visibility state applies here which means if the frozen actor is visible, then we consider the actor to be hidden and therefore tooltips will not appear. In the fixed version we only consider the modifiers. This means a visibility modifier such as Cloak can hide the frozen actor tooltips. But otherwise we do not consider the frozen actor to be hidden. This prevents a frozen actor from hiding its own tooltips in some unintended circular logic. Hidden now becomes just a flag to indicate if the visibility modifiers are overriding things, as intended.
111 lines
3.4 KiB
C#
111 lines
3.4 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright 2007-2022 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, either version 3 of
|
|
* the License, or (at your option) any later version. For more
|
|
* information, see COPYING.
|
|
*/
|
|
#endregion
|
|
|
|
using System;
|
|
using OpenRA.Mods.Common.Traits;
|
|
using OpenRA.Primitives;
|
|
using OpenRA.Traits;
|
|
|
|
namespace OpenRA.Mods.Cnc.Traits
|
|
{
|
|
using FrozenActorAction = Action<FrozenUnderFogUpdatedByGps, FrozenActorLayer, GpsWatcher, FrozenActor>;
|
|
|
|
[Desc("Updates frozen actors of actors that change owners, are sold or die whilst having an active GPS power.")]
|
|
public class FrozenUnderFogUpdatedByGpsInfo : TraitInfo, Requires<FrozenUnderFogInfo>
|
|
{
|
|
public override 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.
|
|
// This only makes sense if the frozen actor has already been revealed (i.e. has renderables)
|
|
if (fa.HasRenderables)
|
|
{
|
|
fa.RefreshState();
|
|
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.
|
|
fa.Invalidate();
|
|
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.FrozenActorLayer;
|
|
GpsWatcher = player.PlayerActor.TraitOrDefault<GpsWatcher>();
|
|
GpsWatcher.RegisterForOnGpsRefreshed(frozenUnderFogUpdatedByGps.self, frozenUnderFogUpdatedByGps);
|
|
}
|
|
}
|
|
|
|
readonly PlayerDictionary<Traits> traits;
|
|
readonly Actor self;
|
|
|
|
public FrozenUnderFogUpdatedByGps(ActorInitializer init)
|
|
{
|
|
self = init.Self;
|
|
traits = new PlayerDictionary<Traits>(init.World, player => new Traits(player, this));
|
|
}
|
|
|
|
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
|
|
{
|
|
ActOnFrozenActorsForAllPlayers(Refresh);
|
|
}
|
|
|
|
void INotifyActorDisposing.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);
|
|
}
|
|
}
|
|
}
|