Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update frozen actors only when required. #20156

Merged
merged 1 commit into from Aug 7, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 20 additions & 35 deletions OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs
Expand Up @@ -26,7 +26,7 @@ public class FrozenUnderFogInfo : TraitInfo, Requires<BuildingInfo>, IDefaultVis
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]
public int VisibilityHash;
Expand Down Expand Up @@ -72,6 +72,18 @@ void INotifyCreated.Created(Actor self)
player.PlayerActor.Trait<FrozenActorLayer>().Add(frozenActor);
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;
abcdefg30 marked this conversation as resolved.
Show resolved Hide resolved
}

void UpdateFrozenActor(FrozenActor frozenActor, int playerIndex)
Expand All @@ -86,9 +98,13 @@ void ICreatesFrozenActors.OnVisibilityChanged(FrozenActor frozen)
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;
// Update state visibility to match the frozen actor to ensure consistency
var state = frozenStates[frozen.Viewer];
var isVisible = !frozen.Visible;
state.IsVisible = isVisible;

if (isVisible)
UpdateFrozenActor(frozen, frozen.Viewer.World.Players.IndexOf(frozen.Viewer));
}

bool IsVisibleInner(Player byPlayer)
Expand All @@ -109,37 +125,6 @@ public bool IsVisible(Actor self, Player 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)
{
IRenderable[] renderables = null;
Expand Down