diff --git a/src/BizHawk.Client.Common/IMainFormForApi.cs b/src/BizHawk.Client.Common/IMainFormForApi.cs
index 3ffe4c099f..0efe9f8d57 100644
--- a/src/BizHawk.Client.Common/IMainFormForApi.cs
+++ b/src/BizHawk.Client.Common/IMainFormForApi.cs
@@ -32,6 +32,10 @@ namespace BizHawk.Client.Common
/// only referenced from EmuClientApi
bool PauseAvi { get; set; }
+ IToolManager Tools { get; }
+
+ IMovieSession MovieSession { get; }
+
/// only referenced from EmuClientApi
void ClearHolds();
diff --git a/src/BizHawk.Client.Common/lua/ILuaLibraries.cs b/src/BizHawk.Client.Common/lua/ILuaLibraries.cs
index d03ec1dfc6..af3643fa79 100644
--- a/src/BizHawk.Client.Common/lua/ILuaLibraries.cs
+++ b/src/BizHawk.Client.Common/lua/ILuaLibraries.cs
@@ -44,7 +44,7 @@ namespace BizHawk.Client.Common
NLuaTableHelper GetTableHelper();
- void Restart(IEmulatorServiceProvider newServiceProvider, Config config, IEmulator emulator, IGameInfo game);
+ void Restart(Config config, IGameInfo game);
bool RemoveNamedFunctionMatching(Func predicate);
diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs
index 79b8523054..7ef78f5049 100644
--- a/src/BizHawk.Client.EmuHawk/MainForm.cs
+++ b/src/BizHawk.Client.EmuHawk/MainForm.cs
@@ -1034,6 +1034,7 @@ namespace BizHawk.Client.EmuHawk
internal readonly ExternalToolManager ExtToolManager;
public readonly ToolManager Tools;
+ IToolManager IMainFormForApi.Tools => Tools;
private DisplayManager DisplayManager;
diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs
index f0c0196d3e..1b4925c0d8 100644
--- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs
+++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs
@@ -195,7 +195,7 @@ namespace BizHawk.Client.EmuHawk
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, Emulator, Game);
+ LuaImp.Restart(Config, Game);
return;
}
@@ -214,12 +214,10 @@ namespace BizHawk.Client.EmuHawk
LuaImp = new LuaLibraries(
newScripts,
registeredFuncList,
- Emulator.ServiceProvider,
(MainForm) MainForm, //HACK
DisplayManager,
InputManager,
Config,
- Emulator,
Game);
InputBox.AutoCompleteCustomSource.AddRange(LuaImp.Docs.Select(a => $"{a.Library}.{a.Name}").ToArray());
diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs
new file mode 100644
index 0000000000..f3693501e6
--- /dev/null
+++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs
@@ -0,0 +1,58 @@
+using BizHawk.Client.Common;
+using BizHawk.Emulation.Common;
+
+namespace BizHawk.Client.EmuHawk
+{
+ internal class LuaLibraries : LuaLibrariesBase
+ {
+ private MainForm _mainForm;
+
+ public LuaLibraries(
+ LuaFileList scriptList,
+ LuaFunctionList registeredFuncList,
+ MainForm mainForm,
+ DisplayManagerBase displayManager,
+ InputManager inputManager,
+ Config config,
+ IGameInfo game)
+ : base(scriptList, registeredFuncList, mainForm, displayManager, inputManager, config, game)
+ {
+ _mainForm = mainForm;
+ RegisterLuaLibraries(ReflectionCache.Types);
+ }
+
+ protected override void HandleSpecialLuaLibraryProperties(LuaLibraryBase library)
+ {
+ base.HandleSpecialLuaLibraryProperties(library);
+
+ // TODO: make EmuHawk libraries have a base class with common properties such as this
+ // and inject them here
+ if (library is ConsoleLuaLibrary consoleLib)
+ {
+ consoleLib.Tools = _mainForm.Tools;
+ _logToLuaConsoleCallback = consoleLib.Log;
+ }
+ else if (library is FormsLuaLibrary formsLib)
+ {
+ formsLib.MainForm = _mainForm;
+ }
+ else if (library is TAStudioLuaLibrary tastudioLib)
+ {
+ tastudioLib.Tools = _mainForm.Tools;
+ }
+ else if (library is GuiLuaLibrary guiLib) // GuiLuaLibrary isn't in EmuHawk, but LuaCanvas is.
+ {
+ // emu lib may be null now, depending on order of ReflectionCache.Types, but definitely won't be null when this is called
+ guiLib.CreateLuaCanvasCallback = (width, height, x, y) =>
+ {
+ var canvas = new LuaCanvas(EmulationLuaLibrary, width, height, x, y, GetTableHelper(), LogToLuaConsole);
+ canvas.Show();
+ return GetTableHelper().ObjectToTable(canvas);
+ };
+
+ EnumerateLuaFunctions(nameof(LuaCanvas), typeof(LuaCanvas), null); // add LuaCanvas to Lua function reference table
+ }
+
+ }
+ }
+}
diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibrariesBase.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibrariesBase.cs
index c645397ed9..221f2e3094 100644
--- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibrariesBase.cs
+++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibrariesBase.cs
@@ -15,94 +15,27 @@ using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
- public class LuaLibraries : ILuaLibraries
+ public class LuaLibrariesBase : ILuaLibraries
{
- public LuaLibraries(
+ public LuaLibrariesBase(
LuaFileList scriptList,
LuaFunctionList registeredFuncList,
- IEmulatorServiceProvider serviceProvider,
- MainForm mainForm,
+ IMainFormForApi mainFormApi,
DisplayManagerBase displayManager,
InputManager inputManager,
Config config,
- IEmulator emulator,
IGameInfo game)
{
- void EnumerateLuaFunctions(string name, Type type, LuaLibraryBase instance)
- {
- if (instance != null) _lua.NewTable(name);
- foreach (var method in type.GetMethods())
- {
- var foundAttrs = method.GetCustomAttributes(typeof(LuaMethodAttribute), false);
- if (foundAttrs.Length == 0) continue;
- if (instance != null) _lua.RegisterFunction($"{name}.{((LuaMethodAttribute)foundAttrs[0]).Name}", instance, method);
- LibraryFunction libFunc = new(
- name,
- type.GetCustomAttributes(typeof(DescriptionAttribute), false).Cast()
- .Select(descAttr => descAttr.Description).FirstOrDefault() ?? string.Empty,
- method
- );
- Docs.Add(libFunc);
- }
- }
-
_th = new NLuaTableHelper(_lua, LogToLuaConsole);
_displayManager = displayManager;
_inputManager = inputManager;
- _mainForm = mainForm;
+ _mainFormApi = mainFormApi;
LuaWait = new AutoResetEvent(false);
PathEntries = config.PathEntries;
RegisteredFunctions = registeredFuncList;
ScriptList = scriptList;
Docs.Clear();
- _apiContainer = ApiManager.RestartLua(serviceProvider, LogToLuaConsole, _mainForm, _displayManager, _inputManager, _mainForm.MovieSession, _mainForm.Tools, config, emulator, game);
-
- // Register lua libraries
- foreach (var lib in Client.Common.ReflectionCache.Types.Concat(EmuHawk.ReflectionCache.Types)
- .Where(t => typeof(LuaLibraryBase).IsAssignableFrom(t) && t.IsSealed && ServiceInjector.IsAvailable(serviceProvider, t)))
- {
- if (VersionInfo.DeveloperBuild
- || lib.GetCustomAttribute(inherit: false)?.Released is not false)
- {
- var instance = (LuaLibraryBase)Activator.CreateInstance(lib, this, _apiContainer, (Action)LogToLuaConsole);
- if (!ServiceInjector.UpdateServices(serviceProvider, instance, mayCache: true)) throw new Exception("Lua lib has required service(s) that can't be fulfilled");
-
- // TODO: make EmuHawk libraries have a base class with common properties such as this
- // and inject them here
- if (instance is ClientLuaLibrary clientLib)
- {
- clientLib.MainForm = _mainForm;
- }
- else if (instance is ConsoleLuaLibrary consoleLib)
- {
- consoleLib.Tools = _mainForm.Tools;
- _logToLuaConsoleCallback = consoleLib.Log;
- }
- else if (instance is FormsLuaLibrary formsLib)
- {
- formsLib.MainForm = _mainForm;
- }
- else if (instance is GuiLuaLibrary guiLib)
- {
- // emu lib may be null now, depending on order of ReflectionCache.Types, but definitely won't be null when this is called
- guiLib.CreateLuaCanvasCallback = (width, height, x, y) =>
- {
- var canvas = new LuaCanvas(EmulationLuaLibrary, width, height, x, y, _th, LogToLuaConsole);
- canvas.Show();
- return _th.ObjectToTable(canvas);
- };
- }
- else if (instance is TAStudioLuaLibrary tastudioLib)
- {
- tastudioLib.Tools = _mainForm.Tools;
- }
-
- EnumerateLuaFunctions(instance.Name, lib, instance);
- Libraries.Add(lib, instance);
- }
- }
-
- _lua.RegisterFunction("print", this, typeof(LuaLibraries).GetMethod(nameof(Print)));
+ _apiContainer = ApiManager.RestartLua(_mainFormApi.Emulator.ServiceProvider, LogToLuaConsole, _mainFormApi, _displayManager, _inputManager, _mainFormApi.MovieSession, _mainFormApi.Tools, config, _mainFormApi.Emulator, game);
var packageTable = (LuaTable) _lua["package"];
var luaPath = PathEntries.LuaAbsolutePath();
@@ -123,10 +56,58 @@ namespace BizHawk.Client.EmuHawk
packageTable["cpath"] = ((string)packageTable["cpath"]).Replace(";.\\?.dll", "");
}
- EmulationLuaLibrary.FrameAdvanceCallback = FrameAdvance;
- EmulationLuaLibrary.YieldCallback = EmuYield;
+ _lua.RegisterFunction("print", this, typeof(LuaLibrariesBase).GetMethod(nameof(Print)));
- EnumerateLuaFunctions(nameof(LuaCanvas), typeof(LuaCanvas), null); // add LuaCanvas to Lua function reference table
+ RegisterLuaLibraries(Common.ReflectionCache.Types);
+ }
+
+ protected void EnumerateLuaFunctions(string name, Type type, LuaLibraryBase instance)
+ {
+ if (instance != null) _lua.NewTable(name);
+ foreach (var method in type.GetMethods())
+ {
+ var foundAttrs = method.GetCustomAttributes(typeof(LuaMethodAttribute), false);
+ if (foundAttrs.Length == 0) continue;
+ if (instance != null) _lua.RegisterFunction($"{name}.{((LuaMethodAttribute)foundAttrs[0]).Name}", instance, method);
+ LibraryFunction libFunc = new(
+ name,
+ type.GetCustomAttributes(typeof(DescriptionAttribute), false).Cast()
+ .Select(descAttr => descAttr.Description).FirstOrDefault() ?? string.Empty,
+ method
+ );
+ Docs.Add(libFunc);
+ }
+ }
+ protected void RegisterLuaLibraries(IEnumerable typesToSearch)
+ {
+ foreach (var lib in typesToSearch
+ .Where(t => typeof(LuaLibraryBase).IsAssignableFrom(t) && t.IsSealed && ServiceInjector.IsAvailable(_mainFormApi.Emulator.ServiceProvider, t)))
+ {
+ if (VersionInfo.DeveloperBuild
+ || lib.GetCustomAttribute(inherit: false)?.Released is not false)
+ {
+ var instance = (LuaLibraryBase)Activator.CreateInstance(lib, this, _apiContainer, (Action)LogToLuaConsole);
+ if (!ServiceInjector.UpdateServices(_mainFormApi.Emulator.ServiceProvider, instance, mayCache: true)) throw new Exception("Lua lib has required service(s) that can't be fulfilled");
+
+ HandleSpecialLuaLibraryProperties(instance);
+
+ EnumerateLuaFunctions(instance.Name, lib, instance);
+ Libraries.Add(lib, instance);
+ }
+ }
+ }
+
+ protected virtual void HandleSpecialLuaLibraryProperties(LuaLibraryBase library)
+ {
+ if (library is ClientLuaLibrary clientLib)
+ {
+ clientLib.MainForm = _mainFormApi;
+ }
+ else if (library is EmulationLuaLibrary emulationLib)
+ {
+ emulationLib.FrameAdvanceCallback = FrameAdvance;
+ emulationLib.YieldCallback = EmuYield;
+ }
}
private ApiContainer _apiContainer;
@@ -137,20 +118,20 @@ namespace BizHawk.Client.EmuHawk
private readonly InputManager _inputManager;
- private readonly MainForm _mainForm;
+ private readonly IMainFormForApi _mainFormApi;
private Lua _lua = new();
private LuaThread _currThread;
private readonly NLuaTableHelper _th;
- private static Action