Update frozen actors only when required.
Previously, actors that were visible would refresh their frozen actor state every tick in preparation for the actor becoming hidden, and the frozen actor appearing as a placeholder instead. By using ICreatesFrozenActors.OnVisibilityChanged when can avoid refreshing the state constantly, and instead just refresh it the moment the frozen actor needs to appear. This provides a nice performance improvement on the cost on managing frozen actors.
This commit is contained in:
@@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public override object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); }
|
public override object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FrozenUnderFog : ICreatesFrozenActors, IRenderModifier, IDefaultVisibility, ITick, ITickRender, ISync, INotifyCreated, INotifyOwnerChanged, INotifyActorDisposing
|
public class FrozenUnderFog : ICreatesFrozenActors, IRenderModifier, IDefaultVisibility, ITickRender, ISync, INotifyCreated, INotifyOwnerChanged, INotifyActorDisposing
|
||||||
{
|
{
|
||||||
[Sync]
|
[Sync]
|
||||||
public int VisibilityHash;
|
public int VisibilityHash;
|
||||||
@@ -72,6 +72,18 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
player.PlayerActor.Trait<FrozenActorLayer>().Add(frozenActor);
|
player.PlayerActor.Trait<FrozenActorLayer>().Add(frozenActor);
|
||||||
return new FrozenState(frozenActor) { IsVisible = startsRevealed };
|
return new FrozenState(frozenActor) { IsVisible = startsRevealed };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set the initial visibility state
|
||||||
|
// This relies on actor.GetTargetablePositions(), which is also setup up in Created.
|
||||||
|
// Since we can't be sure whether our method will run after theirs, defer by a frame.
|
||||||
|
if (startsRevealed)
|
||||||
|
self.World.AddFrameEndTask(_ =>
|
||||||
|
{
|
||||||
|
for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++)
|
||||||
|
UpdateFrozenActor(frozenStates[playerIndex].FrozenActor, playerIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
created = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateFrozenActor(FrozenActor frozenActor, int playerIndex)
|
void UpdateFrozenActor(FrozenActor frozenActor, int playerIndex)
|
||||||
@@ -86,9 +98,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (!created)
|
if (!created)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Update state visibility to match the frozen actor to ensure consistency within the tick
|
// Update state visibility to match the frozen actor to ensure consistency
|
||||||
// The rest of the state will be updated by ITick.Tick below
|
var state = frozenStates[frozen.Viewer];
|
||||||
frozenStates[frozen.Viewer].IsVisible = !frozen.Visible;
|
var isVisible = !frozen.Visible;
|
||||||
|
state.IsVisible = isVisible;
|
||||||
|
|
||||||
|
if (isVisible)
|
||||||
|
UpdateFrozenActor(frozen, frozen.Viewer.World.Players.IndexOf(frozen.Viewer));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsVisibleInner(Player byPlayer)
|
bool IsVisibleInner(Player byPlayer)
|
||||||
@@ -109,37 +125,6 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return info.AlwaysVisibleRelationships.HasRelationship(relationship) || IsVisibleInner(byPlayer);
|
return info.AlwaysVisibleRelationships.HasRelationship(relationship) || IsVisibleInner(byPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ITick.Tick(Actor self)
|
|
||||||
{
|
|
||||||
if (self.Disposed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Set the initial visibility state
|
|
||||||
// This relies on actor.GetTargetablePositions(), which is not safe to use from Created
|
|
||||||
// so we defer until the first real tick.
|
|
||||||
if (!created && startsRevealed)
|
|
||||||
{
|
|
||||||
for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++)
|
|
||||||
UpdateFrozenActor(frozenStates[playerIndex].FrozenActor, playerIndex);
|
|
||||||
|
|
||||||
created = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
VisibilityHash = 0;
|
|
||||||
|
|
||||||
for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++)
|
|
||||||
{
|
|
||||||
var state = frozenStates[playerIndex];
|
|
||||||
var frozenActor = state.FrozenActor;
|
|
||||||
var isVisible = !frozenActor.Visible;
|
|
||||||
state.IsVisible = isVisible;
|
|
||||||
|
|
||||||
if (isVisible)
|
|
||||||
UpdateFrozenActor(frozenActor, playerIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ITickRender.TickRender(WorldRenderer wr, Actor self)
|
void ITickRender.TickRender(WorldRenderer wr, Actor self)
|
||||||
{
|
{
|
||||||
IRenderable[] renderables = null;
|
IRenderable[] renderables = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user