diff --git a/src/BizHawk.Client.Common/tools/Interfaces/IToolForm.cs b/src/BizHawk.Client.Common/tools/Interfaces/IToolForm.cs index 7808226b029..34aaa653151 100644 --- a/src/BizHawk.Client.Common/tools/Interfaces/IToolForm.cs +++ b/src/BizHawk.Client.Common/tools/Interfaces/IToolForm.cs @@ -27,6 +27,12 @@ public interface IToolForm /// void UpdateValues(ToolFormUpdateType type); + /// + /// Stop the tool, in preparation for a game or core change. + /// A tool should expect that either or will be called after this. + /// + void Stop(); + /// /// Will be called anytime the dialog needs to be restarted, such as when a new ROM is loaded /// The tool implementing this needs to account for a Game and Core change diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 500e95cb784..50de85f13a1 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -3936,6 +3936,8 @@ private bool CloseGame(bool clearSram = false) if (saveMovieResult == TryAgainResult.Canceled) return false; } + Tools.Stop(); + if (clearSram) { var path = Config.PathEntries.SaveRamAbsolutePath(Game, MovieSession.Movie); diff --git a/src/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs b/src/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs index 57b36807041..7adc852f3ae 100644 --- a/src/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs +++ b/src/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs @@ -260,6 +260,18 @@ public string FromSlot protected override void UpdateAfter() => Update(fast: false); protected override void FastUpdateAfter() => Update(fast: true); + public override void Stop() + { + if (_isBotting) + { + StopBot(); + } + else if (_replayMode) + { + FinishReplay(); + } + } + public override void Restart() { _ = StatableCore!; // otherwise unused due to loadstating via MainForm; however this service is very much required so the property needs to be present @@ -272,16 +284,6 @@ public override void Restart() _dataSize = 1; } - if (_isBotting) - { - StopBot(); - } - else if (_replayMode) - { - FinishReplay(); - } - - if (_lastRom != MainForm.CurrentlyOpenRom) { _lastRom = MainForm.CurrentlyOpenRom; diff --git a/src/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.IToolForm.cs b/src/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.IToolForm.cs index c5e05550e76..745144dab1c 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.IToolForm.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.IToolForm.cs @@ -112,10 +112,14 @@ private void FullUpdate() BreakPointControl1.UpdateValues(); } + public override void Stop() + { + DisengageDebugger(); + } + public override void Restart() { UpdateCapabilitiesProps(); - DisengageDebugger(); EngageDebugger(); } diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 11cb93b96fa..1b3c8e71e4d 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -163,6 +163,7 @@ public LuaConsole() } private LuaLibraries LuaImp; + private List _scriptsToRestart = new(); private ConsoleLuaLibrary _consoleLib; @@ -198,10 +199,22 @@ private void BranchesMarkersSplit_SplitterMoved(object sender, SplitterEventArgs Settings.SplitDistance = splitContainer1.SplitterDistance; } - public override void Restart() + public override void Stop() { - List runningScripts = new(); + if (LuaImp is not null && !LuaImp.IsRebootingCore) + { + _scriptsToRestart = LuaImp.ScriptList.Where(lf => lf.Enabled).ToList(); + // we don't use _scriptsToRestart here, in case something is somehow partially active + foreach (var file in LuaImp.ScriptList) + { + file.Stop(); + } + } + } + + public override void Restart() + { ApiContainer apiContainer = ApiManager.RestartLua( Emulator.ServiceProvider, WriteToOutputWindow, @@ -215,23 +228,11 @@ public override void Restart() Game, DialogController); - // Things we need to do with the existing LuaImp before we can make a new one - if (LuaImp is not null) + if (LuaImp is not null && LuaImp.IsRebootingCore) { - if (LuaImp.IsRebootingCore) - { - // Even if the lua console is self-rebooting from client.reboot_core() we still want to re-inject dependencies - LuaImp.Restart(Emulator.ServiceProvider, Config, apiContainer); - return; - } - - runningScripts = LuaImp.ScriptList.Where(lf => lf.Enabled).ToList(); - - // we don't use runningScripts here as the other scripts need to be stopped too - foreach (var file in LuaImp.ScriptList) - { - file.Stop(); - } + // Even if the lua console is self-rebooting from client.reboot_core() we still want to re-inject dependencies + LuaImp.Restart(Emulator.ServiceProvider, Config, apiContainer); + return; } _openedFiles = new(_openedFiles, onChanged: SessionChangedCallback); @@ -255,7 +256,7 @@ public override void Restart() .Select(static f => $"{f.Library}.{f.Name}") .ToArray()); - foreach (var file in runningScripts) + foreach (var file in _scriptsToRestart) { EnableLuaFile(file); } diff --git a/src/BizHawk.Client.EmuHawk/tools/ToolFormBase.cs b/src/BizHawk.Client.EmuHawk/tools/ToolFormBase.cs index 176a21d712b..61f8b3450ee 100644 --- a/src/BizHawk.Client.EmuHawk/tools/ToolFormBase.cs +++ b/src/BizHawk.Client.EmuHawk/tools/ToolFormBase.cs @@ -31,6 +31,8 @@ public class ToolFormBase : FormBase, IToolForm, IDialogParent public virtual bool IsActive => IsHandleCreated && !IsDisposed; public virtual bool IsLoaded => IsActive; + public virtual void Stop() {} + public virtual void Restart() {} public void SetToolFormBaseProps( diff --git a/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs index b37e5b5bbee..2c6df8cb1a4 100644 --- a/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -41,6 +41,7 @@ static ToolManager() // For instance, add an IToolForm property called UsesCheats, so that a UpdateCheatRelatedTools() method can update all tools of this type // Also a UsesRam, and similar method private readonly List _tools = new List(); + private readonly List _toolsToRestart = new(); /// /// Initializes a new instance of the class. @@ -582,6 +583,15 @@ public void GeneralUpdateActiveExtTools() } } + public void Stop() + { + foreach (IToolForm tool in _tools.Where(static t => t.IsActive)) + { + _toolsToRestart.Add(tool); + tool.Stop(); + } + } + public void Restart(Config config, IEmulator emulator, IGameInfo game) { _config = config; @@ -597,7 +607,7 @@ public void Restart(Config config, IEmulator emulator, IGameInfo game) if (ServiceInjector.UpdateServices(_emulator.ServiceProvider, tool) && (tool is not IExternalToolForm || ApiInjector.UpdateApis(GetOrInitApiProvider, tool))) { - if (tool.IsActive) tool.Restart(); + if (_toolsToRestart.Contains(tool)) tool.Restart(); } else { @@ -611,6 +621,8 @@ public void Restart(Config config, IEmulator emulator, IGameInfo game) tool.Close(); _tools.Remove(tool); } + + _toolsToRestart.Clear(); } ///