Don't use fragile fully qualified typenames to resolve setting and sync setting types in config files.

Instead, the frontend must know what the type will be ahead of time.

TODO:  Apply the same fix to mooovies
This commit is contained in:
nattthebear 2020-07-11 13:34:41 -04:00
parent a28ca37cfb
commit bcbf124f21
38 changed files with 152 additions and 146 deletions

View File

@ -54,28 +54,28 @@ namespace BizHawk.Client.Common
}
// helper methods for the settings events
private object GetCoreSettings<T>()
where T : IEmulator
private TSetting GetCoreSettings<TCore, TSetting>()
where TCore : IEmulator
{
return GetCoreSettings(typeof(T));
return (TSetting)GetCoreSettings(typeof(TCore), typeof(TSetting));
}
private object GetCoreSyncSettings<T>()
where T : IEmulator
private TSync GetCoreSyncSettings<TCore, TSync>()
where TCore : IEmulator
{
return GetCoreSyncSettings(typeof(T));
return (TSync)GetCoreSyncSettings(typeof(TCore), typeof(TSync));
}
private object GetCoreSettings(Type t)
private object GetCoreSettings(Type t, Type settingsType)
{
var e = new SettingsLoadArgs(t);
var e = new SettingsLoadArgs(t, settingsType);
OnLoadSettings?.Invoke(this, e);
return e.Settings;
}
private object GetCoreSyncSettings(Type t)
private object GetCoreSyncSettings(Type t, Type syncSettingsType)
{
var e = new SettingsLoadArgs(t);
var e = new SettingsLoadArgs(t, syncSettingsType);
OnLoadSyncSettings?.Invoke(this, e);
return e.Settings;
}
@ -125,9 +125,11 @@ namespace BizHawk.Client.Common
{
public object Settings { get; set; }
public Type Core { get; }
public SettingsLoadArgs(Type t)
public Type SettingsType { get; }
public SettingsLoadArgs(Type t, Type s)
{
Core = t;
SettingsType = s;
Settings = null;
}
}
@ -309,16 +311,16 @@ namespace BizHawk.Client.Common
game,
null,
new[] { disc },
GetCoreSettings<GPGX>(),
GetCoreSyncSettings<GPGX>()
GetCoreSettings<GPGX, GPGX.GPGXSettings>(),
GetCoreSyncSettings<GPGX, GPGX.GPGXSyncSettings>()
);
break;
case "SAT":
nextEmulator = new Saturnus(
nextComm, game,
new[] { disc },
(NymaCore.NymaSettings)GetCoreSettings<Saturnus>(),
(NymaCore.NymaSyncSettings)GetCoreSyncSettings<Saturnus>(),
GetCoreSettings<Saturnus, NymaCore.NymaSettings>(),
GetCoreSyncSettings<Saturnus, NymaCore.NymaSyncSettings>(),
Deterministic
);
break;
@ -328,15 +330,15 @@ namespace BizHawk.Client.Common
new List<Disc> { disc },
new List<string> { Path.GetFileNameWithoutExtension(path) },
null,
GetCoreSettings<Octoshock>(),
GetCoreSyncSettings<Octoshock>(),
GetCoreSettings<Octoshock, Octoshock.Settings>(),
GetCoreSyncSettings<Octoshock, Octoshock.SyncSettings>(),
DiscHashWarningText(game, discHash)
);
break;
case "PCFX":
nextEmulator = new Tst(nextComm, game, new[] { disc },
(NymaCore.NymaSettings)GetCoreSettings<Tst>(),
(NymaCore.NymaSyncSettings)GetCoreSyncSettings<Tst>(),
GetCoreSettings<Tst, NymaCore.NymaSettings>(),
GetCoreSyncSettings<Tst, NymaCore.NymaSyncSettings>(),
Deterministic);
break;
case "PCE": // TODO: this is clearly not used, its set to PCE by code above
@ -348,8 +350,8 @@ namespace BizHawk.Client.Common
nextComm,
game,
disc,
GetCoreSettings<PCEngine>(),
GetCoreSyncSettings<PCEngine>()
GetCoreSettings<PCEngine, PCEngine.PCESettings>(),
GetCoreSyncSettings<PCEngine, PCEngine.PCESyncSettings>()
),
// CoreNames.HyperNyma => new HyperNyma(
// game,
@ -363,8 +365,8 @@ namespace BizHawk.Client.Common
game,
new[] { disc },
nextComm,
(NymaCore.NymaSettings) GetCoreSettings<TurboNyma>(),
(NymaCore.NymaSyncSettings) GetCoreSyncSettings<TurboNyma>(),
GetCoreSettings<TurboNyma, NymaCore.NymaSettings>(),
GetCoreSyncSettings<TurboNyma, NymaCore.NymaSyncSettings>(),
Deterministic
)
};
@ -409,8 +411,8 @@ namespace BizHawk.Client.Common
discs,
discNames,
null,
GetCoreSettings<Octoshock>(),
GetCoreSyncSettings<Octoshock>(),
GetCoreSettings<Octoshock, Octoshock.Settings>(),
GetCoreSyncSettings<Octoshock, Octoshock.SyncSettings>(),
swRomDetails.ToString()
);
}
@ -477,7 +479,7 @@ namespace BizHawk.Client.Common
var ti83 = new TI83(
ti83BiosAsRom.GameInfo,
ti83Bios,
GetCoreSettings<TI83>()
GetCoreSettings<TI83, TI83.TI83Settings>()
);
ti83.LinkPort.SendFileToCalc(File.OpenRead(path.SubstringBefore('|')), false);
nextEmulator = ti83;
@ -503,8 +505,8 @@ namespace BizHawk.Client.Common
isXml ? rom.FileData : null,
Path.GetDirectoryName(path.SubstringBefore('|')),
nextComm,
GetCoreSettings<LibsnesCore>(),
GetCoreSyncSettings<LibsnesCore>()
GetCoreSettings<LibsnesCore, LibsnesCore.SnesSettings>(),
GetCoreSyncSettings<LibsnesCore, LibsnesCore.SnesSyncSettings>()
);
return;
}
@ -545,8 +547,8 @@ namespace BizHawk.Client.Common
null,
null,
nextComm,
GetCoreSettings<LibsnesCore>(),
GetCoreSyncSettings<LibsnesCore>()
GetCoreSettings<LibsnesCore, LibsnesCore.SnesSettings>(),
GetCoreSyncSettings<LibsnesCore, LibsnesCore.SnesSyncSettings>()
);
return;
}
@ -562,8 +564,8 @@ namespace BizHawk.Client.Common
nextComm,
new[] { rom.FileData },
rom.GameInfo,
GetCoreSettings<C64>(),
GetCoreSyncSettings<C64>()
GetCoreSettings<C64, C64.C64Settings>(),
GetCoreSyncSettings<C64, C64.C64SyncSettings>()
);
return;
case "ZXSpectrum":
@ -571,8 +573,8 @@ namespace BizHawk.Client.Common
nextComm,
new[] { rom.RomData },
new List<GameInfo> { rom.GameInfo },
GetCoreSettings<ZXSpectrum>(),
GetCoreSyncSettings<ZXSpectrum>(),
GetCoreSettings<ZXSpectrum, ZXSpectrum.ZXSpectrumSettings>(),
GetCoreSyncSettings<ZXSpectrum, ZXSpectrum.ZXSpectrumSyncSettings>(),
Deterministic
);
return;
@ -580,9 +582,7 @@ namespace BizHawk.Client.Common
nextEmulator = new ChannelF(
nextComm,
game,
rom.FileData,
GetCoreSettings<ChannelF>(),
GetCoreSyncSettings<ChannelF>()
rom.FileData
);
return;
case "AmstradCPC":
@ -590,8 +590,8 @@ namespace BizHawk.Client.Common
nextComm,
new[] { rom.RomData },
new List<GameInfo> { rom.GameInfo },
GetCoreSettings<AmstradCPC>(),
GetCoreSyncSettings<AmstradCPC>()
GetCoreSettings<AmstradCPC, AmstradCPC.AmstradCPCSettings>(),
GetCoreSyncSettings<AmstradCPC, AmstradCPC.AmstradCPCSyncSettings>()
);
return;
case "PSX":
@ -600,8 +600,8 @@ namespace BizHawk.Client.Common
null,
null,
rom.FileData,
GetCoreSettings<Octoshock>(),
GetCoreSyncSettings<Octoshock>(),
GetCoreSettings<Octoshock, Octoshock.Settings>(),
GetCoreSyncSettings<Octoshock, Octoshock.SyncSettings>(),
"PSX etc."
);
return;
@ -609,7 +609,7 @@ namespace BizHawk.Client.Common
nextEmulator = new MAME(
file.Directory,
file.CanonicalName,
GetCoreSyncSettings<MAME>(),
GetCoreSyncSettings<MAME, MAME.SyncSettings>(),
out var gameName
);
rom.GameInfo.Name = gameName;
@ -633,8 +633,8 @@ namespace BizHawk.Client.Common
rom.RomData,
rom.FileData,
Deterministic,
GetCoreSettings(core.Type),
GetCoreSyncSettings(core.Type),
GetCoreSettings(core.Type, core.SettingsType),
GetCoreSyncSettings(core.Type, core.SyncSettingsType),
rom.Extension
);
}
@ -652,8 +652,8 @@ namespace BizHawk.Client.Common
nextEmulator = new Octoshock(
nextComm,
psf,
GetCoreSettings<Octoshock>(),
GetCoreSyncSettings<Octoshock>()
GetCoreSettings<Octoshock, Octoshock.Settings>(),
GetCoreSyncSettings<Octoshock, Octoshock.SyncSettings>()
);
// total garbage, this
@ -688,8 +688,8 @@ namespace BizHawk.Client.Common
leftBytes,
right,
rightBytes,
GetCoreSettings<GBHawkLink>(),
GetCoreSyncSettings<GBHawkLink>()
GetCoreSettings<GBHawkLink, GBHawkLink.GBLinkSettings>(),
GetCoreSyncSettings<GBHawkLink, GBHawkLink.GBLinkSyncSettings>()
);
// other stuff todo
return true;
@ -702,8 +702,8 @@ namespace BizHawk.Client.Common
leftBytes,
right,
rightBytes,
GetCoreSettings<GambatteLink>(),
GetCoreSyncSettings<GambatteLink>(),
GetCoreSettings<GambatteLink, GambatteLink.GambatteLinkSettings>(),
GetCoreSyncSettings<GambatteLink, GambatteLink.GambatteLinkSyncSettings>(),
Deterministic
);
// other stuff todo
@ -724,8 +724,8 @@ namespace BizHawk.Client.Common
centerBytes3x,
right3x,
rightBytes3x,
GetCoreSettings<GBHawkLink3x>(),
GetCoreSyncSettings<GBHawkLink3x>()
GetCoreSettings<GBHawkLink3x, GBHawkLink3x.GBLink3xSettings>(),
GetCoreSyncSettings<GBHawkLink3x, GBHawkLink3x.GBLink3xSyncSettings>()
);
return true;
case "GB4x":
@ -747,15 +747,15 @@ namespace BizHawk.Client.Common
C_Bytes4x,
D_4x,
D_Bytes4x,
GetCoreSettings<GBHawkLink4x>(),
GetCoreSyncSettings<GBHawkLink4x>()
GetCoreSettings<GBHawkLink4x, GBHawkLink4x.GBLink4xSettings>(),
GetCoreSyncSettings<GBHawkLink4x, GBHawkLink4x.GBLink4xSyncSettings>()
);
return true;
case "AppleII":
nextEmulator = new AppleII(
nextComm,
xmlGame.Assets.Select(a => a.Value),
(AppleII.Settings) GetCoreSettings<AppleII>()
(AppleII.Settings) GetCoreSettings<AppleII, AppleII.Settings>()
);
return true;
case "C64":
@ -763,8 +763,8 @@ namespace BizHawk.Client.Common
nextComm,
xmlGame.Assets.Select(a => a.Value),
GameInfo.NullInstance,
(C64.C64Settings) GetCoreSettings<C64>(),
(C64.C64SyncSettings) GetCoreSyncSettings<C64>()
GetCoreSettings<C64, C64.C64Settings>(),
GetCoreSyncSettings<C64, C64.C64SyncSettings>()
);
return true;
case "ZXSpectrum":
@ -772,8 +772,8 @@ namespace BizHawk.Client.Common
nextComm,
xmlGame.Assets.Select(kvp => kvp.Value),
xmlGame.Assets.Select(kvp => new GameInfo { Name = Path.GetFileNameWithoutExtension(kvp.Key) }).ToList(),
(ZXSpectrum.ZXSpectrumSettings) GetCoreSettings<ZXSpectrum>(),
(ZXSpectrum.ZXSpectrumSyncSettings) GetCoreSyncSettings<ZXSpectrum>(),
GetCoreSettings<ZXSpectrum, ZXSpectrum.ZXSpectrumSettings>(),
GetCoreSyncSettings<ZXSpectrum, ZXSpectrum.ZXSpectrumSyncSettings>(),
Deterministic
);
return true;
@ -782,8 +782,8 @@ namespace BizHawk.Client.Common
nextComm,
xmlGame.Assets.Select(kvp => kvp.Value),
xmlGame.Assets.Select(kvp => new GameInfo { Name = Path.GetFileNameWithoutExtension(kvp.Key) }).ToList(),
(AmstradCPC.AmstradCPCSettings) GetCoreSettings<AmstradCPC>(),
(AmstradCPC.AmstradCPCSyncSettings) GetCoreSyncSettings<AmstradCPC>()
GetCoreSettings<AmstradCPC, AmstradCPC.AmstradCPCSettings>(),
GetCoreSyncSettings<AmstradCPC, AmstradCPC.AmstradCPCSyncSettings>()
);
return true;
case "PSX":
@ -812,8 +812,8 @@ namespace BizHawk.Client.Common
discs,
discNames,
null,
GetCoreSettings<Octoshock>(),
GetCoreSyncSettings<Octoshock>(),
GetCoreSettings<Octoshock, Octoshock.Settings>(),
GetCoreSyncSettings<Octoshock, Octoshock.SyncSettings>(),
swRomDetails.ToString()
);
return true;
@ -823,8 +823,8 @@ namespace BizHawk.Client.Common
nextEmulator = new Saturnus(
nextComm, game,
saturnDiscs,
(NymaCore.NymaSettings)GetCoreSettings<Saturnus>(),
(NymaCore.NymaSyncSettings)GetCoreSyncSettings<Saturnus>(),
GetCoreSettings<Saturnus, NymaCore.NymaSettings>(),
GetCoreSyncSettings<Saturnus, NymaCore.NymaSyncSettings>(),
Deterministic
);
return true;
@ -832,8 +832,8 @@ namespace BizHawk.Client.Common
var pcfxDiscs = DiscsFromXml(xmlGame, "PCFX", DiscType.PCFX);
if (pcfxDiscs.Count == 0) return false;
nextEmulator = new Tst(nextComm, game, pcfxDiscs,
(NymaCore.NymaSettings)GetCoreSettings<Tst>(),
(NymaCore.NymaSyncSettings)GetCoreSyncSettings<Tst>(),
GetCoreSettings<Tst, NymaCore.NymaSettings>(),
GetCoreSyncSettings<Tst, NymaCore.NymaSyncSettings>(),
Deterministic);
return true;
case "GEN":
@ -845,8 +845,8 @@ namespace BizHawk.Client.Common
game,
romBytes,
genDiscs,
GetCoreSettings<GPGX>(),
GetCoreSyncSettings<GPGX>()
GetCoreSettings<GPGX, GPGX.GPGXSettings>(),
GetCoreSyncSettings<GPGX, GPGX.GPGXSyncSettings>()
);
return true;
case "Game Gear":
@ -860,8 +860,8 @@ namespace BizHawk.Client.Common
leftBytesGG,
rightGG,
rightBytesGG,
GetCoreSettings<GGHawkLink>(),
GetCoreSyncSettings<GGHawkLink>()
GetCoreSettings<GGHawkLink, GGHawkLink.GGLinkSettings>(),
GetCoreSyncSettings<GGHawkLink, GGHawkLink.GGLinkSyncSettings>()
);
return true;
}
@ -881,8 +881,8 @@ namespace BizHawk.Client.Common
rom.FileData,
Path.GetDirectoryName(path.SubstringBefore('|')),
nextComm,
GetCoreSettings<LibsnesCore>(),
GetCoreSyncSettings<LibsnesCore>()
GetCoreSettings<LibsnesCore, LibsnesCore.SnesSettings>(),
GetCoreSyncSettings<LibsnesCore, LibsnesCore.SnesSyncSettings>()
);
return true;
}

