diff --git a/autogen/gen_hooks.py b/autogen/gen_hooks.py index fd76b5534..3ad78c07c 100644 --- a/autogen/gen_hooks.py +++ b/autogen/gen_hooks.py @@ -29,7 +29,7 @@ SMLUA_CALL_EVENT_HOOKS_SET_HOOK_RESULT = """ SMLUA_CALL_EVENT_HOOKS_CALLBACK = """ // call the callback - if (0 != smlua_call_hook(L, {n_inputs}, {n_outputs}, 0, hook->mod[i])) {{ + if (0 != smlua_call_hook(L, {n_inputs}, {n_outputs}, 0, hook->mod[i], hook->modFile[i])) {{ LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[{hook_type}]); continue; }}{set_hook_result} diff --git a/data/dynos.c.h b/data/dynos.c.h index 56f65b360..bbfc0d74c 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -36,9 +36,9 @@ void dynos_generate_packs(const char* directory); // -- geos -- // void dynos_actor_override(struct Object* obj, void** aSharedChild); -void dynos_add_actor_custom(s32 modIndex, const char *filePath, const char* geoName); +void dynos_add_actor_custom(s32 modIndex, s32 modFileIndex, const char *filePath, const char* geoName); const void* dynos_geolayout_get(const char *name); -bool dynos_actor_get_mod_index_and_token(struct GraphNode *graphNode, u32 tokenIndex, s32 *modIndex, const char **token); +bool dynos_actor_get_mod_index_and_token(struct GraphNode *graphNode, u32 tokenIndex, s32 *modIndex, s32 *modFileIndex, const char **token); void dynos_actor_register_modified_graph_node(struct GraphNode *node); // -- collisions -- // @@ -72,7 +72,7 @@ Collision *dynos_level_get_collision(u32 level, u16 area); // -- behaviors -- // void dynos_add_behavior(s32 modIndex, const char *filePath, const char *behaviorName); -s32 dynos_behavior_get_active_mod_index(BehaviorScript *bhvScript); +bool dynos_behavior_get_active_mod_index(BehaviorScript *bhvScript, s32 *modIndex, s32 *modFileIndex); const char *dynos_behavior_get_token(BehaviorScript *bhvScript, u32 index); void dynos_behavior_hook_all_custom_behaviors(void); diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index d3bfa3261..2065b3321 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -572,6 +572,7 @@ struct GfxData : NoCopy { s32 mErrorCount = 0; u32 mModelIdentifier = 0; s32 mModIndex = 0; + s32 mModFileIndex = 0; SysPath mPackFolder; Array mPointerList; Array> mPointerOffsetList; @@ -889,9 +890,9 @@ void DynOS_Pack_AddTex(PackData* aPackData, DataNode* aTexData); // std::map &DynOS_Actor_GetValidActors(); -void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char *aActorName); +void DynOS_Actor_AddCustom(s32 aModIndex, s32 aModFileIndex, const SysPath &aFilename, const char *aActorName); const void *DynOS_Actor_GetLayoutFromName(const char *aActorName); -bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenIndex, s32 *outModIndex, const char **outToken); +bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenIndex, s32 *outModIndex, s32 *outModFileIndex, const char **outToken); ActorGfx* DynOS_Actor_GetActorGfx(const GraphNode* aGraphNode); void DynOS_Actor_Valid(const void* aGeoref, ActorGfx& aActorGfx); void DynOS_Actor_Invalid(const void* aGeoref, s32 aPackIndex); @@ -946,7 +947,7 @@ void DynOS_Lvl_ModShutdown(); Array> &DynOS_Bhv_GetArray(); void DynOS_Bhv_Activate(s32 modIndex, const SysPath &aFilename, const char *aBehaviorName); GfxData *DynOS_Bhv_GetActiveGfx(BehaviorScript *bhvScript); -s32 DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript); +bool DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript, s32 *modIndex, s32 *modFileIndex); const char *DynOS_Bhv_GetToken(BehaviorScript *bhvScript, u32 index); void DynOS_Bhv_HookAllCustomBehaviors(); void DynOS_Bhv_ModShutdown(); diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index bac30dd43..5b59d32f8 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -111,16 +111,16 @@ void dynos_actor_override(struct Object* obj, void** aSharedChild) { DynOS_Actor_Override(obj, aSharedChild); } -void dynos_add_actor_custom(s32 modIndex, const char *filePath, const char* geoName) { - DynOS_Actor_AddCustom(modIndex, filePath, geoName); +void dynos_add_actor_custom(s32 modIndex, s32 modFileIndex, const char *filePath, const char* geoName) { + DynOS_Actor_AddCustom(modIndex, modFileIndex, filePath, geoName); } const void* dynos_geolayout_get(const char *name) { return DynOS_Actor_GetLayoutFromName(name); } -bool dynos_actor_get_mod_index_and_token(struct GraphNode *graphNode, u32 tokenIndex, s32 *modIndex, const char **token) { - return DynOS_Actor_GetModIndexAndToken(graphNode, tokenIndex, modIndex, token); +bool dynos_actor_get_mod_index_and_token(struct GraphNode *graphNode, u32 tokenIndex, s32 *modIndex, s32 *modFileIndex, const char **token) { + return DynOS_Actor_GetModIndexAndToken(graphNode, tokenIndex, modIndex, modFileIndex, token); } void dynos_actor_register_modified_graph_node(struct GraphNode *node) { @@ -232,8 +232,8 @@ void dynos_add_behavior(s32 modIndex, const char *filePath, const char *behavior DynOS_Bhv_Activate(modIndex, filePath, behaviorName); } -s32 dynos_behavior_get_active_mod_index(BehaviorScript *bhvScript) { - return DynOS_Bhv_GetActiveModIndex(bhvScript); +bool dynos_behavior_get_active_mod_index(BehaviorScript *bhvScript, s32 *modIndex, s32 *modFileIndex) { + return DynOS_Bhv_GetActiveModIndex(bhvScript, modIndex, modFileIndex); } const char *dynos_behavior_get_token(BehaviorScript *bhvScript, u32 index) { diff --git a/data/dynos_mgr_actor.cpp b/data/dynos_mgr_actor.cpp index aa9056fb0..92fa14ee8 100644 --- a/data/dynos_mgr_actor.cpp +++ b/data/dynos_mgr_actor.cpp @@ -31,7 +31,7 @@ std::map &DynOS_Actor_GetValidActors() { return DynosValidActors(); } -void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char *aActorName) { +void DynOS_Actor_AddCustom(s32 aModIndex, s32 aModFileIndex, const SysPath &aFilename, const char *aActorName) { const void* georef = DynOS_Builtin_Actor_GetFromName(aActorName); u16 actorLen = strlen(aActorName); @@ -45,6 +45,7 @@ void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char * return; } _GfxData->mModIndex = aModIndex; + _GfxData->mModFileIndex = aModFileIndex; void* geoLayout = (*(_GfxData->mGeoLayouts.end() - 1))->mData; if (!geoLayout) { @@ -117,7 +118,7 @@ const void *DynOS_Actor_GetLayoutFromName(const char *aActorName) { return NULL; } -bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenIndex, s32 *outModIndex, const char **outToken) { +bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenIndex, s32 *outModIndex, s32 *outModFileIndex, const char **outToken) { ActorGfx *_ActorGfx = DynOS_Actor_GetActorGfx(aGraphNode); if (_ActorGfx) { GfxData *_GfxData = _ActorGfx->mGfxData; @@ -125,6 +126,9 @@ bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenInde if (outModIndex) { *outModIndex = _GfxData->mModIndex; } + if (outModFileIndex) { + *outModFileIndex = _GfxData->mModFileIndex; + } if (outToken) { if (!aTokenIndex || aTokenIndex > _GfxData->mLuaTokenList.Count()) { return false; @@ -139,6 +143,9 @@ bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenInde if (outModIndex) { *outModIndex = _GfxData->mModIndex; } + if (outModFileIndex) { + *outModFileIndex = _GfxData->mModFileIndex; + } if (outToken) { if (!aTokenIndex || aTokenIndex > _GfxData->mLuaTokenList.Count()) { return false; diff --git a/data/dynos_mgr_bhv.cpp b/data/dynos_mgr_bhv.cpp index 51d3b2731..9f501d577 100644 --- a/data/dynos_mgr_bhv.cpp +++ b/data/dynos_mgr_bhv.cpp @@ -62,7 +62,7 @@ GfxData *DynOS_Bhv_GetActiveGfx(BehaviorScript *bhvScript) { return NULL; } -s32 DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript) { +bool DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript, s32 *modIndex, s32 *modFileIndex) { auto &_CustomBehaviorScripts = DynOS_Bhv_GetArray(); for (s32 i = 0; i < _CustomBehaviorScripts.Count(); ++i) { @@ -70,10 +70,12 @@ s32 DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript) { auto &scripts = gfxData->mBehaviorScripts; if (scripts.Count() == 0) { continue; } if (bhvScript == scripts[scripts.Count() - 1]->mData) { - return gfxData->mModIndex; + *modIndex = gfxData->mModIndex; + *modFileIndex = gfxData->mModFileIndex; + return true; } } - return -1; + return false; } const char *DynOS_Bhv_GetToken(BehaviorScript *bhvScript, u32 index) { diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index 0d06d3b5d..8bfbdc3aa 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -913,8 +913,9 @@ static s32 bhv_cmd_call_ext(void) { BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; - s32 modIndex = dynos_behavior_get_active_mod_index(behavior); - if (modIndex == -1) { + s32 modIndex = -1; + s32 modFileIndex = -1; + if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) { LOG_ERROR("Could not find behavior script mod index."); return BHV_PROC_CONTINUE; } @@ -946,8 +947,9 @@ static s32 bhv_cmd_call_ext(void) { static s32 bhv_cmd_goto_ext(void) { BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; - s32 modIndex = dynos_behavior_get_active_mod_index(behavior); - if (modIndex == -1) { + s32 modIndex = -1; + s32 modFileIndex = -1; + if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) { LOG_ERROR("Could not find behavior script mod index."); return BHV_PROC_CONTINUE; } @@ -976,8 +978,9 @@ static s32 bhv_cmd_goto_ext(void) { static s32 bhv_cmd_call_native_ext(void) { BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; - s32 modIndex = dynos_behavior_get_active_mod_index(behavior); - if (modIndex == -1) { + s32 modIndex = -1; + s32 modFileIndex = -1; + if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) { LOG_ERROR("Could not find behavior script mod index."); gCurBhvCommand += 2; return BHV_PROC_CONTINUE; @@ -994,19 +997,27 @@ static s32 bhv_cmd_call_native_ext(void) { } if (!gSmLuaConvertSuccess || funcRef == 0) { - LOG_LUA("Failed to call lua function, could not find lua function '%s'", funcStr); + LOG_LUA("Failed to call lua behavior function, could not find lua function '%s'", funcStr); gCurBhvCommand += 2; return BHV_PROC_CONTINUE; } // Get our mod. - if (modIndex >= gActiveMods.entryCount) { - LOG_LUA("Failed to call lua function, could not find mod"); + if (modIndex < 0 || modIndex >= gActiveMods.entryCount) { + LOG_LUA("Failed to call lua behavior function, could not find mod"); gCurBhvCommand += 2; return BHV_PROC_CONTINUE; } struct Mod *mod = gActiveMods.entries[modIndex]; + // Get our mod file + if (modFileIndex < 0 || modFileIndex >= mod->fileCount) { + LOG_LUA("Failed to call lua behavior function, could not find mod file %d", modFileIndex); + gCurBhvCommand += 2; + return BHV_PROC_CONTINUE; + } + struct ModFile *modFile = &mod->files[modFileIndex]; + // Push the callback onto the stack lua_rawgeti(gLuaState, LUA_REGISTRYINDEX, funcRef); @@ -1014,7 +1025,7 @@ static s32 bhv_cmd_call_native_ext(void) { smlua_push_object(gLuaState, LOT_OBJECT, gCurrentObject, NULL); // Call the callback - if (0 != smlua_call_hook(gLuaState, 1, 0, 0, mod)) { + if (0 != smlua_call_hook(gLuaState, 1, 0, 0, mod, modFile)) { LOG_LUA("Failed to call the function callback: '%s'", funcStr); } @@ -1029,8 +1040,9 @@ static s32 bhv_cmd_spawn_child_ext(void) { BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; - s32 modIndex = dynos_behavior_get_active_mod_index(behavior); - if (modIndex == -1) { + s32 modIndex = -1; + s32 modFileIndex = -1; + if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) { LOG_ERROR("Could not find behavior script mod index."); gCurBhvCommand += 3; return BHV_PROC_CONTINUE; @@ -1076,8 +1088,9 @@ static s32 bhv_cmd_spawn_child_with_param_ext(void) { BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; - s32 modIndex = dynos_behavior_get_active_mod_index(behavior); - if (modIndex == -1) { + s32 modIndex = -1; + s32 modFileIndex = -1; + if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) { LOG_ERROR("Could not find behavior script mod index."); gCurBhvCommand += 3; return BHV_PROC_CONTINUE; @@ -1123,8 +1136,9 @@ static s32 bhv_cmd_spawn_obj_ext(void) { BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; - s32 modIndex = dynos_behavior_get_active_mod_index(behavior); - if (modIndex == -1) { + s32 modIndex = -1; + s32 modFileIndex = -1; + if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) { LOG_ERROR("Could not find behavior script mod index."); gCurBhvCommand += 3; return BHV_PROC_CONTINUE; diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 02644b79b..e3071cf7e 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -877,8 +877,9 @@ Gfx *geo_process_lua_function(s32 callContext, struct GraphNode *node, UNUSED Ma // Retrieve mod index and function name s32 modIndex = -1; + s32 modFileIndex = -1; const char *funcStr = NULL; - if (!dynos_actor_get_mod_index_and_token(sharedChild, fnNode->luaTokenIndex, &modIndex, &funcStr)) { + if (!dynos_actor_get_mod_index_and_token(sharedChild, fnNode->luaTokenIndex, &modIndex, &modFileIndex, &funcStr)) { if (modIndex == -1) { LOG_ERROR("Could not find graph node mod index"); } else if (funcStr == NULL) { @@ -895,24 +896,32 @@ Gfx *geo_process_lua_function(s32 callContext, struct GraphNode *node, UNUSED Ma funcRef = smlua_get_any_function_mod_variable(funcStr); } if (!gSmLuaConvertSuccess || funcRef == 0) { - LOG_LUA("Failed to call lua function, could not find lua function '%s'", funcStr); + LOG_LUA("Failed to call lua geo function, could not find lua function '%s'", funcStr); return NULL; } // Get the mod - if (modIndex >= gActiveMods.entryCount) { - LOG_LUA("Failed to call lua function, could not find mod"); + if (modIndex < 0 || modIndex >= gActiveMods.entryCount) { + LOG_LUA("Failed to call lua geo function, could not find mod"); return NULL; } struct Mod *mod = gActiveMods.entries[modIndex]; + // Get our mod file + if (modFileIndex < 0 || modFileIndex >= mod->fileCount) { + LOG_LUA("Failed to call lua geo function, could not find mod file %d", modFileIndex); + gCurBhvCommand += 2; + return BHV_PROC_CONTINUE; + } + struct ModFile *modFile = &mod->files[modFileIndex]; + // Push the callback, the graph node and the current matrix stack index lua_rawgeti(L, LUA_REGISTRYINDEX, funcRef); smlua_push_object(L, LOT_GRAPHNODE, node, NULL); lua_pushinteger(L, gMatStackIndex); // Call the callback - if (0 != smlua_call_hook(L, 2, 0, 0, mod)) { + if (0 != smlua_call_hook(L, 2, 0, 0, mod, modFile)) { LOG_LUA("Failed to call the function callback: '%s'", funcStr); } diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index 9924b3546..49dc4c7aa 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -1,4 +1,5 @@ #include "smlua.h" +#include "pc/lua/smlua_require.h" #include "game/hardcoded.h" #include "pc/mods/mods.h" #include "pc/mods/mods_utils.h" @@ -16,6 +17,7 @@ u8 gLuaInitializingScript = 0; u8 gSmLuaSuppressErrors = 0; struct Mod* gLuaLoadingMod = NULL; struct Mod* gLuaActiveMod = NULL; +struct ModFile* gLuaActiveModFile = NULL; struct Mod* gLuaLastHookMod = NULL; void smlua_mod_error(void) { @@ -190,12 +192,11 @@ static bool smlua_check_binary_header(struct ModFile *file) { return false; } -static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteIndex) { +void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteIndex, bool isModInit) { if (!smlua_check_binary_header(file)) return; - lua_State* L = gLuaState; - lua_settop(L, 0); + s32 prevTop = lua_gettop(L); gSmLuaConvertSuccess = true; gLuaInitializingScript = 1; @@ -205,6 +206,7 @@ static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteI if (!f) { LOG_LUA("Failed to load lua script '%s': File not found.", file->cachedPath); gLuaInitializingScript = 0; + lua_settop(L, prevTop); return; } @@ -214,6 +216,7 @@ static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteI if (!buffer) { LOG_LUA("Failed to load lua script '%s': Cannot allocate buffer.", file->cachedPath); gLuaInitializingScript = 0; + lua_settop(L, prevTop); return; } @@ -221,6 +224,7 @@ static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteI if (f_read(buffer, 1, length, f) < length) { LOG_LUA("Failed to load lua script '%s': Unexpected early end of file.", file->cachedPath); gLuaInitializingScript = 0; + lua_settop(L, prevTop); return; } f_close(f); @@ -231,51 +235,66 @@ static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteI LOG_LUA("%s", smlua_to_string(L, lua_gettop(L))); gLuaInitializingScript = 0; free(buffer); + lua_settop(L, prevTop); return; } free(buffer); - // check if this is the first time this mod has been loaded - lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); - bool firstInit = (lua_type(L, -1) == LUA_TNIL); - lua_pop(L, 1); + if (isModInit) { + // check if this is the first time this mod has been loaded + lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); + bool firstInit = (lua_type(L, -1) == LUA_TNIL); + lua_pop(L, 1); - // create mod's "global" table - if (firstInit) { - lua_newtable(L); // create _ENV tables - lua_newtable(L); // create metatable - lua_getglobal(L, "_G"); // get global table + // create mod's "global" table + if (firstInit) { + lua_newtable(L); // create _ENV tables + lua_newtable(L); // create metatable + lua_getglobal(L, "_G"); // get global table - // remove certain default functions - lua_pushstring(L, "load"); lua_pushnil(L); lua_settable(L, -3); - lua_pushstring(L, "loadfile"); lua_pushnil(L); lua_settable(L, -3); - lua_pushstring(L, "loadstring"); lua_pushnil(L); lua_settable(L, -3); - lua_pushstring(L, "collectgarbage"); lua_pushnil(L); lua_settable(L, -3); - lua_pushstring(L, "dofile"); lua_pushnil(L); lua_settable(L, -3); + // remove certain default functions + lua_pushstring(L, "load"); lua_pushnil(L); lua_settable(L, -3); + lua_pushstring(L, "loadfile"); lua_pushnil(L); lua_settable(L, -3); + lua_pushstring(L, "loadstring"); lua_pushnil(L); lua_settable(L, -3); + lua_pushstring(L, "collectgarbage"); lua_pushnil(L); lua_settable(L, -3); + lua_pushstring(L, "dofile"); lua_pushnil(L); lua_settable(L, -3); - // set global as the metatable - lua_setfield(L, -2, "__index"); - lua_setmetatable(L, -2); + // set global as the metatable + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); - // push to registry with path as name (must be unique) - lua_setfield(L, LUA_REGISTRYINDEX, mod->relativePath); - } + // push to registry with path as name (must be unique) + lua_setfield(L, LUA_REGISTRYINDEX, mod->relativePath); + } - // load mod's "global" table - lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); - lua_setupvalue(L, 1, 1); // set upvalue (_ENV) + // load mod's "global" table + lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); + lua_setupvalue(L, 1, 1); // set upvalue (_ENV) - // load per-file globals - if (firstInit) { - smlua_sync_table_init_globals(mod->relativePath, remoteIndex); - smlua_cobject_init_per_file_globals(mod->relativePath); + // load per-file globals + if (firstInit) { + smlua_sync_table_init_globals(mod->relativePath, remoteIndex); + smlua_cobject_init_per_file_globals(mod->relativePath); + } + } else { + // this block is run on files that are loaded for 'require' function + // get the mod's global table + lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + LOG_LUA("mod environment not found"); + lua_settop(L, prevTop); + return; + } + lua_setupvalue(L, -2, 1); // set _ENV } // run chunks LOG_INFO("Executing '%s'", file->relativePath); - if (smlua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK) { + if (smlua_pcall(L, 0, 1, 0) != LUA_OK) { LOG_LUA("Failed to execute lua script '%s'.", file->cachedPath); } + gLuaInitializingScript = 0; } @@ -304,6 +323,7 @@ void smlua_init(void) { smlua_bind_functions(); smlua_bind_functions_autogen(); smlua_bind_sync_table(); + smlua_init_require_system(); extern char gSmluaConstants[]; smlua_exec_str(gSmluaConstants); @@ -324,12 +344,22 @@ void smlua_init(void) { gPcDebug.lastModRun = gLuaActiveMod; for (int j = 0; j < mod->fileCount; j++) { struct ModFile* file = &mod->files[j]; + // skip loading non-lua files if (!(str_ends_with(file->relativePath, ".lua") || str_ends_with(file->relativePath, ".luac"))) { continue; } - smlua_load_script(mod, file, i); + + // skip loading scripts in subdirectories + if (strchr(file->relativePath, '/') != NULL || strchr(file->relativePath, '\\') != NULL) { + continue; + } + + gLuaActiveModFile = file; + smlua_load_script(mod, file, i, true); + lua_settop(L, 0); } gLuaActiveMod = NULL; + gLuaActiveModFile = NULL; gLuaLoadingMod = NULL; } @@ -374,5 +404,6 @@ void smlua_shutdown(void) { } gLuaLoadingMod = NULL; gLuaActiveMod = NULL; + gLuaActiveModFile = NULL; gLuaLastHookMod = NULL; } diff --git a/src/pc/lua/smlua.h b/src/pc/lua/smlua.h index 3704460b1..185ae978f 100644 --- a/src/pc/lua/smlua.h +++ b/src/pc/lua/smlua.h @@ -38,6 +38,7 @@ extern u8 gLuaInitializingScript; extern u8 gSmLuaSuppressErrors; extern struct Mod* gLuaLoadingMod; extern struct Mod* gLuaActiveMod; +extern struct ModFile* gLuaActiveModFile; extern struct Mod* gLuaLastHookMod; void smlua_mod_error(void); @@ -46,6 +47,7 @@ int smlua_error_handler(UNUSED lua_State* L); int smlua_pcall(lua_State* L, int nargs, int nresults, int errfunc); void smlua_exec_file(const char* path); void smlua_exec_str(const char* str); +void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteIndex, bool isModInit); void smlua_init(void); void smlua_update(void); diff --git a/src/pc/lua/smlua_functions.c b/src/pc/lua/smlua_functions.c index 7a21c50ef..cc7daf8b0 100644 --- a/src/pc/lua/smlua_functions.c +++ b/src/pc/lua/smlua_functions.c @@ -475,6 +475,7 @@ int smlua_func_texture_override_reset(lua_State* L) { struct LuaLevelScriptParse { int reference; struct Mod* mod; + struct ModFile* modFile; }; struct LuaLevelScriptParse sLevelScriptParse = { 0 }; @@ -635,7 +636,7 @@ s32 smlua_func_level_script_parse_callback(u8 type, void *cmd) { } // call the callback - if (0 != smlua_call_hook(L, 5, 0, 0, preprocess->mod)) { + if (0 != smlua_call_hook(L, 5, 0, 0, preprocess->mod, preprocess->modFile)) { LOG_LUA("Failed to call the callback behaviors: %u", type); return 0; } @@ -664,6 +665,7 @@ void smlua_func_level_script_parse(lua_State* L) { preprocess->reference = ref; preprocess->mod = gLuaActiveMod; + preprocess->modFile = gLuaActiveModFile; void *script = dynos_level_get_script(levelNum); if (script == NULL) { diff --git a/src/pc/lua/smlua_hook_events_autogen.inl b/src/pc/lua/smlua_hook_events_autogen.inl index 3c9ac1386..e8f39042a 100644 --- a/src/pc/lua/smlua_hook_events_autogen.inl +++ b/src/pc/lua/smlua_hook_events_autogen.inl @@ -15,7 +15,7 @@ bool smlua_call_event_hooks_HOOK_UPDATE() { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_UPDATE]); continue; } @@ -45,7 +45,7 @@ bool smlua_call_event_hooks_HOOK_MARIO_UPDATE(struct MarioState *m) { lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MARIO_UPDATE]); continue; } @@ -75,7 +75,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_MARIO_UPDATE(struct MarioState *m) { lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_MARIO_UPDATE]); continue; } @@ -105,7 +105,7 @@ bool smlua_call_event_hooks_HOOK_ON_SET_MARIO_ACTION(struct MarioState *m) { lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SET_MARIO_ACTION]); continue; } @@ -140,7 +140,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_PHYS_STEP(struct MarioState *m, s32 step lua_pushinteger(L, stepArg); // call the callback - if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_PHYS_STEP]); continue; } @@ -185,7 +185,7 @@ bool smlua_call_event_hooks_HOOK_ALLOW_PVP_ATTACK(struct MarioState *attacker, s lua_pushinteger(L, interaction); // call the callback - if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ALLOW_PVP_ATTACK]); continue; } @@ -229,7 +229,7 @@ bool smlua_call_event_hooks_HOOK_ON_PVP_ATTACK(struct MarioState *attacker, stru lua_pushinteger(L, interaction); // call the callback - if (0 != smlua_call_hook(L, 3, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PVP_ATTACK]); continue; } @@ -259,7 +259,7 @@ bool smlua_call_event_hooks_HOOK_ON_PLAYER_CONNECTED(struct MarioState *m) { lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PLAYER_CONNECTED]); continue; } @@ -289,7 +289,7 @@ bool smlua_call_event_hooks_HOOK_ON_PLAYER_DISCONNECTED(struct MarioState *m) { lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PLAYER_DISCONNECTED]); continue; } @@ -325,7 +325,7 @@ bool smlua_call_event_hooks_HOOK_ALLOW_INTERACT(struct MarioState *m, struct Obj lua_pushinteger(L, interactType); // call the callback - if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ALLOW_INTERACT]); continue; } @@ -369,7 +369,7 @@ bool smlua_call_event_hooks_HOOK_ON_INTERACT(struct MarioState *m, struct Object lua_pushboolean(L, interactValue); // call the callback - if (0 != smlua_call_hook(L, 4, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 4, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_INTERACT]); continue; } @@ -408,7 +408,7 @@ bool smlua_call_event_hooks_HOOK_ON_LEVEL_INIT(u8 warpType, s16 levelNum, u8 are lua_pushinteger(L, warpArg); // call the callback - if (0 != smlua_call_hook(L, 5, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 5, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_LEVEL_INIT]); continue; } @@ -447,7 +447,7 @@ bool smlua_call_event_hooks_HOOK_ON_WARP(u8 warpType, s16 levelNum, u8 areaIdx, lua_pushinteger(L, warpArg); // call the callback - if (0 != smlua_call_hook(L, 5, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 5, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_WARP]); continue; } @@ -471,7 +471,7 @@ bool smlua_call_event_hooks_HOOK_ON_SYNC_VALID() { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SYNC_VALID]); continue; } @@ -498,7 +498,7 @@ bool smlua_call_event_hooks_HOOK_ON_OBJECT_UNLOAD(struct Object *obj) { smlua_push_object(L, LOT_OBJECT, obj, NULL); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_OBJECT_UNLOAD]); continue; } @@ -525,7 +525,7 @@ bool smlua_call_event_hooks_HOOK_ON_SYNC_OBJECT_UNLOAD(struct Object *obj) { smlua_push_object(L, LOT_OBJECT, obj, NULL); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SYNC_OBJECT_UNLOAD]); continue; } @@ -552,7 +552,7 @@ bool smlua_call_event_hooks_HOOK_ON_PAUSE_EXIT(bool usedExitToCastle, bool *allo lua_pushboolean(L, usedExitToCastle); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PAUSE_EXIT]); continue; } @@ -580,7 +580,7 @@ bool smlua_call_event_hooks_HOOK_GET_STAR_COLLECTION_DIALOG(s32 *dialogID) { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_GET_STAR_COLLECTION_DIALOG]); continue; } @@ -618,7 +618,7 @@ bool smlua_call_event_hooks_HOOK_ON_SET_CAMERA_MODE(struct Camera *c, s16 mode, lua_pushinteger(L, frames); // call the callback - if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SET_CAMERA_MODE]); continue; } @@ -650,7 +650,7 @@ bool smlua_call_event_hooks_HOOK_ON_OBJECT_RENDER(struct Object *obj) { smlua_push_object(L, LOT_OBJECT, obj, NULL); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_OBJECT_RENDER]); continue; } @@ -680,7 +680,7 @@ bool smlua_call_event_hooks_HOOK_ON_DEATH(struct MarioState *m, bool *allowDeath lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_DEATH]); continue; } @@ -715,7 +715,7 @@ bool smlua_call_event_hooks_HOOK_ON_PACKET_RECEIVE(s32 modIndex, s32 valueIndex) lua_pushinteger(L, valueIndex); // call the callback - if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PACKET_RECEIVE]); continue; } @@ -741,7 +741,7 @@ bool smlua_call_event_hooks_HOOK_USE_ACT_SELECT(s32 levelNum, bool *useActSelect lua_pushinteger(L, levelNum); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_USE_ACT_SELECT]); continue; } @@ -774,7 +774,7 @@ bool smlua_call_event_hooks_HOOK_ON_CHANGE_CAMERA_ANGLE(s32 camAngleType, bool * lua_pushinteger(L, camAngleType); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_CHANGE_CAMERA_ANGLE]); continue; } @@ -806,7 +806,7 @@ bool smlua_call_event_hooks_HOOK_ON_SCREEN_TRANSITION(s32 transitionType, bool * lua_pushinteger(L, transitionType); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SCREEN_TRANSITION]); continue; } @@ -844,7 +844,7 @@ bool smlua_call_event_hooks_HOOK_ALLOW_HAZARD_SURFACE(struct MarioState *m, s32 lua_pushinteger(L, hazardType); // call the callback - if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ALLOW_HAZARD_SURFACE]); continue; } @@ -882,7 +882,7 @@ bool smlua_call_event_hooks_HOOK_ON_CHAT_MESSAGE(struct MarioState *m, const cha lua_pushstring(L, message); // call the callback - if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_CHAT_MESSAGE]); continue; } @@ -920,7 +920,7 @@ bool smlua_call_event_hooks_HOOK_OBJECT_SET_MODEL(struct Object *obj, s32 modelI lua_pushinteger(L, modelExtendedId); // call the callback - if (0 != smlua_call_hook(L, 3, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_OBJECT_SET_MODEL]); continue; } @@ -952,7 +952,7 @@ bool smlua_call_event_hooks_HOOK_CHARACTER_SOUND(struct MarioState *m, enum Char lua_pushinteger(L, characterSound); // call the callback - if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_CHARACTER_SOUND]); continue; } @@ -994,7 +994,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_SET_MARIO_ACTION(struct MarioState *m, u lua_pushinteger(L, actionArg); // call the callback - if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_SET_MARIO_ACTION]); continue; } @@ -1023,7 +1023,7 @@ bool smlua_call_event_hooks_HOOK_JOINED_GAME() { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_JOINED_GAME]); continue; } @@ -1050,7 +1050,7 @@ bool smlua_call_event_hooks_HOOK_ON_OBJECT_ANIM_UPDATE(struct Object *obj) { smlua_push_object(L, LOT_OBJECT, obj, NULL); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_OBJECT_ANIM_UPDATE]); continue; } @@ -1077,7 +1077,7 @@ bool smlua_call_event_hooks_HOOK_ON_DIALOG(s32 dialogID, bool *openDialogBox, co lua_pushinteger(L, dialogID); // call the callback - if (0 != smlua_call_hook(L, 1, 2, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 2, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_DIALOG]); continue; } @@ -1111,7 +1111,7 @@ bool smlua_call_event_hooks_HOOK_ON_EXIT() { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_EXIT]); continue; } @@ -1137,7 +1137,7 @@ bool smlua_call_event_hooks_HOOK_DIALOG_SOUND(s32 speaker, s32 *speakerOverride) lua_pushinteger(L, speaker); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_DIALOG_SOUND]); continue; } @@ -1173,7 +1173,7 @@ bool smlua_call_event_hooks_HOOK_ON_COLLIDE_LEVEL_BOUNDS(struct MarioState *m) { lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_COLLIDE_LEVEL_BOUNDS]); continue; } @@ -1203,7 +1203,7 @@ bool smlua_call_event_hooks_HOOK_MIRROR_MARIO_RENDER(struct GraphNodeObject *mir lua_pushinteger(L, playerIndex); // call the callback - if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MIRROR_MARIO_RENDER]); continue; } @@ -1232,7 +1232,7 @@ bool smlua_call_event_hooks_HOOK_MARIO_OVERRIDE_PHYS_STEP_DEFACTO_SPEED(struct M lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MARIO_OVERRIDE_PHYS_STEP_DEFACTO_SPEED]); continue; } @@ -1264,7 +1264,7 @@ bool smlua_call_event_hooks_HOOK_ON_OBJECT_LOAD(struct Object *obj) { smlua_push_object(L, LOT_OBJECT, obj, NULL); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_OBJECT_LOAD]); continue; } @@ -1294,7 +1294,7 @@ bool smlua_call_event_hooks_HOOK_ON_PLAY_SOUND(s32 soundBits, Vec3f pos, s32 *so smlua_new_vec3f(pos); // call the callback - if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PLAY_SOUND]); continue; } @@ -1332,7 +1332,7 @@ bool smlua_call_event_hooks_HOOK_ON_SEQ_LOAD(u32 seqPlayer, u32 seqId, s32 loadA lua_pushinteger(L, loadAsync); // call the callback - if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SEQ_LOAD]); continue; } @@ -1374,7 +1374,7 @@ bool smlua_call_event_hooks_HOOK_ON_ATTACK_OBJECT(struct MarioState *m, struct O lua_pushinteger(L, interaction); // call the callback - if (0 != smlua_call_hook(L, 3, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_ATTACK_OBJECT]); continue; } @@ -1401,7 +1401,7 @@ bool smlua_call_event_hooks_HOOK_ON_LANGUAGE_CHANGED(const char *langName) { lua_pushstring(L, langName); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_LANGUAGE_CHANGED]); continue; } @@ -1425,7 +1425,7 @@ bool smlua_call_event_hooks_HOOK_ON_MODS_LOADED() { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_MODS_LOADED]); continue; } @@ -1449,7 +1449,7 @@ bool smlua_call_event_hooks_HOOK_ON_DJUI_THEME_CHANGED() { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_DJUI_THEME_CHANGED]); continue; } @@ -1479,7 +1479,7 @@ bool smlua_call_event_hooks_HOOK_ON_GEO_PROCESS(struct GraphNode *node, s32 matS lua_pushinteger(L, matStackIndex); // call the callback - if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_GEO_PROCESS]); continue; } @@ -1509,7 +1509,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_GEO_PROCESS(struct GraphNode *node, s32 lua_pushinteger(L, matStackIndex); // call the callback - if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_GEO_PROCESS]); continue; } @@ -1539,7 +1539,7 @@ bool smlua_call_event_hooks_HOOK_ON_GEO_PROCESS_CHILDREN(struct GraphNode *paren lua_pushinteger(L, matStackIndex); // call the callback - if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_GEO_PROCESS_CHILDREN]); continue; } @@ -1569,7 +1569,7 @@ bool smlua_call_event_hooks_HOOK_MARIO_OVERRIDE_GEOMETRY_INPUTS(struct MarioStat lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MARIO_OVERRIDE_GEOMETRY_INPUTS]); continue; } @@ -1604,7 +1604,7 @@ bool smlua_call_event_hooks_HOOK_ON_INTERACTIONS(struct MarioState *m) { lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_INTERACTIONS]); continue; } @@ -1637,7 +1637,7 @@ bool smlua_call_event_hooks_HOOK_ALLOW_FORCE_WATER_ACTION(struct MarioState *m, lua_pushboolean(L, isInWaterAction); // call the callback - if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ALLOW_FORCE_WATER_ACTION]); continue; } @@ -1677,7 +1677,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_WARP(s16 destLevel, s16 destArea, s16 de lua_pushinteger(L, arg); // call the callback - if (0 != smlua_call_hook(L, 4, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 4, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_WARP]); continue; } @@ -1735,7 +1735,7 @@ bool smlua_call_event_hooks_HOOK_ON_INSTANT_WARP(u8 areaIdx, u8 nodeId, Vec3s di smlua_new_vec3s(displacement); // call the callback - if (0 != smlua_call_hook(L, 3, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 3, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_INSTANT_WARP]); continue; } @@ -1767,7 +1767,7 @@ bool smlua_call_event_hooks_HOOK_MARIO_OVERRIDE_FLOOR_CLASS(struct MarioState *m lua_pushinteger(L, floorClass); // call the callback - if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MARIO_OVERRIDE_FLOOR_CLASS]); continue; } @@ -1803,7 +1803,7 @@ bool smlua_call_event_hooks_HOOK_ON_ADD_SURFACE(struct Surface *surface, bool dy lua_pushboolean(L, dynamic); // call the callback - if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_ADD_SURFACE]); continue; } @@ -1827,7 +1827,7 @@ bool smlua_call_event_hooks_HOOK_ON_CLEAR_AREAS() { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_CLEAR_AREAS]); continue; } diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index 2c7ed2329..ccf1e637c 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -34,6 +34,7 @@ u64* gBehaviorOffset = &gPcDebug.bhvOffset; struct LuaHookedEvent { int reference[MAX_HOOKED_REFERENCES]; struct Mod* mod[MAX_HOOKED_REFERENCES]; + struct ModFile* modFile[MAX_HOOKED_REFERENCES]; int count; }; @@ -46,11 +47,14 @@ static const char* sLuaHookedEventTypeName[] = { "HOOK_MAX" }; -int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct Mod* activeMod) { +int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct Mod* activeMod, struct ModFile* activeModFile) { if (!gGameInited) { return 0; } // Don't call hooks while the game is booting - struct Mod* prev = gLuaActiveMod; + struct Mod* prevActiveMod = gLuaActiveMod; + struct ModFile* prevActiveModFile = gLuaActiveModFile; + gLuaActiveMod = activeMod; + gLuaActiveModFile = activeModFile; gLuaLastHookMod = activeMod; gPcDebug.lastModRun = activeMod; @@ -62,7 +66,8 @@ int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct M lua_profiler_stop_counter(activeMod); - gLuaActiveMod = prev; + gLuaActiveMod = prevActiveMod; + gLuaActiveModFile = prevActiveModFile; return rc; } @@ -131,7 +136,7 @@ static bool smlua_call_event_hooks_on_hud_render(void (*resetFunc)(void), bool r lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[hookType]); } else { hookResult = true; @@ -170,7 +175,7 @@ bool smlua_call_event_hooks_HOOK_ON_NAMETAGS_RENDER(s32 playerIndex, Vec3f pos, smlua_new_vec3f(pos); // call the callback - if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i])) { + if (0 != smlua_call_hook(L, 2, 1, 0, hook->mod[i], hook->modFile[i])) { LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_NAMETAGS_RENDER]); continue; } @@ -223,6 +228,7 @@ struct LuaHookedMarioAction { u32 interactionType; int actionHookRefs[ACTION_HOOK_MAX]; struct Mod* mod; + struct ModFile* modFile; }; #define MAX_HOOKED_ACTIONS (ACT_NUM_GROUPS * ACT_NUM_ACTIONS_PER_GROUP) @@ -311,6 +317,7 @@ int smlua_hook_mario_action(lua_State* L) { hooked->action = action; hooked->interactionType = interactionType; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; sHookedMarioActionsCount++; return 1; @@ -334,7 +341,7 @@ bool smlua_call_action_hook(enum LuaActionHookType hookType, struct MarioState* lua_remove(L, -2); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod)) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod, hook->modFile)) { LOG_LUA("Failed to call the action callback: %u", m->action); continue; } @@ -381,6 +388,7 @@ struct LuaHookedBehavior { bool replace; bool luaBehavior; struct Mod* mod; + struct ModFile* modFile; }; #define MAX_HOOKED_BEHAVIORS 1024 @@ -474,6 +482,7 @@ int smlua_hook_custom_bhv(BehaviorScript *bhvScript, const char *bhvName) { hooked->replace = true; hooked->luaBehavior = false; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; sHookedBehaviorsCount++; @@ -620,6 +629,7 @@ int smlua_hook_behavior(lua_State* L) { hooked->replace = replaceBehavior; hooked->luaBehavior = true; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; sHookedBehaviorsCount++; @@ -677,7 +687,7 @@ bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* ob smlua_push_object(L, LOT_OBJECT, object, NULL); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hooked->mod)) { + if (0 != smlua_call_hook(L, 1, 0, 0, hooked->mod, hooked->modFile)) { LOG_LUA("Failed to call the behavior callback: %u", hooked->behaviorId); return true; } @@ -698,6 +708,7 @@ struct LuaHookedChatCommand { char* description; int reference; struct Mod* mod; + struct ModFile* modFile; }; #define MAX_HOOKED_CHAT_COMMANDS 512 @@ -742,6 +753,7 @@ int smlua_hook_chat_command(lua_State* L) { hooked->description = strdup(description); hooked->reference = ref; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; sHookedChatCommandsCount++; return 1; @@ -805,7 +817,7 @@ bool smlua_call_chat_command_hook(char* command) { lua_pushstring(L, params); // call the callback - if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod)) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod, hook->modFile)) { LOG_LUA("Failed to call the chat command callback: %s", command); continue; } @@ -1108,6 +1120,7 @@ int smlua_hook_mod_menu_text(lua_State* L) { hooked->sliderMax = 0; hooked->reference = 0; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; lua_pushinteger(L, gHookedModMenuElementsCount); gHookedModMenuElementsCount++; @@ -1146,6 +1159,7 @@ int smlua_hook_mod_menu_button(lua_State* L) { hooked->sliderMax = 0; hooked->reference = ref; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; lua_pushinteger(L, gHookedModMenuElementsCount); gHookedModMenuElementsCount++; @@ -1190,6 +1204,7 @@ int smlua_hook_mod_menu_checkbox(lua_State* L) { hooked->sliderMax = 0; hooked->reference = ref; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; lua_pushinteger(L, gHookedModMenuElementsCount); gHookedModMenuElementsCount++; @@ -1246,6 +1261,7 @@ int smlua_hook_mod_menu_slider(lua_State* L) { hooked->sliderMax = sliderMax; hooked->reference = ref; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; lua_pushinteger(L, gHookedModMenuElementsCount); gHookedModMenuElementsCount++; @@ -1297,6 +1313,7 @@ int smlua_hook_mod_menu_inputbox(lua_State* L) { hooked->sliderMax = 0; hooked->reference = ref; hooked->mod = gLuaActiveMod; + hooked->modFile = gLuaActiveModFile; lua_pushinteger(L, gHookedModMenuElementsCount); gHookedModMenuElementsCount++; @@ -1428,7 +1445,7 @@ void smlua_call_mod_menu_element_hook(struct LuaHookedModMenuElement* hooked, in } // call the callback - if (0 != smlua_call_hook(L, params, 1, 0, hooked->mod)) { + if (0 != smlua_call_hook(L, params, 1, 0, hooked->mod, hooked->modFile)) { LOG_LUA("Failed to call the mod menu element callback: %s", hooked->name); return; } @@ -1453,6 +1470,7 @@ void smlua_clear_hooks(void) { struct LuaHookedMarioAction* hooked = &sHookedMarioActions[i]; hooked->action = 0; hooked->mod = NULL; + hooked->modFile = NULL; memset(hooked->actionHookRefs, 0, sizeof(hooked->actionHookRefs)); } sHookedMarioActionsCount = 0; @@ -1467,6 +1485,7 @@ void smlua_clear_hooks(void) { hooked->reference = 0; hooked->mod = NULL; + hooked->modFile = NULL; } sHookedChatCommandsCount = 0; @@ -1482,6 +1501,7 @@ void smlua_clear_hooks(void) { hooked->sliderMax = 0; hooked->reference = 0; hooked->mod = NULL; + hooked->modFile = NULL; } gHookedModMenuElementsCount = 0; @@ -1510,6 +1530,7 @@ void smlua_clear_hooks(void) { hooked->replace = false; hooked->luaBehavior = false; hooked->mod = NULL; + hooked->modFile = NULL; } sHookedBehaviorsCount = 0; memset(gLuaMarioActionIndex, 0, sizeof(gLuaMarioActionIndex)); diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index b81841e4b..280bd129d 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -117,6 +117,7 @@ struct LuaHookedModMenuElement { u32 sliderMax; int reference; struct Mod* mod; + struct ModFile* modFile; }; extern u32 gLuaMarioActionIndex[]; @@ -140,7 +141,7 @@ bool smlua_is_behavior_hooked(const BehaviorScript *behavior); const char* smlua_get_name_from_hooked_behavior_id(enum BehaviorId id); bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* object, bool before); -int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct Mod* activeMod); +int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct Mod* activeMod, struct ModFile* activeModFile); bool smlua_call_action_hook(enum LuaActionHookType hookType, struct MarioState* m, s32* returnValue); u32 smlua_get_action_interaction_type(struct MarioState* m); diff --git a/src/pc/lua/smlua_require.c b/src/pc/lua/smlua_require.c new file mode 100644 index 000000000..813a7430b --- /dev/null +++ b/src/pc/lua/smlua_require.c @@ -0,0 +1,180 @@ +#include +#include "smlua.h" +#include "pc/mods/mods.h" +#include "pc/mods/mods_utils.h" +#include "pc/fs/fmem.h" + + +// table to track loaded modules per mod +static void smlua_init_mod_loaded_table(lua_State* L, const char* modPath) { + // Create a unique registry key for this mod's loaded table + char registryKey[SYS_MAX_PATH + 16]; + snprintf(registryKey, sizeof(registryKey), "mod_loaded_%s", modPath); + + lua_getfield(L, LUA_REGISTRYINDEX, registryKey); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, registryKey); + } else { + lua_pop(L, 1); + } +} + +static struct ModFile* smlua_find_mod_file(const char* moduleName) { + char relativeDir[SYS_MAX_PATH] = ""; + + if (!gLuaActiveMod) { + return NULL; + } + + if (gLuaActiveModFile) { + path_get_folder(gLuaActiveModFile->relativePath, relativeDir); + } + + bool hasRelativeDir = strlen(relativeDir) > 0; + + struct ModFile* bestPick = NULL; + int bestRelativeDepth = INT_MAX; + int bestTotalDepth = INT_MAX; + bool foundRelativeFile = false; + + char luaName[SYS_MAX_PATH] = ""; + char luacName[SYS_MAX_PATH] = ""; + snprintf(luaName, SYS_MAX_PATH, "%s.lua", moduleName); + snprintf(luacName, SYS_MAX_PATH, "%s.luac", moduleName); + + for (int i = 0; i < gLuaActiveMod->fileCount; i++) { + struct ModFile* file = &gLuaActiveMod->files[i]; + + // don't consider the currently running file + if (file == gLuaActiveModFile) { + continue; + } + + // only consider lua files + if (!str_ends_with(file->relativePath, ".lua") && !str_ends_with(file->relativePath, ".luac")) { + continue; + } + + // check for match + if (!str_ends_with(file->relativePath, moduleName) && !str_ends_with(file->relativePath, luaName) && !str_ends_with(file->relativePath, luacName)) { + continue; + } + + // get total path depth + int totalDepth = path_depth(file->relativePath); + + // make sure we never load the old-style lua files with require() + if (totalDepth < 1) { + continue; + } + + // get relative path depth + int relativeDepth = INT_MAX; + if (hasRelativeDir && path_is_relative_to(file->relativePath, relativeDir)) { + relativeDepth = path_depth(file->relativePath + strlen(relativeDir)); + foundRelativeFile = true; + } + + // pick new best + // relative files will always win against absolute files + // other than that, shallower files will win + if (relativeDepth < bestRelativeDepth || (!foundRelativeFile && totalDepth < bestTotalDepth)) { + bestPick = file; + bestRelativeDepth = relativeDepth; + bestTotalDepth = totalDepth; + } + } + + return bestPick; +} + +static int smlua_custom_require(lua_State* L) { + const char* moduleName = luaL_checkstring(L, 1); + + struct Mod* activeMod = gLuaActiveMod; + if (!activeMod) { + LOG_LUA("require() called outside of mod context"); + return 0; + } + + // create registry key for this mod's loaded table + char registryKey[SYS_MAX_PATH + 16] = ""; + snprintf(registryKey, sizeof(registryKey), "mod_loaded_%s", activeMod->relativePath); + + // get or create the mod's loaded table + lua_getfield(L, LUA_REGISTRYINDEX, registryKey); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, registryKey); + } + + // find the file in mod files + struct ModFile* file = smlua_find_mod_file(moduleName); + if (!file) { + LOG_LUA("module '%s' not found in mod files", moduleName); + lua_pop(L, 1); // pop table + return 0; + } + + // check if module is already loaded + lua_getfield(L, -1, file->relativePath); + if (!lua_isnil(L, -1)) { + // module already loaded, return it + return 1; + } + lua_pop(L, 1); // pop nil value + + // mark module as "loading" to prevent recursion + lua_pushboolean(L, 1); + lua_setfield(L, -2, file->relativePath); + + // cache the previous mod file + struct ModFile* prevModFile = gLuaActiveModFile; + s32 prevTop = lua_gettop(L); + + // load and execute + gLuaActiveModFile = file; + smlua_load_script(activeMod, file, activeMod->index, false); + gLuaActiveModFile = prevModFile; + + // if the module didn't return anything, use true + if (prevTop == lua_gettop(L)) { + lua_pushboolean(L, 1); + } else if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_pushboolean(L, 1); + } + + // store in loaded table + lua_pushvalue(L, -1); // duplicate return value + lua_setfield(L, -3, file->relativePath); // loaded[file->relativePath] = return_value + + // clean up stack + lua_remove(L, -2); + + return 1; // return the module value +} + +void smlua_bind_custom_require(lua_State* L) { + // replace the global require function + lua_pushcfunction(L, smlua_custom_require); + lua_setglobal(L, "require"); +} + +void smlua_init_require_system(void) { + lua_State* L = gLuaState; + if (!L) return; + + // initialize the custom require function + smlua_bind_custom_require(L); + + // initialize loaded tables for each mod + for (int i = 0; i < gActiveMods.entryCount; i++) { + struct Mod* mod = gActiveMods.entries[i]; + smlua_init_mod_loaded_table(L, mod->relativePath); + } +} \ No newline at end of file diff --git a/src/pc/lua/smlua_require.h b/src/pc/lua/smlua_require.h new file mode 100644 index 000000000..489fe1dc5 --- /dev/null +++ b/src/pc/lua/smlua_require.h @@ -0,0 +1,9 @@ +#ifndef SMLUA_REQUIRE_H +#define SMLUA_REQUIRE_H + +#include "smlua.h" + +void smlua_bind_custom_require(lua_State* L); +void smlua_init_require_system(void); + +#endif \ No newline at end of file diff --git a/src/pc/lua/smlua_sync_table.c b/src/pc/lua/smlua_sync_table.c index 3a984696f..2e800cf23 100644 --- a/src/pc/lua/smlua_sync_table.c +++ b/src/pc/lua/smlua_sync_table.c @@ -143,14 +143,20 @@ static void smlua_sync_table_call_hook(int syncTableIndex, int keyIndex, int pre struct Mod* mod = gActiveMods.entries[modRemoteIndex]; // call hook - struct Mod* prev = gLuaActiveMod; + struct Mod* prevActiveMod = gLuaActiveMod; + struct ModFile* prevActiveModFile = gLuaActiveModFile; + gLuaActiveMod = mod; + gLuaActiveModFile = NULL; gLuaLastHookMod = mod; gPcDebug.lastModRun = mod; + if (0 != smlua_pcall(L, 3, 0, 0)) { LOG_LUA_LINE("Failed to call the hook_on_changed callback"); } - gLuaActiveMod = prev; + + gLuaActiveMod = prevActiveMod; + prevActiveModFile = prevActiveModFile; } lua_pop(L, 1); // pop _hook_on_changed's value diff --git a/src/pc/mods/mod.c b/src/pc/mods/mod.c index dbc97c93e..f9c4871e9 100644 --- a/src/pc/mods/mod.c +++ b/src/pc/mods/mod.c @@ -1,3 +1,4 @@ +#include #include "mod.h" #include "mods.h" #include "mods_utils.h" @@ -39,9 +40,13 @@ static void mod_activate_bin(struct Mod* mod, struct ModFile* file) { g++; } + // get mod file index + s32 fileIndex = (file - &mod->files[0]); + if (fileIndex < 0 || fileIndex >= mod->fileCount) { fileIndex = 0; } + // Add to custom actors LOG_INFO("Activating DynOS bin: '%s', '%s'", file->cachedPath, geoName); - dynos_add_actor_custom(mod->index, file->cachedPath, geoName); + dynos_add_actor_custom(mod->index, fileIndex, file->cachedPath, geoName); } static void mod_activate_col(struct ModFile* file) { @@ -261,7 +266,7 @@ static struct ModFile* mod_allocate_file(struct Mod* mod, char* relativePath) { return file; } -static bool mod_load_files_dir(struct Mod* mod, char* fullPath, const char* subDir, const char** fileTypes) { +static bool mod_load_files_dir(struct Mod* mod, char* fullPath, const char* subDir, const char** fileTypes, bool recursive) { // concat directory char dirPath[SYS_MAX_PATH] = { 0 }; @@ -285,15 +290,33 @@ static bool mod_load_files_dir(struct Mod* mod, char* fullPath, const char* subD if (strlen(subDir) > 0) { if (snprintf(relativePath, SYS_MAX_PATH - 1, "%s/%s", subDir, dir->d_name) < 0) { LOG_ERROR("Could not concat %s path!", subDir); + closedir(d); return false; } } else { if (snprintf(relativePath, SYS_MAX_PATH - 1, "%s", dir->d_name) < 0) { LOG_ERROR("Could not concat %s path!", subDir); + closedir(d); return false; } } + // Check if this is a directory + struct stat st = { 0 }; + if (recursive && stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { + // Skip . and .. directories + if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) { + continue; + } + + // Recursively process subdirectory + if (!mod_load_files_dir(mod, fullPath, relativePath, fileTypes, recursive)) { + closedir(d); + return false; + } + continue; + } + // only consider certain file types bool fileTypeMatch = false; const char** ft = fileTypes; @@ -325,37 +348,37 @@ static bool mod_load_files(struct Mod* mod, char* modName, char* fullPath) { // deal with mod directory { const char* fileTypes[] = { ".lua", ".luac", NULL }; - if (!mod_load_files_dir(mod, fullPath, "", fileTypes)) { return false; } + if (!mod_load_files_dir(mod, fullPath, "", fileTypes, true)) { return false; } } // deal with actors directory { const char* fileTypes[] = { ".bin", ".col", NULL }; - if (!mod_load_files_dir(mod, fullPath, "actors", fileTypes)) { return false; } + if (!mod_load_files_dir(mod, fullPath, "actors", fileTypes, false)) { return false; } } // deal with behaviors directory { const char* fileTypes[] = { ".bhv", NULL }; - if (!mod_load_files_dir(mod, fullPath, "data", fileTypes)) { return false; } + if (!mod_load_files_dir(mod, fullPath, "data", fileTypes, false)) { return false; } } // deal with textures directory { const char* fileTypes[] = { ".tex", NULL }; - if (!mod_load_files_dir(mod, fullPath, "textures", fileTypes)) { return false; } + if (!mod_load_files_dir(mod, fullPath, "textures", fileTypes, false)) { return false; } } // deal with levels directory { const char* fileTypes[] = { ".lvl", NULL }; - if (!mod_load_files_dir(mod, fullPath, "levels", fileTypes)) { return false; } + if (!mod_load_files_dir(mod, fullPath, "levels", fileTypes, false)) { return false; } } // deal with sound directory { const char* fileTypes[] = { ".m64", ".mp3", ".aiff", ".ogg", NULL }; - if (!mod_load_files_dir(mod, fullPath, "sound", fileTypes)) { return false; } + if (!mod_load_files_dir(mod, fullPath, "sound", fileTypes, false)) { return false; } } return true; diff --git a/src/pc/mods/mods_utils.c b/src/pc/mods/mods_utils.c index 734442656..429a22628 100644 --- a/src/pc/mods/mods_utils.c +++ b/src/pc/mods/mods_utils.c @@ -234,6 +234,20 @@ void path_get_folder(char* path, char* outpath) { *o = '\0'; } +int path_depth(const char* path) { + int depth = 0; + for (; *path; path++) { + if (*path == '/' || *path == '\\') { + depth++; + } + } + return depth; +} + +bool path_is_relative_to(const char* fullPath, const char* baseDir) { + return strncmp(fullPath, baseDir, strlen(baseDir)) == 0; +} + bool directory_sanity_check(struct dirent* dir, char* dirPath, char* outPath) { // skip non-portable filenames if (!fs_sys_filename_is_portable(dir->d_name)) { return false; } diff --git a/src/pc/mods/mods_utils.h b/src/pc/mods/mods_utils.h index d7d9d24b5..ad07e8216 100644 --- a/src/pc/mods/mods_utils.h +++ b/src/pc/mods/mods_utils.h @@ -20,6 +20,8 @@ void normalize_path(char* path); bool concat_path(char* destination, char* path, char* fname); char* path_basename(char* path); void path_get_folder(char* path, char* outpath); +int path_depth(const char* path); +bool path_is_relative_to(const char* fullPath, const char* baseDir); bool directory_sanity_check(struct dirent* dir, char* dirPath, char* outPath); #endif \ No newline at end of file