2013-10-28 19:13:01 +00:00
using System ;
2014-11-08 14:08:32 +00:00
using System.ComponentModel ;
2014-10-18 22:13:25 +00:00
using BizHawk.Emulation.Common ;
2014-05-31 14:29:27 +00:00
using BizHawk.Emulation.Common.IEmulatorExtensions ;
2013-12-30 01:58:44 +00:00
using BizHawk.Emulation.Cores.Nintendo.NES ;
2013-11-13 23:36:21 +00:00
using BizHawk.Emulation.Cores.PCEngine ;
using BizHawk.Emulation.Cores.Sega.MasterSystem ;
2014-06-10 20:41:20 +00:00
using BizHawk.Emulation.Cores.WonderSwan ;
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES ;
2013-12-30 01:58:44 +00:00
using LuaInterface ;
2013-10-28 19:13:01 +00:00
2013-11-01 14:51:51 +00:00
namespace BizHawk.Client.Common
2013-10-28 19:13:01 +00:00
{
2014-11-08 14:08:32 +00:00
[Description("A library for interacting with the currently loaded emulator core")]
2014-06-01 22:02:59 +00:00
public sealed class EmulatorLuaLibrary : LuaLibraryBase
2013-10-28 19:13:01 +00:00
{
2015-01-01 19:52:53 +00:00
[RequiredService]
2017-05-19 13:58:23 +00:00
private IEmulator Emulator { get ; set ; }
2015-01-01 19:52:53 +00:00
[OptionalService]
2017-05-19 13:58:23 +00:00
private IDebuggable DebuggableCore { get ; set ; }
2015-01-01 19:52:53 +00:00
2016-02-21 15:13:45 +00:00
[OptionalService]
2017-05-19 13:58:23 +00:00
private IDisassemblable DisassemblableCore { get ; set ; }
2016-02-21 15:13:45 +00:00
[OptionalService]
private IMemoryDomains MemoryDomains { get ; set ; }
2015-01-01 19:52:53 +00:00
[OptionalService]
2017-05-19 13:58:23 +00:00
private IInputPollable InputPollableCore { get ; set ; }
2015-01-01 19:52:53 +00:00
2016-12-15 19:09:52 +00:00
[OptionalService]
2017-05-19 13:58:23 +00:00
private IRegionable RegionableCore { get ; set ; }
2016-12-15 19:09:52 +00:00
2017-05-12 20:18:43 +00:00
[OptionalService]
2017-05-19 13:58:23 +00:00
private IBoardInfo BoardInfo { get ; set ; }
2017-05-12 20:18:43 +00:00
2014-05-21 01:15:52 +00:00
public Action FrameAdvanceCallback { get ; set ; }
public Action YieldCallback { get ; set ; }
2014-05-21 00:17:35 +00:00
public EmulatorLuaLibrary ( Lua lua )
: base ( lua ) { }
public EmulatorLuaLibrary ( Lua lua , Action < string > logOutputCallback )
: base ( lua , logOutputCallback ) { }
2017-04-14 19:59:01 +00:00
public override string Name = > "emu" ;
2013-10-31 18:09:40 +00:00
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("displayvsync", "Sets the display vsync property of the emulator")]
2014-01-26 20:05:45 +00:00
public static void DisplayVsync ( bool enabled )
2013-10-28 19:13:01 +00:00
{
2015-03-27 23:29:15 +00:00
Global . Config . VSync = enabled ;
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("frameadvance", "Signals to the emulator to resume emulation. Necessary for any lua script while loop or else the emulator will freeze!")]
2014-01-25 21:10:51 +00:00
public void FrameAdvance ( )
2013-10-28 19:13:01 +00:00
{
2014-05-21 01:15:52 +00:00
FrameAdvanceCallback ( ) ;
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("framecount", "Returns the current frame count")]
2015-01-01 19:52:53 +00:00
public int FrameCount ( )
2013-10-28 19:13:01 +00:00
{
2015-01-01 19:52:53 +00:00
return Emulator . Frame ;
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("disassemble", "Returns the disassembly object (disasm string and length int) for the given PC address. Uses System Bus domain if no domain name provided")]
2016-02-21 15:13:45 +00:00
public object Disassemble ( uint pc , string name = "" )
{
try
{
if ( DisassemblableCore = = null )
{
throw new NotImplementedException ( ) ;
}
int l ;
MemoryDomain domain = MemoryDomains . SystemBus ;
if ( ! string . IsNullOrEmpty ( name ) )
2017-05-17 18:18:26 +00:00
{
2016-02-21 15:13:45 +00:00
domain = MemoryDomains [ name ] ;
2017-05-17 18:18:26 +00:00
}
2016-02-21 15:13:45 +00:00
var d = DisassemblableCore . Disassemble ( domain , pc , out l ) ;
return new { disasm = d , length = l } ;
}
catch ( NotImplementedException )
{
2017-05-18 16:36:38 +00:00
Log ( $"Error: {Emulator.Attributes().CoreName} does not yet implement disassemble()" ) ;
2016-02-21 15:13:45 +00:00
return null ;
}
}
2014-12-20 03:19:33 +00:00
// TODO: what about 64 bit registers?
2014-01-25 21:10:51 +00:00
[ LuaMethodAttributes (
2017-05-09 18:19:55 +00:00
"getregister" , "returns the value of a cpu register or flag specified by name. For a complete list of possible registers or flags for a given core, use getregisters" ) ]
2014-05-31 14:29:27 +00:00
public int GetRegister ( string name )
2013-11-11 03:20:33 +00:00
{
2014-05-31 14:29:27 +00:00
try
{
2015-01-01 19:52:53 +00:00
if ( DebuggableCore = = null )
2014-12-05 01:01:58 +00:00
{
2014-10-19 01:22:47 +00:00
throw new NotImplementedException ( ) ;
2014-12-05 01:01:58 +00:00
}
2014-10-18 22:13:25 +00:00
2015-01-01 19:52:53 +00:00
var registers = DebuggableCore . GetCpuFlagsAndRegisters ( ) ;
2014-10-19 01:22:47 +00:00
return registers . ContainsKey ( name )
2014-12-20 03:19:33 +00:00
? ( int ) registers [ name ] . Value
2014-10-19 01:22:47 +00:00
: 0 ;
2014-05-31 14:29:27 +00:00
}
catch ( NotImplementedException )
{
2017-05-17 18:18:26 +00:00
Log ( $"Error: {Emulator.Attributes().CoreName} does not yet implement getregister()" ) ;
2014-05-31 14:29:27 +00:00
return 0 ;
}
2013-11-11 03:20:33 +00:00
}
2014-01-25 21:10:51 +00:00
[ LuaMethodAttributes (
2017-05-09 18:19:55 +00:00
"getregisters" , "returns the complete set of available flags and registers for a given core" ) ]
2014-01-25 21:10:51 +00:00
public LuaTable GetRegisters ( )
2013-11-11 03:20:33 +00:00
{
2014-05-20 20:34:51 +00:00
var table = Lua . NewTable ( ) ;
2014-05-31 14:29:27 +00:00
try
{
2015-01-01 19:52:53 +00:00
if ( DebuggableCore = = null )
2014-12-05 01:01:58 +00:00
{
2014-10-19 01:22:47 +00:00
throw new NotImplementedException ( ) ;
2014-12-05 01:01:58 +00:00
}
2014-10-18 22:13:25 +00:00
2015-01-01 19:52:53 +00:00
foreach ( var kvp in DebuggableCore . GetCpuFlagsAndRegisters ( ) )
2014-05-31 14:29:27 +00:00
{
2015-01-01 19:52:53 +00:00
table [ kvp . Key ] = kvp . Value . Value ;
2014-05-31 14:29:27 +00:00
}
}
catch ( NotImplementedException )
2013-11-11 03:20:33 +00:00
{
2017-04-14 19:59:01 +00:00
Log ( $"Error: {Emulator.Attributes().CoreName} does not yet implement getregisters()" ) ;
2013-11-11 03:20:33 +00:00
}
2013-12-30 01:58:44 +00:00
2013-11-11 03:20:33 +00:00
return table ;
}
2014-05-31 17:03:21 +00:00
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("setregister", "sets the given register name to the given value")]
2014-05-31 17:03:21 +00:00
public void SetRegister ( string register , int value )
{
try
{
2015-01-01 19:52:53 +00:00
if ( DebuggableCore = = null )
2014-12-05 01:01:58 +00:00
{
2014-10-19 01:22:47 +00:00
throw new NotImplementedException ( ) ;
2014-12-05 01:01:58 +00:00
}
2014-10-18 22:13:25 +00:00
2015-01-01 19:52:53 +00:00
DebuggableCore . SetCpuRegister ( register , value ) ;
2014-05-31 17:03:21 +00:00
}
catch ( NotImplementedException )
{
2017-04-14 19:59:01 +00:00
Log ( $"Error: {Emulator.Attributes().CoreName} does not yet implement setregister()" ) ;
2014-05-31 17:03:21 +00:00
}
}
2013-11-11 03:20:33 +00:00
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("totalexecutedcycles", "gets the total number of executed cpu cycles")]
2017-01-10 01:23:05 +00:00
public int TotalExecutedycles ( )
{
try
{
if ( DebuggableCore = = null )
{
throw new NotImplementedException ( ) ;
}
return DebuggableCore . TotalExecutedCycles ;
}
catch ( NotImplementedException )
{
2017-05-18 16:36:38 +00:00
Log ( $"Error: {Emulator.Attributes().CoreName} does not yet implement totalexecutedcycles()" ) ;
2017-01-10 01:23:05 +00:00
return 0 ;
}
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("getsystemid", "Returns the ID string of the current core loaded. Note: No ROM loaded will return the string NULL")]
2014-01-25 21:10:51 +00:00
public static string GetSystemId ( )
2013-10-28 19:13:01 +00:00
{
2014-05-03 02:28:12 +00:00
return Global . Game . System ;
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("islagged", "Returns whether or not the current frame is a lag frame")]
2014-11-30 20:29:30 +00:00
public bool IsLagged ( )
2013-10-28 19:13:01 +00:00
{
2015-01-01 19:52:53 +00:00
if ( InputPollableCore ! = null )
2014-11-30 20:29:30 +00:00
{
2015-01-01 19:52:53 +00:00
return InputPollableCore . IsLagFrame ;
2014-11-30 20:29:30 +00:00
}
2017-04-14 19:59:01 +00:00
Log ( $"Can not get lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable" ) ;
return false ;
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("setislagged", "Sets the lag flag for the current frame. If no value is provided, it will default to true")]
2016-01-27 13:41:41 +00:00
public void SetIsLagged ( bool value = true )
{
if ( InputPollableCore ! = null )
{
InputPollableCore . IsLagFrame = value ;
}
else
{
2017-04-14 19:59:01 +00:00
Log ( $"Can not set lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable" ) ;
2016-01-27 13:41:41 +00:00
}
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("lagcount", "Returns the current lag count")]
2014-11-30 20:29:30 +00:00
public int LagCount ( )
2013-10-28 19:13:01 +00:00
{
2015-01-01 19:52:53 +00:00
if ( InputPollableCore ! = null )
2014-11-30 20:29:30 +00:00
{
2015-01-01 19:52:53 +00:00
return InputPollableCore . LagCount ;
2014-11-30 20:29:30 +00:00
}
2017-04-14 19:59:01 +00:00
Log ( $"Can not get lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable" ) ;
return 0 ;
2015-07-09 17:05:30 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("setlagcount", "Sets the current lag count")]
2015-07-09 17:05:30 +00:00
public void SetLagCount ( int count )
{
if ( InputPollableCore ! = null )
{
InputPollableCore . LagCount = count ;
}
else
{
2017-05-18 16:36:38 +00:00
Log ( $"Can not set lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable" ) ;
2014-11-30 20:29:30 +00:00
}
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("limitframerate", "sets the limit framerate property of the emulator")]
2014-01-26 18:36:27 +00:00
public static void LimitFramerate ( bool enabled )
2013-10-28 19:13:01 +00:00
{
2014-01-26 18:36:27 +00:00
Global . Config . ClockThrottle = enabled ;
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("minimizeframeskip", "Sets the autominimizeframeskip value of the emulator")]
2014-01-26 18:36:27 +00:00
public static void MinimizeFrameskip ( bool enabled )
2013-10-28 19:13:01 +00:00
{
2014-01-26 18:36:27 +00:00
Global . Config . AutoMinimizeSkipping = enabled ;
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("setrenderplanes", "Toggles the drawing of sprites and background planes. Set to false or nil to disable a pane, anything else will draw them")]
2015-01-01 19:52:53 +00:00
public void SetRenderPlanes ( params bool [ ] luaParam )
2013-10-28 19:13:01 +00:00
{
2015-01-01 19:52:53 +00:00
if ( Emulator is NES )
2014-05-01 17:09:54 +00:00
{
// in the future, we could do something more arbitrary here.
// but this isn't any worse than the old system
2015-01-01 19:52:53 +00:00
var nes = Emulator as NES ;
2014-10-19 01:22:47 +00:00
var s = nes . GetSettings ( ) ;
2017-05-18 19:53:03 +00:00
s . DispSprites = luaParam [ 0 ] ;
s . DispBackground = luaParam [ 1 ] ;
2014-10-19 01:22:47 +00:00
nes . PutSettings ( s ) ;
2014-05-01 17:09:54 +00:00
}
2015-01-01 19:52:53 +00:00
else if ( Emulator is QuickNES )
2014-06-10 20:41:20 +00:00
{
2015-01-01 19:52:53 +00:00
var quicknes = Emulator as QuickNES ;
2014-10-19 01:22:47 +00:00
var s = quicknes . GetSettings ( ) ;
2017-04-14 19:59:01 +00:00
2014-06-10 20:41:20 +00:00
// this core doesn't support disabling BG
bool showsp = GetSetting ( 0 , luaParam ) ;
if ( showsp & & s . NumSprites = = 0 )
2017-04-14 19:59:01 +00:00
{
2014-06-10 20:41:20 +00:00
s . NumSprites = 8 ;
2017-04-14 19:59:01 +00:00
}
2014-06-10 20:41:20 +00:00
else if ( ! showsp & & s . NumSprites > 0 )
2017-04-14 19:59:01 +00:00
{
2014-06-10 20:41:20 +00:00
s . NumSprites = 0 ;
2017-04-14 19:59:01 +00:00
}
2014-10-19 01:22:47 +00:00
quicknes . PutSettings ( s ) ;
2014-06-10 20:41:20 +00:00
}
2015-01-01 19:52:53 +00:00
else if ( Emulator is PCEngine )
2014-05-01 17:09:54 +00:00
{
2015-01-01 19:52:53 +00:00
var pce = Emulator as PCEngine ;
2014-10-19 01:22:47 +00:00
var s = pce . GetSettings ( ) ;
2014-05-01 17:09:54 +00:00
s . ShowOBJ1 = GetSetting ( 0 , luaParam ) ;
s . ShowBG1 = GetSetting ( 1 , luaParam ) ;
if ( luaParam . Length > 2 )
{
s . ShowOBJ2 = GetSetting ( 2 , luaParam ) ;
s . ShowBG2 = GetSetting ( 3 , luaParam ) ;
}
2014-10-19 01:22:47 +00:00
pce . PutSettings ( s ) ;
2014-05-01 17:09:54 +00:00
}
2015-01-01 19:52:53 +00:00
else if ( Emulator is SMS )
2014-05-01 17:09:54 +00:00
{
2015-01-01 19:52:53 +00:00
var sms = Emulator as SMS ;
2014-10-19 01:22:47 +00:00
var s = sms . GetSettings ( ) ;
2014-05-01 17:09:54 +00:00
s . DispOBJ = GetSetting ( 0 , luaParam ) ;
s . DispBG = GetSetting ( 1 , luaParam ) ;
2014-10-19 01:22:47 +00:00
sms . PutSettings ( s ) ;
2014-05-01 17:09:54 +00:00
}
2015-01-01 19:52:53 +00:00
else if ( Emulator is WonderSwan )
2014-06-10 20:41:20 +00:00
{
2015-01-01 19:52:53 +00:00
var ws = Emulator as WonderSwan ;
2014-10-19 01:22:47 +00:00
var s = ws . GetSettings ( ) ;
2014-06-10 20:41:20 +00:00
s . EnableSprites = GetSetting ( 0 , luaParam ) ;
s . EnableFG = GetSetting ( 1 , luaParam ) ;
s . EnableBG = GetSetting ( 2 , luaParam ) ;
2014-10-19 01:22:47 +00:00
ws . PutSettings ( s ) ;
2014-06-10 20:41:20 +00:00
}
2014-05-01 17:09:54 +00:00
}
private static bool GetSetting ( int index , bool [ ] settings )
{
if ( index < settings . Length )
{
return settings [ index ] ;
}
return true ;
2013-10-28 19:13:01 +00:00
}
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("yield", "allows a script to run while emulation is paused and interact with the gui/main window in realtime ")]
2014-01-25 21:10:51 +00:00
public void Yield ( )
2013-10-28 19:13:01 +00:00
{
2014-05-21 01:15:52 +00:00
YieldCallback ( ) ;
2013-10-28 19:13:01 +00:00
}
2014-04-13 14:22:13 +00:00
2017-05-09 18:19:55 +00:00
[LuaMethodAttributes("getdisplaytype", "returns the display type (PAL vs NTSC) that the emulator is currently running in")]
2014-04-13 14:22:13 +00:00
public string GetDisplayType ( )
{
2016-12-15 19:09:52 +00:00
if ( RegionableCore ! = null )
2014-04-13 14:22:13 +00:00
{
2016-12-15 19:09:52 +00:00
return RegionableCore . Region . ToString ( ) ;
2014-04-13 14:22:13 +00:00
}
2017-05-10 11:45:23 +00:00
return "" ;
2014-04-13 14:22:13 +00:00
}
2017-05-12 20:18:43 +00:00
[LuaMethodAttributes("getboardname", "returns (if available) the board name of the loaded ROM")]
public string GetBoardName ( )
{
if ( BoardInfo ! = null )
{
return BoardInfo . BoardName ;
}
return "" ;
}
2013-10-28 19:13:01 +00:00
}
}