From 9c7036afe3aa59dd95665be173c34c51307f4ebe Mon Sep 17 00:00:00 2001 From: MysterD Date: Fri, 4 Mar 2022 18:16:54 -0800 Subject: [PATCH] Add define_custom_obj_fields() to Lua --- autogen/lua_constants/built-in.lua | 4 +- src/pc/lua/smlua.c | 7 + src/pc/lua/smlua.h | 2 + src/pc/lua/smlua_cobject.c | 231 +++++++++++++++++++++++++-- src/pc/lua/smlua_cobject.h | 1 + src/pc/lua/smlua_constants_autogen.c | 4 +- src/pc/lua/smlua_functions.c | 4 + src/pc/lua/smlua_hooks.c | 60 +++++-- src/pc/lua/smlua_sync_table.c | 15 ++ 9 files changed, 301 insertions(+), 27 deletions(-) diff --git a/autogen/lua_constants/built-in.lua b/autogen/lua_constants/built-in.lua index 004de1ab..27f9326e 100644 --- a/autogen/lua_constants/built-in.lua +++ b/autogen/lua_constants/built-in.lua @@ -1,9 +1,9 @@ _CObject = { __index = function (t,k) - return _get_field(t['_lot'], t['_pointer'], k) + return _get_field(t['_lot'], t['_pointer'], k, t) end, __newindex = function (t,k,v) - _set_field(t['_lot'], t['_pointer'], k, v) + _set_field(t['_lot'], t['_pointer'], k, v, t) end, __eq = function (a, b) return a['_pointer'] == b['_pointer'] and a['_lot'] == b['_lot'] and a['_pointer'] ~= nil and a['_lot'] ~= nil diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index bb9f9869..8251bf18 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -3,6 +3,8 @@ lua_State* gLuaState = NULL; u8 gLuaInitializingScript = 0; +struct ModListEntry* gLuaLoadingEntry = NULL; +struct ModListEntry* gLuaActiveEntry = NULL; static void smlua_exec_file(char* path) { lua_State* L = gLuaState; @@ -46,6 +48,7 @@ static void smlua_load_script(char* path, u16 remoteIndex) { // load per-file globals smlua_sync_table_init_globals(path, remoteIndex); + smlua_cobject_init_per_file_globals(path); // run chunks if (lua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK) { @@ -97,7 +100,11 @@ void smlua_init(void) { struct ModListEntry* entry = &table->entries[i]; if (!entry->enabled) { continue; } LOG_INFO(" %s", entry->path); + gLuaLoadingEntry = entry; + gLuaActiveEntry = entry; smlua_load_script(entry->path, entry->remoteIndex); + gLuaActiveEntry = NULL; + gLuaLoadingEntry = NULL; } } diff --git a/src/pc/lua/smlua.h b/src/pc/lua/smlua.h index 6802c666..d0b833d3 100644 --- a/src/pc/lua/smlua.h +++ b/src/pc/lua/smlua.h @@ -31,6 +31,8 @@ extern lua_State* gLuaState; extern u8 gLuaInitializingScript; +extern struct ModListEntry* gLuaLoadingEntry; +extern struct ModListEntry* gLuaActiveEntry; void smlua_init(void); void smlua_update(void); diff --git a/src/pc/lua/smlua_cobject.c b/src/pc/lua/smlua_cobject.c index 4bb58c7a..b877e435 100644 --- a/src/pc/lua/smlua_cobject.c +++ b/src/pc/lua/smlua_cobject.c @@ -6,7 +6,9 @@ #include "audio/external.h" #include "object_fields.h" #include "pc/djui/djui_hud_utils.h" +#include "pc/lua/smlua.h" #include "pc/lua/smlua_anim_utils.h" +#include "pc/mod_list.h" #define LUA_VEC3S_FIELD_COUNT 3 static struct LuaObjectField sVec3sFields[LUA_VEC3S_FIELD_COUNT] = { @@ -69,8 +71,183 @@ bool smlua_valid_lvt(u16 lvt) { return (lvt < LVT_MAX); } + ////////////////// + // obj behavior // +////////////////// + +static int smlua_func_define_custom_obj_fields(lua_State* L) { + LUA_STACK_CHECK_BEGIN(); + if (!smlua_functions_valid_param_count(L, 1)) { return 0; } + + if (lua_type(L, 1) != LUA_TTABLE) { + LOG_LUA("Invalid parameter for define_custom_obj_fields()"); + return 0; + } + + if (gLuaLoadingEntry == NULL) { + LOG_LUA("define_custom_obj_fields() can only be called on load."); + return 0; + } + + // get _custom_object_fields + lua_getglobal(L, "_G"); // get global table + lua_getfield(L, LUA_REGISTRYINDEX, gLuaLoadingEntry->path); // push file's "global" table + int fileGlobalIndex = lua_gettop(L); + lua_getfield(L, fileGlobalIndex, "_custom_object_fields"); + lua_remove(L, -2); // remove file's "global" table + lua_remove(L, -2); // remove global table + int customObjectFieldsIndex = lua_gettop(L); + + u32 fieldIndex = 0x1B; + + // table is in the stack at index 't' + lua_pushnil(L); // first key + int iterationTop = lua_gettop(L); + while (lua_next(L, 1) != 0) { + int keyIndex = lua_gettop(L) - 1; + int valueIndex = lua_gettop(L) - 0; + // uses 'key' (at index -2) and 'value' (at index -1) + if (lua_type(L, keyIndex) != LUA_TSTRING) { + LOG_LUA("Invalid key type for define_custom_obj_fields() : %u", lua_type(L, keyIndex)); + lua_settop(L, iterationTop); + continue; + } + + if (lua_type(L, valueIndex) != LUA_TSTRING) { + LOG_LUA("Invalid value type for define_custom_obj_fields() : %u", lua_type(L, valueIndex)); + lua_settop(L, iterationTop); + continue; + } + + const char* key = smlua_to_string(L, keyIndex); + if (key[0] != 'o') { + LOG_LUA("Invalid key name for define_custom_obj_fields()"); + lua_settop(L, iterationTop); + continue; + } + + const char* value = smlua_to_string(L, valueIndex); + enum LuaValueType lvt = LVT_U32; + if (!strcmp(value, "u32")) { lvt = LVT_U32; } + else if (!strcmp(value, "s32")) { lvt = LVT_S32; } + else if (!strcmp(value, "f32")) { lvt = LVT_F32; } + else { + LOG_LUA("Invalid value name for define_custom_obj_fields()"); + return 0; + } + + // keep fieldIndex in range + if (fieldIndex < 0x1B) { + fieldIndex = 0x1B; + } else if (fieldIndex > 0x22 && fieldIndex < 0x48) { + fieldIndex = 0x48; + } else if (fieldIndex > 0x4A) { + LOG_LUA("Ran out of custom fields!"); + return 0; + } + + lua_pushvalue(L, customObjectFieldsIndex); + lua_pushvalue(L, keyIndex); + lua_newtable(L); + { + // set fieldIndex + lua_pushstring(L, "_fieldIndex"); + lua_pushinteger(L, fieldIndex); + lua_rawset(L, -3); + + // set lvt + lua_pushstring(L, "_lvt"); + lua_pushinteger(L, lvt); + lua_rawset(L, -3); + } + lua_settable(L, -3); // set _custom_object_fields + + fieldIndex++; + lua_settop(L, iterationTop); + } + + lua_settop(L, iterationTop); + lua_pop(L, 1); // pop key + lua_pop(L, 1); // pop _custom_object_fields + + LUA_STACK_CHECK_END(); + return 1; +} + +static struct LuaObjectField* smlua_get_custom_field(lua_State* L, u32 lot, int keyIndex) { + LUA_STACK_CHECK_BEGIN(); + static struct LuaObjectField lof = { 0 }; + if (lot != LOT_OBJECT) { return NULL; } + + if (gLuaActiveEntry == NULL) { + LOG_LUA("Failed to retrieve active mod entry."); + return NULL; + } + + // get _custom_object_fields + lua_getglobal(L, "_G"); // get global table + lua_getfield(L, LUA_REGISTRYINDEX, gLuaActiveEntry->path); // push file's "global" table + int fileGlobalIndex = lua_gettop(L); + lua_getfield(L, fileGlobalIndex, "_custom_object_fields"); + lua_remove(L, -2); // remove file's "global" table + lua_remove(L, -2); // remove global table + + // get value table from key + lua_pushvalue(L, keyIndex); + lua_rawget(L, -2); + if (lua_type(L, -1) != LUA_TTABLE) { + lua_pop(L, 1); // pop value table + lua_pop(L, 1); // pop _custom_fields + LUA_STACK_CHECK_END(); + return NULL; + } + + // get _fieldIndex + lua_pushstring(L, "_fieldIndex"); + lua_rawget(L, -2); + u32 fieldIndex = smlua_to_integer(L, -1); + lua_pop(L, 1); + bool validFieldIndex = (fieldIndex >= 0x1B && fieldIndex <= 0x22) || (fieldIndex >= 0x48 && fieldIndex <= 0x4A); + if (!gSmLuaConvertSuccess || !validFieldIndex) { + lua_pop(L, 1); // pop value table + lua_pop(L, 1); // pop _custom_fields + LUA_STACK_CHECK_END(); + return NULL; + } + + // get _lvt + lua_pushstring(L, "_lvt"); + lua_rawget(L, -2); + u32 lvt = smlua_to_integer(L, -1); + lua_pop(L, 1); + bool validLvt = (lvt == LVT_U32 || lvt == LVT_S32 || lvt == LVT_F32); + if (!gSmLuaConvertSuccess || !validLvt) { + lua_pop(L, 1); // pop value table + lua_pop(L, 1); // pop _custom_fields + LUA_STACK_CHECK_END(); + return NULL; + } + + lof.immutable = false; + //lof.key = key; + lof.lot = LOT_NONE; + lof.valueOffset = offsetof(struct Object, rawData.asU32[fieldIndex]); + lof.valueType = lvt; + + lua_pop(L, 1); // pop value table + lua_pop(L, 1); // pop _custom_fields + + LUA_STACK_CHECK_END(); + return &lof; +} + + ///////////////////// + // CObject get/set // +///////////////////// + static int smlua__get_field(lua_State* L) { - if (!smlua_functions_valid_param_count(L, 3)) { return 0; } + LUA_STACK_CHECK_BEGIN(); + if (!smlua_functions_valid_param_count(L, 4)) { return 0; } enum LuaObjectType lot = smlua_to_integer(L, 1); if (!gSmLuaConvertSuccess) { return 0; } @@ -100,12 +277,17 @@ static int smlua__get_field(lua_State* L) { } struct LuaObjectField* data = smlua_get_object_field(lot, key); + if (data == NULL) { + data = smlua_get_custom_field(L, lot, 3); + } if (data == NULL) { LOG_LUA("_get_field on invalid key '%s', lot '%d'", key, lot); smlua_logline(); return 0; } + LUA_STACK_CHECK_END(); + u8* p = ((u8*)(intptr_t)pointer) + data->valueOffset; switch (data->valueType) { case LVT_BOOL: lua_pushboolean(L, *(u8* )p); break; @@ -146,7 +328,8 @@ static int smlua__get_field(lua_State* L) { } static int smlua__set_field(lua_State* L) { - if (!smlua_functions_valid_param_count(L, 4)) { return 0; } + LUA_STACK_CHECK_BEGIN(); + if (!smlua_functions_valid_param_count(L, 5)) { return 0; } enum LuaObjectType lot = smlua_to_integer(L, 1); if (!gSmLuaConvertSuccess) { return 0; } @@ -176,6 +359,9 @@ static int smlua__set_field(lua_State* L) { } struct LuaObjectField* data = smlua_get_object_field(lot, key); + if (data == NULL) { + data = smlua_get_custom_field(L, lot, 3); + } if (data == NULL) { LOG_LUA("_set_field on invalid key '%s'", key); smlua_logline(); @@ -191,17 +377,17 @@ static int smlua__set_field(lua_State* L) { void* valuePointer = NULL; u8* p = ((u8*)(intptr_t)pointer) + data->valueOffset; switch (data->valueType) { - case LVT_BOOL:*(u8*) p = smlua_to_boolean(L, -1); break; - case LVT_U8: *(u8*) p = smlua_to_integer(L, -1); break; - case LVT_U16: *(u16*)p = smlua_to_integer(L, -1); break; - case LVT_U32: *(u32*)p = smlua_to_integer(L, -1); break; - case LVT_S8: *(s8*) p = smlua_to_integer(L, -1); break; - case LVT_S16: *(s16*)p = smlua_to_integer(L, -1); break; - case LVT_S32: *(s32*)p = smlua_to_integer(L, -1); break; - case LVT_F32: *(f32*)p = smlua_to_number(L, -1); break; + case LVT_BOOL:*(u8*) p = smlua_to_boolean(L, 4); break; + case LVT_U8: *(u8*) p = smlua_to_integer(L, 4); break; + case LVT_U16: *(u16*)p = smlua_to_integer(L, 4); break; + case LVT_U32: *(u32*)p = smlua_to_integer(L, 4); break; + case LVT_S8: *(s8*) p = smlua_to_integer(L, 4); break; + case LVT_S16: *(s16*)p = smlua_to_integer(L, 4); break; + case LVT_S32: *(s32*)p = smlua_to_integer(L, 4); break; + case LVT_F32: *(f32*)p = smlua_to_number(L, 4); break; case LVT_COBJECT_P: - valuePointer = smlua_to_cobject(L, -1, data->lot); + valuePointer = smlua_to_cobject(L, 4, data->lot); if (gSmLuaConvertSuccess) { *(u8**)p = valuePointer; } @@ -217,7 +403,7 @@ static int smlua__set_field(lua_State* L) { case LVT_F32_P: case LVT_BEHAVIORSCRIPT_P: case LVT_OBJECTANIMPOINTER_P: - valuePointer = smlua_to_cpointer(L, -1, data->valueType); + valuePointer = smlua_to_cpointer(L, 4, data->valueType); if (gSmLuaConvertSuccess) { *(u8**)p = valuePointer; } @@ -234,9 +420,14 @@ static int smlua__set_field(lua_State* L) { return 0; } + LUA_STACK_CHECK_END(); return 1; } + ////////// + // bind // +////////// + void smlua_cobject_init_globals(void) { lua_State* L = gLuaState; @@ -285,9 +476,25 @@ void smlua_cobject_init_globals(void) { } +void smlua_cobject_init_per_file_globals(char* path) { + lua_State* L = gLuaState; + + lua_getfield(L, LUA_REGISTRYINDEX, path); // push per-file globals + + { + lua_pushstring(L, "_custom_object_fields"); + lua_newtable(L); + lua_settable(L, -3); + } + + lua_pop(L, 1); // pop per-file globals +} + void smlua_bind_cobject(void) { lua_State* L = gLuaState; + smlua_bind_function(L, "define_custom_obj_fields", smlua_func_define_custom_obj_fields); + smlua_bind_function(L, "_get_field", smlua__get_field); smlua_bind_function(L, "_set_field", smlua__set_field); diff --git a/src/pc/lua/smlua_cobject.h b/src/pc/lua/smlua_cobject.h index 0c863c54..53c22a9b 100644 --- a/src/pc/lua/smlua_cobject.h +++ b/src/pc/lua/smlua_cobject.h @@ -55,6 +55,7 @@ struct LuaObjectTable { bool smlua_valid_lot(u16 lot); bool smlua_valid_lvt(u16 lvt); void smlua_cobject_init_globals(void); +void smlua_cobject_init_per_file_globals(char* path); void smlua_bind_cobject(void); #endif \ No newline at end of file diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 5a02b3f1..06391f95 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -1,10 +1,10 @@ char gSmluaConstants[] = "" "_CObject = {\n" " __index = function (t,k)\n" -" return _get_field(t['_lot'], t['_pointer'], k)\n" +" return _get_field(t['_lot'], t['_pointer'], k, t)\n" " end,\n" " __newindex = function (t,k,v)\n" -" _set_field(t['_lot'], t['_pointer'], k, v)\n" +" _set_field(t['_lot'], t['_pointer'], k, v, t)\n" " end,\n" " __eq = function (a, b)\n" " return a['_pointer'] == b['_pointer'] and a['_lot'] == b['_lot'] and a['_pointer'] ~= nil and a['_lot'] ~= nil\n" diff --git a/src/pc/lua/smlua_functions.c b/src/pc/lua/smlua_functions.c index 98fe0a0a..db8406fc 100644 --- a/src/pc/lua/smlua_functions.c +++ b/src/pc/lua/smlua_functions.c @@ -79,6 +79,10 @@ int smlua_func_init_mario_after_warp(lua_State* L) { return 1; } + ////////// + // bind // +////////// + void smlua_bind_functions(void) { lua_State* L = gLuaState; diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index b70c99c6..f4a25883 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -11,10 +11,19 @@ static u64* sBehaviorOffset = &gPcDebug.bhvOffset; struct LuaHookedEvent { int reference[MAX_HOOKED_REFERENCES]; int count; + struct ModListEntry* entry; }; static struct LuaHookedEvent sHookedEvents[HOOK_MAX] = { 0 }; +static int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct ModListEntry* activeEntry) { + struct ModListEntry* prev = gLuaActiveEntry; + gLuaActiveEntry = activeEntry; + int rc = lua_pcall(L, nargs, nresults, errfunc); + gLuaActiveEntry = prev; + return rc; +} + int smlua_hook_event(lua_State* L) { if (L == NULL) { return 0; } if (!smlua_functions_valid_param_count(L, 2)) { return 0; } @@ -44,6 +53,7 @@ int smlua_hook_event(lua_State* L) { hook->reference[hook->count] = ref; hook->count++; + hook->entry = gLuaActiveEntry; return 1; } @@ -57,7 +67,7 @@ void smlua_call_event_hooks(enum LuaHookedEventType hookType) { lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); // call the callback - if (0 != lua_pcall(L, 0, 0, 0)) { + if (0 != smlua_call_hook(L, 0, 0, 0, hook->entry)) { LOG_LUA("Failed to call the event_hook callback: %u, %s", hookType, lua_tostring(L, -1)); smlua_logline(); continue; @@ -80,7 +90,7 @@ void smlua_call_event_hooks_mario_param(enum LuaHookedEventType hookType, struct lua_remove(L, -2); // call the callback - if (0 != lua_pcall(L, 1, 0, 0)) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->entry)) { LOG_LUA("Failed to call the callback: %u, %s", hookType, lua_tostring(L, -1)); smlua_logline(); continue; @@ -109,7 +119,7 @@ void smlua_call_event_hooks_mario_params(enum LuaHookedEventType hookType, struc lua_remove(L, -2); // call the callback - if (0 != lua_pcall(L, 2, 0, 0)) { + if (0 != smlua_call_hook(L, 2, 0, 0, hook->entry)) { LOG_LUA("Failed to call the callback: %u, %s", hookType, lua_tostring(L, -1)); smlua_logline(); continue; @@ -141,7 +151,7 @@ void smlua_call_event_hooks_interact_params(enum LuaHookedEventType hookType, st lua_pushboolean(L, interactValue); // call the callback - if (0 != lua_pcall(L, 4, 0, 0)) { + if (0 != smlua_call_hook(L, 4, 0, 0, hook->entry)) { LOG_LUA("Failed to call the callback: %u, %s", hookType, lua_tostring(L, -1)); smlua_logline(); continue; @@ -164,7 +174,7 @@ void smlua_call_event_hooks_network_player_param(enum LuaHookedEventType hookTyp lua_remove(L, -2); // call the callback - if (0 != lua_pcall(L, 1, 0, 0)) { + if (0 != smlua_call_hook(L, 1, 0, 0, hook->entry)) { LOG_LUA("Failed to call the callback: %u, %s", hookType, lua_tostring(L, -1)); smlua_logline(); continue; @@ -180,6 +190,7 @@ struct LuaHookedMarioAction { u32 action; u32 interactionType; int reference; + struct ModListEntry* entry; }; #define MAX_HOOKED_ACTIONS 128 @@ -190,6 +201,12 @@ static int sHookedMarioActionsCount = 0; int smlua_hook_mario_action(lua_State* L) { if (L == NULL) { return 0; } if (!smlua_functions_valid_param_range(L, 2, 3)) { return 0; } + + if (gLuaLoadingEntry == NULL) { + LOG_LUA("hook_mario_action() can only be called on load."); + return 0; + } + int paramCount = lua_gettop(L); if (sHookedMarioActionsCount >= MAX_HOOKED_ACTIONS) { @@ -228,6 +245,7 @@ int smlua_hook_mario_action(lua_State* L) { hooked->action = action; hooked->interactionType = interactionType; hooked->reference = ref; + hooked->entry = gLuaActiveEntry; if (!gSmLuaConvertSuccess) { return 0; } sHookedMarioActionsCount++; @@ -238,9 +256,10 @@ bool smlua_call_action_hook(struct MarioState* m, s32* returnValue) { lua_State* L = gLuaState; if (L == NULL) { return false; } for (int i = 0; i < sHookedMarioActionsCount; i++) { - if (sHookedMarioActions[i].action == m->action) { + struct LuaHookedMarioAction* hook = &sHookedMarioActions[i]; + if (hook->action == m->action) { // push the callback onto the stack - lua_rawgeti(L, LUA_REGISTRYINDEX, sHookedMarioActions[i].reference); + lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference); // push mario state lua_getglobal(L, "gMarioStates"); @@ -249,7 +268,7 @@ bool smlua_call_action_hook(struct MarioState* m, s32* returnValue) { lua_remove(L, -2); // call the callback - if (0 != lua_pcall(L, 1, 1, 0)) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->entry)) { LOG_LUA("Failed to call the action callback: %u, %s", m->action, lua_tostring(L, -1)); smlua_logline(); continue; @@ -289,6 +308,7 @@ struct LuaHookedBehavior { BehaviorScript behavior[2]; int initReference; int loopReference; + struct ModListEntry* entry; }; #define MAX_HOOKED_BEHAVIORS 256 @@ -321,6 +341,11 @@ int smlua_hook_behavior(lua_State* L) { if (L == NULL) { return 0; } if (!smlua_functions_valid_param_count(L, 4)) { return 0; } + if (gLuaLoadingEntry == NULL) { + LOG_LUA("hook_behavior() can only be called on load."); + return 0; + } + if (sHookedBehaviorsCount >= MAX_HOOKED_BEHAVIORS) { LOG_LUA("Hooked behaviors exceeded maximum references!"); smlua_logline(); @@ -376,6 +401,7 @@ int smlua_hook_behavior(lua_State* L) { hooked->behavior[1] = (((unsigned int) (((unsigned int)(0x39) & ((0x01 << (8)) - 1)) << (24))) | ((unsigned int) (((unsigned int)(customBehaviorId) & ((0x01 << (16)) - 1)) << (0)))); // gross. this is ID(customBehaviorId) hooked->initReference = initReference; hooked->loopReference = loopReference; + hooked->entry = gLuaActiveEntry; sHookedBehaviorsCount++; @@ -413,7 +439,7 @@ bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* ob smlua_push_object(L, LOT_OBJECT, object); // call the callback - if (0 != lua_pcall(L, 1, 0, 0)) { + if (0 != smlua_call_hook(L, 1, 0, 0, hooked->entry)) { LOG_LUA("Failed to call the behavior callback: %u, %s", hooked->behaviorId, lua_tostring(L, -1)); smlua_logline(); return true; @@ -433,6 +459,7 @@ struct LuaHookedChatCommand { char* command; char* description; int reference; + struct ModListEntry* entry; }; #define MAX_HOOKED_CHAT_COMMANDS 64 @@ -444,6 +471,11 @@ int smlua_hook_chat_command(lua_State* L) { if (L == NULL) { return 0; } if (!smlua_functions_valid_param_count(L, 3)) { return 0; } + if (gLuaLoadingEntry == NULL) { + LOG_LUA("hook_chat_command() can only be called on load."); + return 0; + } + if (sHookedChatCommandsCount >= MAX_HOOKED_CHAT_COMMANDS) { LOG_LUA("Hooked chat command exceeded maximum references!"); smlua_logline(); @@ -475,6 +507,7 @@ int smlua_hook_chat_command(lua_State* L) { hooked->command = strdup(command); hooked->description = strdup(description); hooked->reference = ref; + hooked->entry = gLuaActiveEntry; if (!gSmLuaConvertSuccess) { return 0; } sHookedChatCommandsCount++; @@ -508,7 +541,7 @@ bool smlua_call_chat_command_hook(char* command) { lua_pushstring(L, params); // call the callback - if (0 != lua_pcall(L, 1, 1, 0)) { + if (0 != smlua_call_hook(L, 1, 1, 0, hook->entry)) { LOG_LUA("Failed to call the chat command callback: %s, %s", command, lua_tostring(L, -1)); smlua_logline(); continue; @@ -537,11 +570,11 @@ void smlua_display_chat_commands(void) { } } + ////////////////////////////// // hooked sync table change // ////////////////////////////// - int smlua_hook_on_sync_table_change(lua_State* L) { LUA_STACK_CHECK_BEGIN(); if (L == NULL) { return 0; } @@ -552,6 +585,11 @@ int smlua_hook_on_sync_table_change(lua_State* L) { int tagIndex = 3; int funcIndex = 4; + if (gLuaLoadingEntry == NULL) { + LOG_LUA("hook_on_sync_table_change() can only be called on load."); + return 0; + } + if (lua_type(L, syncTableIndex) != LUA_TTABLE) { LOG_LUA("Tried to attach a non-table to hook_on_sync_table_change: %d", lua_type(L, syncTableIndex)); smlua_logline(); diff --git a/src/pc/lua/smlua_sync_table.c b/src/pc/lua/smlua_sync_table.c index 85e8144d..10ff62fc 100644 --- a/src/pc/lua/smlua_sync_table.c +++ b/src/pc/lua/smlua_sync_table.c @@ -137,11 +137,26 @@ static void smlua_sync_table_call_hook(int syncTableIndex, int keyIndex, int pre lua_pushvalue(L, prevValueIndex); lua_pushvalue(L, valueIndex); + // get entry + u16 modRemoteIndex = smlua_get_integer_field(syncTableIndex, "_remoteIndex"); + struct ModListEntry* setEntry = NULL; + for (int i = 0; i < gModTableCurrent->entryCount; i++) { + struct ModListEntry* entry = &gModTableCurrent->entries[i]; + if (!entry->enabled) { continue; } + if (entry->remoteIndex == modRemoteIndex) { + setEntry = entry; + break; + } + } + // call hook + struct ModListEntry* prev = gLuaActiveEntry; + gLuaActiveEntry = setEntry; if (0 != lua_pcall(L, 3, 0, 0)) { LOG_LUA("Failed to call the hook_on_changed callback: %s", lua_tostring(L, -1)); smlua_logline(); } + gLuaActiveEntry = prev; } lua_pop(L, 1); // pop _hook_on_changed's value