diff --git a/src/drivers/win/main.cpp b/src/drivers/win/main.cpp index b1f44488..285c89f1 100644 --- a/src/drivers/win/main.cpp +++ b/src/drivers/win/main.cpp @@ -40,6 +40,7 @@ #include "../../state.h" #include "../../debug.h" #include "../../movie.h" +#include "../../fceulua.h" #include "archive.h" #include "input.h" @@ -400,16 +401,15 @@ void DoFCEUExit() } } - - KillDebugger(); //mbg merge 7/19/06 added FCEUI_StopMovie(); FCEUD_AviStop(); + FCEU_LuaStop(); // kill lua script before the gui dies exiting = 1; closeGame = true;//mbg 6/30/06 - for housekeeping purposes we need to exit after the emulation cycle finishes - } + } } void FCEUD_OnCloseGame() diff --git a/src/fceu.cpp b/src/fceu.cpp index 9a46edbc..b09c803e 100644 --- a/src/fceu.cpp +++ b/src/fceu.cpp @@ -629,11 +629,20 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski FCEU_UpdateInput(); lagFlag = 1; + +#ifdef _S9XLUA_H + CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); +#endif + if(geniestage!=1) FCEU_ApplyPeriodicCheats(); r = FCEUPPU_Loop(skip); if (skip != 2) ssize=FlushEmulateSound(); //If skip = 2 we are skipping sound processing - + +#ifdef _S9XLUA_H + CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); +#endif + #ifdef WIN32 //These Windows only dialogs need to be updated only once per frame so they are included here UpdateCheatList(); diff --git a/src/fceulua.h b/src/fceulua.h index e23d4ee2..be4b90cd 100644 --- a/src/fceulua.h +++ b/src/fceulua.h @@ -1,5 +1,14 @@ #ifdef _S9XLUA_H +enum LuaCallID +{ + LUACALL_BEFOREEMULATION, + LUACALL_AFTEREMULATION, + LUACALL_BEFOREEXIT, + + LUACALL_COUNT +}; +extern void CallRegisteredLuaFunctions(LuaCallID calltype); // Just forward function declarations diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 0658e11c..84c04dbc 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -142,6 +142,16 @@ static const char *button_mappings[] = { "A", "B", "select", "start", "up", "down", "left", "right" }; +static const char* luaCallIDStrings [] = +{ + "CALL_BEFOREEMULATION", + "CALL_AFTEREMULATION", + "CALL_BEFOREEXIT", +}; +#ifdef WIN32 // uh... yeah +static const int _makeSureWeHaveTheRightNumberOfStrings [sizeof(luaCallIDStrings)/sizeof(*luaCallIDStrings) == LUACALL_COUNT ? 1 : 0]; +#endif + /** * Resets emulator speed / pause states after script exit. */ @@ -396,6 +406,41 @@ static int fceu_message(lua_State *L) { } +static int fceu_registerbefore(lua_State *L) { + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L,1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); + lua_insert(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} + +static int fceu_registerafter(lua_State *L) { + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L,1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); + lua_insert(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} + +static int fceu_registerexit(lua_State *L) { + if (!lua_isnil(L,1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L,1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + lua_insert(L,1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; +} + + + static int rom_readbyte(lua_State *L) { lua_pushinteger(L, FCEU_ReadRomByte(luaL_checkinteger(L,1))); return 1; } static int rom_readbytesigned(lua_State *L) { lua_pushinteger(L, (signed char)FCEU_ReadRomByte(luaL_checkinteger(L,1))); return 1; } static int memory_readbyte(lua_State *L) { lua_pushinteger(L, FCEU_CheatGetByte(luaL_checkinteger(L,1))); return 1; } @@ -2031,6 +2076,9 @@ static const struct luaL_reg fceulib [] = { {"lagged", fceu_lagged}, {"getreadonly", fceu_getreadonly}, {"setreadonly", fceu_setreadonly}, + {"registerbefore", fceu_registerbefore}, + {"registerafter", fceu_registerafter}, + {"registerexit", fceu_registerexit}, {NULL,NULL} }; @@ -2118,6 +2166,68 @@ static const struct luaL_reg guilib[] = { }; +void HandleCallbackError(lua_State* L) +{ + //if(L->errfunc || L->errorJmp) + // luaL_error(L, "%s", lua_tostring(L,-1)); + //else + { + lua_pushnil(L); + lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable); + + // Error? +#ifdef WIN32 + MessageBox( hAppWnd, lua_tostring(L,-1), "Lua run error", MB_OK | MB_ICONSTOP); +#else + fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(LUA,-1)); +#endif + + FCEU_LuaStop(); + } +} + +void CallExitFunction() { + if (!L) + return; + + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + + int errorcode = 0; + if (lua_isfunction(L, -1)) + { + //chdir(luaCWD); + errorcode = lua_pcall(L, 0, 0, 0); + //_getcwd(luaCWD, _MAX_PATH); + } + + if (errorcode) + HandleCallbackError(L); +} + +void CallRegisteredLuaFunctions(LuaCallID calltype) +{ + assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT); + const char* idstring = luaCallIDStrings[calltype]; + + if (!L) + return; + + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, idstring); + + int errorcode = 0; + if (lua_isfunction(L, -1)) + { + errorcode = lua_pcall(L, 0, 0, 0); + if (errorcode) + HandleCallbackError(L); + } + else + { + lua_pop(L, 1); + } +} void FCEU_LuaFrameBoundary() { @@ -2202,7 +2312,8 @@ int FCEU_LoadLuaCode(const char *filename) { L = lua_open(); luaL_openlibs(L); - luaL_register(L, "FCEU", fceulib); + luaL_register(L, "emu", fceulib); // added for better cross-emulator compatibility + luaL_register(L, "FCEU", fceulib); // kept for backward compatibility luaL_register(L, "memory", memorylib); luaL_register(L, "rom", romlib); luaL_register(L, "joypad", joypadlib); @@ -2223,13 +2334,6 @@ int FCEU_LoadLuaCode(const char *filename) { luabitop_validate(L); - lua_newtable(L); - lua_setglobal(L,"emu"); - lua_getglobal(L,"emu"); - lua_newtable(L); - lua_setfield(L,-2,"OnClose"); - - lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, memoryWatchTable); lua_newtable(L); @@ -2308,14 +2412,7 @@ void FCEU_LuaStop() { if (!L) return; //execute the user's shutdown callbacks - //onCloseCallback - lua_getglobal(L, "emu"); - lua_getfield(L, -1, "OnClose"); - lua_pushnil(L); - while (lua_next(L, -2) != 0) - { - lua_call(L,0,0); - } + CallExitFunction(); //sometimes iup uninitializes com //MBG TODO - test whether this is really necessary. i dont think it is