2013-12-15 20:51:57 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using BizHawk.Common ;
using BizHawk.Emulation.Common ;
using System.Runtime.InteropServices ;
2013-12-16 21:23:32 +00:00
using System.IO ;
2013-12-23 23:03:12 +00:00
using System.ComponentModel ;
2013-12-15 20:51:57 +00:00
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{
public class GPGX : IEmulator , ISyncSoundProvider , IVideoProvider
{
static GPGX AttachedCore = null ;
2013-12-16 18:04:45 +00:00
DiscSystem . Disc CD ;
2013-12-15 20:51:57 +00:00
byte [ ] romfile ;
2013-12-30 20:36:51 +00:00
bool drivelight ;
2013-12-15 20:51:57 +00:00
bool disposed = false ;
LibGPGX . load_archive_cb LoadCallback = null ;
2013-12-21 17:49:32 +00:00
LibGPGX . input_cb InputCallback = null ;
2013-12-15 20:51:57 +00:00
2013-12-16 01:58:40 +00:00
LibGPGX . InputData input = new LibGPGX . InputData ( ) ;
// still working out what all the possibilities are here
public enum ControlType
{
None ,
OnePlayer ,
Normal ,
Xea1p ,
Activator ,
Teamplayer ,
Wayplay
} ;
2013-12-23 23:03:12 +00:00
public GPGX ( CoreComm NextComm , byte [ ] romfile , DiscSystem . Disc CD , string romextension , object SyncSettings )
2013-12-15 20:51:57 +00:00
{
2013-12-16 01:58:40 +00:00
// three or six button?
// http://www.sega-16.com/forum/showthread.php?4398-Forgotten-Worlds-giving-you-GAME-OVER-immediately-Fix-inside&highlight=forgotten%20worlds
2013-12-15 20:51:57 +00:00
try
{
2013-12-23 23:03:12 +00:00
this . SyncSettings = ( GPGXSyncSettings ) SyncSettings ? ? GPGXSyncSettings . GetDefaults ( ) ;
2013-12-15 20:51:57 +00:00
CoreComm = NextComm ;
if ( AttachedCore ! = null )
{
AttachedCore . Dispose ( ) ;
AttachedCore = null ;
}
AttachedCore = this ;
LoadCallback = new LibGPGX . load_archive_cb ( load_archive ) ;
this . romfile = romfile ;
2013-12-16 19:00:05 +00:00
this . CD = CD ;
2013-12-15 20:51:57 +00:00
2013-12-16 01:58:40 +00:00
LibGPGX . INPUT_SYSTEM system_a = LibGPGX . INPUT_SYSTEM . SYSTEM_NONE ;
LibGPGX . INPUT_SYSTEM system_b = LibGPGX . INPUT_SYSTEM . SYSTEM_NONE ;
2013-12-23 23:03:12 +00:00
switch ( this . SyncSettings . ControlType )
2013-12-16 01:58:40 +00:00
{
case ControlType . None :
default :
break ;
case ControlType . Activator :
system_a = LibGPGX . INPUT_SYSTEM . SYSTEM_ACTIVATOR ;
system_b = LibGPGX . INPUT_SYSTEM . SYSTEM_ACTIVATOR ;
break ;
case ControlType . Normal :
system_a = LibGPGX . INPUT_SYSTEM . SYSTEM_MD_GAMEPAD ;
system_b = LibGPGX . INPUT_SYSTEM . SYSTEM_MD_GAMEPAD ;
break ;
case ControlType . OnePlayer :
system_a = LibGPGX . INPUT_SYSTEM . SYSTEM_MD_GAMEPAD ;
break ;
case ControlType . Xea1p :
system_a = LibGPGX . INPUT_SYSTEM . SYSTEM_XE_A1P ;
break ;
case ControlType . Teamplayer :
system_a = LibGPGX . INPUT_SYSTEM . SYSTEM_TEAMPLAYER ;
system_b = LibGPGX . INPUT_SYSTEM . SYSTEM_TEAMPLAYER ;
break ;
case ControlType . Wayplay :
system_a = LibGPGX . INPUT_SYSTEM . SYSTEM_WAYPLAY ;
system_b = LibGPGX . INPUT_SYSTEM . SYSTEM_WAYPLAY ;
break ;
}
2014-01-15 00:56:13 +00:00
if ( ! LibGPGX . gpgx_init ( romextension , LoadCallback , this . SyncSettings . UseSixButton , system_a , system_b , this . SyncSettings . Region ) )
2013-12-15 20:51:57 +00:00
throw new Exception ( "gpgx_init() failed" ) ;
2013-12-16 01:58:40 +00:00
{
int fpsnum = 60 ;
int fpsden = 1 ;
LibGPGX . gpgx_get_fps ( ref fpsnum , ref fpsden ) ;
CoreComm . VsyncNum = fpsnum ;
CoreComm . VsyncDen = fpsden ;
}
2014-02-03 18:07:21 +00:00
// compute state size
{
byte [ ] tmp = new byte [ LibGPGX . gpgx_state_max_size ( ) ] ;
int size = LibGPGX . gpgx_state_size ( tmp , tmp . Length ) ;
if ( size < = 0 )
throw new Exception ( "Couldn't Determine GPGX internal state size!" ) ;
savebuff = new byte [ size ] ;
savebuff2 = new byte [ savebuff . Length + 13 ] ;
Console . WriteLine ( "GPGX Internal State Size: {0}" , size ) ;
}
2013-12-16 01:58:40 +00:00
SetControllerDefinition ( ) ;
2013-12-18 02:16:17 +00:00
// pull the default video size from the core
update_video ( ) ;
2013-12-19 03:33:53 +00:00
SetMemoryDomains ( ) ;
2013-12-21 17:49:32 +00:00
InputCallback = new LibGPGX . input_cb ( input_callback ) ;
LibGPGX . gpgx_set_input_callback ( InputCallback ) ;
2013-12-30 20:36:51 +00:00
if ( CD ! = null )
CoreComm . UsesDriveLed = true ;
2013-12-15 20:51:57 +00:00
}
catch
{
Dispose ( ) ;
throw ;
}
}
/// <summary>
/// core callback for file loading
/// </summary>
/// <param name="filename">string identifying file to be loaded</param>
/// <param name="buffer">buffer to load file to</param>
/// <param name="maxsize">maximum length buffer can hold</param>
/// <returns>actual size loaded, or 0 on failure</returns>
int load_archive ( string filename , IntPtr buffer , int maxsize )
{
byte [ ] srcdata = null ;
if ( buffer = = IntPtr . Zero )
{
Console . WriteLine ( "Couldn't satisfy firmware request {0} because buffer == NULL" , filename ) ;
return 0 ;
}
if ( filename = = "PRIMARY_ROM" )
2013-12-16 18:04:45 +00:00
{
if ( romfile = = null )
{
Console . WriteLine ( "Couldn't satisfy firmware request PRIMARY_ROM because none was provided." ) ;
return 0 ;
}
2013-12-15 20:51:57 +00:00
srcdata = romfile ;
2013-12-16 18:04:45 +00:00
}
else if ( filename = = "PRIMARY_CD" )
{
if ( CD = = null )
{
Console . WriteLine ( "Couldn't satisfy firmware request PRIMARY_CD because none was provided." ) ;
return 0 ;
}
srcdata = GetCDData ( ) ;
2013-12-16 18:20:47 +00:00
if ( srcdata . Length ! = maxsize )
{
Console . WriteLine ( "Couldn't satisfy firmware request PRIMARY_CD because of struct size." ) ;
return 0 ;
}
2013-12-16 18:04:45 +00:00
}
2013-12-15 20:51:57 +00:00
else
{
2013-12-16 03:57:54 +00:00
// use fromtend firmware interface
string firmwareID = null ;
switch ( filename )
{
case "CD_BIOS_EU" : firmwareID = "CD_BIOS_EU" ; break ;
case "CD_BIOS_JP" : firmwareID = "CD_BIOS_JP" ; break ;
case "CD_BIOS_US" : firmwareID = "CD_BIOS_US" ; break ;
default :
break ;
}
if ( firmwareID ! = null )
{
srcdata = CoreComm . CoreFileProvider . GetFirmware ( "GEN" , firmwareID , false ) ;
if ( srcdata = = null )
{
Console . WriteLine ( "Frontend couldn't satisfy firmware request GEN:{0}" , firmwareID ) ;
return 0 ;
}
}
else
{
Console . WriteLine ( "Unrecognized firmware request {0}" , filename ) ;
return 0 ;
}
2013-12-15 20:51:57 +00:00
}
if ( srcdata ! = null )
{
if ( srcdata . Length > maxsize )
{
Console . WriteLine ( "Couldn't satisfy firmware request {0} because {1} > {2}" , filename , srcdata . Length , maxsize ) ;
return 0 ;
}
else
{
Marshal . Copy ( srcdata , 0 , buffer , srcdata . Length ) ;
Console . WriteLine ( "Firmware request {0} satisfied at size {1}" , filename , srcdata . Length ) ;
return srcdata . Length ;
}
}
else
{
2013-12-16 18:04:45 +00:00
throw new Exception ( ) ;
//Console.WriteLine("Couldn't satisfy firmware request {0} for unknown reasons", filename);
//return 0;
}
}
2013-12-20 00:51:48 +00:00
void CDRead ( int lba , IntPtr dest , bool audio )
2013-12-16 18:04:45 +00:00
{
2013-12-20 00:51:48 +00:00
if ( audio )
{
byte [ ] data = new byte [ 2352 ] ;
CD . ReadLBA_2352 ( lba , data , 0 ) ;
Marshal . Copy ( data , 0 , dest , 2352 ) ;
}
else
{
byte [ ] data = new byte [ 2048 ] ;
CD . ReadLBA_2048 ( lba , data , 0 ) ;
Marshal . Copy ( data , 0 , dest , 2048 ) ;
2013-12-30 20:36:51 +00:00
drivelight = true ;
2013-12-20 00:51:48 +00:00
}
2013-12-16 18:04:45 +00:00
}
LibGPGX . cd_read_cb cd_callback_handle ;
unsafe byte [ ] GetCDData ( )
{
LibGPGX . CDData ret = new LibGPGX . CDData ( ) ;
int size = Marshal . SizeOf ( ret ) ;
ret . readcallback = cd_callback_handle = new LibGPGX . cd_read_cb ( CDRead ) ;
var ses = CD . TOC . Sessions [ 0 ] ;
int ntrack = ses . Tracks . Count ;
// bet you a dollar this is all wrong
for ( int i = 0 ; i < LibGPGX . CD_MAX_TRACKS ; i + + )
{
if ( i < ntrack )
{
ret . tracks [ i ] . start = ses . Tracks [ i ] . Indexes [ 1 ] . aba - 150 ;
ret . tracks [ i ] . end = ses . Tracks [ i ] . length_aba + ret . tracks [ i ] . start ;
if ( i = = ntrack - 1 )
{
ret . end = ret . tracks [ i ] . end ;
ret . last = ntrack ;
}
}
else
{
ret . tracks [ i ] . start = 0 ;
ret . tracks [ i ] . end = 0 ;
}
2013-12-15 20:51:57 +00:00
}
2013-12-16 18:04:45 +00:00
byte [ ] retdata = new byte [ size ] ;
fixed ( byte * p = & retdata [ 0 ] )
{
Marshal . StructureToPtr ( ret , ( IntPtr ) p , false ) ;
}
return retdata ;
2013-12-15 20:51:57 +00:00
}
2013-12-16 18:04:45 +00:00
2013-12-15 20:51:57 +00:00
#region controller
2014-02-02 02:05:36 +00:00
/// <summary>
/// size of native input struct
/// </summary>
int inputsize ;
2013-12-16 01:58:40 +00:00
GPGXControlConverter ControlConverter ;
public ControllerDefinition ControllerDefinition { get ; private set ; }
2013-12-15 20:51:57 +00:00
public IController Controller { get ; set ; }
2013-12-16 01:58:40 +00:00
void SetControllerDefinition ( )
{
2014-02-02 02:05:36 +00:00
inputsize = Marshal . SizeOf ( typeof ( LibGPGX . InputData ) ) ;
if ( ! LibGPGX . gpgx_get_control ( input , inputsize ) )
2013-12-16 01:58:40 +00:00
throw new Exception ( "gpgx_get_control() failed" ) ;
ControlConverter = new GPGXControlConverter ( input ) ;
ControllerDefinition = ControlConverter . ControllerDef ;
}
2013-12-21 17:49:32 +00:00
// core callback for input
void input_callback ( )
{
CoreComm . InputCallback . Call ( ) ;
IsLagFrame = false ;
}
2013-12-15 20:51:57 +00:00
#endregion
2013-12-16 01:58:40 +00:00
// TODO: use render and rendersound
2013-12-15 20:51:57 +00:00
public void FrameAdvance ( bool render , bool rendersound = true )
{
2013-12-20 19:32:12 +00:00
if ( Controller [ "Reset" ] )
LibGPGX . gpgx_reset ( false ) ;
if ( Controller [ "Power" ] )
LibGPGX . gpgx_reset ( true ) ;
2013-12-16 01:58:40 +00:00
// do we really have to get each time? nothing has changed
2014-02-02 02:05:36 +00:00
if ( ! LibGPGX . gpgx_get_control ( input , inputsize ) )
2013-12-16 01:58:40 +00:00
throw new Exception ( "gpgx_get_control() failed!" ) ;
ControlConverter . Convert ( Controller , input ) ;
2014-02-02 02:05:36 +00:00
if ( ! LibGPGX . gpgx_put_control ( input , inputsize ) )
2013-12-16 01:58:40 +00:00
throw new Exception ( "gpgx_put_control() failed!" ) ;
2013-12-15 20:51:57 +00:00
IsLagFrame = true ;
Frame + + ;
2013-12-30 20:36:51 +00:00
drivelight = false ;
2013-12-15 20:51:57 +00:00
LibGPGX . gpgx_advance ( ) ;
update_video ( ) ;
update_audio ( ) ;
2013-12-16 01:58:40 +00:00
if ( IsLagFrame )
LagCount + + ;
2013-12-30 20:36:51 +00:00
if ( CD ! = null )
CoreComm . DriveLED = drivelight ;
2013-12-15 20:51:57 +00:00
}
public int Frame { get ; private set ; }
public int LagCount { get ; set ; }
public bool IsLagFrame { get ; private set ; }
public string SystemId { get { return "GEN" ; } }
public bool DeterministicEmulation { get { return true ; } }
public string BoardName { get { return null ; } }
public CoreComm CoreComm { get ; private set ; }
#region saveram
2013-12-18 02:12:21 +00:00
byte [ ] DisposedSaveRam = null ;
2013-12-15 20:51:57 +00:00
public byte [ ] ReadSaveRam ( )
{
2013-12-18 02:12:21 +00:00
if ( disposed )
{
return DisposedSaveRam ? ? new byte [ 0 ] ;
}
else
{
int size = 0 ;
IntPtr area = IntPtr . Zero ;
LibGPGX . gpgx_get_sram ( ref area , ref size ) ;
if ( size < = 0 | | area = = IntPtr . Zero )
return new byte [ 0 ] ;
LibGPGX . gpgx_sram_prepread ( ) ;
byte [ ] ret = new byte [ size ] ;
Marshal . Copy ( area , ret , 0 , size ) ;
return ret ;
}
2013-12-15 20:51:57 +00:00
}
public void StoreSaveRam ( byte [ ] data )
{
2013-12-18 02:12:21 +00:00
if ( disposed )
{
throw new ObjectDisposedException ( typeof ( GPGX ) . ToString ( ) ) ;
}
else
{
int size = 0 ;
IntPtr area = IntPtr . Zero ;
LibGPGX . gpgx_get_sram ( ref area , ref size ) ;
if ( size < = 0 | | area = = IntPtr . Zero )
return ;
if ( size ! = data . Length )
throw new Exception ( "Unexpected saveram size" ) ;
Marshal . Copy ( data , 0 , area , size ) ;
LibGPGX . gpgx_sram_commitwrite ( ) ;
}
2013-12-15 20:51:57 +00:00
}
public void ClearSaveRam ( )
{
2013-12-18 02:12:21 +00:00
if ( disposed )
{
throw new ObjectDisposedException ( typeof ( GPGX ) . ToString ( ) ) ;
}
else
{
LibGPGX . gpgx_clear_sram ( ) ;
}
2013-12-15 20:51:57 +00:00
}
public bool SaveRamModified
{
get
{
2013-12-18 02:12:21 +00:00
if ( disposed )
{
2013-12-18 02:19:00 +00:00
return DisposedSaveRam ! = null ;
2013-12-18 02:12:21 +00:00
}
else
{
int size = 0 ;
IntPtr area = IntPtr . Zero ;
LibGPGX . gpgx_get_sram ( ref area , ref size ) ;
return size > 0 & & area ! = IntPtr . Zero ;
}
2013-12-15 20:51:57 +00:00
}
set
{
2013-12-16 21:23:32 +00:00
throw new Exception ( ) ;
2013-12-15 20:51:57 +00:00
}
}
#endregion
public void ResetCounters ( )
{
Frame = 0 ;
IsLagFrame = false ;
LagCount = 0 ;
}
#region savestates
2013-12-16 01:58:40 +00:00
private byte [ ] savebuff ;
private byte [ ] savebuff2 ;
2013-12-15 20:51:57 +00:00
public void SaveStateText ( System . IO . TextWriter writer )
{
2013-12-16 03:39:47 +00:00
var temp = SaveStateBinary ( ) ;
temp . SaveAsHexFast ( writer ) ;
// write extra copy of stuff we don't use
writer . WriteLine ( "Frame {0}" , Frame ) ;
2013-12-15 20:51:57 +00:00
}
public void LoadStateText ( System . IO . TextReader reader )
{
2013-12-16 03:39:47 +00:00
string hex = reader . ReadLine ( ) ;
if ( hex . StartsWith ( "emuVersion" ) ) // movie save
{
do // theoretically, our portion should start right after StartsFromSavestate, maybe...
{
hex = reader . ReadLine ( ) ;
} while ( ! hex . StartsWith ( "StartsFromSavestate" ) ) ;
hex = reader . ReadLine ( ) ;
}
byte [ ] state = new byte [ hex . Length / 2 ] ;
state . ReadFromHexFast ( hex ) ;
LoadStateBinary ( new System . IO . BinaryReader ( new System . IO . MemoryStream ( state ) ) ) ;
2013-12-15 20:51:57 +00:00
}
public void SaveStateBinary ( System . IO . BinaryWriter writer )
{
2013-12-16 01:58:40 +00:00
if ( ! LibGPGX . gpgx_state_save ( savebuff , savebuff . Length ) )
throw new Exception ( "gpgx_state_save() returned false" ) ;
writer . Write ( savebuff . Length ) ;
writer . Write ( savebuff ) ;
// other variables
writer . Write ( Frame ) ;
writer . Write ( LagCount ) ;
writer . Write ( IsLagFrame ) ;
2013-12-15 20:51:57 +00:00
}
public void LoadStateBinary ( System . IO . BinaryReader reader )
{
2013-12-16 01:58:40 +00:00
int newlen = reader . ReadInt32 ( ) ;
if ( newlen ! = savebuff . Length )
throw new Exception ( "Unexpected state size" ) ;
reader . Read ( savebuff , 0 , savebuff . Length ) ;
if ( ! LibGPGX . gpgx_state_load ( savebuff , savebuff . Length ) )
throw new Exception ( "gpgx_state_load() returned false" ) ;
// other variables
Frame = reader . ReadInt32 ( ) ;
LagCount = reader . ReadInt32 ( ) ;
IsLagFrame = reader . ReadBoolean ( ) ;
2013-12-20 21:21:21 +00:00
update_video ( ) ;
2013-12-15 20:51:57 +00:00
}
public byte [ ] SaveStateBinary ( )
{
2013-12-16 01:58:40 +00:00
var ms = new System . IO . MemoryStream ( savebuff2 , true ) ;
var bw = new System . IO . BinaryWriter ( ms ) ;
SaveStateBinary ( bw ) ;
bw . Flush ( ) ;
ms . Close ( ) ;
return savebuff2 ;
2013-12-15 20:51:57 +00:00
}
public bool BinarySaveStatesPreferred { get { return true ; } }
#endregion
2013-12-21 17:49:32 +00:00
#region debugging tools
2013-12-15 20:51:57 +00:00
public MemoryDomainList MemoryDomains { get ; private set ; }
2013-12-19 03:33:53 +00:00
unsafe void SetMemoryDomains ( )
{
var mm = new List < MemoryDomain > ( ) ;
for ( int i = LibGPGX . MIN_MEM_DOMAIN ; i < = LibGPGX . MAX_MEM_DOMAIN ; i + + )
{
IntPtr area = IntPtr . Zero ;
int size = 0 ;
IntPtr pname = LibGPGX . gpgx_get_memdom ( i , ref area , ref size ) ;
if ( area = = IntPtr . Zero | | pname = = IntPtr . Zero | | size = = 0 )
continue ;
string name = Marshal . PtrToStringAnsi ( pname ) ;
byte * p = ( byte * ) area ;
mm . Add ( new MemoryDomain ( name , size , MemoryDomain . Endian . Unknown ,
delegate ( int addr )
{
2014-01-04 16:30:26 +00:00
return p [ addr & ( size - 1 ) ] ;
2013-12-19 03:33:53 +00:00
} ,
delegate ( int addr , byte val )
{
2014-01-04 16:30:26 +00:00
p [ addr & ( size - 1 ) ] = val ;
2013-12-19 03:33:53 +00:00
} ) ) ;
}
MemoryDomains = new MemoryDomainList ( mm , 0 ) ;
}
2013-12-15 20:51:57 +00:00
public List < KeyValuePair < string , int > > GetCpuFlagsAndRegisters ( )
{
return new List < KeyValuePair < string , int > > ( ) ;
}
2013-12-21 17:49:32 +00:00
#endregion
2013-12-15 20:51:57 +00:00
public void Dispose ( )
{
if ( ! disposed )
{
if ( AttachedCore ! = this )
throw new Exception ( ) ;
2013-12-18 02:12:21 +00:00
if ( SaveRamModified )
DisposedSaveRam = ReadSaveRam ( ) ;
2013-12-15 20:51:57 +00:00
AttachedCore = null ;
2013-12-16 03:29:41 +00:00
disposed = true ;
2013-12-15 20:51:57 +00:00
}
}
#region SoundProvider
short [ ] samples = new short [ 4096 ] ;
int nsamp = 0 ;
public ISoundProvider SoundProvider { get { return null ; } }
public ISyncSoundProvider SyncSoundProvider { get { return this ; } }
public bool StartAsyncSound ( ) { return false ; }
public void EndAsyncSound ( ) { }
public void GetSamples ( out short [ ] samples , out int nsamp )
{
nsamp = this . nsamp ;
samples = this . samples ;
this . nsamp = 0 ;
}
public void DiscardSamples ( )
{
this . nsamp = 0 ;
}
void update_audio ( )
{
IntPtr src = IntPtr . Zero ;
LibGPGX . gpgx_get_audio ( ref nsamp , ref src ) ;
if ( src ! = IntPtr . Zero )
{
Marshal . Copy ( src , samples , 0 , nsamp * 2 ) ;
}
}
#endregion
#region VideoProvider
public IVideoProvider VideoProvider { get { return this ; } }
int [ ] vidbuff = new int [ 0 ] ;
int vwidth ;
int vheight ;
public int [ ] GetVideoBuffer ( ) { return vidbuff ; }
public int VirtualWidth { get { return BufferWidth ; } } // TODO
public int BufferWidth { get { return vwidth ; } }
public int BufferHeight { get { return vheight ; } }
public int BackgroundColor { get { return unchecked ( ( int ) 0xff000000 ) ; } }
unsafe void update_video ( )
{
int pitch = 0 ;
IntPtr src = IntPtr . Zero ;
LibGPGX . gpgx_get_video ( ref vwidth , ref vheight , ref pitch , ref src ) ;
if ( vidbuff . Length < vwidth * vheight )
vidbuff = new int [ vwidth * vheight ] ;
int rinc = ( pitch / 4 ) - vwidth ;
fixed ( int * pdst_ = & vidbuff [ 0 ] )
{
int * pdst = pdst_ ;
int * psrc = ( int * ) src ;
for ( int j = 0 ; j < vheight ; j + + )
{
for ( int i = 0 ; i < vwidth ; i + + )
* pdst + + = * psrc + + | unchecked ( ( int ) 0xff000000 ) ;
psrc + = rinc ;
}
}
}
#endregion
2013-12-22 00:44:39 +00:00
2013-12-23 23:03:12 +00:00
GPGXSyncSettings SyncSettings ;
2013-12-22 00:44:39 +00:00
public object GetSettings ( ) { return null ; }
2013-12-23 23:03:12 +00:00
public object GetSyncSettings ( ) { return SyncSettings . Clone ( ) ; }
2013-12-22 00:44:39 +00:00
public bool PutSettings ( object o ) { return false ; }
2013-12-23 23:03:12 +00:00
public bool PutSyncSettings ( object o )
{
bool ret ;
var n = ( GPGXSyncSettings ) o ;
2014-01-15 00:56:13 +00:00
ret = GPGXSyncSettings . NeedsReboot ( SyncSettings , n ) ;
2013-12-23 23:03:12 +00:00
SyncSettings = n ;
return ret ;
}
public class GPGXSyncSettings
{
[Description("Controls the type of any attached normal controllers; six button controllers are used if true, otherwise three button controllers. Some games don't work correctly with six button controllers. Not relevant if other controller types are connected.")]
2014-01-15 00:56:13 +00:00
[DefaultValue(true)]
2013-12-23 23:03:12 +00:00
public bool UseSixButton { get ; set ; }
[Description("Sets the type of controls that are plugged into the console. Some games will automatically load with a different control type.")]
2014-01-15 00:56:13 +00:00
[DefaultValue(ControlType.Normal)]
2013-12-23 23:03:12 +00:00
public ControlType ControlType { get ; set ; }
2014-01-15 00:56:13 +00:00
[Description("Sets the region of the emulated console. Many games can run on multiple regions and will behave differently on different ones. Some games may require a particular region.")]
[DefaultValue(LibGPGX.Region.Autodetect)]
public LibGPGX . Region Region { get ; set ; }
public GPGXSyncSettings ( )
{
UseSixButton = true ;
ControlType = ControlType . Normal ;
Region = LibGPGX . Region . Autodetect ;
}
2013-12-23 23:03:12 +00:00
public static GPGXSyncSettings GetDefaults ( )
{
2014-01-15 00:56:13 +00:00
return new GPGXSyncSettings ( ) ;
2013-12-23 23:03:12 +00:00
}
public GPGXSyncSettings Clone ( )
{
return ( GPGXSyncSettings ) MemberwiseClone ( ) ;
}
2014-01-15 00:56:13 +00:00
public static bool NeedsReboot ( GPGXSyncSettings x , GPGXSyncSettings y )
{
return x . UseSixButton ! = y . UseSixButton | | x . ControlType ! = y . ControlType | | x . Region ! = y . Region ;
}
2013-12-23 23:03:12 +00:00
}
2013-12-15 20:51:57 +00:00
}
}