Add define_custom_obj_fields() to Lua

This commit is contained in:
MysterD 2022-03-04 18:16:54 -08:00
parent bac0879ee7
commit 9c7036afe3
9 changed files with 301 additions and 27 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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