Fix TOCTOU issues when calling Game.RunAfterDelay.
Since the action runs after a delay, the state of the game may no longer be the same and it may no longer be valid to run the action. Anything that references the world now calls IsCurrentWorld to ensure the world hasn't changed or been disposed.
This commit is contained in:
@@ -767,7 +767,7 @@ namespace OpenRA
|
||||
|
||||
public static bool IsCurrentWorld(World world)
|
||||
{
|
||||
return OrderManager != null && OrderManager.World == world;
|
||||
return OrderManager != null && OrderManager.World == world && !world.Disposing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,22 +62,22 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var a in player.World.Actors.Where(a => a.Owner == player))
|
||||
a.Kill(a);
|
||||
|
||||
if (player == player.World.LocalPlayer)
|
||||
Game.RunAfterDelay(info.NotificationDelay, () =>
|
||||
{
|
||||
Game.RunAfterDelay(info.NotificationDelay, () =>
|
||||
{
|
||||
if (Game.IsCurrentWorld(player.World))
|
||||
Game.Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Lose", player.Faction.InternalName);
|
||||
});
|
||||
}
|
||||
if (Game.IsCurrentWorld(player.World) && player == player.World.LocalPlayer)
|
||||
Game.Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Lose", player.Faction.InternalName);
|
||||
});
|
||||
}
|
||||
|
||||
public void OnPlayerWon(Player player)
|
||||
{
|
||||
Game.Debug("{0} is victorious.", player.PlayerName);
|
||||
|
||||
if (player == player.World.LocalPlayer)
|
||||
Game.RunAfterDelay(info.NotificationDelay, () => Game.Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Win", player.Faction.InternalName));
|
||||
Game.RunAfterDelay(info.NotificationDelay, () =>
|
||||
{
|
||||
if (Game.IsCurrentWorld(player.World) && player == player.World.LocalPlayer)
|
||||
Game.Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Win", player.Faction.InternalName);
|
||||
});
|
||||
}
|
||||
|
||||
public void OnObjectiveAdded(Player player, int id) { }
|
||||
|
||||
@@ -150,6 +150,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (gameOver)
|
||||
Game.RunAfterDelay(Info.GameOverDelay, () =>
|
||||
{
|
||||
if (!Game.IsCurrentWorld(player.World))
|
||||
return;
|
||||
|
||||
player.World.EndGame();
|
||||
player.World.SetPauseState(true);
|
||||
player.World.PauseStateLocked = true;
|
||||
|
||||
@@ -107,22 +107,22 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var a in player.World.Actors.Where(a => a.Owner == player))
|
||||
a.Kill(a);
|
||||
|
||||
if (player == player.World.LocalPlayer)
|
||||
Game.RunAfterDelay(info.NotificationDelay, () =>
|
||||
{
|
||||
Game.RunAfterDelay(info.NotificationDelay, () =>
|
||||
{
|
||||
if (Game.IsCurrentWorld(player.World))
|
||||
Game.Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Lose", player.Faction.InternalName);
|
||||
});
|
||||
}
|
||||
if (Game.IsCurrentWorld(player.World) && player == player.World.LocalPlayer)
|
||||
Game.Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Lose", player.Faction.InternalName);
|
||||
});
|
||||
}
|
||||
|
||||
public void OnPlayerWon(Player player)
|
||||
{
|
||||
Game.Debug("{0} is victorious.", player.PlayerName);
|
||||
|
||||
if (player == player.World.LocalPlayer)
|
||||
Game.RunAfterDelay(info.NotificationDelay, () => Game.Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Win", player.Faction.InternalName));
|
||||
Game.RunAfterDelay(info.NotificationDelay, () =>
|
||||
{
|
||||
if (Game.IsCurrentWorld(player.World) && player == player.World.LocalPlayer)
|
||||
Game.Sound.PlayNotification(player.World.Map.Rules, player, "Speech", "Win", player.Faction.InternalName);
|
||||
});
|
||||
}
|
||||
|
||||
public void OnObjectiveAdded(Player player, int id) { }
|
||||
|
||||
@@ -51,12 +51,19 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var exitDelay = iop != null ? iop.ExitDelay : 0;
|
||||
if (mpe != null)
|
||||
{
|
||||
Game.RunAfterDelay(exitDelay, () => mpe.Fade(MenuPaletteEffect.EffectType.Black));
|
||||
Game.RunAfterDelay(exitDelay, () =>
|
||||
{
|
||||
if (Game.IsCurrentWorld(world))
|
||||
mpe.Fade(MenuPaletteEffect.EffectType.Black);
|
||||
});
|
||||
exitDelay += 40 * mpe.Info.FadeLength;
|
||||
}
|
||||
|
||||
Game.RunAfterDelay(exitDelay, () =>
|
||||
{
|
||||
if (!Game.IsCurrentWorld(world))
|
||||
return;
|
||||
|
||||
Game.Disconnect();
|
||||
Ui.ResetAll();
|
||||
Game.LoadShellMap();
|
||||
|
||||
@@ -42,6 +42,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
loadingObserverWidgets = true;
|
||||
Game.RunAfterDelay(objectives != null ? objectives.GameOverDelay : 0, () =>
|
||||
{
|
||||
if (!Game.IsCurrentWorld(world))
|
||||
return;
|
||||
|
||||
playerRoot.RemoveChildren();
|
||||
Game.LoadWidget(world, "OBSERVER_WIDGETS", playerRoot, new WidgetArgs());
|
||||
});
|
||||
|
||||
@@ -109,8 +109,9 @@ namespace OpenRA.Mods.D2k.Activities
|
||||
|
||||
Game.RunAfterDelay(1000, () =>
|
||||
{
|
||||
foreach (var affectedPlayer in affectedPlayers)
|
||||
NotifyPlayer(affectedPlayer, attackPosition);
|
||||
if (Game.IsCurrentWorld(self.World))
|
||||
foreach (var affectedPlayer in affectedPlayers)
|
||||
NotifyPlayer(affectedPlayer, attackPosition);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user