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();
}
///