From 52b09bdfe82df04a36968dcbb05cfb0af1887b37 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Tue, 10 Jun 2014 16:17:27 +0100 Subject: [PATCH 1/2] If changed settings require a restart, offer the user to do it now. Add a dialog when closing the settings screen asking the user if they would like to restart the game now in order to apply any settings that are only applied after restarting the game. The game is reloaded in-process by spinning up a new AppDomain in order to reset state. --- OpenRA.Game/Game.cs | 20 +++++++--- OpenRA.Game/Support/Program.cs | 39 +++++++++++++----- OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs | 40 +++++++++++++++++-- OpenRA.Renderer.Sdl2/Sdl2Input.cs | 2 - 4 files changed, 82 insertions(+), 19 deletions(-) diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 804939411b..881949eacc 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -14,8 +14,8 @@ using System.Drawing; using System.IO; using System.Linq; using System.Net; -using OpenRA.FileSystem; using MaxMind.GeoIP2; +using OpenRA.FileSystem; using OpenRA.Graphics; using OpenRA.Network; using OpenRA.Primitives; @@ -464,7 +464,7 @@ namespace OpenRA return shellmaps.Random(CosmeticRandom); } - static bool quit; + static RunStatus state = RunStatus.Running; public static event Action OnQuit = () => { }; static double idealFrameTime; @@ -473,7 +473,7 @@ namespace OpenRA idealFrameTime = 1.0 / fps; } - internal static void Run() + internal static RunStatus Run() { if (Settings.Graphics.MaxFramerate < 1) { @@ -483,7 +483,7 @@ namespace OpenRA SetIdealFrameTime(Settings.Graphics.MaxFramerate); - while (!quit) + while (state == RunStatus.Running) { if (Settings.Graphics.CapFramerate) { @@ -506,9 +506,19 @@ namespace OpenRA Renderer.Device.Dispose(); OnQuit(); + + return state; } - public static void Exit() { quit = true; } + public static void Exit() + { + state = RunStatus.Success; + } + + public static void Restart() + { + state = RunStatus.Restart; + } public static Action AddChatLine = (c, n, s) => { }; diff --git a/OpenRA.Game/Support/Program.cs b/OpenRA.Game/Support/Program.cs index 4257d61c5a..1313760448 100644 --- a/OpenRA.Game/Support/Program.cs +++ b/OpenRA.Game/Support/Program.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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, @@ -11,30 +11,37 @@ using System; using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Text; namespace OpenRA { + enum RunStatus + { + Error = -1, + Success = 0, + Restart = 1, + Running = int.MaxValue + } + static class Program { [STAThread] - static void Main(string[] args) + static int Main(string[] args) { if (Debugger.IsAttached || args.Contains("--just-die")) - { - Run(args); - return; - } + return (int)Run(args); AppDomain.CurrentDomain.UnhandledException += (_, e) => FatalError((Exception)e.ExceptionObject); try { - Run(args); + return (int)Run(args); } catch (Exception e) { FatalError(e); + return (int)RunStatus.Error; } } @@ -102,11 +109,25 @@ namespace OpenRA return sb; } - static void Run(string[] args) + static RunStatus Run(string[] args) { + if (AppDomain.CurrentDomain.IsDefaultAppDomain()) + { + var name = Assembly.GetEntryAssembly().GetName(); + int retCode; + do + { + var domain = AppDomain.CreateDomain("Game"); + retCode = domain.ExecuteAssemblyByName(name, args); + AppDomain.Unload(domain); + } + while (retCode == (int)RunStatus.Restart); + return RunStatus.Success; + } + Game.Initialize(new Arguments(args)); GC.Collect(); - Game.Run(); + return Game.Run(); } } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs index 0510e992eb..f3e829fe4e 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs @@ -28,6 +28,24 @@ namespace OpenRA.Mods.RA.Widgets.Logic WorldRenderer worldRenderer; SoundDevice soundDevice; + static readonly string originalSoundDevice; + static readonly string originalSoundEngine; + static readonly WindowMode originalGraphicsMode; + static readonly string originalGraphicsRenderer; + static readonly int2 originalGraphicsWindowedSize; + static readonly int2 originalGraphicsFullscreenSize; + + static SettingsLogic() + { + var original = Game.Settings; + originalSoundDevice = original.Sound.Device; + originalSoundEngine = original.Sound.Engine; + originalGraphicsMode = original.Graphics.Mode; + originalGraphicsRenderer = original.Graphics.Renderer; + originalGraphicsWindowedSize = original.Graphics.WindowedSize; + originalGraphicsFullscreenSize = original.Graphics.FullscreenSize; + } + [ObjectCreator.UseCtor] public SettingsLogic(Widget widget, Action onExit, WorldRenderer worldRenderer) { @@ -44,9 +62,25 @@ namespace OpenRA.Mods.RA.Widgets.Logic panelContainer.Get("BACK_BUTTON").OnClick = () => { leavePanelActions[settingsPanel](); - Game.Settings.Save(); - Ui.CloseWindow(); - onExit(); + var current = Game.Settings; + current.Save(); + + Action closeAndExit = () => { Ui.CloseWindow(); onExit(); }; + if (originalSoundDevice != current.Sound.Device || + originalSoundEngine != current.Sound.Engine || + originalGraphicsMode != current.Graphics.Mode || + originalGraphicsRenderer != current.Graphics.Renderer || + originalGraphicsWindowedSize != current.Graphics.WindowedSize || + originalGraphicsFullscreenSize != current.Graphics.FullscreenSize) + ConfirmationDialogs.PromptConfirmAction( + "Restart Now?", + "Some changes will not be applied until\nthe game is restarted. Restart now?", + Game.Restart, + closeAndExit, + "Restart Now", + "Restart Later"); + else + closeAndExit(); }; panelContainer.Get("RESET_BUTTON").OnClick = () => diff --git a/OpenRA.Renderer.Sdl2/Sdl2Input.cs b/OpenRA.Renderer.Sdl2/Sdl2Input.cs index b90b4c7604..6b133589ae 100644 --- a/OpenRA.Renderer.Sdl2/Sdl2Input.cs +++ b/OpenRA.Renderer.Sdl2/Sdl2Input.cs @@ -170,9 +170,7 @@ namespace OpenRA.Renderer.Sdl2 // Special case workaround for windows users if (e.key.keysym.sym == SDL.SDL_Keycode.SDLK_F4 && mods.HasModifier(Modifiers.Alt) && Platform.CurrentPlatform == PlatformType.Windows) - { Game.Exit(); - } else inputHandler.OnKeyInput(keyEvent); From e8111e8ac6ea6497dc474f21251cb323f737f261 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Wed, 18 Jun 2014 21:33:31 +0100 Subject: [PATCH 2/2] Restart the process rather than reloading a new AppDomain. --- OpenRA.Game/Support/Program.cs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/OpenRA.Game/Support/Program.cs b/OpenRA.Game/Support/Program.cs index 1313760448..60b3333ff5 100644 --- a/OpenRA.Game/Support/Program.cs +++ b/OpenRA.Game/Support/Program.cs @@ -111,23 +111,13 @@ namespace OpenRA static RunStatus Run(string[] args) { - if (AppDomain.CurrentDomain.IsDefaultAppDomain()) - { - var name = Assembly.GetEntryAssembly().GetName(); - int retCode; - do - { - var domain = AppDomain.CreateDomain("Game"); - retCode = domain.ExecuteAssemblyByName(name, args); - AppDomain.Unload(domain); - } - while (retCode == (int)RunStatus.Restart); - return RunStatus.Success; - } - Game.Initialize(new Arguments(args)); GC.Collect(); - return Game.Run(); + var status = Game.Run(); + if (status == RunStatus.Restart) + using (var p = Process.GetCurrentProcess()) + Process.Start(Assembly.GetEntryAssembly().Location, p.StartInfo.Arguments); + return status; } } } \ No newline at end of file