Refactor to make loading external tools simpler by not requiring passing around a load callback method.
Add TestExternalToolCanUseApi (passes)
This commit is contained in:
parent
74e210e80b
commit
6c1cb1e951
|
@ -14,13 +14,9 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
public struct MenuItemInfo
|
||||
{
|
||||
private readonly string _asmChecksum = "";
|
||||
public readonly string AsmChecksum = "";
|
||||
|
||||
private readonly string _entryPointTypeName = "";
|
||||
|
||||
private readonly ExternalToolManager _extToolMan;
|
||||
|
||||
private bool _skipExtToolWarning = false;
|
||||
public readonly string EntryPointTypeName = "";
|
||||
|
||||
public readonly string AsmFilename = "";
|
||||
|
||||
|
@ -33,7 +29,6 @@ namespace BizHawk.Client.Common
|
|||
public readonly bool Enabled = false;
|
||||
|
||||
public MenuItemInfo(
|
||||
ExternalToolManager extToolMan,
|
||||
string asmChecksum,
|
||||
string asmFilename,
|
||||
string entryPointTypeName,
|
||||
|
@ -42,10 +37,8 @@ namespace BizHawk.Client.Common
|
|||
string toolTip,
|
||||
bool enabled)
|
||||
{
|
||||
_asmChecksum = asmChecksum;
|
||||
_entryPointTypeName = entryPointTypeName;
|
||||
_extToolMan = extToolMan;
|
||||
_skipExtToolWarning = _extToolMan._config.TrustedExtTools.TryGetValue(asmFilename, out var s) && s == _asmChecksum;
|
||||
AsmChecksum = asmChecksum;
|
||||
EntryPointTypeName = entryPointTypeName;
|
||||
AsmFilename = asmFilename;
|
||||
Text = text;
|
||||
Icon = icon;
|
||||
|
@ -53,31 +46,17 @@ namespace BizHawk.Client.Common
|
|||
Enabled = enabled;
|
||||
}
|
||||
|
||||
public MenuItemInfo(ExternalToolManager extToolMan, string text, string toolTip)
|
||||
public MenuItemInfo(string text, string toolTip)
|
||||
{
|
||||
_extToolMan = extToolMan;
|
||||
Text = text;
|
||||
ToolTip = toolTip;
|
||||
}
|
||||
|
||||
public void TryLoad()
|
||||
{
|
||||
var success = _extToolMan._loadCallback(
|
||||
/*toolPath:*/ AsmFilename,
|
||||
/*customFormTypeName:*/ _entryPointTypeName,
|
||||
/*skipExtToolWarning:*/ _skipExtToolWarning);
|
||||
if (!success || _skipExtToolWarning) return;
|
||||
_skipExtToolWarning = true;
|
||||
_extToolMan._config.TrustedExtTools[AsmFilename] = _asmChecksum;
|
||||
}
|
||||
}
|
||||
|
||||
private Config _config;
|
||||
|
||||
private readonly Func<(string SysID, string Hash)> _getLoadedRomInfoCallback;
|
||||
|
||||
private readonly Func<string, string, bool, bool> _loadCallback;
|
||||
|
||||
private FileSystemWatcher DirectoryMonitor;
|
||||
|
||||
private readonly List<MenuItemInfo> MenuItems = new List<MenuItemInfo>();
|
||||
|
@ -86,11 +65,9 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public ExternalToolManager(
|
||||
Config config,
|
||||
Func<(string SysID, string Hash)> getLoadedRomInfoCallback,
|
||||
Func<string, string, bool, bool> loadCallback)
|
||||
Func<(string SysID, string Hash)> getLoadedRomInfoCallback)
|
||||
{
|
||||
_getLoadedRomInfoCallback = getLoadedRomInfoCallback;
|
||||
_loadCallback = loadCallback;
|
||||
Restart(config);
|
||||
}
|
||||
|
||||
|
@ -179,7 +156,6 @@ namespace BizHawk.Client.Common
|
|||
toolTip = toolAttribute.Description;
|
||||
|
||||
return new MenuItemInfo(
|
||||
this,
|
||||
asmChecksum: SHA1Checksum.ComputePrefixedHex(asmBytes),
|
||||
asmFilename: fileName,
|
||||
entryPointTypeName: entryPoint.FullName,
|
||||
|
@ -205,7 +181,7 @@ namespace BizHawk.Client.Common
|
|||
ReflectionTypeLoadException => "Something went wrong while trying to load the assembly.",
|
||||
_ => $"An exception of type {e.GetType().FullName} was thrown while trying to load the assembly and look for an IExternalToolForm:\n{e.Message}"
|
||||
};
|
||||
return new MenuItemInfo(this, text, toolTip);
|
||||
return new MenuItemInfo(text, toolTip);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
public interface IToolManager
|
||||
{
|
||||
IReadOnlyCollection<ExternalToolManager.MenuItemInfo> ExternalToolInfos { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Loads the tool dialog T (T must implements <see cref="IToolForm"/>) , if it does not exist it will be created, if it is already open, it will be focused
|
||||
/// This method should be used only if you can't use the generic one
|
||||
|
@ -29,7 +31,7 @@ namespace BizHawk.Client.Common
|
|||
where T : class, IToolForm;
|
||||
|
||||
/// <summary>Loads the external tool's entry form.</summary>
|
||||
IExternalToolForm LoadExternalToolForm(string toolPath, string customFormTypeName, bool focus = true, bool skipExtToolWarning = false);
|
||||
IExternalToolForm LoadExternalToolForm(ExternalToolManager.MenuItemInfo info, bool focus = true);
|
||||
|
||||
void AutoLoad();
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace BizHawk.Client.Common
|
|||
protected readonly IMovieSession _movieSession;
|
||||
protected IGameInfo _game;
|
||||
|
||||
public IReadOnlyCollection<ExternalToolManager.MenuItemInfo> ExternalToolInfos => _extToolManager.ToolStripItems;
|
||||
|
||||
// TODO: merge ToolHelper code where logical
|
||||
// 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
|
||||
|
@ -140,9 +142,9 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
/// <summary>Loads the external tool's entry form.</summary>
|
||||
public IExternalToolForm LoadExternalToolForm(string toolPath, string customFormTypeName, bool focus = true, bool skipExtToolWarning = false)
|
||||
public IExternalToolForm LoadExternalToolForm(ExternalToolManager.MenuItemInfo info, bool focus = true)
|
||||
{
|
||||
var existingTool = _tools.OfType<IExternalToolForm>().FirstOrDefault(t => t.GetType().Assembly.Location == toolPath);
|
||||
var existingTool = _tools.OfType<IExternalToolForm>().FirstOrDefault(t => t.GetType().Assembly.Location == info.AsmFilename);
|
||||
if (existingTool != null)
|
||||
{
|
||||
if (existingTool.IsActive)
|
||||
|
@ -158,7 +160,8 @@ namespace BizHawk.Client.Common
|
|||
_tools.Remove(existingTool);
|
||||
}
|
||||
|
||||
var newTool = (IExternalToolForm)CreateInstance(typeof(IExternalToolForm), toolPath, customFormTypeName, skipExtToolWarning: skipExtToolWarning);
|
||||
bool skipWarning = _config.TrustedExtTools.TryGetValue(info.AsmFilename, out var s) && s == info.AsmChecksum;
|
||||
var newTool = (IExternalToolForm)CreateInstance(typeof(IExternalToolForm), info.AsmFilename, info.EntryPointTypeName, skipExtToolWarning: skipWarning);
|
||||
if (newTool == null) return null;
|
||||
SetFormParent(newTool);
|
||||
if (!(ServiceInjector.UpdateServices(_emulator.ServiceProvider, newTool) && ApiInjector.UpdateApis(ApiProvider, newTool))) return null;
|
||||
|
@ -166,14 +169,16 @@ namespace BizHawk.Client.Common
|
|||
// auto settings
|
||||
if (newTool is IToolFormAutoConfig autoConfigTool)
|
||||
{
|
||||
AttachSettingHooks(autoConfigTool, _config.CommonToolSettings.GetValueOrPutNew(customFormTypeName));
|
||||
AttachSettingHooks(autoConfigTool, _config.CommonToolSettings.GetValueOrPutNew(info.EntryPointTypeName));
|
||||
}
|
||||
// custom settings
|
||||
if (HasCustomConfig(newTool))
|
||||
{
|
||||
InstallCustomConfig(newTool, _config.CustomToolSettings.GetValueOrPutNew(customFormTypeName));
|
||||
InstallCustomConfig(newTool, _config.CustomToolSettings.GetValueOrPutNew(info.EntryPointTypeName));
|
||||
}
|
||||
|
||||
_config.TrustedExtTools[info.AsmFilename] = info.AsmChecksum;
|
||||
|
||||
newTool.Restart();
|
||||
newTool.Show();
|
||||
return newTool;
|
||||
|
@ -467,7 +472,6 @@ namespace BizHawk.Client.Common
|
|||
|
||||
try
|
||||
{
|
||||
//tool = Activator.CreateInstanceFrom(dllPath, toolTypeName ?? "BizHawk.Client.EmuHawk.CustomMainForm").Unwrap() as IExternalToolForm;
|
||||
tool = CreateInstanceFrom(dllPath, toolTypeName);
|
||||
if (tool == null)
|
||||
{
|
||||
|
|
|
@ -1182,9 +1182,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
private void ExternalToolMenuItem_DropDownOpening(object sender, EventArgs e)
|
||||
{
|
||||
ExternalToolMenuItem.DropDownItems.Clear();
|
||||
ExternalToolMenuItem.DropDownItems.AddRange(ExtToolManager.ToolStripItems.Select(static (info) =>
|
||||
ExternalToolMenuItem.DropDownItems.AddRange(ExtToolManager.ToolStripItems.Select((info) =>
|
||||
{
|
||||
return new ToolStripMenuItem(info.Text, info.Icon, (_, _) => info.TryLoad())
|
||||
return new ToolStripMenuItem(info.Text, info.Icon, (_, _) => Tools.LoadExternalToolForm(info))
|
||||
{
|
||||
ToolTipText = info.ToolTip,
|
||||
Enabled = info.Enabled,
|
||||
|
|
|
@ -196,7 +196,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
.FirstOrNull(info => info.AsmFilename == requestedExtToolDll
|
||||
|| Path.GetFileName(info.AsmFilename) == requestedExtToolDll
|
||||
|| Path.GetFileNameWithoutExtension(info.AsmFilename) == requestedExtToolDll);
|
||||
if (found is not null) found.Value.TryLoad();
|
||||
if (found is not null) Tools.LoadExternalToolForm(found.Value);
|
||||
else Console.WriteLine($"requested ext. tool dll {requestedExtToolDll} could not be loaded");
|
||||
}
|
||||
|
||||
|
@ -473,11 +473,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
ExtToolManager = new(
|
||||
Config,
|
||||
() => (Emulator.SystemId, Game.Hash),
|
||||
(toolPath, customFormTypeName, skipExtToolWarning) => Tools!.LoadExternalToolForm(
|
||||
toolPath: toolPath,
|
||||
customFormTypeName: customFormTypeName,
|
||||
skipExtToolWarning: skipExtToolWarning) is not null);
|
||||
() => (Emulator.SystemId, Game.Hash));
|
||||
Tools = new ToolManager(this, Config, DisplayManager, ExtToolManager, InputManager, Emulator, MovieSession, Game);
|
||||
|
||||
// TODO GL - move these event handlers somewhere less obnoxious line in the On* overrides
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
Image = tsi.Icon ?? IconMissingIcon.Value,
|
||||
Text = tsi.Text,
|
||||
};
|
||||
tsb.Click += (_, _) => tsi.TryLoad();
|
||||
tsb.Click += (_, _) => Tools.LoadExternalToolForm(tsi);
|
||||
ToolBoxStrip.Items.Add(tsb);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,10 +31,16 @@ namespace BizHawk.Tests.Client.Common.Api
|
|||
)!.Path = "./extTools";
|
||||
}
|
||||
|
||||
private TestExternalAPI LoadExternalTool(ToolManagerBase toolManager)
|
||||
{
|
||||
var info = toolManager.ExternalToolInfos.First(static (i) => i.Text == "TEST");
|
||||
return (toolManager.LoadExternalToolForm(info) as TestExternalAPI)!;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestExternalToolIsFound()
|
||||
{
|
||||
ExternalToolManager manager = new ExternalToolManager(config, () => ("", ""), (p1, p2, p3) => true);
|
||||
ExternalToolManager manager = new ExternalToolManager(config, () => ("", ""));
|
||||
|
||||
Assert.IsTrue(manager.ToolStripItems.Count != 0);
|
||||
var item = manager.ToolStripItems.First(static (info) => info.Text == "TEST");
|
||||
|
@ -48,11 +54,22 @@ namespace BizHawk.Tests.Client.Common.Api
|
|||
DisplayManagerBase displayManager = new TestDisplayManager(mainFormApi.Emulator);
|
||||
TestToolManager toolManager = new TestToolManager(mainFormApi, config, displayManager);
|
||||
|
||||
TestExternalAPI externalApi = toolManager.Load<TestExternalAPI>();
|
||||
TestExternalAPI externalApi = LoadExternalTool(toolManager);
|
||||
Assert.AreEqual(0, externalApi.frameCount);
|
||||
toolManager.UpdateToolsBefore();
|
||||
toolManager.UpdateToolsAfter();
|
||||
Assert.AreEqual(1, externalApi.frameCount);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestExternalToolCanUseApi()
|
||||
{
|
||||
IMainFormForApi mainFormApi = new MockMainFormForApi(new NullEmulator());
|
||||
DisplayManagerBase displayManager = new TestDisplayManager(mainFormApi.Emulator);
|
||||
TestToolManager toolManager = new TestToolManager(mainFormApi, config, displayManager);
|
||||
|
||||
TestExternalAPI externalApi = LoadExternalTool(toolManager);
|
||||
Assert.AreEqual(mainFormApi.Emulator.AsVideoProviderOrDefault().BufferHeight, externalApi.APIs.EmuClient.BufferHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace BizHawk.Tests.Implementations
|
|||
mainFormApi,
|
||||
config,
|
||||
displayManager,
|
||||
new ExternalToolManager(config, () => ("", ""), (p1, p2, p3) => false),
|
||||
new ExternalToolManager(config, () => ("", "")),
|
||||
null,
|
||||
mainFormApi.Emulator,
|
||||
mainFormApi.MovieSession,
|
||||
|
@ -29,7 +29,7 @@ namespace BizHawk.Tests.Implementations
|
|||
.ToList();
|
||||
protected override bool CaptureIconAndName(object tool, Type toolType, ref Image? icon, ref string name)
|
||||
{
|
||||
ExternalToolAttribute? eta = toolType.GetCustomAttribute<ExternalToolAttribute>();
|
||||
ExternalToolAttribute? eta = tool.GetType().GetCustomAttribute<ExternalToolAttribute>();
|
||||
if (eta == null)
|
||||
throw new NotImplementedException(); // not an external tool
|
||||
|
||||
|
@ -41,6 +41,11 @@ namespace BizHawk.Tests.Implementations
|
|||
protected override void SetFormParent(IToolForm form) { }
|
||||
protected override void SetBaseProperties(IToolForm form) { }
|
||||
|
||||
protected override IExternalToolForm CreateInstanceFrom(string dllPath, string toolTypeName)
|
||||
{
|
||||
return (Activator.CreateInstanceFrom(dllPath, toolTypeName)!.Unwrap() as IExternalToolForm)!;
|
||||
}
|
||||
|
||||
public override IEnumerable<Type> AvailableTools => throw new NotImplementedException();
|
||||
|
||||
public override (Image Icon, string Name) GetIconAndNameFor(Type toolType) => throw new NotImplementedException();
|
||||
|
@ -49,7 +54,6 @@ namespace BizHawk.Tests.Implementations
|
|||
public override void UpdateCheatRelatedTools(object sender, CheatCollection.CheatListEventArgs e) => throw new NotImplementedException();
|
||||
protected override void AttachSettingHooks(IToolFormAutoConfig tool, ToolDialogSettings settings) => throw new NotImplementedException();
|
||||
|
||||
protected override IExternalToolForm CreateInstanceFrom(string dllPath, string toolTypeName) => throw new NotImplementedException();
|
||||
protected override void MaybeClearCheats() => throw new NotImplementedException();
|
||||
protected override void SetFormClosingEvent(IToolForm form, Action action) => throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace BizHawk.Tests.Mocks
|
|||
{
|
||||
public EmuClientApi? EmuClient { get ; set; }
|
||||
|
||||
public bool ShowMessageBox2(IDialogParent? owner, string text, string? caption = null, EMsgBoxIcon? icon = null, bool useOKCancel = false) => true;
|
||||
|
||||
public CheatCollection CheatList => throw new NotImplementedException();
|
||||
|
||||
public string CurrentlyOpenRom => throw new NotImplementedException();
|
||||
|
@ -55,7 +57,6 @@ namespace BizHawk.Tests.Mocks
|
|||
public IReadOnlyList<string>? ShowFileMultiOpenDialog(IDialogParent dialogParent, string? filterStr, ref int filterIndex, string initDir, bool discardCWDChange = false, string? initFileName = null, bool maySelectMultiple = false, string? windowTitle = null) => throw new NotImplementedException();
|
||||
public string? ShowFileSaveDialog(IDialogParent dialogParent, bool discardCWDChange, string? fileExt, string? filterStr, string initDir, string? initFileName, bool muteOverwriteWarning) => throw new NotImplementedException();
|
||||
public void ShowMessageBox(IDialogParent? owner, string text, string? caption = null, EMsgBoxIcon? icon = null) => throw new NotImplementedException();
|
||||
public bool ShowMessageBox2(IDialogParent? owner, string text, string? caption = null, EMsgBoxIcon? icon = null, bool useOKCancel = false) => throw new NotImplementedException();
|
||||
public bool? ShowMessageBox3(IDialogParent? owner, string text, string? caption = null, EMsgBoxIcon? icon = null) => throw new NotImplementedException();
|
||||
public bool StartNewMovie(IMovie movie, bool record) => throw new NotImplementedException();
|
||||
public void StartSound() => throw new NotImplementedException();
|
||||
|
|
Loading…
Reference in New Issue