using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; namespace BizHawk.Emulation.Common { public static class EmulatorExtensions { public static CoreAttribute Attributes(this IEmulator core) { return (CoreAttribute)Attribute.GetCustomAttribute(core.GetType(), typeof(CoreAttribute)); } // todo: most of the special cases involving the NullEmulator should probably go away public static bool IsNull(this IEmulator core) { return core == null || core is NullEmulator; } public static bool HasVideoProvider(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IVideoProvider AsVideoProvider(this IEmulator core) { return core.ServiceProvider.GetService(); } /// /// Returns the core's VideoProvider, or a suitable dummy provider /// public static IVideoProvider AsVideoProviderOrDefault(this IEmulator core) { return core.ServiceProvider.GetService() ?? NullVideo.Instance; } public static bool HasSoundProvider(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static ISoundProvider AsSoundProvider(this IEmulator core) { return core.ServiceProvider.GetService(); } private static readonly ConditionalWeakTable CachedNullSoundProviders = new ConditionalWeakTable(); /// /// returns the core's SoundProvider, or a suitable dummy provider /// public static ISoundProvider AsSoundProviderOrDefault(this IEmulator core) { return core.ServiceProvider.GetService() ?? CachedNullSoundProviders.GetValue(core, e => new NullSound(core.VsyncNumerator(), core.VsyncDenominator())); } public static bool HasMemoryDomains(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IMemoryDomains AsMemoryDomains(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool HasSaveRam(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static ISaveRam AsSaveRam(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool HasSavestates(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IStatable AsStatable(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool CanPollInput(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IInputPollable AsInputPollable(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool InputCallbacksAvailable(this IEmulator core) { // TODO: this is a pretty ugly way to handle this var pollable = core?.ServiceProvider.GetService(); if (pollable != null) { try { var callbacks = pollable.InputCallbacks; return true; } catch (NotImplementedException) { return false; } } return false; } public static bool HasDriveLight(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IDriveLight AsDriveLight(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool CanDebug(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IDebuggable AsDebuggable(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool CpuTraceAvailable(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static ITraceable AsTracer(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool MemoryCallbacksAvailable(this IEmulator core) { // TODO: this is a pretty ugly way to handle this var debuggable = core?.ServiceProvider.GetService(); if (debuggable != null) { try { var callbacks = debuggable.MemoryCallbacks; return true; } catch (NotImplementedException) { return false; } } return false; } public static bool MemoryCallbacksAvailable(this IDebuggable core) { if (core == null) { return false; } try { var callbacks = core.MemoryCallbacks; return true; } catch (NotImplementedException) { return false; } } public static bool CanDisassemble(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IDisassemblable AsDisassembler(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool HasRegions(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IRegionable AsRegionable(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool CanCDLog(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static ICodeDataLogger AsCodeDataLogger(this IEmulator core) { return core.ServiceProvider.GetService(); } public static ILinkable AsLinkable(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool UsesLinkCable(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static bool CanGenerateGameDBEntries(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static ICreateGameDBEntries AsGameDBEntryGenerator(this IEmulator core) { return core.ServiceProvider.GetService(); } public static bool HasBoardInfo(this IEmulator core) { return core != null && core.ServiceProvider.HasService(); } public static IBoardInfo AsBoardInfo(this IEmulator core) { return core.ServiceProvider.GetService(); } public static int VsyncNumerator(this IEmulator core) { if (core != null && core.HasVideoProvider()) { return core.AsVideoProvider().VsyncNumerator; } return 60; } public static int VsyncDenominator(this IEmulator core) { if (core != null && core.HasVideoProvider()) { return core.AsVideoProvider().VsyncDenominator; } return 1; } public static double VsyncRate(this IEmulator core) { return core.VsyncNumerator() / (double)core.VsyncDenominator(); } // TODO: a better place for this public static bool IsImplemented(this MethodInfo info) { return !info.GetCustomAttributes(false).Any(a => a is FeatureNotImplementedAttribute); } public static IDictionary ToDictionary(this IController controller, int? controllerNum = null) { var buttons = new Dictionary(); 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; } } }