View File

@ -6,21 +6,15 @@ namespace BizHawk.Client.Common
{
public static class ConfigExtensions
{
private class TypeNameEncapsulator
{
public object o;
}
private static JToken Serialize(object o)
{
var tne = new TypeNameEncapsulator { o = o };
return JToken.FromObject(tne, ConfigService.Serializer)["o"];
return JToken.FromObject(o, ConfigService.Serializer);
}
private static object Deserialize(JToken j)
private static object Deserialize(JToken j, Type type)
{
var jne = new JObject(new JProperty("o", j));
try
{
return jne.ToObject<TypeNameEncapsulator>(ConfigService.Serializer).o;
return j.ToObject(type, ConfigService.Serializer);
}
catch
{
@ -35,22 +29,20 @@ namespace BizHawk.Client.Common
/// <param name="config"></param>
/// <param name="coreType"></param>
/// <returns>null if no settings were saved, or there was an error deserializing</returns>
public static object GetCoreSettings(this Config config, Type coreType)
public static object GetCoreSettings(this Config config, Type coreType, Type settingsType)
{
config.CoreSettings.TryGetValue(coreType.ToString(), out var j);
return Deserialize(j);
return Deserialize(j, settingsType);
}
/// <summary>
/// Returns the core settings for a core
/// </summary>
/// <param name="config"></param>
/// <typeparam name="TCore"></typeparam>
/// <returns>null if no settings were saved, or there was an error deserializing</returns>
public static object GetCoreSettings<TCore>(this Config config)
public static TSetting GetCoreSettings<TCore, TSetting>(this Config config)
where TCore : IEmulator
{
return config.GetCoreSettings(typeof(TCore));
return (TSetting)config.GetCoreSettings(typeof(TCore), typeof(TSetting));
}
/// <summary>
@ -89,22 +81,20 @@ namespace BizHawk.Client.Common
/// <param name="config"></param>
/// <param name="coreType"></param>
/// <returns>null if no settings were saved, or there was an error deserializing</returns>
public static object GetCoreSyncSettings(this Config config, Type coreType)
public static object GetCoreSyncSettings(this Config config, Type coreType, Type syncSettingsType)
{
config.CoreSyncSettings.TryGetValue(coreType.ToString(), out var j);
return Deserialize(j);
return Deserialize(j, syncSettingsType);
}
/// <summary>
/// Returns the core syncsettings for a core
/// </summary>
/// <param name="config"></param>
/// <typeparam name="TCore"></typeparam>
/// <returns>null if no settings were saved, or there was an error deserializing</returns>
public static object GetCoreSyncSettings<TCore>(this Config config)
public static TSync GetCoreSyncSettings<TCore, TSync>(this Config config)
where TCore : IEmulator
{
return config.GetCoreSyncSettings(typeof(TCore));
return (TSync)config.GetCoreSyncSettings(typeof(TCore), typeof(TSync));
}
/// <summary>

View File

@ -2225,7 +2225,7 @@ namespace BizHawk.Client.EmuHawk
}
else
{
e.Settings = Config.GetCoreSyncSettings(e.Core);
e.Settings = Config.GetCoreSyncSettings(e.Core, e.SettingsType);
// Only show this nag if the core actually has sync settings, not all cores do
if (e.Settings != null && !_suppressSyncSettingsWarning)
@ -2240,13 +2240,13 @@ namespace BizHawk.Client.EmuHawk
}
else
{
e.Settings = Config.GetCoreSyncSettings(e.Core);
e.Settings = Config.GetCoreSyncSettings(e.Core, e.SettingsType);
}
}
private void CoreSettings(object sender, RomLoader.SettingsLoadArgs e)
{
e.Settings = Config.GetCoreSettings(e.Core);
e.Settings = Config.GetCoreSettings(e.Core, e.SettingsType);
}
/// <summary>

View File

@ -57,9 +57,9 @@ namespace BizHawk.Client.EmuHawk
}
else
{
_s = (N64Settings)_config.GetCoreSettings<N64>()
_s = _config.GetCoreSettings<N64, N64Settings>()
?? new N64Settings();
_ss = (N64SyncSettings)_config.GetCoreSyncSettings<N64>()
_ss = _config.GetCoreSyncSettings<N64, N64SyncSettings>()
?? new N64SyncSettings();
}

View File

@ -233,7 +233,6 @@ namespace BizHawk.Client.EmuHawk
where TSetting : class, new()
where TEmulator : IEmulator
{
// should we complain if we get a successful object from the config file, but it is the wrong type?
object fromCore = null;
var settable = new SettingsAdapter(_emulator);
if (settable.HasSyncSettings)
@ -242,7 +241,7 @@ namespace BizHawk.Client.EmuHawk
}
return fromCore as TSetting
?? _config.GetCoreSyncSettings<TEmulator>() as TSetting
?? _config.GetCoreSyncSettings<TEmulator, TSetting>()
?? new TSetting(); // guaranteed to give sensible defaults
}

