2014-04-25 01:19:57 +00:00
|
|
|
|
using System;
|
2020-02-28 03:18:59 +00:00
|
|
|
|
using System.Collections.Generic;
|
2014-11-24 00:38:29 +00:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
2016-12-11 19:07:12 +00:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2014-04-25 01:19:57 +00:00
|
|
|
|
|
2020-02-15 18:33:15 +00:00
|
|
|
|
namespace BizHawk.Emulation.Common
|
2014-04-25 01:19:57 +00:00
|
|
|
|
{
|
2020-02-15 18:33:15 +00:00
|
|
|
|
public static class EmulatorExtensions
|
2014-04-25 01:19:57 +00:00
|
|
|
|
{
|
2017-07-12 19:10:55 +00:00
|
|
|
|
public static CoreAttribute Attributes(this IEmulator core)
|
2014-04-25 01:19:57 +00:00
|
|
|
|
{
|
2017-07-12 19:10:55 +00:00
|
|
|
|
return (CoreAttribute)Attribute.GetCustomAttribute(core.GetType(), typeof(CoreAttribute));
|
2014-04-25 01:19:57 +00:00
|
|
|
|
}
|
2014-09-01 18:43:41 +00:00
|
|
|
|
|
2014-12-15 22:25:06 +00:00
|
|
|
|
// todo: most of the special cases involving the NullEmulator should probably go away
|
2014-12-05 00:15:28 +00:00
|
|
|
|
public static bool IsNull(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
return core == null || core is NullEmulator;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-04 16:17:16 +00:00
|
|
|
|
public static bool HasVideoProvider(this IEmulator core)
|
|
|
|
|
{
|
2020-02-15 18:22:16 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IVideoProvider>();
|
2016-12-04 16:17:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IVideoProvider AsVideoProvider(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
return core.ServiceProvider.GetService<IVideoProvider>();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-12 19:47:11 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the core's VideoProvider, or a suitable dummy provider
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static IVideoProvider AsVideoProviderOrDefault(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
return core.ServiceProvider.GetService<IVideoProvider>()
|
|
|
|
|
?? NullVideo.Instance;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-11 17:14:42 +00:00
|
|
|
|
public static bool HasSoundProvider(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<ISoundProvider>();
|
2016-12-11 17:14:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ISoundProvider AsSoundProvider(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
return core.ServiceProvider.GetService<ISoundProvider>();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-11 19:07:12 +00:00
|
|
|
|
private static readonly ConditionalWeakTable<IEmulator, ISoundProvider> CachedNullSoundProviders = new ConditionalWeakTable<IEmulator, ISoundProvider>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// returns the core's SoundProvider, or a suitable dummy provider
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static ISoundProvider AsSoundProviderOrDefault(this IEmulator core)
|
|
|
|
|
{
|
2017-04-14 17:28:23 +00:00
|
|
|
|
return core.ServiceProvider.GetService<ISoundProvider>()
|
2017-05-05 16:25:38 +00:00
|
|
|
|
?? CachedNullSoundProviders.GetValue(core, e => new NullSound(core.VsyncNumerator(), core.VsyncDenominator()));
|
2016-12-11 19:07:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-01 18:43:41 +00:00
|
|
|
|
public static bool HasMemoryDomains(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IMemoryDomains>();
|
2014-09-01 18:43:41 +00:00
|
|
|
|
}
|
2014-11-24 00:38:29 +00:00
|
|
|
|
|
2014-12-05 00:32:29 +00:00
|
|
|
|
public static IMemoryDomains AsMemoryDomains(this IEmulator core)
|
2014-12-05 00:17:34 +00:00
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<IMemoryDomains>();
|
2014-12-05 00:17:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-30 15:22:08 +00:00
|
|
|
|
public static bool HasSaveRam(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<ISaveRam>();
|
2014-11-30 15:22:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 00:32:29 +00:00
|
|
|
|
public static ISaveRam AsSaveRam(this IEmulator core)
|
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<ISaveRam>();
|
2014-12-05 00:32:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-30 16:42:58 +00:00
|
|
|
|
public static bool HasSavestates(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IStatable>();
|
2014-11-30 16:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 00:32:29 +00:00
|
|
|
|
public static IStatable AsStatable(this IEmulator core)
|
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<IStatable>();
|
2014-12-05 00:32:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-30 20:29:30 +00:00
|
|
|
|
public static bool CanPollInput(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IInputPollable>();
|
2014-11-30 14:18:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 00:32:29 +00:00
|
|
|
|
public static IInputPollable AsInputPollable(this IEmulator core)
|
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<IInputPollable>();
|
2014-12-05 00:32:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-12 23:02:03 +00:00
|
|
|
|
public static bool InputCallbacksAvailable(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
// TODO: this is a pretty ugly way to handle this
|
2019-10-29 18:59:08 +00:00
|
|
|
|
var pollable = core?.ServiceProvider.GetService<IInputPollable>();
|
2015-10-12 23:02:03 +00:00
|
|
|
|
if (pollable != null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var callbacks = pollable.InputCallbacks;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (NotImplementedException)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-12 01:49:54 +00:00
|
|
|
|
public static bool HasDriveLight(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IDriveLight>();
|
2014-12-12 01:49:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IDriveLight AsDriveLight(this IEmulator core)
|
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<IDriveLight>();
|
2014-12-12 01:49:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 01:56:45 +00:00
|
|
|
|
public static bool CanDebug(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IDebuggable>();
|
2014-12-05 01:56:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IDebuggable AsDebuggable(this IEmulator core)
|
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<IDebuggable>();
|
2014-12-05 01:56:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 00:05:40 +00:00
|
|
|
|
public static bool CpuTraceAvailable(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<ITraceable>();
|
2014-12-23 01:58:12 +00:00
|
|
|
|
}
|
2014-12-05 00:05:40 +00:00
|
|
|
|
|
2014-12-23 01:58:12 +00:00
|
|
|
|
public static ITraceable AsTracer(this IEmulator core)
|
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<ITraceable>();
|
2014-12-05 00:05:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 01:56:45 +00:00
|
|
|
|
public static bool MemoryCallbacksAvailable(this IEmulator core)
|
2014-12-05 00:05:40 +00:00
|
|
|
|
{
|
2014-12-05 01:56:45 +00:00
|
|
|
|
// TODO: this is a pretty ugly way to handle this
|
2020-02-26 22:32:00 +00:00
|
|
|
|
var debuggable = core?.ServiceProvider.GetService<IDebuggable>();
|
2014-12-05 01:56:45 +00:00
|
|
|
|
if (debuggable != null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2015-01-25 22:14:58 +00:00
|
|
|
|
var callbacks = debuggable.MemoryCallbacks;
|
2014-12-05 01:56:45 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (NotImplementedException)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-05 00:05:40 +00:00
|
|
|
|
|
2014-12-05 01:56:45 +00:00
|
|
|
|
return false;
|
2014-12-05 00:05:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-25 22:14:58 +00:00
|
|
|
|
public static bool MemoryCallbacksAvailable(this IDebuggable core)
|
|
|
|
|
{
|
|
|
|
|
if (core == null)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var callbacks = core.MemoryCallbacks;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (NotImplementedException)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-13 20:52:52 +00:00
|
|
|
|
public static bool CanDisassemble(this IEmulator core)
|
|
|
|
|
{
|
2020-02-26 21:51:29 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IDisassemblable>();
|
2014-12-13 20:52:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-29 18:59:08 +00:00
|
|
|
|
public static IDisassemblable AsDisassembler(this IEmulator core)
|
2014-12-13 20:52:52 +00:00
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<IDisassemblable>();
|
2014-12-13 20:52:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-06 00:12:09 +00:00
|
|
|
|
public static bool HasRegions(this IEmulator core)
|
|
|
|
|
{
|
2020-02-15 18:22:16 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IRegionable>();
|
2015-08-06 00:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IRegionable AsRegionable(this IEmulator core)
|
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
return core.ServiceProvider.GetService<IRegionable>();
|
2015-08-06 00:12:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-28 00:49:13 +00:00
|
|
|
|
public static bool CanCDLog(this IEmulator core)
|
2015-10-27 23:03:56 +00:00
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<ICodeDataLogger>();
|
2015-10-27 23:03:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ICodeDataLogger AsCodeDataLogger(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
return core.ServiceProvider.GetService<ICodeDataLogger>();
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-28 18:52:17 +00:00
|
|
|
|
public static ILinkable AsLinkable(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
return core.ServiceProvider.GetService<ILinkable>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool UsesLinkCable(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<ILinkable>();
|
2016-02-28 18:52:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-15 16:45:20 +00:00
|
|
|
|
public static bool CanGenerateGameDBEntries(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<ICreateGameDBEntries>();
|
2016-12-15 16:45:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ICreateGameDBEntries AsGameDBEntryGenerator(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
return core.ServiceProvider.GetService<ICreateGameDBEntries>();
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-01 02:01:37 +00:00
|
|
|
|
public static bool HasBoardInfo(this IEmulator core)
|
|
|
|
|
{
|
2019-10-29 18:59:08 +00:00
|
|
|
|
return core != null && core.ServiceProvider.HasService<IBoardInfo>();
|
2017-05-01 02:01:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IBoardInfo AsBoardInfo(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
return core.ServiceProvider.GetService<IBoardInfo>();
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-14 21:35:54 +00:00
|
|
|
|
public static (int x, int y) ScreenLogicalOffsets(this IEmulator core)
|
|
|
|
|
{
|
|
|
|
|
if (core != null && core.ServiceProvider.HasService<IVideoLogicalOffsets>())
|
|
|
|
|
{
|
|
|
|
|
var offsets = core.ServiceProvider.GetService<IVideoLogicalOffsets>();
|
|
|
|
|
return (offsets.ScreenX, offsets.ScreenY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-05 16:25:38 +00:00
|
|
|
|
public static int VsyncNumerator(this IEmulator core)
|
2017-05-05 16:21:37 +00:00
|
|
|
|
{
|
|
|
|
|
if (core != null && core.HasVideoProvider())
|
|
|
|
|
{
|
2017-05-05 16:25:38 +00:00
|
|
|
|
return core.AsVideoProvider().VsyncNumerator;
|
2017-05-05 16:21:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 60;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-05 16:25:38 +00:00
|
|
|
|
public static int VsyncDenominator(this IEmulator core)
|
2017-05-05 16:21:37 +00:00
|
|
|
|
{
|
|
|
|
|
if (core != null && core.HasVideoProvider())
|
|
|
|
|
{
|
2017-05-05 16:25:38 +00:00
|
|
|
|
return core.AsVideoProvider().VsyncDenominator;
|
2017-05-05 16:21:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-05 21:23:13 +00:00
|
|
|
|
public static double VsyncRate(this IEmulator core)
|
2017-05-05 16:21:37 +00:00
|
|
|
|
{
|
2017-05-05 21:23:13 +00:00
|
|
|
|
return core.VsyncNumerator() / (double)core.VsyncDenominator();
|
2017-05-05 16:21:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-15 18:22:16 +00:00
|
|
|
|
// TODO: a better place for this
|
2014-11-24 00:38:29 +00:00
|
|
|
|
public static bool IsImplemented(this MethodInfo info)
|
|
|
|
|
{
|
2017-07-12 19:40:10 +00:00
|
|
|
|
return !info.GetCustomAttributes(false).Any(a => a is FeatureNotImplementedAttribute);
|
2014-11-24 00:38:29 +00:00
|
|
|
|
}
|
2020-02-28 03:18:59 +00:00
|
|
|
|
|
|
|
|
|
public static IDictionary<string, dynamic> ToDictionary(this IController controller, int? controllerNum = null)
|
|
|
|
|
{
|
|
|
|
|
var buttons = new Dictionary<string, dynamic>();
|
|
|
|
|
|
|
|
|
|
foreach (var button in controller.Definition.BoolButtons)
|
|
|
|
|
{
|
|
|
|
|
if (controllerNum == null)
|
|
|
|
|
{
|
|
|
|
|
buttons[button] = controller.IsPressed(button);
|
|
|
|
|
}
|
|
|
|
|
else if (button.Length > 2 && button.Substring(0, 2) == $"P{controllerNum}")
|
|
|
|
|
{
|
|
|
|
|
var sub = button.Substring(3);
|
|
|
|
|
buttons[sub] = controller.IsPressed($"P{controllerNum} {sub}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
foreach (var button in controller.Definition.FloatControls)
|
|
|
|
|
{
|
|
|
|
|
if (controllerNum == null)
|
|
|
|
|
{
|
|
|
|
|
buttons[button] = controller.GetFloat(button);
|
|
|
|
|
}
|
|
|
|
|
else if (button.Length > 2 && button.Substring(0, 2) == $"P{controllerNum}")
|
|
|
|
|
{
|
|
|
|
|
var sub = button.Substring(3);
|
|
|
|
|
buttons[sub] = controller.GetFloat($"P{controllerNum} {sub}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buttons;
|
|
|
|
|
}
|
2014-04-25 01:19:57 +00:00
|
|
|
|
}
|
2017-05-05 16:21:37 +00:00
|
|
|
|
}
|