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 = """
// 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}

View file

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

View file

@ -572,6 +572,7 @@ struct GfxData : NoCopy {
s32 mErrorCount = 0;
u32 mModelIdentifier = 0;
s32 mModIndex = 0;
s32 mModFileIndex = 0;
SysPath mPackFolder;
Array<void *> mPointerList;
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();
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<Pair<const char *, GfxData *>> &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();

View file

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

View file

@ -31,7 +31,7 @@ std::map<const void *, ActorGfx> &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;

View file

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

View file

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

View file

@ -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);
}

View file

@ -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,10 +235,12 @@ 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);
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);
@ -270,12 +276,25 @@ static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteI
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;
}

View file

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

View file

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

View file

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

View file

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

View file

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

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];
// 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

View file

@ -1,3 +1,4 @@
#include <sys/stat.h>
#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;

View file

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

View file

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