cleanup CoreInventory.cs
This commit is contained in:
parent
29cddca49a
commit
01640e8c0b
|
@ -1,10 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.DiscSystem;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores
|
namespace BizHawk.Emulation.Cores
|
||||||
{
|
{
|
||||||
|
@ -13,56 +11,66 @@ namespace BizHawk.Emulation.Cores
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CoreInventory
|
public class CoreInventory
|
||||||
{
|
{
|
||||||
|
private readonly Dictionary<string, List<Core>> _systems = new Dictionary<string, List<Core>>();
|
||||||
|
|
||||||
public class Core
|
public class Core
|
||||||
{
|
{
|
||||||
public readonly string Name;
|
// expected names and types of the parameters
|
||||||
public readonly Type Type;
|
private static readonly Dictionary<string, Type> ParamTypes = new Dictionary<string, Type>();
|
||||||
public readonly ConstructorInfo CTor;
|
|
||||||
|
|
||||||
public Core(string Name, Type Type, ConstructorInfo CTor)
|
// map parameter names to locations in the constructor
|
||||||
|
private readonly Dictionary<string, int> _paramMap = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
static Core()
|
||||||
{
|
{
|
||||||
this.Name = Name;
|
var pp = typeof(Core).GetMethod("Create")?.GetParameters();
|
||||||
this.Type = Type;
|
if (pp != null)
|
||||||
this.CTor = CTor;
|
{
|
||||||
|
foreach (var p in pp)
|
||||||
|
{
|
||||||
|
ParamTypes.Add(p.Name.ToLowerInvariant(), p.ParameterType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Core(string name, Type type, ConstructorInfo ctor)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Type = type;
|
||||||
|
CTor = ctor;
|
||||||
|
|
||||||
var pp = CTor.GetParameters();
|
var pp = CTor.GetParameters();
|
||||||
for (int i = 0; i < pp.Length ; i++)
|
for (int i = 0; i < pp.Length ; i++)
|
||||||
{
|
{
|
||||||
var p = pp[i];
|
var p = pp[i];
|
||||||
string pname = p.Name.ToLowerInvariant();
|
string pName = p.Name.ToLowerInvariant();
|
||||||
Type expectedtype;
|
if (!ParamTypes.TryGetValue(pName, out _))
|
||||||
if (!paramtypes.TryGetValue(pname, out expectedtype))
|
{
|
||||||
throw new InvalidOperationException($"Unexpected parameter name {p.Name} in constructor for {Type}");
|
throw new InvalidOperationException($"Unexpected parameter name {p.Name} in constructor for {Type}");
|
||||||
|
}
|
||||||
|
|
||||||
// disabling the typecheck here doesn't really hurt anything, because the Invoke call will still catch any forbidden casts
|
// disabling the type check here doesn't really hurt anything, because the Invoke call will still catch any forbidden casts
|
||||||
// it does allow us to write "MySettingsType settings" instead of "object settings"
|
// it does allow us to write "MySettingsType settings" instead of "object settings"
|
||||||
// if (expectedtype != p.ParameterType)
|
// if (expectedType != p.ParameterType)
|
||||||
// throw new InvalidOperationException($"Unexpected type mismatch in parameter {p.Name} in constructor for {Type}");
|
// throw new InvalidOperationException($"Unexpected type mismatch in parameter {p.Name} in constructor for {Type}");
|
||||||
parammap.Add(pname, i);
|
_paramMap.Add(pName, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// map parameter names to locations in the constructor
|
public string Name { get; }
|
||||||
private readonly Dictionary<string, int> parammap = new Dictionary<string, int>();
|
public Type Type { get; }
|
||||||
// expected names and types of the parameters
|
public ConstructorInfo CTor { get; }
|
||||||
private static readonly Dictionary<string, Type> paramtypes = new Dictionary<string, Type>();
|
|
||||||
|
|
||||||
static Core()
|
private void Bp(object[] parameters, string name, object value)
|
||||||
{
|
{
|
||||||
var pp = typeof(Core).GetMethod("Create").GetParameters();
|
if (_paramMap.TryGetValue(name, out var i))
|
||||||
foreach (var p in pp)
|
{
|
||||||
paramtypes.Add(p.Name.ToLowerInvariant(), p.ParameterType);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bp(object[] parameters, string name, object value)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
if (parammap.TryGetValue(name, out i))
|
|
||||||
parameters[i] = value;
|
parameters[i] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// instatiate an emulator core
|
/// Instantiate an emulator core
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEmulator Create
|
public IEmulator Create
|
||||||
(
|
(
|
||||||
|
@ -72,34 +80,31 @@ namespace BizHawk.Emulation.Cores
|
||||||
byte[] file,
|
byte[] file,
|
||||||
bool deterministic,
|
bool deterministic,
|
||||||
object settings,
|
object settings,
|
||||||
object syncsettings
|
object syncSettings
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
object[] o = new object[parammap.Count];
|
object[] o = new object[_paramMap.Count];
|
||||||
bp(o, "comm", comm);
|
Bp(o, "comm", comm);
|
||||||
bp(o, "game", game);
|
Bp(o, "game", game);
|
||||||
bp(o, "rom", rom);
|
Bp(o, "rom", rom);
|
||||||
bp(o, "file", file);
|
Bp(o, "file", file);
|
||||||
bp(o, "deterministic", deterministic);
|
Bp(o, "deterministic", deterministic);
|
||||||
bp(o, "settings", settings);
|
Bp(o, "settings", settings);
|
||||||
bp(o, "syncsettings", syncsettings);
|
Bp(o, "syncsettings", syncSettings);
|
||||||
|
|
||||||
return (IEmulator)CTor.Invoke(o);
|
return (IEmulator)CTor.Invoke(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Dictionary<string, List<Core>> systems = new Dictionary<string, List<Core>>();
|
private void ProcessConstructor(Type type, string system, CoreAttribute coreAttr, ConstructorInfo cons)
|
||||||
|
|
||||||
|
|
||||||
private void ProcessConstructor(Type type, string system, CoreAttribute coreattr, ConstructorInfo cons)
|
|
||||||
{
|
{
|
||||||
Core core = new Core(coreattr.CoreName, type, cons);
|
Core core = new Core(coreAttr.CoreName, type, cons);
|
||||||
List<Core> ss;
|
if (!_systems.TryGetValue(system, out var ss))
|
||||||
if (!systems.TryGetValue(system, out ss))
|
|
||||||
{
|
{
|
||||||
ss = new List<Core>();
|
ss = new List<Core>();
|
||||||
systems.Add(system, ss);
|
_systems.Add(system, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss.Add(core);
|
ss.Add(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,48 +115,38 @@ namespace BizHawk.Emulation.Cores
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
List<Core> ss = systems[system];
|
List<Core> ss = _systems[system];
|
||||||
if (ss.Count != 1)
|
if (ss.Count != 1)
|
||||||
|
{
|
||||||
throw new InvalidOperationException("Ambiguous core selection!");
|
throw new InvalidOperationException("Ambiguous core selection!");
|
||||||
|
}
|
||||||
|
|
||||||
return ss[0];
|
return ss[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// find a core matching a particular game.system with a particular coreattributes.name
|
/// find a core matching a particular game.system with a particular CoreAttributes.Name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Core this[string system, string core]
|
public Core this[string system, string core]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
List<Core> ss = systems[system];
|
List<Core> ss = _systems[system];
|
||||||
foreach (Core c in ss)
|
foreach (Core c in ss)
|
||||||
{
|
{
|
||||||
if (c.Name == core)
|
if (c.Name == core)
|
||||||
|
{
|
||||||
return c;
|
return c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidOperationException("No such core!");
|
throw new InvalidOperationException("No such core!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// find an exact core type. slow lookup.
|
/// create a core inventory, collecting all IEmulators from some assemblies
|
||||||
/// </summary>
|
|
||||||
public Core FindByType(Type type)
|
|
||||||
{
|
|
||||||
foreach (List<Core> cc in systems.Values)
|
|
||||||
{
|
|
||||||
foreach (Core c in cc)
|
|
||||||
{
|
|
||||||
if (c.Type == type)
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new InvalidOperationException("No such core!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// create a core inventory, collecting all IEmulators from some assembilies
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CoreInventory(IEnumerable<Assembly> assys)
|
public CoreInventory(IEnumerable<Assembly> assys)
|
||||||
{
|
{
|
||||||
|
@ -161,8 +156,8 @@ namespace BizHawk.Emulation.Cores
|
||||||
{
|
{
|
||||||
if (!typ.IsAbstract && typ.GetInterfaces().Contains(typeof(IEmulator)))
|
if (!typ.IsAbstract && typ.GetInterfaces().Contains(typeof(IEmulator)))
|
||||||
{
|
{
|
||||||
var coreattr = typ.GetCustomAttributes(typeof(CoreAttribute), false);
|
var coreAttr = typ.GetCustomAttributes(typeof(CoreAttribute), false);
|
||||||
if (coreattr.Length != 1)
|
if (coreAttr.Length != 1)
|
||||||
throw new InvalidOperationException($"{nameof(IEmulator)} {typ} without {nameof(CoreAttribute)}s!");
|
throw new InvalidOperationException($"{nameof(IEmulator)} {typ} without {nameof(CoreAttribute)}s!");
|
||||||
var cons = typ.GetConstructors(BindingFlags.Public | BindingFlags.Instance)
|
var cons = typ.GetConstructors(BindingFlags.Public | BindingFlags.Instance)
|
||||||
.Where(c => c.GetCustomAttributes(typeof(CoreConstructorAttribute), false).Length > 0);
|
.Where(c => c.GetCustomAttributes(typeof(CoreConstructorAttribute), false).Length > 0);
|
||||||
|
@ -170,7 +165,7 @@ namespace BizHawk.Emulation.Cores
|
||||||
{
|
{
|
||||||
foreach (string system in ((CoreConstructorAttribute)con.GetCustomAttributes(typeof(CoreConstructorAttribute), false)[0]).Systems)
|
foreach (string system in ((CoreConstructorAttribute)con.GetCustomAttributes(typeof(CoreConstructorAttribute), false)[0]).Systems)
|
||||||
{
|
{
|
||||||
ProcessConstructor(typ, system, (CoreAttribute)coreattr[0], con);
|
ProcessConstructor(typ, system, (CoreAttribute)coreAttr[0], con);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,11 +179,13 @@ namespace BizHawk.Emulation.Cores
|
||||||
[AttributeUsage(AttributeTargets.Constructor)]
|
[AttributeUsage(AttributeTargets.Constructor)]
|
||||||
public class CoreConstructorAttribute : Attribute
|
public class CoreConstructorAttribute : Attribute
|
||||||
{
|
{
|
||||||
public IEnumerable<string> Systems { get { return _systems; } }
|
|
||||||
private readonly List<string> _systems = new List<string>();
|
private readonly List<string> _systems = new List<string>();
|
||||||
public CoreConstructorAttribute(params string[] Systems)
|
|
||||||
|
public CoreConstructorAttribute(params string[] systems)
|
||||||
{
|
{
|
||||||
_systems.AddRange(Systems);
|
_systems.AddRange(systems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> Systems => _systems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,8 @@
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=amstrad/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=amstrad/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Anaglyph/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Anaglyph/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Arkanoid/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Arkanoid/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=assy/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=assys/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=atten/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=atten/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Attribs/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Attribs/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Autofire/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Autofire/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
Loading…
Reference in New Issue