Mesen-S/Core/LuaApi.cpp
2020-06-30 16:51:13 -04:00

904 lines
31 KiB
C++

#include "stdafx.h"
#ifndef LIBRETRO
#include "LuaApi.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FolderUtilities.h"
#include "../Lua/lua.hpp"
#include "LuaCallHelper.h"
#include "Debugger.h"
#include "MemoryDumper.h"
#include "MessageManager.h"
#include "ScriptingContext.h"
#include "DebugHud.h"
#include "VideoDecoder.h"
#include "RewindManager.h"
#include "SaveStateManager.h"
#include "Console.h"
#include "BaseCartridge.h"
#include "IKeyManager.h"
#include "ControlManager.h"
#include "SnesController.h"
#include "Ppu.h"
#include "KeyManager.h"
#include "MemoryAccessCounter.h"
#include "LabelManager.h"
#include "DefaultVideoFilter.h"
#define lua_pushintvalue(name, value) lua_pushliteral(lua, #name); lua_pushinteger(lua, (int)value); lua_settable(lua, -3);
#define lua_pushdoublevalue(name, value) lua_pushliteral(lua, #name); lua_pushnumber(lua, (double)value); lua_settable(lua, -3);
#define lua_pushboolvalue(name, value) lua_pushliteral(lua, #name); lua_pushboolean(lua, (int)value); lua_settable(lua, -3);
#define lua_pushstringvalue(name, value) lua_pushliteral(lua, #name); lua_pushstring(lua, value.c_str()); lua_settable(lua, -3);
#define lua_pusharrayvalue(index, value) lua_pushinteger(lua, index); lua_pushinteger(lua, value); lua_settable(lua, -3);
#define lua_starttable(name) lua_pushliteral(lua, name); lua_newtable(lua);
#define lua_endtable() lua_settable(lua, -3);
#define lua_readint(name, dest) lua_getfield(lua, -1, #name); dest = l.ReadInteger();
#define lua_readbool(name, dest) lua_getfield(lua, -1, #name); dest = l.ReadBool();
#define error(text) luaL_error(lua, text); return 0;
#define errorCond(cond, text) if(cond) { luaL_error(lua, text); return 0; }
#define checkparams() if(!l.CheckParamCount()) { return 0; }
#define checkminparams(x) if(!l.CheckParamCount(x)) { return 0; }
#define checkinitdone() if(!_context->CheckInitDone()) { error("This function cannot be called outside a callback"); return 0; }
#define checksavestateconditions() if(!_context->CheckInStartFrameEvent() && !_context->CheckInExecOpEvent()) { error("This function must be called inside a StartFrame event callback or a CpuExec memory operation callback"); return 0; }
Debugger* LuaApi::_debugger = nullptr;
Console* LuaApi::_console = nullptr;
Ppu* LuaApi::_ppu = nullptr;
MemoryDumper* LuaApi::_memoryDumper = nullptr;
ScriptingContext* LuaApi::_context = nullptr;
void LuaApi::SetContext(ScriptingContext* context)
{
_context = context;
_debugger = _context->GetDebugger();
_memoryDumper = _debugger->GetMemoryDumper().get();
_console = _debugger->GetConsole().get();
_ppu = _console->GetPpu().get();
}
int LuaApi::GetLibrary(lua_State *lua)
{
static const luaL_Reg apilib[] = {
{ "read", LuaApi::ReadMemory },
{ "write", LuaApi::WriteMemory },
{ "readWord", LuaApi::ReadMemoryWord },
{ "writeWord", LuaApi::WriteMemoryWord },
{ "getPrgRomOffset", LuaApi::GetPrgRomOffset },
{ "addMemoryCallback", LuaApi::RegisterMemoryCallback },
{ "removeMemoryCallback", LuaApi::UnregisterMemoryCallback },
{ "addEventCallback", LuaApi::RegisterEventCallback },
{ "removeEventCallback", LuaApi::UnregisterEventCallback },
{ "drawString", LuaApi::DrawString },
{ "drawPixel", LuaApi::DrawPixel },
{ "drawLine", LuaApi::DrawLine },
{ "drawRectangle", LuaApi::DrawRectangle },
{ "clearScreen", LuaApi::ClearScreen },
{ "getScreenBuffer", LuaApi::GetScreenBuffer },
{ "setScreenBuffer", LuaApi::SetScreenBuffer },
{ "getPixel", LuaApi::GetPixel },
{ "getMouseState", LuaApi::GetMouseState },
{ "log", LuaApi::Log },
{ "displayMessage", LuaApi::DisplayMessage },
{ "reset", LuaApi::Reset },
{ "breakExecution", LuaApi::Break },
{ "resume", LuaApi::Resume },
{ "execute", LuaApi::Execute },
{ "rewind", LuaApi::Rewind },
{ "takeScreenshot", LuaApi::TakeScreenshot },
{ "isKeyPressed", LuaApi::IsKeyPressed },
{ "getInput", LuaApi::GetInput },
{ "getAccessCounters", LuaApi::GetAccessCounters },
{ "resetAccessCounters", LuaApi::ResetAccessCounters },
{ "getState", LuaApi::GetState },
{ "getScriptDataFolder", LuaApi::GetScriptDataFolder },
{ "getRomInfo", LuaApi::GetRomInfo },
{ "getLogWindowLog", LuaApi::GetLogWindowLog },
{ "getLabelAddress", LuaApi::GetLabelAddress },
{ NULL,NULL }
};
luaL_newlib(lua, apilib);
//Expose SnesMemoryType enum as "emu.memType"
lua_pushliteral(lua, "memType");
lua_newtable(lua);
lua_pushintvalue(cpu, SnesMemoryType::CpuMemory);
lua_pushintvalue(spc, SnesMemoryType::SpcMemory);
lua_pushintvalue(sa1, SnesMemoryType::Sa1Memory);
lua_pushintvalue(gsu, SnesMemoryType::GsuMemory);
lua_pushintvalue(cx4, SnesMemoryType::Cx4Memory);
lua_pushintvalue(gameboy, SnesMemoryType::GameboyMemory);
lua_pushintvalue(cgram, SnesMemoryType::CGRam);
lua_pushintvalue(vram, SnesMemoryType::VideoRam);
lua_pushintvalue(oam, SnesMemoryType::SpriteRam);
lua_pushintvalue(prgRom, SnesMemoryType::PrgRom);
lua_pushintvalue(workRam, SnesMemoryType::WorkRam);
lua_pushintvalue(saveRam, SnesMemoryType::SaveRam);
lua_pushintvalue(gbPrgRom, SnesMemoryType::GbPrgRom);
lua_pushintvalue(gbWorkRam, SnesMemoryType::GbWorkRam);
lua_pushintvalue(gbCartRam, SnesMemoryType::GbCartRam);
lua_pushintvalue(gbVideoRam, SnesMemoryType::GbVideoRam);
lua_pushintvalue(cpuDebug, SnesMemoryType::CpuMemory | 0x100);
lua_pushintvalue(spcDebug, SnesMemoryType::SpcMemory | 0x100);
lua_pushintvalue(sa1Debug, SnesMemoryType::Sa1Memory | 0x100);
lua_pushintvalue(gsuDebug, SnesMemoryType::GsuMemory | 0x100);
lua_pushintvalue(cx4Debug, SnesMemoryType::Cx4Memory | 0x100);
lua_pushintvalue(gameboyDebug, SnesMemoryType::GameboyMemory | 0x100);
lua_settable(lua, -3);
lua_pushliteral(lua, "memCallbackType");
lua_newtable(lua);
lua_pushintvalue(read, CallbackType::CpuRead);
lua_pushintvalue(write, CallbackType::CpuWrite);
lua_pushintvalue(exec, CallbackType::CpuExec);
lua_settable(lua, -3);
lua_pushliteral(lua, "counterMemType");
lua_newtable(lua);
lua_pushintvalue(prgRom, SnesMemoryType::PrgRom);
lua_pushintvalue(workRam, SnesMemoryType::WorkRam);
lua_pushintvalue(saveRam, SnesMemoryType::SaveRam);
lua_pushintvalue(videoRam, SnesMemoryType::VideoRam);
lua_pushintvalue(spriteRam, SnesMemoryType::SpriteRam);
lua_pushintvalue(cgRam, SnesMemoryType::CGRam);
lua_pushintvalue(spcRam, SnesMemoryType::SpcRam);
lua_pushintvalue(spcRom, SnesMemoryType::SpcRom);
lua_pushintvalue(dspProgramRom, SnesMemoryType::DspProgramRom);
lua_pushintvalue(dspDataRom, SnesMemoryType::DspDataRom);
lua_pushintvalue(dspDataRam, SnesMemoryType::DspDataRam);
lua_pushintvalue(sa1InternalRam, SnesMemoryType::Sa1InternalRam);
lua_pushintvalue(gsuWorkRam, SnesMemoryType::GsuWorkRam);
lua_pushintvalue(cx4DataRam, SnesMemoryType::Cx4DataRam);
lua_pushintvalue(bsxPsRam, SnesMemoryType::BsxPsRam);
lua_pushintvalue(bsxMemoryPack, SnesMemoryType::BsxMemoryPack);
lua_pushintvalue(gbPrgRom, SnesMemoryType::GbPrgRom);
lua_pushintvalue(gbWorkRam, SnesMemoryType::GbWorkRam);
lua_pushintvalue(gbCartRam, SnesMemoryType::GbCartRam);
lua_pushintvalue(gbVideoRam, SnesMemoryType::GbVideoRam);
lua_pushintvalue(gbHighRam, SnesMemoryType::GbHighRam);
lua_pushintvalue(gbBootRom, SnesMemoryType::GbBootRom);
lua_settable(lua, -3);
lua_pushliteral(lua, "counterOpType");
lua_newtable(lua);
lua_pushintvalue(read, MemoryOperationType::Read);
lua_pushintvalue(write, MemoryOperationType::Write);
lua_pushintvalue(exec, MemoryOperationType::ExecOpCode);
lua_settable(lua, -3);
lua_pushliteral(lua, "eventType");
lua_newtable(lua);
lua_pushintvalue(reset, EventType::Reset);
lua_pushintvalue(nmi, EventType::Nmi);
lua_pushintvalue(irq, EventType::Irq);
lua_pushintvalue(startFrame, EventType::StartFrame);
lua_pushintvalue(endFrame, EventType::EndFrame);
lua_pushintvalue(inputPolled, EventType::InputPolled);
lua_pushintvalue(scriptEnded, EventType::ScriptEnded);
lua_pushintvalue(stateLoaded, EventType::StateLoaded);
lua_pushintvalue(stateSaved, EventType::StateSaved);
lua_pushintvalue(gbStartFrame, EventType::GbStartFrame);
lua_pushintvalue(gbEndFrame, EventType::GbEndFrame);
//TODO
/*lua_pushintvalue(codeBreak, EventType::CodeBreak);
*/
lua_settable(lua, -3);
lua_pushliteral(lua, "stepType");
lua_newtable(lua);
lua_pushintvalue(cpuInstructions, StepType::Step);
lua_pushintvalue(ppuCycles, StepType::PpuStep);
lua_settable(lua, -3);
lua_pushliteral(lua, "cpuType");
lua_newtable(lua);
lua_pushintvalue(cpu, CpuType::Cpu);
lua_pushintvalue(spc, CpuType::Spc);
lua_pushintvalue(dsp, CpuType::NecDsp);
lua_pushintvalue(sa1, CpuType::Sa1);
lua_pushintvalue(gsu, CpuType::Gsu);
lua_pushintvalue(cx4, CpuType::Cx4);
lua_pushintvalue(gameboy, CpuType::Gameboy);
lua_settable(lua, -3);
return 1;
}
int LuaApi::GetLabelAddress(lua_State *lua)
{
LuaCallHelper l(lua);
string label = l.ReadString();
checkparams();
errorCond(label.length() == 0, "label cannot be empty");
std::shared_ptr<LabelManager> lblMan = _debugger->GetLabelManager();
int32_t value = lblMan->GetLabelRelativeAddress(label);
if(value == -2) {
//Check to see if the label is a multi-byte label instead
string mbLabel = label + "+0";
value = lblMan->GetLabelRelativeAddress(mbLabel);
}
errorCond(value == -1, "label out of scope (not mapped to CPU memory)");
errorCond(value <= -2, "label not found");
l.Return(value);
return l.ReturnCount();
}
int LuaApi::ReadMemory(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(3);
bool returnSignedValue = l.ReadBool();
int type = l.ReadInteger();
bool disableSideEffects = (type & 0x100) == 0x100;
SnesMemoryType memType = (SnesMemoryType)(type & 0xFF);
int address = l.ReadInteger();
checkminparams(2);
errorCond(address < 0, "address must be >= 0");
uint8_t value = _memoryDumper->GetMemoryValue(memType, address, disableSideEffects);
l.Return(returnSignedValue ? (int8_t)value : value);
return l.ReturnCount();
}
int LuaApi::WriteMemory(lua_State *lua)
{
LuaCallHelper l(lua);
int type = l.ReadInteger();
bool disableSideEffects = (type & 0x100) == 0x100;
SnesMemoryType memType = (SnesMemoryType)(type & 0xFF);
int value = l.ReadInteger();
int address = l.ReadInteger();
checkparams();
errorCond(value > 255 || value < -128, "value out of range");
errorCond(address < 0, "address must be >= 0");
_memoryDumper->SetMemoryValue(memType, address, value, disableSideEffects);
return l.ReturnCount();
}
int LuaApi::ReadMemoryWord(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(3);
bool returnSignedValue = l.ReadBool();
int type = l.ReadInteger();
bool disableSideEffects = (type & 0x100) == 0x100;
SnesMemoryType memType = (SnesMemoryType)(type & 0xFF);
int address = l.ReadInteger();
checkminparams(2);
errorCond(address < 0, "address must be >= 0");
uint16_t value = _memoryDumper->GetMemoryValueWord(memType, address, disableSideEffects);
l.Return(returnSignedValue ? (int16_t)value : value);
return l.ReturnCount();
}
int LuaApi::WriteMemoryWord(lua_State *lua)
{
LuaCallHelper l(lua);
int type = l.ReadInteger();
bool disableSideEffects = (type & 0x100) == 0x100;
SnesMemoryType memType = (SnesMemoryType)(type & 0xFF);
int value = l.ReadInteger();
int address = l.ReadInteger();
checkparams();
errorCond(value > 65535 || value < -32768, "value out of range");
errorCond(address < 0, "address must be >= 0");
_memoryDumper->SetMemoryValueWord(memType, address, value, disableSideEffects);
return l.ReturnCount();
}
int LuaApi::GetPrgRomOffset(lua_State *lua)
{
LuaCallHelper l(lua);
int address = l.ReadInteger();
checkminparams(1);
errorCond(address < 0 || address > 0xFFFF, "address must be between 0 and $FFFF");
AddressInfo relAddress { address, SnesMemoryType::CpuMemory };
int32_t prgRomOffset = _debugger->GetAbsoluteAddress(relAddress).Address;
l.Return(prgRomOffset);
return l.ReturnCount();
}
int LuaApi::RegisterMemoryCallback(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(5);
CpuType cpuType = (CpuType)l.ReadInteger((int)CpuType::Cpu);
int32_t endAddr = l.ReadInteger(-1);
int32_t startAddr = l.ReadInteger();
CallbackType callbackType = (CallbackType)l.ReadInteger();
int reference = l.GetReference();
checkminparams(3);
if(endAddr == -1) {
endAddr = startAddr;
}
errorCond(startAddr > endAddr, "start address must be <= end address");
errorCond(callbackType < CallbackType::CpuRead || callbackType > CallbackType::CpuExec, "the specified type is invalid");
errorCond(cpuType < CpuType::Cpu || cpuType > CpuType::Gameboy, "the cpu type is invalid");
errorCond(reference == LUA_NOREF, "the specified function could not be found");
_context->RegisterMemoryCallback(callbackType, startAddr, endAddr, cpuType, reference);
_context->Log("Registered memory callback from $" + HexUtilities::ToHex((uint32_t)startAddr) + " to $" + HexUtilities::ToHex((uint32_t)endAddr));
l.Return(reference);
return l.ReturnCount();
}
int LuaApi::UnregisterMemoryCallback(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(5);
CpuType cpuType = (CpuType)l.ReadInteger((int)CpuType::Cpu);
int endAddr = l.ReadInteger(-1);
int startAddr = l.ReadInteger();
CallbackType type = (CallbackType)l.ReadInteger();
int reference = l.ReadInteger();
checkminparams(3);
if(endAddr == -1) {
endAddr = startAddr;
}
errorCond(startAddr > endAddr, "start address must be <= end address");
errorCond(type < CallbackType::CpuRead || type > CallbackType::CpuExec, "the specified type is invalid");
errorCond(reference == LUA_NOREF, "function reference is invalid");
_context->UnregisterMemoryCallback(type, startAddr, endAddr, cpuType, reference);
return l.ReturnCount();
}
int LuaApi::RegisterEventCallback(lua_State *lua)
{
LuaCallHelper l(lua);
EventType type = (EventType)l.ReadInteger();
int reference = l.GetReference();
checkparams();
errorCond(type < EventType::Nmi || type >= EventType::EventTypeSize, "the specified type is invalid");
errorCond(reference == LUA_NOREF, "the specified function could not be found");
_context->RegisterEventCallback(type, reference);
l.Return(reference);
return l.ReturnCount();
}
int LuaApi::UnregisterEventCallback(lua_State *lua)
{
LuaCallHelper l(lua);
EventType type = (EventType)l.ReadInteger();
int reference = l.ReadInteger();
checkparams();
errorCond(type < EventType::Nmi || type >= EventType::EventTypeSize, "the specified type is invalid");
errorCond(reference == LUA_NOREF, "function reference is invalid");
_context->UnregisterEventCallback(type, reference);
return l.ReturnCount();
}
int LuaApi::DrawString(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(7);
int displayDelay = l.ReadInteger(0);
int frameCount = l.ReadInteger(1);
int backColor = l.ReadInteger(0);
int color = l.ReadInteger(0xFFFFFF);
string text = l.ReadString();
int y = l.ReadInteger();
int x = l.ReadInteger();
checkminparams(3);
int startFrame = _console->GetFrameCount() + displayDelay;
_console->GetDebugHud()->DrawString(x, y, text, color, backColor, frameCount, startFrame);
return l.ReturnCount();
}
int LuaApi::DrawLine(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(7);
int displayDelay = l.ReadInteger(0);
int frameCount = l.ReadInteger(1);
int color = l.ReadInteger(0xFFFFFF);
int y2 = l.ReadInteger();
int x2 = l.ReadInteger();
int y = l.ReadInteger();
int x = l.ReadInteger();
checkminparams(4);
int startFrame = _console->GetFrameCount() + displayDelay;
_console->GetDebugHud()->DrawLine(x, y, x2, y2, color, frameCount, startFrame);
return l.ReturnCount();
}
int LuaApi::DrawPixel(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(5);
int displayDelay = l.ReadInteger(0);
int frameCount = l.ReadInteger(1);
int color = l.ReadInteger();
int y = l.ReadInteger();
int x = l.ReadInteger();
checkminparams(3);
int startFrame = _console->GetFrameCount() + displayDelay;
_console->GetDebugHud()->DrawPixel(x, y, color, frameCount, startFrame);
return l.ReturnCount();
}
int LuaApi::DrawRectangle(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(8);
int displayDelay = l.ReadInteger(0);
int frameCount = l.ReadInteger(1);
bool fill = l.ReadBool(false);
int color = l.ReadInteger(0xFFFFFF);
int height = l.ReadInteger();
int width = l.ReadInteger();
int y = l.ReadInteger();
int x = l.ReadInteger();
checkminparams(4);
int startFrame = _console->GetFrameCount() + displayDelay;
_console->GetDebugHud()->DrawRectangle(x, y, width, height, color, fill, frameCount, startFrame);
return l.ReturnCount();
}
int LuaApi::ClearScreen(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
_console->GetDebugHud()->ClearScreen();
return l.ReturnCount();
}
int LuaApi::GetScreenBuffer(lua_State *lua)
{
LuaCallHelper l(lua);
int multiplier = _ppu->IsHighResOutput() ? 2 : 1;
lua_newtable(lua);
for(int y = 0; y < 239; y++) {
for(int x = 0; x < 256; x++) {
lua_pushinteger(lua, DefaultVideoFilter::ToArgb(*(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & 0xFFFFFF);
lua_rawseti(lua, -2, (y << 8) + x);
}
}
return 1;
}
int LuaApi::SetScreenBuffer(lua_State *lua)
{
LuaCallHelper l(lua);
uint32_t pixels[256*239] = {};
luaL_checktype(lua, 1, LUA_TTABLE);
for(int i = 0; i < 256*239; i++) {
lua_rawgeti(lua, 1, i);
pixels[i] = l.ReadInteger() ^ 0xFF000000;
}
int startFrame = _console->GetFrameCount();
_console->GetDebugHud()->DrawScreenBuffer(pixels, startFrame);
return l.ReturnCount();
}
int LuaApi::GetPixel(lua_State *lua)
{
LuaCallHelper l(lua);
int y = l.ReadInteger();
int x = l.ReadInteger();
checkparams();
errorCond(x < 0 || x > 255 || y < 0 || y > 238, "invalid x,y coordinates (must be between 0-255, 0-238)");
int multiplier = _ppu->IsHighResOutput() ? 2 : 1;
//Ignores intensify & grayscale bits
l.Return(DefaultVideoFilter::ToArgb(*(_ppu->GetScreenBuffer() + y * 256 * multiplier * multiplier + x * multiplier)) & 0xFFFFFF);
return l.ReturnCount();
}
int LuaApi::GetMouseState(lua_State *lua)
{
LuaCallHelper l(lua);
MousePosition pos = KeyManager::GetMousePosition();
checkparams();
lua_newtable(lua);
lua_pushintvalue(x, pos.X);
lua_pushintvalue(y, pos.Y);
lua_pushboolvalue(left, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
lua_pushboolvalue(middle, KeyManager::IsMouseButtonPressed(MouseButton::MiddleButton));
lua_pushboolvalue(right, KeyManager::IsMouseButtonPressed(MouseButton::RightButton));
return 1;
}
int LuaApi::Log(lua_State *lua)
{
LuaCallHelper l(lua);
string text = l.ReadString();
checkparams();
_context->Log(text);
return l.ReturnCount();
}
int LuaApi::DisplayMessage(lua_State *lua)
{
LuaCallHelper l(lua);
string text = l.ReadString();
string category = l.ReadString();
checkparams();
MessageManager::DisplayMessage(category, text);
return l.ReturnCount();
}
int LuaApi::Reset(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
checkinitdone();
_console->Reset();
return l.ReturnCount();
}
int LuaApi::Break(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
checkinitdone();
_debugger->Step(CpuType::Cpu, 1, StepType::Step);
return l.ReturnCount();
}
int LuaApi::Resume(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
checkinitdone();
_debugger->Run();
return l.ReturnCount();
}
int LuaApi::Execute(lua_State *lua)
{
LuaCallHelper l(lua);
StepType type = (StepType)l.ReadInteger();
int count = l.ReadInteger();
checkparams();
checkinitdone();
errorCond(count <= 0, "count must be >= 1");
errorCond(type != StepType::Step && type != StepType::PpuStep, "type is invalid");
_debugger->Step(CpuType::Cpu, count, type);
return l.ReturnCount();
}
int LuaApi::Rewind(lua_State *lua)
{
LuaCallHelper l(lua);
int seconds = l.ReadInteger();
checkparams();
checksavestateconditions();
errorCond(seconds <= 0, "seconds must be >= 1");
_console->GetRewindManager()->RewindSeconds(seconds);
return l.ReturnCount();
}
int LuaApi::TakeScreenshot(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
stringstream ss;
_console->GetVideoDecoder()->TakeScreenshot(ss);
l.Return(ss.str());
return l.ReturnCount();
}
int LuaApi::IsKeyPressed(lua_State *lua)
{
LuaCallHelper l(lua);
string keyName = l.ReadString();
checkparams();
uint32_t keyCode = KeyManager::GetKeyCode(keyName);
errorCond(keyCode == 0, "Invalid key name");
l.Return(KeyManager::IsKeyPressed(keyCode));
return l.ReturnCount();
}
int LuaApi::GetInput(lua_State *lua)
{
LuaCallHelper l(lua);
int port = l.ReadInteger();
checkparams();
errorCond(port < 0 || port > 4, "Invalid port number - must be between 0 to 4");
shared_ptr<SnesController> controller = std::dynamic_pointer_cast<SnesController>(_console->GetControlManager()->GetControlDevice(port));
errorCond(controller == nullptr, "Input port must be connected to a standard controller");
lua_newtable(lua);
lua_pushboolvalue(a, controller->IsPressed(SnesController::Buttons::A));
lua_pushboolvalue(b, controller->IsPressed(SnesController::Buttons::B));
lua_pushboolvalue(x, controller->IsPressed(SnesController::Buttons::X));
lua_pushboolvalue(y, controller->IsPressed(SnesController::Buttons::Y));
lua_pushboolvalue(l, controller->IsPressed(SnesController::Buttons::L));
lua_pushboolvalue(r, controller->IsPressed(SnesController::Buttons::R));
lua_pushboolvalue(start, controller->IsPressed(SnesController::Buttons::Start));
lua_pushboolvalue(select, controller->IsPressed(SnesController::Buttons::Select));
lua_pushboolvalue(up, controller->IsPressed(SnesController::Buttons::Up));
lua_pushboolvalue(down, controller->IsPressed(SnesController::Buttons::Down));
lua_pushboolvalue(left, controller->IsPressed(SnesController::Buttons::Left));
lua_pushboolvalue(right, controller->IsPressed(SnesController::Buttons::Right));
return 1;
}
int LuaApi::GetAccessCounters(lua_State *lua)
{
LuaCallHelper l(lua);
l.ForceParamCount(2);
MemoryOperationType operationType = (MemoryOperationType)l.ReadInteger();
SnesMemoryType memoryType = (SnesMemoryType)l.ReadInteger();
errorCond(operationType >= MemoryOperationType::ExecOperand, "Invalid operation type");
errorCond(memoryType >= SnesMemoryType::Register, "Invalid memory type");
checkparams();
uint32_t size = 0;
vector<AddressCounters> counts;
counts.resize(_memoryDumper->GetMemorySize(memoryType), {});
_debugger->GetMemoryAccessCounter()->GetAccessCounts(0, size, memoryType, counts.data());
lua_newtable(lua);
switch(operationType) {
default:
case MemoryOperationType::Read:
for(uint32_t i = 0; i < size; i++) {
lua_pushinteger(lua, counts[i].ReadCount);
lua_rawseti(lua, -2, i);
}
break;
case MemoryOperationType::Write:
for(uint32_t i = 0; i < size; i++) {
lua_pushinteger(lua, counts[i].WriteCount);
lua_rawseti(lua, -2, i);
}
break;
case MemoryOperationType::ExecOpCode:
for(uint32_t i = 0; i < size; i++) {
lua_pushinteger(lua, counts[i].ExecCount);
lua_rawseti(lua, -2, i);
}
break;
}
return 1;
}
int LuaApi::ResetAccessCounters(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
_debugger->GetMemoryAccessCounter()->ResetCounts();
return l.ReturnCount();
}
int LuaApi::GetScriptDataFolder(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
string baseFolder = FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "LuaScriptData");
FolderUtilities::CreateFolder(baseFolder);
string scriptFolder = FolderUtilities::CombinePath(baseFolder, FolderUtilities::GetFilename(_context->GetScriptName(), false));
FolderUtilities::CreateFolder(scriptFolder);
l.Return(scriptFolder);
return l.ReturnCount();
}
int LuaApi::GetRomInfo(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
RomInfo romInfo = _console->GetRomInfo();
lua_newtable(lua);
lua_pushstringvalue(name, romInfo.RomFile.GetFileName());
lua_pushstringvalue(path, romInfo.RomFile.GetFilePath());
lua_pushstringvalue(fileSha1Hash, _console->GetCartridge()->GetSha1Hash());
return 1;
}
int LuaApi::GetLogWindowLog(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
l.Return(MessageManager::GetLog());
return l.ReturnCount();
}
int LuaApi::GetState(lua_State *lua)
{
LuaCallHelper l(lua);
checkparams();
DebugState state;
_debugger->GetState(state, false);
lua_newtable(lua);
lua_pushintvalue(masterClock, state.MasterClock);
lua_starttable("cpu");
lua_pushintvalue(a, state.Cpu.A);
lua_pushintvalue(cycleCount, state.Cpu.CycleCount);
lua_pushboolvalue(emulationMode, state.Cpu.EmulationMode);
lua_pushintvalue(irqFlag, state.Cpu.IrqSource);
lua_pushboolvalue(nmiFlag, state.Cpu.NmiFlag);
lua_pushintvalue(k, state.Cpu.K);
lua_pushintvalue(pc, state.Cpu.PC);
lua_pushintvalue(status, state.Cpu.PS);
lua_pushintvalue(sp, state.Cpu.SP);
lua_pushintvalue(x, state.Cpu.X);
lua_pushintvalue(y, state.Cpu.Y);
lua_pushintvalue(d, state.Cpu.D);
lua_pushintvalue(db, state.Cpu.DBR);
lua_endtable(); //end cpu
lua_starttable("ppu");
lua_pushintvalue(cycle, state.Ppu.Cycle);
lua_pushintvalue(frameCount, state.Ppu.FrameCount);
lua_pushintvalue(scanline, state.Ppu.Scanline);
lua_pushintvalue(hClock, state.Ppu.HClock);
lua_pushboolvalue(forcedVblank, state.Ppu.ForcedVblank);
lua_pushintvalue(screenBrightness, state.Ppu.ScreenBrightness);
lua_starttable("mode7");
lua_starttable("matrix");
lua_pusharrayvalue(0, state.Ppu.Mode7.Matrix[0]);
lua_pusharrayvalue(1, state.Ppu.Mode7.Matrix[0]);
lua_pusharrayvalue(2, state.Ppu.Mode7.Matrix[0]);
lua_pusharrayvalue(3, state.Ppu.Mode7.Matrix[0]);
lua_endtable();
lua_pushintvalue(hScroll, state.Ppu.Mode7.HScroll);
lua_pushintvalue(vScroll, state.Ppu.Mode7.VScroll);
lua_pushintvalue(centerX, state.Ppu.Mode7.CenterX);
lua_pushintvalue(centerY, state.Ppu.Mode7.CenterY);
lua_pushintvalue(valueLatch, state.Ppu.Mode7.ValueLatch);
lua_pushboolvalue(largeMap, state.Ppu.Mode7.LargeMap);
lua_pushboolvalue(fillWithTile0, state.Ppu.Mode7.FillWithTile0);
lua_pushboolvalue(horizontalMirroring, state.Ppu.Mode7.HorizontalMirroring);
lua_pushboolvalue(verticalMirroring, state.Ppu.Mode7.VerticalMirroring);
lua_endtable(); //end mode7
lua_pushintvalue(bgMode, state.Ppu.BgMode);
lua_pushboolvalue(mode1Bg3Priority, state.Ppu.Mode1Bg3Priority);
lua_pushintvalue(mainScreenLayers, state.Ppu.MainScreenLayers);
lua_pushintvalue(subScreenLayers, state.Ppu.SubScreenLayers);
lua_starttable("layers")
for(int i = 0; i < 4; i++) {
lua_pushinteger(lua, i);
lua_newtable(lua);
lua_pushintvalue(tilemapAddress, state.Ppu.Layers[i].TilemapAddress);
lua_pushintvalue(chrAddress, state.Ppu.Layers[i].ChrAddress);
lua_pushintvalue(hScroll, state.Ppu.Layers[i].HScroll);
lua_pushintvalue(vScroll, state.Ppu.Layers[i].VScroll);
lua_pushintvalue(doubleWidth, state.Ppu.Layers[i].DoubleWidth);
lua_pushintvalue(doubleHeight, state.Ppu.Layers[i].DoubleHeight);
lua_pushintvalue(largeTiles, state.Ppu.Layers[i].LargeTiles);
lua_settable(lua, -3);
}
lua_endtable(); //end layers
lua_starttable("windows")
for(int i = 0; i < 2; i++) {
lua_pushinteger(lua, i);
lua_newtable(lua);
lua_pushintvalue(activeLayers, (
(uint8_t)state.Ppu.Window[i].ActiveLayers[0] |
((uint8_t)state.Ppu.Window[i].ActiveLayers[1] << 1) |
((uint8_t)state.Ppu.Window[i].ActiveLayers[2] << 2) |
((uint8_t)state.Ppu.Window[i].ActiveLayers[3] << 3) |
((uint8_t)state.Ppu.Window[i].ActiveLayers[4] << 4) |
((uint8_t)state.Ppu.Window[i].ActiveLayers[5] << 5)
));
lua_pushintvalue(invertedLayers, (
(uint8_t)state.Ppu.Window[i].InvertedLayers[0] |
((uint8_t)state.Ppu.Window[i].InvertedLayers[1] << 1) |
((uint8_t)state.Ppu.Window[i].InvertedLayers[2] << 2) |
((uint8_t)state.Ppu.Window[i].InvertedLayers[3] << 3) |
((uint8_t)state.Ppu.Window[i].InvertedLayers[4] << 4) |
((uint8_t)state.Ppu.Window[i].InvertedLayers[5] << 5)
));
lua_pushintvalue(left, state.Ppu.Window[i].Left);
lua_pushintvalue(right, state.Ppu.Window[i].Right);
lua_settable(lua, -3);
}
lua_endtable(); //end windows
lua_pushboolvalue(windowMaskLogicBg0, (int)state.Ppu.MaskLogic[0]);
lua_pushboolvalue(windowMaskLogicBg1, (int)state.Ppu.MaskLogic[1]);
lua_pushboolvalue(windowMaskLogicBg2, (int)state.Ppu.MaskLogic[2]);
lua_pushboolvalue(windowMaskLogicBg3, (int)state.Ppu.MaskLogic[3]);
lua_pushboolvalue(windowMaskLogicSprites, (int)state.Ppu.MaskLogic[4]);
lua_pushboolvalue(windowMaskLogicColor, (int)state.Ppu.MaskLogic[5]);
lua_pushboolvalue(windowMaskMainBg0, state.Ppu.WindowMaskMain[0]);
lua_pushboolvalue(windowMaskMainBg1, state.Ppu.WindowMaskMain[1]);
lua_pushboolvalue(windowMaskMainBg2, state.Ppu.WindowMaskMain[2]);
lua_pushboolvalue(windowMaskMainBg3, state.Ppu.WindowMaskMain[3]);
lua_pushboolvalue(windowMaskMainSprites, state.Ppu.WindowMaskMain[4]);
lua_pushboolvalue(windowMaskSubBg0, state.Ppu.WindowMaskSub[0]);
lua_pushboolvalue(windowMaskSubBg1, state.Ppu.WindowMaskSub[1]);
lua_pushboolvalue(windowMaskSubBg2, state.Ppu.WindowMaskSub[2]);
lua_pushboolvalue(windowMaskSubBg3, state.Ppu.WindowMaskSub[3]);
lua_pushboolvalue(windowMaskSubSprites, state.Ppu.WindowMaskSub[4]);
lua_pushintvalue(vramAddress, state.Ppu.VramAddress);
lua_pushintvalue(vramIncrementValue, state.Ppu.VramIncrementValue);
lua_pushintvalue(vramAddressRemapping, state.Ppu.VramAddressRemapping);
lua_pushboolvalue(vramAddrIncrementOnSecondReg, state.Ppu.VramAddrIncrementOnSecondReg);
lua_pushintvalue(vramReadBuffer, state.Ppu.VramReadBuffer);
lua_pushintvalue(ppu1OpenBus, state.Ppu.Ppu1OpenBus);
lua_pushintvalue(ppu2OpenBus, state.Ppu.Ppu2OpenBus);
lua_pushintvalue(cgramAddress, state.Ppu.CgramAddress);
lua_pushintvalue(cgramWriteBuffer, state.Ppu.CgramWriteBuffer);
lua_pushboolvalue(cgramAddressLatch, state.Ppu.CgramAddressLatch);
lua_pushintvalue(mosaicSize, state.Ppu.MosaicSize);
lua_pushintvalue(mosaicEnabled, state.Ppu.MosaicEnabled);
lua_pushintvalue(oamRamAddress, state.Ppu.OamRamAddress);
lua_pushintvalue(oamMode, state.Ppu.OamMode);
lua_pushintvalue(oamBaseAddress, state.Ppu.OamBaseAddress);
lua_pushintvalue(oamAddressOffset, state.Ppu.OamAddressOffset);
lua_pushboolvalue(enableOamPriority, state.Ppu.EnableOamPriority);
lua_pushboolvalue(extBgEnabled, state.Ppu.ExtBgEnabled);
lua_pushboolvalue(hiResMode, state.Ppu.HiResMode);
lua_pushboolvalue(screenInterlace, state.Ppu.ScreenInterlace);
lua_pushboolvalue(objInterlace, state.Ppu.ObjInterlace);
lua_pushboolvalue(overscanMode, state.Ppu.OverscanMode);
lua_pushboolvalue(directColorMode, state.Ppu.DirectColorMode);
lua_pushintvalue(colorMathClipMode, (int)state.Ppu.ColorMathClipMode);
lua_pushintvalue(colorMathPreventMode, (int)state.Ppu.ColorMathPreventMode);
lua_pushboolvalue(colorMathAddSubscreen, state.Ppu.ColorMathAddSubscreen);
lua_pushintvalue(colorMathEnabled, state.Ppu.ColorMathEnabled);
lua_pushboolvalue(colorMathSubstractMode, state.Ppu.ColorMathSubstractMode);
lua_pushboolvalue(colorMathHalveResult, state.Ppu.ColorMathHalveResult);
lua_pushintvalue(fixedColor, state.Ppu.FixedColor);
lua_endtable(); //end ppu
lua_starttable("spc");
lua_pushintvalue(a, state.Spc.A);
lua_pushintvalue(pc, state.Spc.PC);
lua_pushintvalue(status, state.Spc.PS);
lua_pushintvalue(sp, state.Spc.SP);
lua_pushintvalue(x, state.Spc.X);
lua_pushintvalue(y, state.Spc.Y);
lua_endtable(); //end spc
return 1;
}
#endif