Skip to content

Commit

Permalink
Merge pull request #282 from wheremyfoodat/lua
Browse files Browse the repository at this point in the history
Lua bindings now work(tm)
  • Loading branch information
wheremyfoodat authored Sep 17, 2023
2 parents d3b9e50 + 4734e0b commit c8ee798
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 9 deletions.
16 changes: 16 additions & 0 deletions include/lua.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <lauxlib.h>
Expand All @@ -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
Expand All @@ -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
Expand All @@ -38,5 +53,6 @@ class LuaManager {
void initialize() {}
void loadFile(const char* path) {}
void reset() {}
void signalEvent(LuaEvent e) {}
};
#endif
2 changes: 1 addition & 1 deletion src/emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ Emulator::Emulator()
}
}

lua.initialize();
reset(ReloadOption::NoReload);
}

Expand Down Expand Up @@ -414,6 +413,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();
Expand Down
81 changes: 73 additions & 8 deletions src/lua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,54 @@ void LuaManager::initialize() {
initializeThunks();

initialized = true;
haveScript = false;
}

void LuaManager::close() {
if (initialized) {
lua_close(L);
initialized = false;
haveScript = false;
L = nullptr;
}
}

void LuaManager::loadFile(const char* path) {
// Initialize Lua if it has not been initialized
if (!initialized) {
initialize();
}

// If init failed, don't execute
if (!initialized) {
printf("Lua initialization failed, file won't run\n");
haveScript = false;

return;
}

int status = luaL_loadfile(L, path); // load Lua script
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<int>(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
Expand Down Expand Up @@ -62,15 +89,53 @@ MAKE_MEMORY_FUNCTIONS(32)
MAKE_MEMORY_FUNCTIONS(64)
#undef MAKE_MEMORY_FUNCTIONS

// clang-format off
static constexpr luaL_Reg functions[] = {
{ "__read8", read8Thunk },
{ "__read16", read16Thunk },
{ "__read32", read32Thunk },
{ "__read64", read64Thunk },
{ "__write8", write8Thunk} ,
{ "__write16", write16Thunk },
{ "__write32", write32Thunk },
{ "__write64", write64Thunk },
{ nullptr, nullptr },
};
// clang-format on

void LuaManager::initializeThunks() {
lua_register(L, "read8", read8Thunk);
lua_register(L, "read16", read16Thunk);
lua_register(L, "read32", read32Thunk);
lua_register(L, "read64", read64Thunk);
lua_register(L, "write8", write8Thunk);
lua_register(L, "write16", write16Thunk);
lua_register(L, "write32", write32Thunk);
lua_register(L, "write64", write64Thunk);
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 = [&]<typename T>(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

0 comments on commit c8ee798

Please sign in to comment.