using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using BizHawk.Emulation.Common; using BizHawk.Emulation.DiscSystem; namespace BizHawk.Emulation.Cores { /// /// finds and instantiates IEmulator cores /// public class CoreInventory { public class Core { public readonly string Name; public readonly Type Type; public readonly ConstructorInfo CTor; public Core(string Name, Type Type, ConstructorInfo CTor) { this.Name = Name; this.Type = Type; this.CTor = CTor; var pp = CTor.GetParameters(); for (int i = 0; i < pp.Length ; i++) { var p = pp[i]; string pname = p.Name.ToLowerInvariant(); Type expectedtype; if (!paramtypes.TryGetValue(pname, out expectedtype)) throw new InvalidOperationException(string.Format("Unexpected parameter name {0} in constructor for {1}", p.Name, Type)); if (expectedtype != p.ParameterType) throw new InvalidOperationException(string.Format("Unexpected type mismatch in parameter {0} in constructor for {1}", p.Name, Type)); parammap.Add(pname, i); } } // map parameter names to locations in the constructor private readonly Dictionary parammap = new Dictionary(); // expected names and types of the parameters private static readonly Dictionary paramtypes = new Dictionary(); static Core() { var pp = typeof(Core).GetMethod("Create").GetParameters(); 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; } /// /// instatiate an emulator core /// /// /// /// /// /// /// /// public IEmulator Create ( CoreComm comm, GameInfo game, byte[] rom, byte[] file, bool deterministic, object settings, object syncsettings ) { object[] o = new object[parammap.Count]; bp(o, "comm", comm); bp(o, "game", game); bp(o, "rom", rom); bp(o, "file", file); bp(o, "deterministic", deterministic); bp(o, "settings", settings); bp(o, "syncsettings", syncsettings); return (IEmulator)CTor.Invoke(o); } } private readonly Dictionary> systems = new Dictionary>(); private void ProcessConstructor(Type type, string system, CoreAttributes coreattr, ConstructorInfo cons) { Core core = new Core(coreattr.CoreName, type, cons); List ss; if (!systems.TryGetValue(system, out ss)) { ss = new List(); systems.Add(system, ss); } ss.Add(core); } /// /// find a core matching a particular game.system /// /// /// public Core this[string system] { get { List ss = systems[system]; if (ss.Count != 1) throw new InvalidOperationException("Ambiguous core selection!"); return ss[0]; } } /// /// find a core matching a particular game.system with a particular coreattributes.name /// /// /// /// public Core this[string system, string core] { get { List ss = systems[system]; foreach (Core c in ss) { if (c.Name == core) return c; } throw new InvalidOperationException("No such core!"); } } /// /// create a core inventory, collecting all IEmulators from some assembilies /// /// public CoreInventory(IEnumerable assys) { foreach (var assy in assys) { foreach (var typ in assy.GetTypes()) { if (typ.GetInterfaces().Contains(typeof(IEmulator))) { var coreattr = typ.GetCustomAttributes(typeof(CoreAttributes), false); if (coreattr.Length != 1) throw new InvalidOperationException(string.Format("IEmulator {0} without CoreAttributes!", typ)); var cons = typ.GetConstructors(BindingFlags.Public | BindingFlags.Instance) .Where(c => c.GetCustomAttributes(typeof(CoreConstructorAttribute), false).Length > 0).ToList(); foreach(var con in cons) { foreach (string system in ((CoreConstructorAttribute)con.GetCustomAttributes(typeof(CoreConstructorAttribute), false)[0]).Systems) { ProcessConstructor(typ, system, (CoreAttributes)coreattr[0], con); } } } } } } public static readonly CoreInventory Instance = new CoreInventory(new[] { typeof(CoreInventory).Assembly }); } [AttributeUsage(AttributeTargets.Constructor)] public class CoreConstructorAttribute : Attribute { public IEnumerable Systems { get { return _systems; } } private readonly List _systems = new List(); public CoreConstructorAttribute(params string[] Systems) { _systems.AddRange(Systems); } } }