From 7936a87fb06b19d1129b0fcbf97493f465026d25 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Mon, 18 Sep 2023 00:35:29 +0300 Subject: [PATCH] [Lua] Add event handles --- include/lua.hpp | 16 ++++++++++++ src/emulator.cpp | 1 + src/lua.cpp | 65 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/include/lua.hpp b/include/lua.hpp index ceb91cae..eebc15f7 100644 --- a/include/lua.hpp +++ b/include/lua.hpp @@ -2,6 +2,13 @@ #include "helpers.hpp" #include "memory.hpp" +// The kinds of events that can cause a Lua call. +// Frame: Call program on frame end +// TODO: Add more +enum class LuaEvent { + Frame, +}; + #ifdef PANDA3DS_ENABLE_LUA extern "C" { #include @@ -14,6 +21,9 @@ extern "C" { class LuaManager { lua_State* L = nullptr; bool initialized = false; + bool haveScript = false; + + void signalEventInternal(LuaEvent e); public: // For Lua we must have some global pointers to our emulator objects to use them in script code via thunks. See the thunks in lua.cpp as an @@ -27,6 +37,11 @@ class LuaManager { void initializeThunks(); void loadFile(const char* path); void reset(); + void signalEvent(LuaEvent e) { + if (haveScript) [[unlikely]] { + signalEventInternal(e); + } + } }; #elif // Lua not enabled, Lua manager does nothing @@ -38,5 +53,6 @@ class LuaManager { void initialize() {} void loadFile(const char* path) {} void reset() {} + void signalEvent(LuaEvent e) {} }; #endif \ No newline at end of file diff --git a/src/emulator.cpp b/src/emulator.cpp index c21e86b9..fab95d49 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -414,6 +414,7 @@ void Emulator::runFrame() { if (running) { cpu.runFrame(); // Run 1 frame of instructions gpu.display(); // Display graphics + lua.signalEvent(LuaEvent::Frame); // Send VBlank interrupts ServiceManager& srv = kernel.getServiceManager(); diff --git a/src/lua.cpp b/src/lua.cpp index 5f86f292..ae491eb9 100644 --- a/src/lua.cpp +++ b/src/lua.cpp @@ -14,12 +14,14 @@ void LuaManager::initialize() { initializeThunks(); initialized = true; + haveScript = false; } void LuaManager::close() { if (initialized) { lua_close(L); initialized = false; + haveScript = false; L = nullptr; } } @@ -29,12 +31,24 @@ void LuaManager::loadFile(const char* path) { int ret = lua_pcall(L, 0, 0, 0); // tell Lua to run the script if (ret != 0) { + haveScript = false; fprintf(stderr, "%s\n", lua_tostring(L, -1)); // tell us what mistake we made + } else { + haveScript = true; } } +void LuaManager::signalEventInternal(LuaEvent e) { + lua_getglobal(L, "eventHandler"); // We want to call the event handler + lua_pushnumber(L, static_cast(e)); // Push event type + + // Call the function with 1 argument and 0 outputs, without an error handler + lua_pcall(L, 1, 0, 0); +} + void LuaManager::reset() { // Reset scripts + haveScript = false; } // Initialize C++ thunks for Lua code to call here @@ -64,18 +78,51 @@ MAKE_MEMORY_FUNCTIONS(64) // clang-format off static constexpr luaL_Reg functions[] = { - { "read8", read8Thunk }, - { "read16", read16Thunk }, - { "read32", read32Thunk }, - { "read64", read64Thunk }, - { "write8", write8Thunk} , - { "write16", write16Thunk }, - { "write32", write32Thunk }, - { "write64", write64Thunk }, + { "__read8", read8Thunk }, + { "__read16", read16Thunk }, + { "__read32", read32Thunk }, + { "__read64", read64Thunk }, + { "__write8", write8Thunk} , + { "__write16", write16Thunk }, + { "__write32", write32Thunk }, + { "__write64", write64Thunk }, { nullptr, nullptr }, }; // clang-format on -void LuaManager::initializeThunks() { luaL_register(L, "pand", functions); } +void LuaManager::initializeThunks() { + static const char* runtimeInit = R"( + Pand = { + read8 = function(addr) return GLOBALS.__read8(addr) end, + read16 = function(addr) return GLOBALS.__read16(addr) end, + read32 = function(addr) return GLOBALS.__read32(addr) end, + read64 = function(addr) return GLOBALS.__read64(addr) end, + write8 = function(addr, value) GLOBALS.__write8(addr, value) end, + write16 = function(addr, value) GLOBALS.__write16(addr, value) end, + write32 = function(addr, value) GLOBALS.__write32(addr, value) end, + write64 = function(addr, value) GLOBALS.__write64(addr, value) end, + Frame = __Frame, + } +)"; + + auto addIntConstant = [&](T x, const char* name) { + lua_pushinteger(L, (int)x); + lua_setglobal(L, name); + }; + + luaL_register(L, "GLOBALS", functions); + addIntConstant(LuaEvent::Frame, "__Frame"); + + // Call our Lua runtime initialization before any Lua script runs + luaL_loadstring(L, runtimeInit); + int ret = lua_pcall(L, 0, 0, 0); // tell Lua to run the script + + if (ret != 0) { + initialized = false; + fprintf(stderr, "%s\n", lua_tostring(L, -1)); // Init should never fail! + } else { + initialized = true; + } +} #endif \ No newline at end of file