Add a safer version of Lua's require() (#847)
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run

I didn't add standard Lua require() because I've always been
afraid of it. I'm not sure we can guarantee which files it
will read (or not read).

Instead, here is a custom implementation. It should work more
or less the same and allow for more modular code.

For backwards compatibility reasons, all of the lua files in
the base mod folder will be loaded as in the past. Aka one at
a time and alphabetically.

However, now coop will look for Lua files in subdirectories
and will load them in when another Lua file calls require().

The file search order is more reasonable than normal Lua
require(). It will first look for files relative to the
currently running script. If there is no matching relative
file, it will pick from any Lua file that is in any of the
mod's subdirectories.

---------

Co-authored-by: MysterD <myster@d>
This commit is contained in:
djoslin0 2025-06-14 02:49:07 -07:00 committed by GitHub
parent 8f1830b079
commit 24b92ecc2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 473 additions and 149 deletions

View file

@ -29,7 +29,7 @@ SMLUA_CALL_EVENT_HOOKS_SET_HOOK_RESULT = """
SMLUA_CALL_EVENT_HOOKS_CALLBACK = """ SMLUA_CALL_EVENT_HOOKS_CALLBACK = """
// call the 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}]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[{hook_type}]);
continue; continue;
}}{set_hook_result} }}{set_hook_result}

View file

@ -36,9 +36,9 @@ void dynos_generate_packs(const char* directory);
// -- geos -- // // -- geos -- //
void dynos_actor_override(struct Object* obj, void** aSharedChild); 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); 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); void dynos_actor_register_modified_graph_node(struct GraphNode *node);
// -- collisions -- // // -- collisions -- //
@ -72,7 +72,7 @@ Collision *dynos_level_get_collision(u32 level, u16 area);
// -- behaviors -- // // -- behaviors -- //
void dynos_add_behavior(s32 modIndex, const char *filePath, const char *behaviorName); 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); const char *dynos_behavior_get_token(BehaviorScript *bhvScript, u32 index);
void dynos_behavior_hook_all_custom_behaviors(void); void dynos_behavior_hook_all_custom_behaviors(void);

View file

@ -572,6 +572,7 @@ struct GfxData : NoCopy {
s32 mErrorCount = 0; s32 mErrorCount = 0;
u32 mModelIdentifier = 0; u32 mModelIdentifier = 0;
s32 mModIndex = 0; s32 mModIndex = 0;
s32 mModFileIndex = 0;
SysPath mPackFolder; SysPath mPackFolder;
Array<void *> mPointerList; Array<void *> mPointerList;
Array<Pair<const void*, const void*>> mPointerOffsetList; Array<Pair<const void*, const void*>> mPointerOffsetList;
@ -889,9 +890,9 @@ void DynOS_Pack_AddTex(PackData* aPackData, DataNode<TexData>* aTexData);
// //
std::map<const void *, ActorGfx> &DynOS_Actor_GetValidActors(); std::map<const void *, ActorGfx> &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); 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); ActorGfx* DynOS_Actor_GetActorGfx(const GraphNode* aGraphNode);
void DynOS_Actor_Valid(const void* aGeoref, ActorGfx& aActorGfx); void DynOS_Actor_Valid(const void* aGeoref, ActorGfx& aActorGfx);
void DynOS_Actor_Invalid(const void* aGeoref, s32 aPackIndex); void DynOS_Actor_Invalid(const void* aGeoref, s32 aPackIndex);
@ -946,7 +947,7 @@ void DynOS_Lvl_ModShutdown();
Array<Pair<const char *, GfxData *>> &DynOS_Bhv_GetArray(); Array<Pair<const char *, GfxData *>> &DynOS_Bhv_GetArray();
void DynOS_Bhv_Activate(s32 modIndex, const SysPath &aFilename, const char *aBehaviorName); void DynOS_Bhv_Activate(s32 modIndex, const SysPath &aFilename, const char *aBehaviorName);
GfxData *DynOS_Bhv_GetActiveGfx(BehaviorScript *bhvScript); 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); const char *DynOS_Bhv_GetToken(BehaviorScript *bhvScript, u32 index);
void DynOS_Bhv_HookAllCustomBehaviors(); void DynOS_Bhv_HookAllCustomBehaviors();
void DynOS_Bhv_ModShutdown(); void DynOS_Bhv_ModShutdown();

View file

@ -111,16 +111,16 @@ void dynos_actor_override(struct Object* obj, void** aSharedChild) {
DynOS_Actor_Override(obj, aSharedChild); DynOS_Actor_Override(obj, 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) {
DynOS_Actor_AddCustom(modIndex, filePath, geoName); DynOS_Actor_AddCustom(modIndex, modFileIndex, filePath, geoName);
} }
const void* dynos_geolayout_get(const char *name) { const void* dynos_geolayout_get(const char *name) {
return DynOS_Actor_GetLayoutFromName(name); return DynOS_Actor_GetLayoutFromName(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) {
return DynOS_Actor_GetModIndexAndToken(graphNode, tokenIndex, modIndex, token); return DynOS_Actor_GetModIndexAndToken(graphNode, tokenIndex, modIndex, modFileIndex, token);
} }
void dynos_actor_register_modified_graph_node(struct GraphNode *node) { 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); DynOS_Bhv_Activate(modIndex, filePath, behaviorName);
} }
s32 dynos_behavior_get_active_mod_index(BehaviorScript *bhvScript) { bool dynos_behavior_get_active_mod_index(BehaviorScript *bhvScript, s32 *modIndex, s32 *modFileIndex) {
return DynOS_Bhv_GetActiveModIndex(bhvScript); return DynOS_Bhv_GetActiveModIndex(bhvScript, modIndex, modFileIndex);
} }
const char *dynos_behavior_get_token(BehaviorScript *bhvScript, u32 index) { const char *dynos_behavior_get_token(BehaviorScript *bhvScript, u32 index) {

View file

@ -31,7 +31,7 @@ std::map<const void *, ActorGfx> &DynOS_Actor_GetValidActors() {
return DynosValidActors(); 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); const void* georef = DynOS_Builtin_Actor_GetFromName(aActorName);
u16 actorLen = strlen(aActorName); u16 actorLen = strlen(aActorName);
@ -45,6 +45,7 @@ void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char *
return; return;
} }
_GfxData->mModIndex = aModIndex; _GfxData->mModIndex = aModIndex;
_GfxData->mModFileIndex = aModFileIndex;
void* geoLayout = (*(_GfxData->mGeoLayouts.end() - 1))->mData; void* geoLayout = (*(_GfxData->mGeoLayouts.end() - 1))->mData;
if (!geoLayout) { if (!geoLayout) {
@ -117,7 +118,7 @@ const void *DynOS_Actor_GetLayoutFromName(const char *aActorName) {
return NULL; 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); ActorGfx *_ActorGfx = DynOS_Actor_GetActorGfx(aGraphNode);
if (_ActorGfx) { if (_ActorGfx) {
GfxData *_GfxData = _ActorGfx->mGfxData; GfxData *_GfxData = _ActorGfx->mGfxData;
@ -125,6 +126,9 @@ bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenInde
if (outModIndex) { if (outModIndex) {
*outModIndex = _GfxData->mModIndex; *outModIndex = _GfxData->mModIndex;
} }
if (outModFileIndex) {
*outModFileIndex = _GfxData->mModFileIndex;
}
if (outToken) { if (outToken) {
if (!aTokenIndex || aTokenIndex > _GfxData->mLuaTokenList.Count()) { if (!aTokenIndex || aTokenIndex > _GfxData->mLuaTokenList.Count()) {
return false; return false;
@ -139,6 +143,9 @@ bool DynOS_Actor_GetModIndexAndToken(const GraphNode *aGraphNode, u32 aTokenInde
if (outModIndex) { if (outModIndex) {
*outModIndex = _GfxData->mModIndex; *outModIndex = _GfxData->mModIndex;
} }
if (outModFileIndex) {
*outModFileIndex = _GfxData->mModFileIndex;
}
if (outToken) { if (outToken) {
if (!aTokenIndex || aTokenIndex > _GfxData->mLuaTokenList.Count()) { if (!aTokenIndex || aTokenIndex > _GfxData->mLuaTokenList.Count()) {
return false; return false;

View file

@ -62,7 +62,7 @@ GfxData *DynOS_Bhv_GetActiveGfx(BehaviorScript *bhvScript) {
return NULL; return NULL;
} }
s32 DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript) { bool DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript, s32 *modIndex, s32 *modFileIndex) {
auto &_CustomBehaviorScripts = DynOS_Bhv_GetArray(); auto &_CustomBehaviorScripts = DynOS_Bhv_GetArray();
for (s32 i = 0; i < _CustomBehaviorScripts.Count(); ++i) { for (s32 i = 0; i < _CustomBehaviorScripts.Count(); ++i) {
@ -70,10 +70,12 @@ s32 DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript) {
auto &scripts = gfxData->mBehaviorScripts; auto &scripts = gfxData->mBehaviorScripts;
if (scripts.Count() == 0) { continue; } if (scripts.Count() == 0) { continue; }
if (bhvScript == scripts[scripts.Count() - 1]->mData) { 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) { const char *DynOS_Bhv_GetToken(BehaviorScript *bhvScript, u32 index) {

View file

@ -913,8 +913,9 @@ static s32 bhv_cmd_call_ext(void) {
BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior;
s32 modIndex = dynos_behavior_get_active_mod_index(behavior); s32 modIndex = -1;
if (modIndex == -1) { s32 modFileIndex = -1;
if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) {
LOG_ERROR("Could not find behavior script mod index."); LOG_ERROR("Could not find behavior script mod index.");
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;
} }
@ -946,8 +947,9 @@ static s32 bhv_cmd_call_ext(void) {
static s32 bhv_cmd_goto_ext(void) { static s32 bhv_cmd_goto_ext(void) {
BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior;
s32 modIndex = dynos_behavior_get_active_mod_index(behavior); s32 modIndex = -1;
if (modIndex == -1) { s32 modFileIndex = -1;
if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) {
LOG_ERROR("Could not find behavior script mod index."); LOG_ERROR("Could not find behavior script mod index.");
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;
} }
@ -976,8 +978,9 @@ static s32 bhv_cmd_goto_ext(void) {
static s32 bhv_cmd_call_native_ext(void) { static s32 bhv_cmd_call_native_ext(void) {
BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior;
s32 modIndex = dynos_behavior_get_active_mod_index(behavior); s32 modIndex = -1;
if (modIndex == -1) { s32 modFileIndex = -1;
if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) {
LOG_ERROR("Could not find behavior script mod index."); LOG_ERROR("Could not find behavior script mod index.");
gCurBhvCommand += 2; gCurBhvCommand += 2;
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;
@ -994,19 +997,27 @@ static s32 bhv_cmd_call_native_ext(void) {
} }
if (!gSmLuaConvertSuccess || funcRef == 0) { 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; gCurBhvCommand += 2;
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;
} }
// Get our mod. // Get our mod.
if (modIndex >= gActiveMods.entryCount) { if (modIndex < 0 || modIndex >= gActiveMods.entryCount) {
LOG_LUA("Failed to call lua function, could not find mod"); LOG_LUA("Failed to call lua behavior function, could not find mod");
gCurBhvCommand += 2; gCurBhvCommand += 2;
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;
} }
struct Mod *mod = gActiveMods.entries[modIndex]; 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 // Push the callback onto the stack
lua_rawgeti(gLuaState, LUA_REGISTRYINDEX, funcRef); 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); smlua_push_object(gLuaState, LOT_OBJECT, gCurrentObject, NULL);
// Call the callback // 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); 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; BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior;
s32 modIndex = dynos_behavior_get_active_mod_index(behavior); s32 modIndex = -1;
if (modIndex == -1) { s32 modFileIndex = -1;
if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) {
LOG_ERROR("Could not find behavior script mod index."); LOG_ERROR("Could not find behavior script mod index.");
gCurBhvCommand += 3; gCurBhvCommand += 3;
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;
@ -1076,8 +1088,9 @@ static s32 bhv_cmd_spawn_child_with_param_ext(void) {
BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior;
s32 modIndex = dynos_behavior_get_active_mod_index(behavior); s32 modIndex = -1;
if (modIndex == -1) { s32 modFileIndex = -1;
if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) {
LOG_ERROR("Could not find behavior script mod index."); LOG_ERROR("Could not find behavior script mod index.");
gCurBhvCommand += 3; gCurBhvCommand += 3;
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;
@ -1123,8 +1136,9 @@ static s32 bhv_cmd_spawn_obj_ext(void) {
BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior; BehaviorScript *behavior = (BehaviorScript *)gCurrentObject->behavior;
s32 modIndex = dynos_behavior_get_active_mod_index(behavior); s32 modIndex = -1;
if (modIndex == -1) { s32 modFileIndex = -1;
if (!dynos_behavior_get_active_mod_index(behavior, &modIndex, &modFileIndex)) {
LOG_ERROR("Could not find behavior script mod index."); LOG_ERROR("Could not find behavior script mod index.");
gCurBhvCommand += 3; gCurBhvCommand += 3;
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;

View file

@ -877,8 +877,9 @@ Gfx *geo_process_lua_function(s32 callContext, struct GraphNode *node, UNUSED Ma
// Retrieve mod index and function name // Retrieve mod index and function name
s32 modIndex = -1; s32 modIndex = -1;
s32 modFileIndex = -1;
const char *funcStr = NULL; 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) { if (modIndex == -1) {
LOG_ERROR("Could not find graph node mod index"); LOG_ERROR("Could not find graph node mod index");
} else if (funcStr == NULL) { } 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); funcRef = smlua_get_any_function_mod_variable(funcStr);
} }
if (!gSmLuaConvertSuccess || funcRef == 0) { 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; return NULL;
} }
// Get the mod // Get the mod
if (modIndex >= gActiveMods.entryCount) { if (modIndex < 0 || modIndex >= gActiveMods.entryCount) {
LOG_LUA("Failed to call lua function, could not find mod"); LOG_LUA("Failed to call lua geo function, could not find mod");
return NULL; return NULL;
} }
struct Mod *mod = gActiveMods.entries[modIndex]; 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 // Push the callback, the graph node and the current matrix stack index
lua_rawgeti(L, LUA_REGISTRYINDEX, funcRef); lua_rawgeti(L, LUA_REGISTRYINDEX, funcRef);
smlua_push_object(L, LOT_GRAPHNODE, node, NULL); smlua_push_object(L, LOT_GRAPHNODE, node, NULL);
lua_pushinteger(L, gMatStackIndex); lua_pushinteger(L, gMatStackIndex);
// Call the callback // 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); LOG_LUA("Failed to call the function callback: '%s'", funcStr);
} }

View file

@ -1,4 +1,5 @@
#include "smlua.h" #include "smlua.h"
#include "pc/lua/smlua_require.h"
#include "game/hardcoded.h" #include "game/hardcoded.h"
#include "pc/mods/mods.h" #include "pc/mods/mods.h"
#include "pc/mods/mods_utils.h" #include "pc/mods/mods_utils.h"
@ -16,6 +17,7 @@ u8 gLuaInitializingScript = 0;
u8 gSmLuaSuppressErrors = 0; u8 gSmLuaSuppressErrors = 0;
struct Mod* gLuaLoadingMod = NULL; struct Mod* gLuaLoadingMod = NULL;
struct Mod* gLuaActiveMod = NULL; struct Mod* gLuaActiveMod = NULL;
struct ModFile* gLuaActiveModFile = NULL;
struct Mod* gLuaLastHookMod = NULL; struct Mod* gLuaLastHookMod = NULL;
void smlua_mod_error(void) { void smlua_mod_error(void) {
@ -190,12 +192,11 @@ static bool smlua_check_binary_header(struct ModFile *file) {
return false; 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; if (!smlua_check_binary_header(file)) return;
lua_State* L = gLuaState; lua_State* L = gLuaState;
lua_settop(L, 0); s32 prevTop = lua_gettop(L);
gSmLuaConvertSuccess = true; gSmLuaConvertSuccess = true;
gLuaInitializingScript = 1; gLuaInitializingScript = 1;
@ -205,6 +206,7 @@ static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteI
if (!f) { if (!f) {
LOG_LUA("Failed to load lua script '%s': File not found.", file->cachedPath); LOG_LUA("Failed to load lua script '%s': File not found.", file->cachedPath);
gLuaInitializingScript = 0; gLuaInitializingScript = 0;
lua_settop(L, prevTop);
return; return;
} }
@ -214,6 +216,7 @@ static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteI
if (!buffer) { if (!buffer) {
LOG_LUA("Failed to load lua script '%s': Cannot allocate buffer.", file->cachedPath); LOG_LUA("Failed to load lua script '%s': Cannot allocate buffer.", file->cachedPath);
gLuaInitializingScript = 0; gLuaInitializingScript = 0;
lua_settop(L, prevTop);
return; 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) { if (f_read(buffer, 1, length, f) < length) {
LOG_LUA("Failed to load lua script '%s': Unexpected early end of file.", file->cachedPath); LOG_LUA("Failed to load lua script '%s': Unexpected early end of file.", file->cachedPath);
gLuaInitializingScript = 0; gLuaInitializingScript = 0;
lua_settop(L, prevTop);
return; return;
} }
f_close(f); 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))); LOG_LUA("%s", smlua_to_string(L, lua_gettop(L)));
gLuaInitializingScript = 0; gLuaInitializingScript = 0;
free(buffer); free(buffer);
lua_settop(L, prevTop);
return; return;
} }
free(buffer); free(buffer);
// check if this is the first time this mod has been loaded if (isModInit) {
lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); // check if this is the first time this mod has been loaded
bool firstInit = (lua_type(L, -1) == LUA_TNIL); lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath);
lua_pop(L, 1); bool firstInit = (lua_type(L, -1) == LUA_TNIL);
lua_pop(L, 1);
// create mod's "global" table // create mod's "global" table
if (firstInit) { if (firstInit) {
lua_newtable(L); // create _ENV tables lua_newtable(L); // create _ENV tables
lua_newtable(L); // create metatable lua_newtable(L); // create metatable
lua_getglobal(L, "_G"); // get global table lua_getglobal(L, "_G"); // get global table
// remove certain default functions // remove certain default functions
lua_pushstring(L, "load"); lua_pushnil(L); lua_settable(L, -3); 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, "loadfile"); lua_pushnil(L); lua_settable(L, -3);
lua_pushstring(L, "loadstring"); 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, "collectgarbage"); lua_pushnil(L); lua_settable(L, -3);
lua_pushstring(L, "dofile"); lua_pushnil(L); lua_settable(L, -3); lua_pushstring(L, "dofile"); lua_pushnil(L); lua_settable(L, -3);
// set global as the metatable // set global as the metatable
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
// push to registry with path as name (must be unique) // push to registry with path as name (must be unique)
lua_setfield(L, LUA_REGISTRYINDEX, mod->relativePath); lua_setfield(L, LUA_REGISTRYINDEX, mod->relativePath);
} }
// load mod's "global" table // load mod's "global" table
lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath);
lua_setupvalue(L, 1, 1); // set upvalue (_ENV) lua_setupvalue(L, 1, 1); // set upvalue (_ENV)
// load per-file globals // load per-file globals
if (firstInit) { if (firstInit) {
smlua_sync_table_init_globals(mod->relativePath, remoteIndex); smlua_sync_table_init_globals(mod->relativePath, remoteIndex);
smlua_cobject_init_per_file_globals(mod->relativePath); 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 // run chunks
LOG_INFO("Executing '%s'", file->relativePath); 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); LOG_LUA("Failed to execute lua script '%s'.", file->cachedPath);
} }
gLuaInitializingScript = 0; gLuaInitializingScript = 0;
} }
@ -304,6 +323,7 @@ void smlua_init(void) {
smlua_bind_functions(); smlua_bind_functions();
smlua_bind_functions_autogen(); smlua_bind_functions_autogen();
smlua_bind_sync_table(); smlua_bind_sync_table();
smlua_init_require_system();
extern char gSmluaConstants[]; extern char gSmluaConstants[];
smlua_exec_str(gSmluaConstants); smlua_exec_str(gSmluaConstants);
@ -324,12 +344,22 @@ void smlua_init(void) {
gPcDebug.lastModRun = gLuaActiveMod; gPcDebug.lastModRun = gLuaActiveMod;
for (int j = 0; j < mod->fileCount; j++) { for (int j = 0; j < mod->fileCount; j++) {
struct ModFile* file = &mod->files[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"))) { if (!(str_ends_with(file->relativePath, ".lua") || str_ends_with(file->relativePath, ".luac"))) {
continue; 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; gLuaActiveMod = NULL;
gLuaActiveModFile = NULL;
gLuaLoadingMod = NULL; gLuaLoadingMod = NULL;
} }
@ -374,5 +404,6 @@ void smlua_shutdown(void) {
} }
gLuaLoadingMod = NULL; gLuaLoadingMod = NULL;
gLuaActiveMod = NULL; gLuaActiveMod = NULL;
gLuaActiveModFile = NULL;
gLuaLastHookMod = NULL; gLuaLastHookMod = NULL;
} }

View file

@ -38,6 +38,7 @@ extern u8 gLuaInitializingScript;
extern u8 gSmLuaSuppressErrors; extern u8 gSmLuaSuppressErrors;
extern struct Mod* gLuaLoadingMod; extern struct Mod* gLuaLoadingMod;
extern struct Mod* gLuaActiveMod; extern struct Mod* gLuaActiveMod;
extern struct ModFile* gLuaActiveModFile;
extern struct Mod* gLuaLastHookMod; extern struct Mod* gLuaLastHookMod;
void smlua_mod_error(void); 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); int smlua_pcall(lua_State* L, int nargs, int nresults, int errfunc);
void smlua_exec_file(const char* path); void smlua_exec_file(const char* path);
void smlua_exec_str(const char* str); 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_init(void);
void smlua_update(void); void smlua_update(void);

View file

@ -475,6 +475,7 @@ int smlua_func_texture_override_reset(lua_State* L) {
struct LuaLevelScriptParse { struct LuaLevelScriptParse {
int reference; int reference;
struct Mod* mod; struct Mod* mod;
struct ModFile* modFile;
}; };
struct LuaLevelScriptParse sLevelScriptParse = { 0 }; struct LuaLevelScriptParse sLevelScriptParse = { 0 };
@ -635,7 +636,7 @@ s32 smlua_func_level_script_parse_callback(u8 type, void *cmd) {
} }
// call the callback // 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); LOG_LUA("Failed to call the callback behaviors: %u", type);
return 0; return 0;
} }
@ -664,6 +665,7 @@ void smlua_func_level_script_parse(lua_State* L) {
preprocess->reference = ref; preprocess->reference = ref;
preprocess->mod = gLuaActiveMod; preprocess->mod = gLuaActiveMod;
preprocess->modFile = gLuaActiveModFile;
void *script = dynos_level_get_script(levelNum); void *script = dynos_level_get_script(levelNum);
if (script == NULL) { if (script == NULL) {

View file

@ -15,7 +15,7 @@ bool smlua_call_event_hooks_HOOK_UPDATE() {
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_UPDATE]);
continue; continue;
} }
@ -45,7 +45,7 @@ bool smlua_call_event_hooks_HOOK_MARIO_UPDATE(struct MarioState *m) {
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MARIO_UPDATE]);
continue; continue;
} }
@ -75,7 +75,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_MARIO_UPDATE(struct MarioState *m) {
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_MARIO_UPDATE]);
continue; continue;
} }
@ -105,7 +105,7 @@ bool smlua_call_event_hooks_HOOK_ON_SET_MARIO_ACTION(struct MarioState *m) {
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SET_MARIO_ACTION]);
continue; continue;
} }
@ -140,7 +140,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_PHYS_STEP(struct MarioState *m, s32 step
lua_pushinteger(L, stepArg); lua_pushinteger(L, stepArg);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_PHYS_STEP]);
continue; continue;
} }
@ -185,7 +185,7 @@ bool smlua_call_event_hooks_HOOK_ALLOW_PVP_ATTACK(struct MarioState *attacker, s
lua_pushinteger(L, interaction); lua_pushinteger(L, interaction);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ALLOW_PVP_ATTACK]);
continue; continue;
} }
@ -229,7 +229,7 @@ bool smlua_call_event_hooks_HOOK_ON_PVP_ATTACK(struct MarioState *attacker, stru
lua_pushinteger(L, interaction); lua_pushinteger(L, interaction);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PVP_ATTACK]);
continue; continue;
} }
@ -259,7 +259,7 @@ bool smlua_call_event_hooks_HOOK_ON_PLAYER_CONNECTED(struct MarioState *m) {
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PLAYER_CONNECTED]);
continue; continue;
} }
@ -289,7 +289,7 @@ bool smlua_call_event_hooks_HOOK_ON_PLAYER_DISCONNECTED(struct MarioState *m) {
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PLAYER_DISCONNECTED]);
continue; continue;
} }
@ -325,7 +325,7 @@ bool smlua_call_event_hooks_HOOK_ALLOW_INTERACT(struct MarioState *m, struct Obj
lua_pushinteger(L, interactType); lua_pushinteger(L, interactType);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ALLOW_INTERACT]);
continue; continue;
} }
@ -369,7 +369,7 @@ bool smlua_call_event_hooks_HOOK_ON_INTERACT(struct MarioState *m, struct Object
lua_pushboolean(L, interactValue); lua_pushboolean(L, interactValue);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_INTERACT]);
continue; continue;
} }
@ -408,7 +408,7 @@ bool smlua_call_event_hooks_HOOK_ON_LEVEL_INIT(u8 warpType, s16 levelNum, u8 are
lua_pushinteger(L, warpArg); lua_pushinteger(L, warpArg);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_LEVEL_INIT]);
continue; continue;
} }
@ -447,7 +447,7 @@ bool smlua_call_event_hooks_HOOK_ON_WARP(u8 warpType, s16 levelNum, u8 areaIdx,
lua_pushinteger(L, warpArg); lua_pushinteger(L, warpArg);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_WARP]);
continue; continue;
} }
@ -471,7 +471,7 @@ bool smlua_call_event_hooks_HOOK_ON_SYNC_VALID() {
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SYNC_VALID]);
continue; 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); smlua_push_object(L, LOT_OBJECT, obj, NULL);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_OBJECT_UNLOAD]);
continue; 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); smlua_push_object(L, LOT_OBJECT, obj, NULL);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SYNC_OBJECT_UNLOAD]);
continue; continue;
} }
@ -552,7 +552,7 @@ bool smlua_call_event_hooks_HOOK_ON_PAUSE_EXIT(bool usedExitToCastle, bool *allo
lua_pushboolean(L, usedExitToCastle); lua_pushboolean(L, usedExitToCastle);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PAUSE_EXIT]);
continue; 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]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_GET_STAR_COLLECTION_DIALOG]);
continue; continue;
} }
@ -618,7 +618,7 @@ bool smlua_call_event_hooks_HOOK_ON_SET_CAMERA_MODE(struct Camera *c, s16 mode,
lua_pushinteger(L, frames); lua_pushinteger(L, frames);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SET_CAMERA_MODE]);
continue; 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); smlua_push_object(L, LOT_OBJECT, obj, NULL);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_OBJECT_RENDER]);
continue; continue;
} }
@ -680,7 +680,7 @@ bool smlua_call_event_hooks_HOOK_ON_DEATH(struct MarioState *m, bool *allowDeath
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_DEATH]);
continue; continue;
} }
@ -715,7 +715,7 @@ bool smlua_call_event_hooks_HOOK_ON_PACKET_RECEIVE(s32 modIndex, s32 valueIndex)
lua_pushinteger(L, valueIndex); lua_pushinteger(L, valueIndex);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PACKET_RECEIVE]);
continue; continue;
} }
@ -741,7 +741,7 @@ bool smlua_call_event_hooks_HOOK_USE_ACT_SELECT(s32 levelNum, bool *useActSelect
lua_pushinteger(L, levelNum); lua_pushinteger(L, levelNum);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_USE_ACT_SELECT]);
continue; continue;
} }
@ -774,7 +774,7 @@ bool smlua_call_event_hooks_HOOK_ON_CHANGE_CAMERA_ANGLE(s32 camAngleType, bool *
lua_pushinteger(L, camAngleType); lua_pushinteger(L, camAngleType);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_CHANGE_CAMERA_ANGLE]);
continue; continue;
} }
@ -806,7 +806,7 @@ bool smlua_call_event_hooks_HOOK_ON_SCREEN_TRANSITION(s32 transitionType, bool *
lua_pushinteger(L, transitionType); lua_pushinteger(L, transitionType);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SCREEN_TRANSITION]);
continue; continue;
} }
@ -844,7 +844,7 @@ bool smlua_call_event_hooks_HOOK_ALLOW_HAZARD_SURFACE(struct MarioState *m, s32
lua_pushinteger(L, hazardType); lua_pushinteger(L, hazardType);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ALLOW_HAZARD_SURFACE]);
continue; continue;
} }
@ -882,7 +882,7 @@ bool smlua_call_event_hooks_HOOK_ON_CHAT_MESSAGE(struct MarioState *m, const cha
lua_pushstring(L, message); lua_pushstring(L, message);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_CHAT_MESSAGE]);
continue; continue;
} }
@ -920,7 +920,7 @@ bool smlua_call_event_hooks_HOOK_OBJECT_SET_MODEL(struct Object *obj, s32 modelI
lua_pushinteger(L, modelExtendedId); lua_pushinteger(L, modelExtendedId);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_OBJECT_SET_MODEL]);
continue; continue;
} }
@ -952,7 +952,7 @@ bool smlua_call_event_hooks_HOOK_CHARACTER_SOUND(struct MarioState *m, enum Char
lua_pushinteger(L, characterSound); lua_pushinteger(L, characterSound);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_CHARACTER_SOUND]);
continue; continue;
} }
@ -994,7 +994,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_SET_MARIO_ACTION(struct MarioState *m, u
lua_pushinteger(L, actionArg); lua_pushinteger(L, actionArg);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_SET_MARIO_ACTION]);
continue; continue;
} }
@ -1023,7 +1023,7 @@ bool smlua_call_event_hooks_HOOK_JOINED_GAME() {
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_JOINED_GAME]);
continue; 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); smlua_push_object(L, LOT_OBJECT, obj, NULL);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_OBJECT_ANIM_UPDATE]);
continue; continue;
} }
@ -1077,7 +1077,7 @@ bool smlua_call_event_hooks_HOOK_ON_DIALOG(s32 dialogID, bool *openDialogBox, co
lua_pushinteger(L, dialogID); lua_pushinteger(L, dialogID);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_DIALOG]);
continue; continue;
} }
@ -1111,7 +1111,7 @@ bool smlua_call_event_hooks_HOOK_ON_EXIT() {
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_EXIT]);
continue; continue;
} }
@ -1137,7 +1137,7 @@ bool smlua_call_event_hooks_HOOK_DIALOG_SOUND(s32 speaker, s32 *speakerOverride)
lua_pushinteger(L, speaker); lua_pushinteger(L, speaker);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_DIALOG_SOUND]);
continue; continue;
} }
@ -1173,7 +1173,7 @@ bool smlua_call_event_hooks_HOOK_ON_COLLIDE_LEVEL_BOUNDS(struct MarioState *m) {
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_COLLIDE_LEVEL_BOUNDS]);
continue; continue;
} }
@ -1203,7 +1203,7 @@ bool smlua_call_event_hooks_HOOK_MIRROR_MARIO_RENDER(struct GraphNodeObject *mir
lua_pushinteger(L, playerIndex); lua_pushinteger(L, playerIndex);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MIRROR_MARIO_RENDER]);
continue; continue;
} }
@ -1232,7 +1232,7 @@ bool smlua_call_event_hooks_HOOK_MARIO_OVERRIDE_PHYS_STEP_DEFACTO_SPEED(struct M
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MARIO_OVERRIDE_PHYS_STEP_DEFACTO_SPEED]);
continue; 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); smlua_push_object(L, LOT_OBJECT, obj, NULL);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_OBJECT_LOAD]);
continue; continue;
} }
@ -1294,7 +1294,7 @@ bool smlua_call_event_hooks_HOOK_ON_PLAY_SOUND(s32 soundBits, Vec3f pos, s32 *so
smlua_new_vec3f(pos); smlua_new_vec3f(pos);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_PLAY_SOUND]);
continue; continue;
} }
@ -1332,7 +1332,7 @@ bool smlua_call_event_hooks_HOOK_ON_SEQ_LOAD(u32 seqPlayer, u32 seqId, s32 loadA
lua_pushinteger(L, loadAsync); lua_pushinteger(L, loadAsync);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_SEQ_LOAD]);
continue; continue;
} }
@ -1374,7 +1374,7 @@ bool smlua_call_event_hooks_HOOK_ON_ATTACK_OBJECT(struct MarioState *m, struct O
lua_pushinteger(L, interaction); lua_pushinteger(L, interaction);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_ATTACK_OBJECT]);
continue; continue;
} }
@ -1401,7 +1401,7 @@ bool smlua_call_event_hooks_HOOK_ON_LANGUAGE_CHANGED(const char *langName) {
lua_pushstring(L, langName); lua_pushstring(L, langName);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_LANGUAGE_CHANGED]);
continue; continue;
} }
@ -1425,7 +1425,7 @@ bool smlua_call_event_hooks_HOOK_ON_MODS_LOADED() {
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_MODS_LOADED]);
continue; continue;
} }
@ -1449,7 +1449,7 @@ bool smlua_call_event_hooks_HOOK_ON_DJUI_THEME_CHANGED() {
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_DJUI_THEME_CHANGED]);
continue; continue;
} }
@ -1479,7 +1479,7 @@ bool smlua_call_event_hooks_HOOK_ON_GEO_PROCESS(struct GraphNode *node, s32 matS
lua_pushinteger(L, matStackIndex); lua_pushinteger(L, matStackIndex);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_GEO_PROCESS]);
continue; continue;
} }
@ -1509,7 +1509,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_GEO_PROCESS(struct GraphNode *node, s32
lua_pushinteger(L, matStackIndex); lua_pushinteger(L, matStackIndex);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_GEO_PROCESS]);
continue; continue;
} }
@ -1539,7 +1539,7 @@ bool smlua_call_event_hooks_HOOK_ON_GEO_PROCESS_CHILDREN(struct GraphNode *paren
lua_pushinteger(L, matStackIndex); lua_pushinteger(L, matStackIndex);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_GEO_PROCESS_CHILDREN]);
continue; continue;
} }
@ -1569,7 +1569,7 @@ bool smlua_call_event_hooks_HOOK_MARIO_OVERRIDE_GEOMETRY_INPUTS(struct MarioStat
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MARIO_OVERRIDE_GEOMETRY_INPUTS]);
continue; continue;
} }
@ -1604,7 +1604,7 @@ bool smlua_call_event_hooks_HOOK_ON_INTERACTIONS(struct MarioState *m) {
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_INTERACTIONS]);
continue; continue;
} }
@ -1637,7 +1637,7 @@ bool smlua_call_event_hooks_HOOK_ALLOW_FORCE_WATER_ACTION(struct MarioState *m,
lua_pushboolean(L, isInWaterAction); lua_pushboolean(L, isInWaterAction);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ALLOW_FORCE_WATER_ACTION]);
continue; continue;
} }
@ -1677,7 +1677,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_WARP(s16 destLevel, s16 destArea, s16 de
lua_pushinteger(L, arg); lua_pushinteger(L, arg);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_BEFORE_WARP]);
continue; continue;
} }
@ -1735,7 +1735,7 @@ bool smlua_call_event_hooks_HOOK_ON_INSTANT_WARP(u8 areaIdx, u8 nodeId, Vec3s di
smlua_new_vec3s(displacement); smlua_new_vec3s(displacement);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_INSTANT_WARP]);
continue; continue;
} }
@ -1767,7 +1767,7 @@ bool smlua_call_event_hooks_HOOK_MARIO_OVERRIDE_FLOOR_CLASS(struct MarioState *m
lua_pushinteger(L, floorClass); lua_pushinteger(L, floorClass);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_MARIO_OVERRIDE_FLOOR_CLASS]);
continue; continue;
} }
@ -1803,7 +1803,7 @@ bool smlua_call_event_hooks_HOOK_ON_ADD_SURFACE(struct Surface *surface, bool dy
lua_pushboolean(L, dynamic); lua_pushboolean(L, dynamic);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_ADD_SURFACE]);
continue; continue;
} }
@ -1827,7 +1827,7 @@ bool smlua_call_event_hooks_HOOK_ON_CLEAR_AREAS() {
lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_CLEAR_AREAS]);
continue; continue;
} }

View file

@ -34,6 +34,7 @@ u64* gBehaviorOffset = &gPcDebug.bhvOffset;
struct LuaHookedEvent { struct LuaHookedEvent {
int reference[MAX_HOOKED_REFERENCES]; int reference[MAX_HOOKED_REFERENCES];
struct Mod* mod[MAX_HOOKED_REFERENCES]; struct Mod* mod[MAX_HOOKED_REFERENCES];
struct ModFile* modFile[MAX_HOOKED_REFERENCES];
int count; int count;
}; };
@ -46,11 +47,14 @@ static const char* sLuaHookedEventTypeName[] = {
"HOOK_MAX" "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 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; gLuaActiveMod = activeMod;
gLuaActiveModFile = activeModFile;
gLuaLastHookMod = activeMod; gLuaLastHookMod = activeMod;
gPcDebug.lastModRun = 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); lua_profiler_stop_counter(activeMod);
gLuaActiveMod = prev; gLuaActiveMod = prevActiveMod;
gLuaActiveModFile = prevActiveModFile;
return rc; 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]); lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[hookType]);
} else { } else {
hookResult = true; hookResult = true;
@ -170,7 +175,7 @@ bool smlua_call_event_hooks_HOOK_ON_NAMETAGS_RENDER(s32 playerIndex, Vec3f pos,
smlua_new_vec3f(pos); smlua_new_vec3f(pos);
// call the callback // 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]); LOG_LUA("Failed to call the callback for hook %s", sLuaHookedEventTypeName[HOOK_ON_NAMETAGS_RENDER]);
continue; continue;
} }
@ -223,6 +228,7 @@ struct LuaHookedMarioAction {
u32 interactionType; u32 interactionType;
int actionHookRefs[ACTION_HOOK_MAX]; int actionHookRefs[ACTION_HOOK_MAX];
struct Mod* mod; struct Mod* mod;
struct ModFile* modFile;
}; };
#define MAX_HOOKED_ACTIONS (ACT_NUM_GROUPS * ACT_NUM_ACTIONS_PER_GROUP) #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->action = action;
hooked->interactionType = interactionType; hooked->interactionType = interactionType;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
sHookedMarioActionsCount++; sHookedMarioActionsCount++;
return 1; return 1;
@ -334,7 +341,7 @@ bool smlua_call_action_hook(enum LuaActionHookType hookType, struct MarioState*
lua_remove(L, -2); lua_remove(L, -2);
// call the callback // 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); LOG_LUA("Failed to call the action callback: %u", m->action);
continue; continue;
} }
@ -381,6 +388,7 @@ struct LuaHookedBehavior {
bool replace; bool replace;
bool luaBehavior; bool luaBehavior;
struct Mod* mod; struct Mod* mod;
struct ModFile* modFile;
}; };
#define MAX_HOOKED_BEHAVIORS 1024 #define MAX_HOOKED_BEHAVIORS 1024
@ -474,6 +482,7 @@ int smlua_hook_custom_bhv(BehaviorScript *bhvScript, const char *bhvName) {
hooked->replace = true; hooked->replace = true;
hooked->luaBehavior = false; hooked->luaBehavior = false;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
sHookedBehaviorsCount++; sHookedBehaviorsCount++;
@ -620,6 +629,7 @@ int smlua_hook_behavior(lua_State* L) {
hooked->replace = replaceBehavior; hooked->replace = replaceBehavior;
hooked->luaBehavior = true; hooked->luaBehavior = true;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
sHookedBehaviorsCount++; sHookedBehaviorsCount++;
@ -677,7 +687,7 @@ bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* ob
smlua_push_object(L, LOT_OBJECT, object, NULL); smlua_push_object(L, LOT_OBJECT, object, NULL);
// call the callback // 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); LOG_LUA("Failed to call the behavior callback: %u", hooked->behaviorId);
return true; return true;
} }
@ -698,6 +708,7 @@ struct LuaHookedChatCommand {
char* description; char* description;
int reference; int reference;
struct Mod* mod; struct Mod* mod;
struct ModFile* modFile;
}; };
#define MAX_HOOKED_CHAT_COMMANDS 512 #define MAX_HOOKED_CHAT_COMMANDS 512
@ -742,6 +753,7 @@ int smlua_hook_chat_command(lua_State* L) {
hooked->description = strdup(description); hooked->description = strdup(description);
hooked->reference = ref; hooked->reference = ref;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
sHookedChatCommandsCount++; sHookedChatCommandsCount++;
return 1; return 1;
@ -805,7 +817,7 @@ bool smlua_call_chat_command_hook(char* command) {
lua_pushstring(L, params); lua_pushstring(L, params);
// call the callback // 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); LOG_LUA("Failed to call the chat command callback: %s", command);
continue; continue;
} }
@ -1108,6 +1120,7 @@ int smlua_hook_mod_menu_text(lua_State* L) {
hooked->sliderMax = 0; hooked->sliderMax = 0;
hooked->reference = 0; hooked->reference = 0;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
lua_pushinteger(L, gHookedModMenuElementsCount); lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++; gHookedModMenuElementsCount++;
@ -1146,6 +1159,7 @@ int smlua_hook_mod_menu_button(lua_State* L) {
hooked->sliderMax = 0; hooked->sliderMax = 0;
hooked->reference = ref; hooked->reference = ref;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
lua_pushinteger(L, gHookedModMenuElementsCount); lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++; gHookedModMenuElementsCount++;
@ -1190,6 +1204,7 @@ int smlua_hook_mod_menu_checkbox(lua_State* L) {
hooked->sliderMax = 0; hooked->sliderMax = 0;
hooked->reference = ref; hooked->reference = ref;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
lua_pushinteger(L, gHookedModMenuElementsCount); lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++; gHookedModMenuElementsCount++;
@ -1246,6 +1261,7 @@ int smlua_hook_mod_menu_slider(lua_State* L) {
hooked->sliderMax = sliderMax; hooked->sliderMax = sliderMax;
hooked->reference = ref; hooked->reference = ref;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
lua_pushinteger(L, gHookedModMenuElementsCount); lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++; gHookedModMenuElementsCount++;
@ -1297,6 +1313,7 @@ int smlua_hook_mod_menu_inputbox(lua_State* L) {
hooked->sliderMax = 0; hooked->sliderMax = 0;
hooked->reference = ref; hooked->reference = ref;
hooked->mod = gLuaActiveMod; hooked->mod = gLuaActiveMod;
hooked->modFile = gLuaActiveModFile;
lua_pushinteger(L, gHookedModMenuElementsCount); lua_pushinteger(L, gHookedModMenuElementsCount);
gHookedModMenuElementsCount++; gHookedModMenuElementsCount++;
@ -1428,7 +1445,7 @@ void smlua_call_mod_menu_element_hook(struct LuaHookedModMenuElement* hooked, in
} }
// call the callback // 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); LOG_LUA("Failed to call the mod menu element callback: %s", hooked->name);
return; return;
} }
@ -1453,6 +1470,7 @@ void smlua_clear_hooks(void) {
struct LuaHookedMarioAction* hooked = &sHookedMarioActions[i]; struct LuaHookedMarioAction* hooked = &sHookedMarioActions[i];
hooked->action = 0; hooked->action = 0;
hooked->mod = NULL; hooked->mod = NULL;
hooked->modFile = NULL;
memset(hooked->actionHookRefs, 0, sizeof(hooked->actionHookRefs)); memset(hooked->actionHookRefs, 0, sizeof(hooked->actionHookRefs));
} }
sHookedMarioActionsCount = 0; sHookedMarioActionsCount = 0;
@ -1467,6 +1485,7 @@ void smlua_clear_hooks(void) {
hooked->reference = 0; hooked->reference = 0;
hooked->mod = NULL; hooked->mod = NULL;
hooked->modFile = NULL;
} }
sHookedChatCommandsCount = 0; sHookedChatCommandsCount = 0;
@ -1482,6 +1501,7 @@ void smlua_clear_hooks(void) {
hooked->sliderMax = 0; hooked->sliderMax = 0;
hooked->reference = 0; hooked->reference = 0;
hooked->mod = NULL; hooked->mod = NULL;
hooked->modFile = NULL;
} }
gHookedModMenuElementsCount = 0; gHookedModMenuElementsCount = 0;
@ -1510,6 +1530,7 @@ void smlua_clear_hooks(void) {
hooked->replace = false; hooked->replace = false;
hooked->luaBehavior = false; hooked->luaBehavior = false;
hooked->mod = NULL; hooked->mod = NULL;
hooked->modFile = NULL;
} }
sHookedBehaviorsCount = 0; sHookedBehaviorsCount = 0;
memset(gLuaMarioActionIndex, 0, sizeof(gLuaMarioActionIndex)); memset(gLuaMarioActionIndex, 0, sizeof(gLuaMarioActionIndex));

View file

@ -117,6 +117,7 @@ struct LuaHookedModMenuElement {
u32 sliderMax; u32 sliderMax;
int reference; int reference;
struct Mod* mod; struct Mod* mod;
struct ModFile* modFile;
}; };
extern u32 gLuaMarioActionIndex[]; 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); 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); 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); bool smlua_call_action_hook(enum LuaActionHookType hookType, struct MarioState* m, s32* returnValue);
u32 smlua_get_action_interaction_type(struct MarioState* m); u32 smlua_get_action_interaction_type(struct MarioState* m);

180
src/pc/lua/smlua_require.c Normal file
View file

@ -0,0 +1,180 @@
#include <stdbool.h>
#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);
}
}

View file

@ -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

View file

@ -143,14 +143,20 @@ static void smlua_sync_table_call_hook(int syncTableIndex, int keyIndex, int pre
struct Mod* mod = gActiveMods.entries[modRemoteIndex]; struct Mod* mod = gActiveMods.entries[modRemoteIndex];
// call hook // call hook
struct Mod* prev = gLuaActiveMod; struct Mod* prevActiveMod = gLuaActiveMod;
struct ModFile* prevActiveModFile = gLuaActiveModFile;
gLuaActiveMod = mod; gLuaActiveMod = mod;
gLuaActiveModFile = NULL;
gLuaLastHookMod = mod; gLuaLastHookMod = mod;
gPcDebug.lastModRun = mod; gPcDebug.lastModRun = mod;
if (0 != smlua_pcall(L, 3, 0, 0)) { if (0 != smlua_pcall(L, 3, 0, 0)) {
LOG_LUA_LINE("Failed to call the hook_on_changed callback"); 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 lua_pop(L, 1); // pop _hook_on_changed's value

View file

@ -1,3 +1,4 @@
#include <sys/stat.h>
#include "mod.h" #include "mod.h"
#include "mods.h" #include "mods.h"
#include "mods_utils.h" #include "mods_utils.h"
@ -39,9 +40,13 @@ static void mod_activate_bin(struct Mod* mod, struct ModFile* file) {
g++; g++;
} }
// get mod file index
s32 fileIndex = (file - &mod->files[0]);
if (fileIndex < 0 || fileIndex >= mod->fileCount) { fileIndex = 0; }
// Add to custom actors // Add to custom actors
LOG_INFO("Activating DynOS bin: '%s', '%s'", file->cachedPath, geoName); 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) { 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; 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 // concat directory
char dirPath[SYS_MAX_PATH] = { 0 }; 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 (strlen(subDir) > 0) {
if (snprintf(relativePath, SYS_MAX_PATH - 1, "%s/%s", subDir, dir->d_name) < 0) { if (snprintf(relativePath, SYS_MAX_PATH - 1, "%s/%s", subDir, dir->d_name) < 0) {
LOG_ERROR("Could not concat %s path!", subDir); LOG_ERROR("Could not concat %s path!", subDir);
closedir(d);
return false; return false;
} }
} else { } else {
if (snprintf(relativePath, SYS_MAX_PATH - 1, "%s", dir->d_name) < 0) { if (snprintf(relativePath, SYS_MAX_PATH - 1, "%s", dir->d_name) < 0) {
LOG_ERROR("Could not concat %s path!", subDir); LOG_ERROR("Could not concat %s path!", subDir);
closedir(d);
return false; 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 // only consider certain file types
bool fileTypeMatch = false; bool fileTypeMatch = false;
const char** ft = fileTypes; const char** ft = fileTypes;
@ -325,37 +348,37 @@ static bool mod_load_files(struct Mod* mod, char* modName, char* fullPath) {
// deal with mod directory // deal with mod directory
{ {
const char* fileTypes[] = { ".lua", ".luac", NULL }; 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 // deal with actors directory
{ {
const char* fileTypes[] = { ".bin", ".col", NULL }; 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 // deal with behaviors directory
{ {
const char* fileTypes[] = { ".bhv", NULL }; 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 // deal with textures directory
{ {
const char* fileTypes[] = { ".tex", NULL }; 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 // deal with levels directory
{ {
const char* fileTypes[] = { ".lvl", NULL }; 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 // deal with sound directory
{ {
const char* fileTypes[] = { ".m64", ".mp3", ".aiff", ".ogg", NULL }; 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; return true;

View file

@ -234,6 +234,20 @@ void path_get_folder(char* path, char* outpath) {
*o = '\0'; *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) { bool directory_sanity_check(struct dirent* dir, char* dirPath, char* outPath) {
// skip non-portable filenames // skip non-portable filenames
if (!fs_sys_filename_is_portable(dir->d_name)) { return false; } if (!fs_sys_filename_is_portable(dir->d_name)) { return false; }

View file

@ -20,6 +20,8 @@ void normalize_path(char* path);
bool concat_path(char* destination, char* path, char* fname); bool concat_path(char* destination, char* path, char* fname);
char* path_basename(char* path); char* path_basename(char* path);
void path_get_folder(char* path, char* outpath); 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); bool directory_sanity_check(struct dirent* dir, char* dirPath, char* outPath);
#endif #endif