Cleanup some ApiHawk management code
This commit is contained in:
parent
9e4595c184
commit
c1cd1b9e0f
|
@ -7,15 +7,15 @@ namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
public Dictionary<Type, IExternalApi> Libraries { get; set; }
|
public Dictionary<Type, IExternalApi> Libraries { get; set; }
|
||||||
|
|
||||||
public IEmu Emu => (IEmu) Libraries[typeof(EmuApi)];
|
public IEmu Emu => (IEmu) Libraries[typeof(IEmu)];
|
||||||
public IGameInfo GameInfo => (IGameInfo) Libraries[typeof(GameInfoApi)];
|
public IGameInfo GameInfo => (IGameInfo) Libraries[typeof(IGameInfo)];
|
||||||
public IJoypad Joypad => (IJoypad) Libraries[typeof(JoypadApi)];
|
public IJoypad Joypad => (IJoypad) Libraries[typeof(IJoypad)];
|
||||||
public IMem Mem => (IMem) Libraries[typeof(MemApi)];
|
public IMem Mem => (IMem) Libraries[typeof(IMem)];
|
||||||
public IMemEvents MemEvents => (IMemEvents) Libraries[typeof(MemEventsApi)];
|
public IMemEvents MemEvents => (IMemEvents) Libraries[typeof(IMemEvents)];
|
||||||
public IMemorySaveState MemorySaveState => (IMemorySaveState) Libraries[typeof(MemorySaveStateApi)];
|
public IMemorySaveState MemorySaveState => (IMemorySaveState) Libraries[typeof(IMemorySaveState)];
|
||||||
public IInputMovie Movie => (IInputMovie) Libraries[typeof(MovieApi)];
|
public IInputMovie Movie => (IInputMovie) Libraries[typeof(IInputMovie)];
|
||||||
public ISql Sql => (ISql) Libraries[typeof(SqlApi)];
|
public ISql Sql => (ISql) Libraries[typeof(ISql)];
|
||||||
public IUserData UserData => (IUserData) Libraries[typeof(UserDataApi)];
|
public IUserData UserData => (IUserData) Libraries[typeof(IUserData)];
|
||||||
|
|
||||||
public ApiSubsetContainer(Dictionary<Type, IExternalApi> libs)
|
public ApiSubsetContainer(Dictionary<Type, IExternalApi> libs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace BizHawk.Client.Common
|
||||||
|
{
|
||||||
|
public static class ApiHawkExtensions
|
||||||
|
{
|
||||||
|
/// <returns>an instance of the <see cref="IExternalApi"/> <typeparamref name="T"/> iff available else <see langword="null"/></returns>
|
||||||
|
public static T? GetApi<T>(this IExternalApiProvider apiProvider)
|
||||||
|
where T : class, IExternalApi
|
||||||
|
=> apiProvider.GetApi(typeof(T)) as T;
|
||||||
|
|
||||||
|
/// <returns><see langword="true"/> iff an instance of the <see cref="IExternalApi"/> <typeparamref name="T"/> is available</returns>
|
||||||
|
public static bool HasApi<T>(this IExternalApiProvider apiProvider)
|
||||||
|
where T : class, IExternalApi
|
||||||
|
=> apiProvider.HasApi(typeof(T));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +1,21 @@
|
||||||
using System;
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace BizHawk.Client.Common
|
namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// A generic implementation of IExternalApi provider that provides
|
|
||||||
/// this functionality to any core.
|
|
||||||
/// The provider will scan an IExternal and register all IExternalApis
|
|
||||||
/// that the core object itself implements. In addition it provides
|
|
||||||
/// a Register() method to allow the core to pass in any additional Apis
|
|
||||||
/// </summary>
|
|
||||||
/// <seealso cref="IExternalApiProvider"/>
|
|
||||||
public class BasicApiProvider : IExternalApiProvider
|
public class BasicApiProvider : IExternalApiProvider
|
||||||
{
|
{
|
||||||
private readonly Dictionary<Type, IExternalApi> _apis;
|
private readonly IReadOnlyDictionary<Type, IExternalApi> _libs;
|
||||||
|
|
||||||
public BasicApiProvider(IApiContainer container)
|
public IReadOnlyCollection<Type> AvailableApis => _libs.Keys.ToList();
|
||||||
{
|
|
||||||
// simplified logic here doesn't scan for possible Apis; just adds what it knows is implemented by the PluginApi
|
|
||||||
// this removes the possibility of automagically picking up a Api in a nested class, (find the type, then
|
|
||||||
// find the field), but we're going to keep such logic out of the basic provider. Anything the passed
|
|
||||||
// container doesn't implement directly needs to be added with Register()
|
|
||||||
// this also fully allows apis that are not IExternalApi
|
|
||||||
var libs = container.Libraries;
|
|
||||||
|
|
||||||
_apis = libs;
|
public BasicApiProvider(IReadOnlyDictionary<Type, IExternalApi> libs) => _libs = libs;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>the client can call this to register an additional API</summary>
|
public object? GetApi(Type t) => _libs.TryGetValue(t, out var api) ? api : null;
|
||||||
/// <typeparam name="T">the type, inheriting <see cref="IExternalApi"/>, to be registered</typeparam>
|
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="api"/> is null</exception>
|
|
||||||
public void Register<T>(T api)
|
|
||||||
where T : IExternalApi
|
|
||||||
{
|
|
||||||
if (api == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(api));
|
|
||||||
}
|
|
||||||
|
|
||||||
_apis[typeof(T)] = api;
|
public bool HasApi(Type t) => _libs.ContainsKey(t);
|
||||||
}
|
|
||||||
|
|
||||||
public T GetApi<T>()
|
|
||||||
where T : IExternalApi
|
|
||||||
{
|
|
||||||
return (T)GetApi(typeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetApi(Type t)
|
|
||||||
{
|
|
||||||
var k = _apis.Where(kvp => t.IsAssignableFrom(kvp.Key)).ToArray();
|
|
||||||
return k.Length > 0 ? k[0].Value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasApi<T>()
|
|
||||||
where T : IExternalApi
|
|
||||||
{
|
|
||||||
return HasApi(typeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasApi(Type t) => _apis.ContainsKey(t);
|
|
||||||
|
|
||||||
public IEnumerable<Type> AvailableApis => _apis.Select(d => d.Key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,19 @@
|
||||||
using System;
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace BizHawk.Client.Common
|
namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// This interface defines the mechanism by which External tools can retrieve <seealso cref="IExternalApi" />
|
|
||||||
/// from a client implementation
|
|
||||||
/// An implementation should collect all available IExternalApi instances.
|
|
||||||
/// This interface defines only the external interaction. This interface does not specify the means
|
|
||||||
/// by which a api provider will be populated with available apis. However, an implementation
|
|
||||||
/// by design must provide this mechanism
|
|
||||||
/// </summary>
|
|
||||||
/// <seealso cref="IExternalApi"/>
|
|
||||||
public interface IExternalApiProvider
|
public interface IExternalApiProvider
|
||||||
{
|
{
|
||||||
/// <summary>e
|
/// <returns>a list of all currently registered <see cref="IExternalApi">APIs</see> that are available</returns>
|
||||||
/// Returns whether or not T is available
|
IReadOnlyCollection<Type> AvailableApis { get; }
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The <seealso cref="IExternalApi" /> to check</typeparam>
|
|
||||||
bool HasApi<T>() where T : IExternalApi;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <returns>an instance of the <see cref="IExternalApi"/> <paramref name="t"/> iff available else <see langword="null"/></returns>
|
||||||
/// Returns whether or not t is available
|
object? GetApi(Type t);
|
||||||
/// </summary>
|
|
||||||
|
/// <returns><see langword="true"/> iff an instance of the <see cref="IExternalApi"/> <paramref name="t"/> is available</returns>
|
||||||
bool HasApi(Type t);
|
bool HasApi(Type t);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns an instance of T if T is available
|
|
||||||
/// Else returns null
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The requested <seealso cref="IExternalApi" /></typeparam>
|
|
||||||
T GetApi<T>() where T : IExternalApi;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns an instance of t if t is available
|
|
||||||
/// Else returns null
|
|
||||||
/// </summary>
|
|
||||||
object GetApi(Type t);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of all currently registered Apis available to be retrieved
|
|
||||||
/// </summary>
|
|
||||||
IEnumerable<Type> AvailableApis { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,11 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
public sealed class ApiContainer : ApiSubsetContainer
|
public sealed class ApiContainer : ApiSubsetContainer
|
||||||
{
|
{
|
||||||
public IComm Comm => (IComm) Libraries[typeof(CommApi)];
|
public IComm Comm => (IComm) Libraries[typeof(IComm)];
|
||||||
public IGui Gui => (IGui) Libraries[typeof(GuiApi)];
|
public IGui Gui => (IGui) Libraries[typeof(IGui)];
|
||||||
public IInput Input => (IInput) Libraries[typeof(InputApi)];
|
public IInput Input => (IInput) Libraries[typeof(IInput)];
|
||||||
public ISaveState SaveState => (ISaveState) Libraries[typeof(SaveStateApi)];
|
public ISaveState SaveState => (ISaveState) Libraries[typeof(ISaveState)];
|
||||||
public ITool Tool => (ITool) Libraries[typeof(ToolApi)];
|
public ITool Tool => (ITool) Libraries[typeof(ITool)];
|
||||||
|
|
||||||
public ApiContainer(Dictionary<Type, IExternalApi> libs) : base(libs) {}
|
public ApiContainer(Dictionary<Type, IExternalApi> libs) : base(libs) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,22 +11,25 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
public static class ApiManager
|
public static class ApiManager
|
||||||
{
|
{
|
||||||
|
/// <remarks>TODO do we need to keep this reference around? --yoshi</remarks>
|
||||||
private static ApiContainer _container;
|
private static ApiContainer _container;
|
||||||
|
|
||||||
private static IExternalApiProvider Register(IEmulatorServiceProvider serviceProvider)
|
private static IExternalApiProvider Register(IEmulatorServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
foreach (var api in Assembly.GetAssembly(typeof(ApiSubsetContainer)).GetTypes()
|
foreach (var api in Assembly.GetAssembly(typeof(ApiSubsetContainer)).GetTypes()
|
||||||
.Concat(Assembly.GetAssembly(typeof(ApiContainer)).GetTypes())
|
.Concat(Assembly.GetAssembly(typeof(ApiContainer)).GetTypes())
|
||||||
.Where(t => typeof(IExternalApi).IsAssignableFrom(t) && t.IsSealed && ServiceInjector.IsAvailable(serviceProvider, t)))
|
.Where(t => /*t.IsClass && */t.IsSealed && typeof(IExternalApi).IsAssignableFrom(t) && ServiceInjector.IsAvailable(serviceProvider, t)))
|
||||||
{
|
{
|
||||||
var instance = (IExternalApi)Activator.CreateInstance(api);
|
var instance = (IExternalApi)Activator.CreateInstance(api);
|
||||||
ServiceInjector.UpdateServices(serviceProvider, instance);
|
ServiceInjector.UpdateServices(serviceProvider, instance);
|
||||||
Libraries.Add(api, instance);
|
Libraries.Add(api.GetInterfaces().First(intf => typeof(IExternalApi).IsAssignableFrom(intf) && intf != typeof(IExternalApi)), instance);
|
||||||
}
|
}
|
||||||
_container = new ApiContainer(Libraries);
|
_container = new ApiContainer(Libraries);
|
||||||
return new BasicApiProvider(_container);
|
return new BasicApiProvider(Libraries);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Dictionary<Type, IExternalApi> Libraries = new Dictionary<Type, IExternalApi>();
|
private static readonly Dictionary<Type, IExternalApi> Libraries = new Dictionary<Type, IExternalApi>();
|
||||||
|
|
||||||
public static IExternalApiProvider Restart(IEmulatorServiceProvider newServiceProvider)
|
public static IExternalApiProvider Restart(IEmulatorServiceProvider newServiceProvider)
|
||||||
{
|
{
|
||||||
Libraries.Clear();
|
Libraries.Clear();
|
||||||
|
|
Loading…
Reference in New Issue