2014-04-25 01:19:57 +00:00
using System ;
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
2014-05-31 14:29:27 +00:00
namespace BizHawk.Emulation.Common.IEmulatorExtensions
2014-04-25 01:19:57 +00:00
{
public static class Extensions
{
public static CoreAttributes Attributes ( this IEmulator core )
{
return ( CoreAttributes ) Attribute . GetCustomAttribute ( core . GetType ( ) , typeof ( CoreAttributes ) ) ;
}
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 )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < IVideoProvider > ( ) ;
}
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 )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < ISoundProvider > ( ) ;
}
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 )
{
2014-12-05 00:52:16 +00:00
if ( core = = null )
{
return false ;
}
return 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 )
{
2014-12-05 00:52:16 +00:00
if ( core = = null )
{
return false ;
}
return 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 )
{
2014-12-05 00:52:16 +00:00
if ( core = = null )
{
return false ;
}
return 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 )
{
2014-12-05 00:52:16 +00:00
if ( core = = null )
{
return false ;
}
return 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 )
{
if ( core = = null )
{
return false ;
}
// TODO: this is a pretty ugly way to handle this
2016-02-29 00:03:01 +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 )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < IDriveLight > ( ) ;
}
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 )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < IDebuggable > ( ) ;
}
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 )
{
2014-12-05 01:56:45 +00:00
if ( core = = null )
{
return false ;
}
2014-12-23 01:58:12 +00:00
return core . ServiceProvider . HasService < ITraceable > ( ) ;
}
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 00:52:16 +00:00
if ( core = = null )
{
return false ;
}
2014-12-05 01:56:45 +00:00
// TODO: this is a pretty ugly way to handle this
var debuggable = ( IDebuggable ) core . ServiceProvider . GetService < IDebuggable > ( ) ;
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 )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < IDisassemblable > ( ) ;
}
public static IDisassemblable AsDissassembler ( this IEmulator core )
{
2016-02-29 00:03:01 +00:00
return core . ServiceProvider . GetService < IDisassemblable > ( ) ;
2014-12-13 20:52:52 +00:00
}
2015-01-25 14:37:37 +00:00
public static bool CanPoke ( this MemoryDomain d )
{
2016-04-13 23:50:06 +00:00
if ( ! d . Writable )
2015-01-25 14:37:37 +00:00
{
return false ;
}
2017-05-05 16:21:37 +00:00
2017-04-14 17:28:23 +00:00
// once upon a time, we did a try { poke(peek) } here, but that was before Writable was added. the poke(peek) is not acceptable. If there are further problems, make sure Writable is correct.
2015-01-25 14:37:37 +00:00
return true ;
}
2015-08-06 00:12:09 +00:00
public static bool HasRegions ( this IEmulator core )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < IRegionable > ( ) ;
}
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
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < ICodeDataLogger > ( ) ;
}
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 )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < ILinkable > ( ) ;
}
2016-12-15 16:45:20 +00:00
public static bool CanGenerateGameDBEntries ( this IEmulator core )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < ICreateGameDBEntries > ( ) ;
}
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 )
{
if ( core = = null )
{
return false ;
}
return core . ServiceProvider . HasService < IBoardInfo > ( ) ;
}
public static IBoardInfo AsBoardInfo ( this IEmulator core )
{
return core . ServiceProvider . GetService < IBoardInfo > ( ) ;
}
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 ;
}
public static int VsyncRate ( this IEmulator core )
{
2017-05-05 16:25:38 +00:00
return core . VsyncNumerator ( ) / core . VsyncDenominator ( ) ;
2017-05-05 16:21:37 +00:00
}
2014-11-24 00:38:29 +00:00
// TODO: a better place for these
public static bool IsImplemented ( this MethodInfo info )
{
2014-11-30 14:52:52 +00:00
// If a method is marked as Not implemented, it is not implemented no matter what the body is
2014-12-04 00:38:42 +00:00
if ( info . GetCustomAttributes ( false ) . Any ( a = > a is FeatureNotImplemented ) )
2014-11-30 14:52:52 +00:00
{
2014-12-04 00:38:42 +00:00
return false ;
2014-11-30 14:52:52 +00:00
}
2017-02-08 23:48:32 +00:00
// adelikat: we can't rely on this anymore
// Some methods throw an exception by design, such as ISoundProvider.GetSamplesAsync()
// If async is not provided by the implementation this method will throw an exception
// We need to figure out a reliable way to check specifically for a NotImplementedException, then maybe this method will be more useful
2014-11-30 14:52:52 +00:00
// If a method is not marked but all it does is throw an exception, consider it not implemented
2017-04-27 16:37:26 +00:00
////return !info.ThrowsError();
2017-02-08 23:48:32 +00:00
return true ;
2014-11-24 00:38:29 +00:00
}
public static bool IsImplemented ( this PropertyInfo info )
{
2014-12-04 00:38:42 +00:00
return ! info . GetCustomAttributes ( false ) . Any ( a = > a is FeatureNotImplemented ) ;
2014-11-24 00:38:29 +00:00
}
2014-04-25 01:19:57 +00:00
}
2017-05-05 16:21:37 +00:00
}