View File

@ -96,7 +96,7 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
displayName: "Arcade")]
public partial class MAME : IEmulator, IVideoProvider, ISoundProvider, ISettable<object, MAME.SyncSettings>, IStatable, IInputPollable
{
public MAME(string dir, string file, object syncSettings, out string gamename)
public MAME(string dir, string file, MAME.SyncSettings syncSettings, out string gamename)
{
ServiceProvider = new BasicServiceProvider(this);

View File

@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Calculators
public partial class TI83 : IEmulator, IVideoProvider, IDebuggable, IInputPollable, ISettable<TI83.TI83Settings, object>
{
[CoreConstructor("TI83")]
public TI83(GameInfo game, byte[] rom, object settings)
public TI83(GameInfo game, byte[] rom, TI83.TI83Settings settings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -20,7 +20,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
isReleased: false)]
public partial class AmstradCPC : IRegionable, IDriveLight
{
public AmstradCPC(CoreComm comm, IEnumerable<byte[]> files, List<GameInfo> game, object settings, object syncSettings)
public AmstradCPC(CoreComm comm, IEnumerable<byte[]> files, List<GameInfo> game, AmstradCPCSettings settings, AmstradCPCSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
isReleased: true)]
public sealed partial class C64 : IEmulator, IRegionable, IBoardInfo, IRomInfo
{
public C64(CoreComm comm, IEnumerable<byte[]> roms, GameInfo game, object settings, object syncSettings)
public C64(CoreComm comm, IEnumerable<byte[]> roms, GameInfo game, C64Settings settings, C64SyncSettings syncSettings)
{
PutSyncSettings((C64SyncSettings)syncSettings ?? new C64SyncSettings());
PutSettings((C64Settings)settings ?? new C64Settings());

View File

@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
public partial class MSX : IEmulator, IVideoProvider, ISoundProvider, ISaveRam, IInputPollable, IRegionable, ISettable<MSX.MSXSettings, MSX.MSXSyncSettings>
{
[CoreConstructor("MSX")]
public MSX(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
public MSX(CoreComm comm, GameInfo game, byte[] rom, MSX.MSXSettings settings, MSX.MSXSyncSettings syncSettings)
{
ServiceProvider = new BasicServiceProvider(this);
Settings = (MSXSettings)settings ?? new MSXSettings();

View File

@ -21,7 +21,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
isReleased: true)]
public partial class ZXSpectrum : IRegionable, IDriveLight
{
public ZXSpectrum(CoreComm comm, IEnumerable<byte[]> files, List<GameInfo> game, object settings, object syncSettings, bool? deterministic)
public ZXSpectrum(CoreComm comm, IEnumerable<byte[]> files, List<GameInfo> game, ZXSpectrumSettings settings, ZXSpectrumSyncSettings syncSettings, bool? deterministic)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
IRegionable, ICreateGameDBEntries, ISettable<Atari2600.A2600Settings, Atari2600.A2600SyncSettings>
{
[CoreConstructor("A26")]
public Atari2600(GameInfo game, byte[] rom, object settings, object syncSettings)
public Atari2600(GameInfo game, byte[] rom, Atari2600.A2600Settings settings, Atari2600.A2600SyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -73,7 +73,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
}
[CoreConstructor("A78")]
public A7800Hawk(CoreComm comm, byte[] rom, object settings, object syncSettings)
public A7800Hawk(CoreComm comm, byte[] rom, A7800Hawk.A7800Settings settings, A7800Hawk.A7800SyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);

View File

@ -13,7 +13,9 @@ namespace BizHawk.Emulation.Cores.ColecoVision
public sealed partial class ColecoVision : IEmulator, IDebuggable, IInputPollable, ISettable<ColecoVision.ColecoSettings, ColecoVision.ColecoSyncSettings>
{
[CoreConstructor("Coleco")]
public ColecoVision(CoreComm comm, GameInfo game, byte[] rom, object syncSettings)
public ColecoVision(CoreComm comm, GameInfo game, byte[] rom,
ColecoSettings settings,
ColecoSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -11,7 +11,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
public partial class ChannelF
{
public ChannelF(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
public ChannelF(CoreComm comm, GameInfo game, byte[] rom)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Vectrex
public SerialPort serialport;
[CoreConstructor("VEC")]
public VectrexHawk(CoreComm comm, byte[] rom, object settings, object syncSettings)
public VectrexHawk(CoreComm comm, byte[] rom, VectrexHawk.VectrexSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
@ -50,7 +50,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Vectrex
ppu = new PPU();
serialport = new SerialPort();
_settings = settings ?? new object();
_settings = new object(); // TODO: wtf is this
_syncSettings = (VectrexSyncSettings)syncSettings ?? new VectrexSyncSettings();
_controllerDeck = new VectrexHawkControllerDeck(_syncSettings.Port1, _syncSettings.Port2);
@ -110,7 +110,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Vectrex
ser.Register<ISoundProvider>(audio);
ServiceProvider = ser;
_settings = settings ?? new object();
_settings = new object(); // TODO: wtf is this
_syncSettings = (VectrexSyncSettings)syncSettings ?? new VectrexSyncSettings();
_tracer = new TraceBuffer { Header = cpu.TraceHeader };

View File

@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Intellivision
IBoardInfo, IDebuggable, ISettable<Intellivision.IntvSettings, Intellivision.IntvSyncSettings>
{
[CoreConstructor("INTV")]
public Intellivision(CoreComm comm, byte[] rom, object settings, object syncSettings)
public Intellivision(CoreComm comm, byte[] rom, Intellivision.IntvSettings settings, Intellivision.IntvSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -44,7 +44,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
public bool is_G7400;
[CoreConstructor("O2")]
public O2Hawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings)
public O2Hawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ O2Settings settings, O2SyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);

View File

@ -94,7 +94,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
private static byte[] GBA_override = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0xAA, 0x31, 0x90, 0x94, 0x00, 0x00, 0x00, 0x00 };
[CoreConstructor(new[] { "GB", "GBC" })]
public GBHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings)
public GBHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ GBSettings settings, GBSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);

View File

@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
displayName: "Gameboy")]
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
public partial class GBHawkLink : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ILinkable,
ISettable<GBHawkLink.GBLinkSettings, GBHawkLink.GBLinkSyncSettings>
ISettable<GBHawkLink.GBLinkSettings, GBHawkLink.GBLinkSyncSettings>
{
// we want to create two GBHawk instances that we will run concurrently
// maybe up to 4 eventually?
@ -30,7 +30,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
public bool do_frame_fill;
//[CoreConstructor("GB", "GBC")]
public GBHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings)
public GBHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/
GBHawkLink.GBLinkSettings settings, GBHawkLink.GBLinkSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -30,7 +30,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
public bool do_frame_fill;
//[CoreConstructor("GB", "GBC")]
public GBHawkLink3x(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_C, byte[] rom_C, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings)
public GBHawkLink3x(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_C, byte[] rom_C, GameInfo game_R, byte[] rom_R,
/*string gameDbFn,*/ GBHawkLink3x.GBLink3xSettings settings, GBHawkLink3x.GBLink3xSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -51,7 +51,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x
public bool do_frame_fill;
//[CoreConstructor("GB", "GBC")]
public GBHawkLink4x(CoreComm comm, GameInfo game_A, byte[] rom_A, GameInfo game_B, byte[] rom_B, GameInfo game_C, byte[] rom_C, GameInfo game_D, byte[] rom_D, /*string gameDbFn,*/ object settings, object syncSettings)
public GBHawkLink4x(CoreComm comm, GameInfo game_A, byte[] rom_A, GameInfo game_B, byte[] rom_B, GameInfo game_C, byte[] rom_C, GameInfo game_D, byte[] rom_D, /*string gameDbFn,*/
GBHawkLink4x.GBLink4xSettings settings, GBHawkLink4x.GBLink4xSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);

View File

@ -24,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
IGameboyCommon, ICycleTiming, ILinkable
{
[CoreConstructor(new[] { "GB", "GBC" })]
public Gameboy(CoreComm comm, GameInfo game, byte[] file, object settings, object syncSettings, bool deterministic)
public Gameboy(CoreComm comm, GameInfo game, byte[] file, Gameboy.GambatteSettings settings, Gameboy.GambatteSyncSettings syncSettings, bool deterministic)
{
var ser = new BasicServiceProvider(this);
ser.Register<IDisassemblable>(new GBDisassembler());

View File

@ -11,7 +11,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
public partial class GambatteLink : IEmulator, IVideoProvider, ISoundProvider, IInputPollable, ISaveRam, IStatable, ILinkable,
IBoardInfo, IRomInfo, IDebuggable, ISettable<GambatteLink.GambatteLinkSettings, GambatteLink.GambatteLinkSyncSettings>, ICodeDataLogger
{
public GambatteLink(CoreComm comm, GameInfo leftinfo, byte[] leftrom, GameInfo rightinfo, byte[] rightrom, object settings, object syncSettings, bool deterministic)
public GambatteLink(CoreComm comm, GameInfo leftinfo, byte[] leftrom, GameInfo rightinfo, byte[] rightrom,
GambatteLink.GambatteLinkSettings settings, GambatteLink.GambatteLinkSyncSettings syncSettings, bool deterministic)
{
ServiceProvider = new BasicServiceProvider(this);
GambatteLinkSettings linkSettings = (GambatteLinkSettings)settings ?? new GambatteLinkSettings();

View File

@ -25,7 +25,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
/// <param name="file">Rom that should be loaded</param>
/// <param name="syncSettings">N64SyncSettings object</param>
[CoreConstructor("N64")]
public N64(GameInfo game, byte[] file, object settings, object syncSettings)
public N64(GameInfo game, byte[] file, N64Settings settings, N64SyncSettings syncSettings)
{
ServiceProvider = new BasicServiceProvider(this);
InputCallbacks = new InputCallbackSystem();

View File

@ -78,7 +78,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
private static extern void FrameAdvance(uint buttons, byte touchX, byte touchY);
[CoreConstructor("NDS")]
public MelonDS(byte[] file, CoreComm comm, object settings, object syncSettings)
public MelonDS(byte[] file, CoreComm comm, MelonSettings settings, MelonSyncSettings syncSettings)
{
_serviceProvider = new BasicServiceProvider(this);
ControllerDefinition = new ControllerDefinition { Name = "NDS Controller" };

View File

@ -18,7 +18,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
IBoardInfo, IRomInfo, ISettable<NES.NESSettings, NES.NESSyncSettings>, ICodeDataLogger
{
[CoreConstructor("NES")]
public NES(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
public NES(CoreComm comm, GameInfo game, byte[] rom, NESSettings settings, NESSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
}
[CoreConstructor("NES")]
public QuickNES(byte[] file, object settings, object syncSettings)
public QuickNES(byte[] file, QuickNESSettings settings, QuickNESSyncSettings syncSettings)
{
FP = OSTailoredCode.IsUnixHost
? (IFPCtrl) new Unix_FPCtrl()

View File

@ -29,7 +29,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
public unsafe partial class LibsnesCore : IEmulator, IVideoProvider, ISaveRam, IStatable, IInputPollable, IRegionable, ICodeDataLogger,
IDebuggable, ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings>
{
public LibsnesCore(GameInfo game, byte[] romData, byte[] xmlData, string baseRomPath, CoreComm comm, object settings, object syncSettings)
public LibsnesCore(GameInfo game, byte[] romData, byte[] xmlData, string baseRomPath, CoreComm comm,
LibsnesCore.SnesSettings settings, LibsnesCore.SnesSyncSettings syncSettings)
{
_baseRomPath = baseRomPath;
var ser = new BasicServiceProvider(this);

View File

@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
ISettable<GBHawk.GBHawk.GBSettings, GBHawk.GBHawk.GBSyncSettings>, IDebuggable
{
[CoreConstructor(new[] { "GB", "GBC" })]
public SubGBHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings)
public SubGBHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ GBHawk.GBHawk.GBSettings settings, GBHawk.GBHawk.GBSyncSettings syncSettings)
{
var subGBSettings = (GBHawk.GBHawk.GBSettings)settings ?? new GBHawk.GBHawk.GBSettings();

View File

@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
ISettable<NES.NES.NESSettings, NES.NES.NESSyncSettings>
{
[CoreConstructor("NES")]
public SubNESHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings)
public SubNESHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ NES.NES.NESSettings settings, NES.NES.NESSyncSettings syncSettings)
{
var subNesSettings = (NES.NES.NESSettings)settings ?? new NES.NES.NESSettings();
var subNesSyncSettings = (NES.NES.NESSyncSettings)syncSettings ?? new NES.NES.NESSyncSettings();

View File

@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
IPceGpuView
{
[CoreConstructor(new[] { "PCE", "SGX" })]
public PCEngine(GameInfo game, byte[] rom, object settings, object syncSettings)
public PCEngine(GameInfo game, byte[] rom, PCEngine.PCESettings settings, PCEngine.PCESyncSettings syncSettings)
{
switch (game.System)
{
@ -53,7 +53,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
int IVideoLogicalOffsets.ScreenY => Settings.TopLine;
public PCEngine(CoreComm comm, GameInfo game, Disc disc, object settings, object syncSettings)
public PCEngine(CoreComm comm, GameInfo game, Disc disc, PCESettings settings, PCESyncSettings syncSettings)
{
SystemId = "PCECD";
Type = NecSystemType.TurboCD;

View File

@ -11,7 +11,7 @@ namespace BizHawk.Emulation.Cores.Sega.GGHawkLink
displayName: "Game Gear")]
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
public partial class GGHawkLink : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ILinkable,
ISettable<GGHawkLink.GGLinkSettings, GGHawkLink.GGLinkSyncSettings>
ISettable<GGHawkLink.GGLinkSettings, GGHawkLink.GGLinkSyncSettings>
{
// we want to create two GG instances that we will run concurrently
public SMS L;
@ -25,7 +25,8 @@ namespace BizHawk.Emulation.Cores.Sega.GGHawkLink
private bool do_r_next = false;
public GGHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings)
public GGHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/
GGLinkSettings settings, GGLinkSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);

View File

@ -24,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
IDebuggable, ISettable<SMS.SmsSettings, SMS.SmsSyncSettings>, ICodeDataLogger
{
[CoreConstructor(new[] { "SMS", "SG", "GG" })]
public SMS(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
public SMS(CoreComm comm, GameInfo game, byte[] rom, SmsSettings settings, SmsSyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

View File

@ -24,12 +24,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
IInputPollable, IDebuggable, IDriveLight, ICodeDataLogger, IDisassemblable
{
[CoreConstructor("GEN")]
public GPGX(CoreComm comm, GameInfo game, byte[] file, object settings, object syncSettings)
public GPGX(CoreComm comm, GameInfo game, byte[] file, GPGXSettings settings, GPGXSyncSettings syncSettings)
: this(comm, game, file, null, settings, syncSettings)
{
}
public GPGX(CoreComm comm, GameInfo game, byte[] rom, IEnumerable<Disc> cds, object settings, object syncSettings)
public GPGX(CoreComm comm, GameInfo game, byte[] rom, IEnumerable<Disc> cds, GPGXSettings settings, GPGXSyncSettings syncSettings)
{
LoadCallback = new LibGPGX.load_archive_cb(load_archive);
_inputCallback = new LibGPGX.input_cb(input_callback);

View File

@ -35,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
isReleased: true)]
public unsafe partial class Octoshock : IEmulator, IVideoProvider, ISoundProvider, ISaveRam, IStatable, IDriveLight, ISettable<Octoshock.Settings, Octoshock.SyncSettings>, IRegionable, IInputPollable, IRomInfo
{
public Octoshock(CoreComm comm, PSF psf, object settings, object syncSettings)
public Octoshock(CoreComm comm, PSF psf, Octoshock.Settings settings, Octoshock.SyncSettings syncSettings)
{
string romDetails = "It's a PSF, what do you want. Oh, tags maybe?";
Load(comm, null, null, null, settings, syncSettings, psf, romDetails);
@ -44,13 +44,13 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
//note: its annoying that we have to have a disc before constructing this.
//might want to change that later. HOWEVER - we need to definitely have a region, at least
public Octoshock(CoreComm comm, List<Disc> discs, List<string> discNames, byte[] exe, object settings, object syncSettings, string romDetails)
public Octoshock(CoreComm comm, List<Disc> discs, List<string> discNames, byte[] exe, Octoshock.Settings settings, Octoshock.SyncSettings syncSettings, string romDetails)
{
Load(comm, discs, discNames, exe, settings, syncSettings, null, romDetails);
OctoshockDll.shock_PowerOn(psx);
}
void Load(CoreComm comm, List<Disc> discs, List<string> discNames, byte[] exe, object settings, object syncSettings, PSF psf, string romDetails)
void Load(CoreComm comm, List<Disc> discs, List<string> discNames, byte[] exe, Octoshock.Settings settings, Octoshock.SyncSettings syncSettings, PSF psf, string romDetails)
{
RomDetails = romDetails;
ConnectTracer();

View File

@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan
IInputPollable, IDebuggable
{
[CoreConstructor("WSWAN")]
public WonderSwan(byte[] file, bool deterministic, object settings, object syncSettings)
public WonderSwan(byte[] file, bool deterministic, WonderSwan.Settings settings, WonderSwan.SyncSettings syncSettings)
{
ServiceProvider = new BasicServiceProvider(this);
_settings = (Settings)settings ?? new Settings();

View File

@ -48,11 +48,18 @@ namespace BizHawk.Emulation.Cores
{
throw new InvalidOperationException($"Unexpected parameter name {p.Name} in constructor for {Type}");
}
// 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"
// if (expectedType != p.ParameterType)
// throw new InvalidOperationException($"Unexpected type mismatch in parameter {p.Name} in constructor for {Type}");
if (pName == "settings")
{
if (p.ParameterType == typeof(object))
throw new InvalidOperationException($"Setting and SyncSetting constructor parameters for {type} must be annotated with the actual type");
SettingsType = p.ParameterType;
}
else if (pName == "syncsettings")
{
if (p.ParameterType == typeof(object))
throw new InvalidOperationException($"Setting and SyncSetting constructor parameters for {type} must be annotated with the actual type");
SyncSettingsType = p.ParameterType;
}
_paramMap.Add(pName, i);
}
}
@ -60,6 +67,8 @@ namespace BizHawk.Emulation.Cores
public string Name { get; }
public Type Type { get; }
public ConstructorInfo CTor { get; }
public Type SettingsType { get; } = typeof(object);
public Type SyncSettingsType { get; } = typeof(object);
private void Bp(object[] parameters, string name, object value)
{