Simplify API impl. instantiation

This commit is contained in:
YoshiRulz 2020-08-05 23:52:42 +10:00
parent c8b8efedac
commit 13ab27ca4e
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
11 changed files with 39 additions and 74 deletions

View File

@ -17,13 +17,6 @@ namespace BizHawk.Client.Common
[OptionalService]
private IMemoryDomains MemoryDomainCore { get; set; }
public MemoryApi(Action<string> logCallback)
{
LogCallback = logCallback;
}
public MemoryApi() : this(Console.WriteLine) {}
private readonly Action<string> LogCallback;
private bool _isBigEndian;
@ -63,6 +56,8 @@ namespace BizHawk.Client.Common
}
}
public MemoryApi(Action<string> logCallback) => LogCallback = logCallback;
private MemoryDomain NamedDomainOrCurrent(string name)
{
if (!string.IsNullOrEmpty(name))

View File

@ -9,17 +9,12 @@ namespace BizHawk.Client.Common
[RequiredService]
private IStatable StatableCore { get; set; }
public MemorySaveStateApi(Action<string> logCallback)
{
LogCallback = logCallback;
}
public MemorySaveStateApi() : this(Console.WriteLine) {}
private readonly Action<string> LogCallback;
private readonly Dictionary<Guid, byte[]> _memorySavestates = new Dictionary<Guid, byte[]>();
public MemorySaveStateApi(Action<string> logCallback) => LogCallback = logCallback;
public string SaveCoreStateToMemory()
{
var guid = Guid.NewGuid();

View File

@ -12,11 +12,20 @@ namespace BizHawk.Client.EmuHawk
{
public static class ApiManager
{
private static readonly Type[] CtorParamTypesA = { typeof(Action<string>), typeof(DisplayManager), typeof(InputManager), typeof(IMainFormForApi) };
/// <remarks>keys are impl., values are interface</remarks>
private static readonly IReadOnlyDictionary<Type, Type> _apiTypes
= Assembly.GetAssembly(typeof(IEmuClientApi)).GetTypes()
.Concat(Assembly.GetAssembly(typeof(EmuClientApi)).GetTypes())
.Where(t => /*t.IsClass &&*/t.IsSealed) // small optimisation; api impl. types are all sealed classes
.Select(t => (t, t.GetInterfaces().FirstOrDefault(t1 => typeof(IExternalApi).IsAssignableFrom(t1) && t1 != typeof(IExternalApi)))) // grab interface from impl. type...
.Where(tuple => tuple.Item2 != null) // ...if we couldn't determine what it's implementing, then it's not an api impl. type
.ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2);
private static readonly Type[] CtorParamTypesB = { typeof(Action<string>) };
private static readonly Type[] _ctorParamTypesA = { typeof(Action<string>) };
private static readonly Type[] CtorParamTypesEmuClientApi = { typeof(Action<string>), typeof(DisplayManager), typeof(InputManager), typeof(IMainFormForApi), typeof(Config), typeof(IEmulator), typeof(GameInfo) };
private static readonly Type[] _ctorParamTypesB = { typeof(Action<string>), typeof(IMainFormForApi) };
private static readonly Type[] _ctorParamTypesC = { typeof(Action<string>), typeof(IMainFormForApi), typeof(DisplayManager), typeof(InputManager), typeof(Config), typeof(IEmulator), typeof(GameInfo) };
/// <remarks>TODO do we need to keep references to these because of GC weirdness? --yoshi</remarks>
private static ApiContainer? _container;
@ -28,32 +37,17 @@ namespace BizHawk.Client.EmuHawk
IEmulatorServiceProvider serviceProvider,
Action<string> logCallback)
{
var libDict = new Dictionary<Type, IExternalApi>();
foreach (var api in Assembly.GetAssembly(typeof(IEmuClientApi)).GetTypes()
.Concat(Assembly.GetAssembly(typeof(EmuClientApi)).GetTypes())
.Where(t => /*t.IsClass && */t.IsSealed
&& typeof(IExternalApi).IsAssignableFrom(t)
&& ServiceInjector.IsAvailable(serviceProvider, t)))
{
//TODO if extra params are ignored, we can use the same array for every ConstructorInfo.Invoke call --yoshi
object instance;
if (typeof(IEmuClientApi).IsAssignableFrom(api))
{
instance = (api.GetConstructor(CtorParamTypesEmuClientApi) ?? throw new Exception("failed to call EmuClientApi's hack-filled ctor"))
.Invoke(new object[] { logCallback, GlobalWin.DisplayManager, GlobalWin.InputManager, mainForm, GlobalWin.Config, GlobalWin.Emulator, GlobalWin.Game });
}
else
{
instance = api.GetConstructor(CtorParamTypesA)?.Invoke(new object[] { logCallback, GlobalWin.DisplayManager, GlobalWin.InputManager, mainForm })
?? api.GetConstructor(CtorParamTypesB)?.Invoke(new object[] { logCallback })
?? Activator.CreateInstance(api);
}
ServiceInjector.UpdateServices(serviceProvider, instance);
libDict.Add(
api.GetInterfaces().First(intf => typeof(IExternalApi).IsAssignableFrom(intf) && intf != typeof(IExternalApi)),
(IExternalApi) instance
var libDict = _apiTypes.Keys.Where(t => ServiceInjector.IsAvailable(serviceProvider, t))
.ToDictionary(
t => _apiTypes[t],
t => (IExternalApi) (
t.GetConstructor(_ctorParamTypesC)?.Invoke(new object[] { logCallback, mainForm, GlobalWin.DisplayManager, GlobalWin.InputManager, GlobalWin.Config, GlobalWin.Emulator, GlobalWin.Game })
?? t.GetConstructor(_ctorParamTypesB)?.Invoke(new object[] { logCallback, mainForm })
?? t.GetConstructor(_ctorParamTypesA)?.Invoke(new object[] { logCallback })
?? Activator.CreateInstance(t)
)
);
}
foreach (var instance in libDict.Values) ServiceInjector.UpdateServices(serviceProvider, instance);
return new ApiContainer(libDict);
}

View File

@ -20,7 +20,7 @@ namespace BizHawk.Client.EmuHawk
public WebSocketServer? WebSockets => _wsServer;
public CommApi(Action<string> logCallback, DisplayManager displayManager, InputManager inputManager, IMainFormForApi mainForm)
public CommApi(Action<string> logCallback, IMainFormForApi mainForm)
{
_networkingHelpers = mainForm.NetworkingHelpers;
}

View File

@ -86,7 +86,7 @@ namespace BizHawk.Client.EmuHawk
public event StateSavedEventHandler StateSaved;
public EmuClientApi(Action<string> logCallback, DisplayManager displayManager, InputManager inputManager, IMainFormForApi mainForm, Config config, IEmulator emulator, GameInfo game)
public EmuClientApi(Action<string> logCallback, IMainFormForApi mainForm, DisplayManager displayManager, InputManager inputManager, Config config, IEmulator emulator, GameInfo game)
{
_config = config;
_displayManager = displayManager;

View File

@ -37,13 +37,6 @@ namespace BizHawk.Client.EmuHawk
[OptionalService]
private IRegionable RegionableCore { get; set; }
public EmulationApi(Action<string> logCallback)
{
LogCallback = logCallback;
}
public EmulationApi() : this(Console.WriteLine) {}
private readonly Action<string> LogCallback;
/// <summary>Using this property to get a reference to <see cref="GlobalWin.Config">GlobalWin.Config</see> is a terrible, horrible, no good, very bad idea. That's why it's not in the <see cref="IEmulationApi">interface</see>.</summary>
@ -62,6 +55,8 @@ namespace BizHawk.Client.EmuHawk
public Action YieldCallback { get; set; }
public EmulationApi(Action<string> logCallback) => LogCallback = logCallback;
public void DisplayVsync(bool enabled) => GlobalWin.Config.VSync = enabled;
public void FrameAdvance() => FrameAdvanceCallback();

View File

@ -17,13 +17,6 @@ namespace BizHawk.Client.EmuHawk
[RequiredService]
private IEmulator Emulator { get; set; }
public GuiApi(Action<string> logCallback)
{
LogCallback = logCallback;
}
public GuiApi() : this(Console.WriteLine) {}
private readonly Action<string> LogCallback;
private readonly Dictionary<string, Image> _imageCache = new Dictionary<string, Image>();
@ -52,6 +45,8 @@ namespace BizHawk.Client.EmuHawk
public bool HasGUISurface => _GUISurface != null;
public GuiApi(Action<string> logCallback) => LogCallback = logCallback;
private SolidBrush GetBrush(Color color) => _solidBrushes.TryGetValue(color, out var b) ? b : (_solidBrushes[color] = new SolidBrush(color));
private Pen GetPen(Color color) => _pens.TryGetValue(color, out var p) ? p : (_pens[color] = new Pen(color));

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
@ -15,7 +16,7 @@ namespace BizHawk.Client.EmuHawk
private readonly IMainFormForApi _mainForm;
public InputApi(Action<string> logCallback, DisplayManager displayManager, InputManager inputManager, IMainFormForApi mainForm)
public InputApi(Action<string> logCallback, IMainFormForApi mainForm, DisplayManager displayManager, InputManager inputManager, Config config, IEmulator emulator, GameInfo game)
{
_displayManager = displayManager;
_inputManager = inputManager;

View File

@ -7,15 +7,10 @@ namespace BizHawk.Client.EmuHawk
{
public sealed class JoypadApi : IJoypadApi
{
public JoypadApi(Action<string> logCallback)
{
LogCallback = logCallback;
}
public JoypadApi() : this(Console.WriteLine) {}
private readonly Action<string> LogCallback;
public JoypadApi(Action<string> logCallback) => LogCallback = logCallback;
public IDictionary<string, object> Get(int? controller = null)
{
return GlobalWin.InputManager.AutofireStickyXorAdapter.ToDictionary(controller);

View File

@ -9,15 +9,10 @@ namespace BizHawk.Client.EmuHawk
{
public sealed class MovieApi : IMovieApi
{
public MovieApi(Action<string> logCallback)
{
LogCallback = logCallback;
}
public MovieApi() : this(Console.WriteLine) {}
private readonly Action<string> LogCallback;
public MovieApi(Action<string> logCallback) => LogCallback = logCallback;
public bool StartsFromSavestate() => GlobalWin.MovieSession.Movie.IsActive() && GlobalWin.MovieSession.Movie.StartsFromSavestate;
public bool StartsFromSaveram() => GlobalWin.MovieSession.Movie.IsActive() && GlobalWin.MovieSession.Movie.StartsFromSaveRam;

View File

@ -12,7 +12,7 @@ namespace BizHawk.Client.EmuHawk
private readonly Action<string> LogCallback;
public SaveStateApi(Action<string> logCallback, DisplayManager displayManager, InputManager inputManager, IMainFormForApi mainForm)
public SaveStateApi(Action<string> logCallback, IMainFormForApi mainForm)
{
LogCallback = logCallback;
_mainForm = mainForm;