Files
OpenRA/OpenRA.Mods.Common/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs
RoosterDragon 7c889c5ef0 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.
2015-10-25 19:44:21 +00:00

78 lines
2.4 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2015 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. For more information,
* see COPYING.
*/
#endregion
using OpenRA.Mods.Common.Scripting;
using OpenRA.Mods.Common.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
public class LoadIngamePlayerOrObserverUILogic : ChromeLogic
{
bool loadingObserverWidgets = false;
[ObjectCreator.UseCtor]
public LoadIngamePlayerOrObserverUILogic(Widget widget, World world)
{
var ingameRoot = widget.Get("INGAME_ROOT");
var worldRoot = ingameRoot.Get("WORLD_ROOT");
var menuRoot = ingameRoot.Get("MENU_ROOT");
var playerRoot = worldRoot.Get("PLAYER_ROOT");
if (world.LocalPlayer == null)
Game.LoadWidget(world, "OBSERVER_WIDGETS", playerRoot, new WidgetArgs());
else
{
var playerWidgets = Game.LoadWidget(world, "PLAYER_WIDGETS", playerRoot, new WidgetArgs());
var sidebarTicker = playerWidgets.Get<LogicTickerWidget>("SIDEBAR_TICKER");
var objectives = world.LocalPlayer.PlayerActor.Info.TraitInfoOrDefault<MissionObjectivesInfo>();
sidebarTicker.OnTick = () =>
{
// Switch to observer mode after win/loss
if (world.LocalPlayer.WinState != WinState.Undefined && !loadingObserverWidgets)
{
loadingObserverWidgets = true;
Game.RunAfterDelay(objectives != null ? objectives.GameOverDelay : 0, () =>
{
if (!Game.IsCurrentWorld(world))
return;
playerRoot.RemoveChildren();
Game.LoadWidget(world, "OBSERVER_WIDGETS", playerRoot, new WidgetArgs());
});
}
};
}
Game.LoadWidget(world, "CHAT_PANEL", worldRoot, new WidgetArgs());
world.GameOver += () =>
{
Ui.CloseWindow();
menuRoot.RemoveChildren();
if (world.LocalPlayer != null)
{
var scriptContext = world.WorldActor.TraitOrDefault<LuaScript>();
var video = world.LocalPlayer.WinState == WinState.Won ? world.Map.Videos.GameWon : world.Map.Videos.GameLost;
if (!string.IsNullOrEmpty(video) && !(scriptContext != null && scriptContext.FatalErrorOccurred))
Media.PlayFMVFullscreen(world, video, () => { });
}
var optionsButton = playerRoot.GetOrNull<MenuButtonWidget>("OPTIONS_BUTTON");
if (optionsButton != null)
optionsButton.OnClick();
};
}
}
}