diff --git a/BizHawk.Client.EmuHawk/Program.cs b/BizHawk.Client.EmuHawk/Program.cs index ca69912195..f38148808b 100644 --- a/BizHawk.Client.EmuHawk/Program.cs +++ b/BizHawk.Client.EmuHawk/Program.cs @@ -72,6 +72,9 @@ namespace BizHawk.Client.EmuHawk //We need to do it here too... otherwise people get exceptions when externaltools we distribute try to startup } + + // Assembly.ReflectionOnlyLoadFrom doesn't automatically load deps, this stops it from throwing when called + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (sender, args) => Assembly.ReflectionOnlyLoad(args.Name); } [STAThread] diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 27d1ed70e8..fef10a6b4b 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -736,60 +736,39 @@ namespace BizHawk.Client.EmuHawk } } - public bool IsAvailable() - { - return IsAvailable(typeof(T)); - } + private static readonly Lazy> lazyAsmTypes = new Lazy>(() => + Assembly.ReflectionOnlyLoadFrom(Assembly.GetExecutingAssembly().Location) + .GetTypes() + .Select(t => t.AssemblyQualifiedName) + .ToList() + ); - public bool IsAvailable(Type t) + public bool IsAvailable(Type tool) { - if (!ServiceInjector.IsAvailable(Global.Emulator.ServiceProvider, t)) + if (!ServiceInjector.IsAvailable(Global.Emulator.ServiceProvider, tool) + || !lazyAsmTypes.Value.Contains(tool.AssemblyQualifiedName) // not a tool + || (tool == typeof(LuaConsole) && OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)) // simply doesn't work (for now) { return false; } - if (t == typeof(LuaConsole) && OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows) return false; - - var tool = Assembly - .GetExecutingAssembly() - .GetTypes() - .FirstOrDefault(type => type == t); - - if (tool == null) // This isn't a tool, must not be available + ToolAttribute attr; + try { - return false; + attr = tool.GetCustomAttributes(false).OfType().Single(); + } + catch (InvalidOperationException e) + { + return true; // no ToolAttribute on given type -> assumed all supported } - var attr = tool.GetCustomAttributes(false) - .OfType() - .FirstOrDefault(); - - // start with the assumption that if no supported systems are mentioned and no unsupported cores are mentioned - // then this is available for all - bool supported = true; - - if (attr?.SupportedSystems != null && attr.SupportedSystems.Any()) - { - // supported systems are available - supported = attr.SupportedSystems.Contains(Global.Emulator.SystemId); - - if (supported) - { - // check for a core not supported override - if (attr.UnsupportedCores.Contains(Global.Emulator.DisplayName())) - supported = false; - } - } - else if (attr?.UnsupportedCores != null && attr.UnsupportedCores.Any()) - { - // no supported system specified, but unsupported cores are - if (attr.UnsupportedCores.Contains(Global.Emulator.DisplayName())) - supported = false; - } - - return supported; + var sysName = Global.Emulator.DisplayName(); + return !attr.UnsupportedCores.Contains(sysName) // not unsupported + && (!attr.SupportedSystems.Any() || attr.SupportedSystems.Contains(sysName)); // supported (no supported list -> assumed all supported) } + public bool IsAvailable() => IsAvailable(typeof(T)); + // Note: Referencing these properties creates an instance of the tool and persists it. They should be referenced by type if this is not desired #region Tools