From ecdf3412c0f60b0d6a15ac1888783f9ffb348418 Mon Sep 17 00:00:00 2001 From: Yukita Mayako Date: Wed, 10 Jun 2015 07:28:09 -0400 Subject: [PATCH] Rewrote the entirety of lua_hooklib.c This _should_ solve some significant performance issues Lua experiences. If not, I will be very upset for having wasted so much time and effort. There will be bugs, this kind of thing needs to be thuroughly tested and this is just the first iteration of it. --- src/lua_hook.h | 9 +- src/lua_hooklib.c | 1048 ++++++++++++++++++--------------------------- src/p_inter.c | 2 +- 3 files changed, 414 insertions(+), 645 deletions(-) diff --git a/src/lua_hook.h b/src/lua_hook.h index fae3bb7e6..da2dcdc38 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -41,7 +41,7 @@ enum hook { hook_BotAI, hook_LinedefExecute, hook_PlayerMsg, - hook_DeathMsg, + hook_HurtMsg, hook_MAX // last hook }; @@ -54,8 +54,9 @@ void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers) boolean LUAh_MobjHook(mobj_t *mo, enum hook which); boolean LUAh_PlayerHook(player_t *plr, enum hook which); #define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type -UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2); // Hook for PIT_CheckThing by (thing) mobj type -UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2); // Hook for PIT_CheckThing by (tmthing) mobj type +UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which); +#define LUAh_MobjCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjCollide) // Hook for PIT_CheckThing by (thing) mobj type +#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type #define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type #define LUAh_MobjThinker(mo) LUAh_MobjHook(mo, hook_MobjThinker) // Hook for P_MobjThinker or P_SceneryThinker by mobj type @@ -73,6 +74,6 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages -boolean LUAh_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages +boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 532726ac2..c314ed045 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -56,23 +56,40 @@ const char *const hookNames[hook_MAX+1] = { NULL }; +// Hook metadata +struct hook_s +{ + struct hook_s *next; + enum hook type; + UINT16 id; + union { + mobjtype_t mt; + char *skinname; + char *funcname; + } s; + boolean error; +}; +typedef struct hook_s* hook_p; + +#define FMT_HOOKID "hook_%04x" + +hook_p roothook; + // Takes hook, function, and additional arguments (mobj type to act on, etc.) static int lib_addHook(lua_State *L) { - UINT16 hook; - boolean notable = false; - boolean subtable = false; - UINT32 subindex = 0; - char *subfield = NULL; - const char *lsubfield = NULL; + static struct hook_s hook = {NULL, 0, 0, {0}, false}; + hook_p hookp, *lastp; - hook = (UINT16)luaL_checkoption(L, 1, NULL, hookNames); - luaL_checktype(L, 2, LUA_TFUNCTION); + hook.type = luaL_checkoption(L, 1, NULL, hookNames); + lua_remove(L, 1); + + luaL_checktype(L, 1, LUA_TFUNCTION); if (hud_running) return luaL_error(L, "HUD rendering code should not call this function!"); - switch(hook) + switch(hook.type) { // Take a mobjtype enum which this hook is specifically for. case hook_MobjSpawn: @@ -87,277 +104,140 @@ static int lib_addHook(lua_State *L) case hook_MobjDeath: case hook_BossDeath: case hook_MobjRemoved: - subtable = true; - if (lua_isnumber(L, 3)) - subindex = (UINT32)luaL_checkinteger(L, 3); - else - lsubfield = "a"; - lua_settop(L, 2); + case hook_HurtMsg: + hook.s.mt = MT_NULL; + if (lua_isnumber(L, 2)) + hook.s.mt = lua_tonumber(L, 2); break; - case hook_BotAI: // Only one AI function per skin, please! - notable = true; - subtable = true; - subfield = ZZ_Alloc(strlen(luaL_checkstring(L, 3))+1); + case hook_BotAI: + hook.s.skinname = NULL; + if (lua_isstring(L, 2)) { // lowercase copy - char *p = subfield; - const char *s = luaL_checkstring(L, 3); + const char *s = lua_tostring(L, 2); + char *p = hook.s.skinname = ZZ_Alloc(strlen(s)+1); do { *p = tolower(*s); ++p; } while(*(++s)); *p = 0; } - lua_settop(L, 3); break; - case hook_LinedefExecute: // Get one linedef executor function by name - notable = true; - subtable = true; - subfield = ZZ_Alloc(strlen(luaL_checkstring(L, 3))+1); + case hook_LinedefExecute: // Linedef executor functions { // uppercase copy - char *p = subfield; - const char *s = luaL_checkstring(L, 3); + const char *s = luaL_checkstring(L, 2); + char *p = hook.s.funcname = ZZ_Alloc(strlen(s)+1); do { *p = toupper(*s); ++p; } while(*(++s)); *p = 0; } - lua_settop(L, 3); break; default: - lua_settop(L, 2); break; } + lua_settop(L, 1); // lua stack contains only the function now. - lua_getfield(L, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(L, -1)); + hooksAvailable[hook.type/8] |= 1<<(hook.type%8); - // This hook type only allows one entry, not an array of hooks. - // New hooks will overwrite the previous ones, and the stack is one table shorter. - if (notable) + // iterate the hook metadata structs + // set hook.id to the highest id + 1 + // set lastp to the last hook struct's "next" pointer. + lastp = &roothook; + hook.id = 0; + for (hookp = roothook; hookp; hookp = hookp->next) { - if (subtable) - { - lua_rawgeti(L, -1, hook); - lua_remove(L, -2); // pop "hook" - I_Assert(lua_istable(L, -1)); - lua_pushvalue(L, 2); - if (subfield) - lua_setfield(L, -2, subfield); - else if (lsubfield) - lua_setfield(L, -2, lsubfield); - else - lua_rawseti(L, -2, subindex); - } else { - lua_pushvalue(L, 2); - lua_rawseti(L, -2, hook); - } - hooksAvailable[hook/8] |= 1<<(hook%8); - return 0; + if (hookp->id >= hook.id) + hook.id = hookp->id+1; + lastp = &hookp->next; } - // Fetch the hook's table from the registry. - // It should always exist, since LUA_HookLib creates a table for every hook. - lua_rawgeti(L, -1, hook); - lua_remove(L, -2); // pop "hook" - I_Assert(lua_istable(L, -1)); - if (subtable) - { - // Fetch a subtable based on index - if (subfield) - lua_getfield(L, -1, subfield); - else if (lsubfield) - lua_getfield(L, -1, lsubfield); - else - lua_rawgeti(L, -1, subindex); + // allocate a permanent memory struct to stuff hook. + hookp = ZZ_Alloc(sizeof(struct hook_s)); + memcpy(hookp, &hook, sizeof(struct hook_s)); + // tack it onto the end of the linked list. + *lastp = hookp; - // Subtable doesn't exist, make one now. - if (lua_isnil(L, -1)) - { - lua_pop(L, 1); - lua_newtable(L); - - // Store a link to the subtable for later. - lua_pushvalue(L, -1); - if (subfield) - lua_setfield(L, -3, subfield); - else if (lsubfield) - lua_setfield(L, -3, lsubfield); - else - lua_rawseti(L, -3, subindex); - } } - - // Add function to the table. - lua_pushvalue(L, 2); - lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1)); - - if (subfield) - Z_Free(subfield); - - hooksAvailable[hook/8] |= 1<<(hook%8); + // set the hook function in the registry. + lua_pushfstring(L, FMT_HOOKID, hook.id); + lua_pushvalue(L, 1); + lua_settable(L, LUA_REGISTRYINDEX); return 0; } int LUA_HookLib(lua_State *L) { - // Create all registry tables - enum hook i; memset(hooksAvailable,0,sizeof(UINT8[(hook_MAX/8)+1])); - - lua_newtable(L); - for (i = 0; i < hook_MAX; i++) - { - lua_newtable(L); - switch(i) - { - default: - break; - case hook_MobjSpawn: - case hook_MobjCollide: - case hook_MobjMoveCollide: - case hook_TouchSpecial: - case hook_MobjFuse: - case hook_MobjThinker: - case hook_BossThinker: - case hook_ShouldDamage: - case hook_MobjDamage: - case hook_MobjDeath: - case hook_BossDeath: - case hook_MobjRemoved: - lua_pushstring(L, "a"); - lua_newtable(L); - lua_rawset(L, -3); - break; - } - lua_rawseti(L, -2, i); - } - lua_setfield(L, LUA_REGISTRYINDEX, "hook"); + roothook = NULL; lua_register(L, "addHook", lib_addHook); return 0; } boolean LUAh_MobjHook(mobj_t *mo, enum hook which) { + hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return false; - // clear the stack (just in case) lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, which); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // generic subtable - lua_pushstring(gL, "a"); - lua_rawget(gL, -2); - I_Assert(lua_istable(gL, -1)); - LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, -3)) { - CONS_Debug(DBG_LUA, "MobjHook: Calling hook_%s for generic mobj types\n", hookNames[which]); - lua_pushvalue(gL, -3); // mo - // stack is: hook_Mobj table, subtable "a", mobj, i, function, mobj - if (lua_pcall(gL, 1, 1, 0)) { - // A run-time error occurred. - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL, 1); - // Remove this function from the hook table to prevent further errors. - lua_pushvalue(gL, -1); // key - lua_pushnil(gL); // value - lua_rawset(gL, -5); // table - CONS_Printf("Hook removed.\n"); - } - else + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == which + && (hookp->s.mt == MT_NULL || hookp->s.mt == mo->type)) { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } if (lua_toboolean(gL, -1)) hooked = true; lua_pop(gL, 1); } - } - // stack is: hook_Mobj table, subtable "a", mobj - lua_remove(gL, -2); // pop subtable, leave mobj - // mobjtype subtable - // stack is: hook_Mobj table, mobj - lua_rawgeti(gL, -2, mo->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 3); // pop hook_Mobj table, mobj, and nil - // the stack should now be empty. - return false; - } - lua_remove(gL, -3); // remove hook table - // stack is: mobj, mobjtype subtable - lua_insert(gL, lua_gettop(gL)-1); // swap subtable with mobj - // stack is: mobjtype subtable, mobj + lua_pop(gL, 1); - lua_pushnil(gL); - while (lua_next(gL, -3)) { - CONS_Debug(DBG_LUA, "MobjHook: Calling hook_%s for mobj type %d\n", hookNames[which], mo->type); - lua_pushvalue(gL, -3); // mo - // stack is: mobjtype subtable, mobj, i, function, mobj - if (lua_pcall(gL, 1, 1, 0)) { - // A run-time error occurred. - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL, 1); - // Remove this function from the hook table to prevent further errors. - lua_pushvalue(gL, -1); // key - lua_pushnil(gL); // value - lua_rawset(gL, -5); // table - CONS_Printf("Hook removed.\n"); - } - else - { - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - } - - lua_pop(gL, 2); // pop mobj and subtable - // the stack should now be empty. - - lua_gc(gL, LUA_GCSTEP, 3); + lua_gc(gL, LUA_GCSTEP, 1); return hooked; } boolean LUAh_PlayerHook(player_t *plr, enum hook which) { + hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return false; - // clear the stack (just in case) lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, which); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - LUA_PushUserdata(gL, plr, META_PLAYER); - lua_pushnil(gL); - while (lua_next(gL, -3) != 0) { - lua_pushvalue(gL, -3); // player - if (lua_pcall(gL, 1, 1, 0)) { // pops hook function, player, pushes 1 return result - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == which) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) // if return true, - hooked = true; // override vanilla behavior - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, -1); + lua_pop(gL, 1); + lua_gc(gL, LUA_GCSTEP, 1); return hooked; } @@ -365,21 +245,22 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which) // Hook for map change (before load) void LUAh_MapChange(void) { + hook_p hookp; if (!gL || !(hooksAvailable[hook_MapChange/8] & (1<<(hook_MapChange%8)))) return; - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MapChange); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - + lua_pop(gL, -1); lua_pushinteger(gL, gamemap); - lua_pushnil(gL); - while (lua_next(gL, -3) != 0) { - lua_pushvalue(gL, -3); // gamemap - LUA_Call(gL, 1); - } + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MapChange) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } + lua_pop(gL, 1); lua_gc(gL, LUA_GCSTEP, 1); } @@ -387,182 +268,112 @@ void LUAh_MapChange(void) // Hook for map load void LUAh_MapLoad(void) { + hook_p hookp; if (!gL || !(hooksAvailable[hook_MapLoad/8] & (1<<(hook_MapLoad%8)))) return; lua_pop(gL, -1); - - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MapLoad); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - lua_pushinteger(gL, gamemap); - lua_pushnil(gL); - while (lua_next(gL, -3) != 0) { - lua_pushvalue(gL, -3); // gamemap - LUA_Call(gL, 1); - } - lua_pop(gL, -1); - lua_gc(gL, LUA_GCCOLLECT, 0); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MapLoad) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } + + lua_pop(gL, 1); + lua_gc(gL, LUA_GCSTEP, 1); } // Hook for Got_AddPlayer void LUAh_PlayerJoin(int playernum) { + hook_p hookp; if (!gL || !(hooksAvailable[hook_PlayerJoin/8] & (1<<(hook_PlayerJoin%8)))) return; lua_pop(gL, -1); - - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_PlayerJoin); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - lua_pushinteger(gL, playernum); - lua_pushnil(gL); - while (lua_next(gL, -3) != 0) { - lua_pushvalue(gL, -3); // playernum - LUA_Call(gL, 1); - } - lua_pop(gL, -1); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_PlayerJoin) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } + + lua_pop(gL, 1); lua_gc(gL, LUA_GCCOLLECT, 0); } // Hook for frame (after mobj and player thinkers) void LUAh_ThinkFrame(void) { + hook_p hookp; if (!gL || !(hooksAvailable[hook_ThinkFrame/8] & (1<<(hook_ThinkFrame%8)))) return; lua_pop(gL, -1); - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_ThinkFrame); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - lua_pushnil(gL); - while (lua_next(gL, -2) != 0) - { - //LUA_Call(gL, 0); - if (lua_pcall(gL, 0, 0, 0)) + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_ThinkFrame) { - // A run-time error occurred. - CONS_Alert(CONS_WARNING,"%s\n", lua_tostring(gL, -1)); - lua_pop(gL, 1); - // Remove this function from the hook table to prevent further errors. - lua_pushvalue(gL, -1); // key - lua_pushnil(gL); // value - lua_rawset(gL, -4); // table - CONS_Printf("Hook removed.\n"); + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + if (lua_pcall(gL, 0, 0, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } } - } - lua_pop(gL, -1); - lua_gc(gL, LUA_GCCOLLECT, 0); -} - -// Hook for PIT_CheckThing by (thing) mobj type (thing1 = thing, thing2 = tmthing) -UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2) -{ - UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[hook_MobjCollide/8] & (1<<(hook_MobjCollide%8)))) - return 0; - - // clear the stack - lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MobjCollide); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, thing1->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return 0; - } - lua_remove(gL, -2); // remove hook table - - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, -4)) { - lua_pushvalue(gL, -4); // thing1 - lua_pushvalue(gL, -4); // thing2 - if (lua_pcall(gL, 2, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL, 1); - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 3); // pop arguments and mobjtype table lua_gc(gL, LUA_GCSTEP, 1); - return shouldCollide; } -// Hook for PIT_CheckThing by (tmthing) mobj type (thing1 = tmthing, thing2 = thing) -UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2) +// Hook for mobj collisions +UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) { + hook_p hookp; UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[hook_MobjMoveCollide/8] & (1<<(hook_MobjMoveCollide%8)))) + if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return 0; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MobjMoveCollide); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, thing1->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return 0; - } - lua_remove(gL, -2); // remove hook table - LUA_PushUserdata(gL, thing1, META_MOBJ); LUA_PushUserdata(gL, thing2, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, -4)) { - lua_pushvalue(gL, -4); // thing1 - lua_pushvalue(gL, -4); // thing2 - if (lua_pcall(gL, 2, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == which + && (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } lua_pop(gL, 1); - continue; } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 3); // pop arguments and mobjtype table + + lua_pop(gL, 2); lua_gc(gL, LUA_GCSTEP, 1); return shouldCollide; @@ -571,47 +382,37 @@ UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2) // Hook for P_TouchSpecialThing by mobj type boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) { + hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_TouchSpecial/8] & (1<<(hook_TouchSpecial%8)))) - return false; + return 0; - // clear the stack lua_pop(gL, -1); - - // get hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_TouchSpecial); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // get mobjtype subtable - lua_pushinteger(gL, special->type); - lua_rawget(gL, 1); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, 1); // pop hook table off the stack - LUA_PushUserdata(gL, special, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, 1) != 0) { - lua_pushvalue(gL, 2); // special - lua_pushvalue(gL, 3); // toucher - if (lua_pcall(gL, 2, 1, 0)) { // pops hook function, special, toucher, pushes 1 return result - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_TouchSpecial + && (hookp->s.mt == MT_NULL || hookp->s.mt == special->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) // if return true, - hooked = true; // override vanilla behavior - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, -1); + lua_pop(gL, 2); + lua_gc(gL, LUA_GCSTEP, 1); return hooked; } @@ -619,53 +420,45 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) // Hook for P_DamageMobj by mobj type (Should mobj take damage?) UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) { + hook_p hookp; UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. if (!gL || !(hooksAvailable[hook_ShouldDamage/8] & (1<<(hook_ShouldDamage%8)))) return 0; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_ShouldDamage); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, target->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return 0; - } - lua_remove(gL, -2); // remove hook table - LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); - lua_pushnil(gL); - while (lua_next(gL, -6)) { - lua_pushvalue(gL, -6); // target - lua_pushvalue(gL, -6); // inflictor - lua_pushvalue(gL, -6); // source - lua_pushvalue(gL, -6); // damage - if (lua_pcall(gL, 4, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_ShouldDamage + && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } lua_pop(gL, 1); - continue; } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldDamage = 0. - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 5); // pop arguments and mobjtype table + + lua_pop(gL, 4); lua_gc(gL, LUA_GCSTEP, 1); return shouldDamage; @@ -674,136 +467,118 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) { - boolean handled = false; + hook_p hookp; + boolean hooked = false; if (!gL || !(hooksAvailable[hook_MobjDamage/8] & (1<<(hook_MobjDamage%8)))) - return false; + return 0; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MobjDamage); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, target->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, -2); // remove hook table - LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); - lua_pushnil(gL); - while (lua_next(gL, -6)) { - lua_pushvalue(gL, -6); // target - lua_pushvalue(gL, -6); // inflictor - lua_pushvalue(gL, -6); // source - lua_pushvalue(gL, -6); // damage - if (lua_pcall(gL, 4, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MobjDamage + && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - handled = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 5); // pop arguments and mobjtype table + + lua_pop(gL, 4); lua_gc(gL, LUA_GCSTEP, 1); - return handled; + return hooked; } // Hook for P_KillMobj by mobj type boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source) { - boolean handled = false; + hook_p hookp; + boolean hooked = false; if (!gL || !(hooksAvailable[hook_MobjDeath/8] & (1<<(hook_MobjDeath%8)))) - return false; + return 0; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MobjDeath); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, target->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, -2); // remove hook table - LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, -5)) { - lua_pushvalue(gL, -5); // target - lua_pushvalue(gL, -5); // inflictor - lua_pushvalue(gL, -5); // source - if (lua_pcall(gL, 3, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MobjDeath + && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - handled = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 4); // pop arguments and mobjtype table + + lua_pop(gL, 3); lua_gc(gL, LUA_GCSTEP, 1); - return handled; + return hooked; } // Hook for B_BuildTiccmd boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) { + hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_BotTiccmd/8] & (1<<(hook_BotTiccmd%8)))) return false; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_BotTiccmd); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - LUA_PushUserdata(gL, bot, META_PLAYER); LUA_PushUserdata(gL, cmd, META_TICCMD); - lua_pushnil(gL); - while (lua_next(gL, 1)) { - lua_pushvalue(gL, 2); // bot - lua_pushvalue(gL, 3); // cmd - if (lua_pcall(gL, 2, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_BotTiccmd) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, -1); + lua_pop(gL, 2); + lua_gc(gL, LUA_GCSTEP, 1); return hooked; } @@ -811,117 +586,107 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) // Hook for B_BuildTailsTiccmd by skin name boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) { - if (!gL || !tails->skin || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8)))) + hook_p hookp; + boolean hooked = false; + int n; + if (!gL || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8)))) return false; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_BotAI); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // bot skin ai function - lua_getfield(gL, 1, ((skin_t *)tails->skin)->name); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, 1); // pop the hook table - - // Takes sonic, tails - // Returns forward, backward, left, right, jump, spin LUA_PushUserdata(gL, sonic, META_MOBJ); LUA_PushUserdata(gL, tails, META_MOBJ); - if (lua_pcall(gL, 2, 8, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL,-1); - return false; - } + n = lua_gettop(gL); - // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. - if (lua_istable(gL, 1)) { - boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_BotAI + && (hookp->s.skinname == NULL || !strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 8, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. + if (lua_istable(gL, n+1)) { + boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; #define CHECKFIELD(field) \ - lua_getfield(gL, 1, #field);\ - if (lua_toboolean(gL, -1))\ - field = true;\ - lua_pop(gL, 1); - - CHECKFIELD(forward) - CHECKFIELD(backward) - CHECKFIELD(left) - CHECKFIELD(right) - CHECKFIELD(strafeleft) - CHECKFIELD(straferight) - CHECKFIELD(jump) - CHECKFIELD(spin) + lua_getfield(gL, n+1, #field);\ + if (lua_toboolean(gL, -1))\ + field = true;\ + lua_pop(gL, 1); + CHECKFIELD(forward) + CHECKFIELD(backward) + CHECKFIELD(left) + CHECKFIELD(right) + CHECKFIELD(strafeleft) + CHECKFIELD(straferight) + CHECKFIELD(jump) + CHECKFIELD(spin) #undef CHECKFIELD + B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); + } else + B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, n+1), lua_toboolean(gL, n+2), lua_toboolean(gL, n+3), lua_toboolean(gL, n+4), lua_toboolean(gL, n+5), lua_toboolean(gL, n+6), lua_toboolean(gL, n+7), lua_toboolean(gL, n+8)); - B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); - } else - B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 1), lua_toboolean(gL, 2), lua_toboolean(gL, 3), lua_toboolean(gL, 4), lua_toboolean(gL, 5), lua_toboolean(gL, 6), lua_toboolean(gL, 7), lua_toboolean(gL, 8)); + lua_pop(gL, 8); + hooked = true; + } + + lua_pop(gL, 2); - lua_pop(gL, -1); lua_gc(gL, LUA_GCSTEP, 1); - return true; + return hooked; } // Hook for linedef executors boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) { + hook_p hookp; + boolean hooked = false; if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8)))) - return false; + return 0; - // clear the stack lua_pop(gL, -1); - - // get hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_LinedefExecute); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // get function by line text - lua_getfield(gL, 1, line->text); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, 1); // pop hook table off the stack - LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, sector, META_SECTOR); - LUA_Call(gL, 3); // pops hook function, line, mo, sector - lua_pop(gL, -1); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_LinedefExecute + && !strcmp(hookp->s.funcname, line->text)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + LUA_Call(gL, 3); + hooked = true; + } + + lua_pop(gL, 3); + lua_gc(gL, LUA_GCSTEP, 1); - return true; + return hooked; } -// Hook for PlayerMsg -Red +// Hook for player chat boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) { - boolean handled = false; - + hook_p hookp; + boolean hooked = false; if (!gL || !(hooksAvailable[hook_PlayerMsg/8] & (1<<(hook_PlayerMsg%8)))) return false; - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_PlayerMsg); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - + lua_pop(gL, -1); LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player - if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c lua_pushinteger(gL, 3); // type lua_pushnil(gL); // target @@ -935,70 +700,73 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) lua_pushinteger(gL, 2); // type LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target } - lua_pushstring(gL, msg); // msg - lua_pushnil(gL); - - while (lua_next(gL, -6)) { - lua_pushvalue(gL, -6); // source - lua_pushvalue(gL, -6); // type - lua_pushvalue(gL, -6); // target - lua_pushvalue(gL, -6); // msg - if (lua_pcall(gL, 4, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_PlayerMsg) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - handled = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 4); // pop arguments and mobjtype table + + lua_pop(gL, 4); lua_gc(gL, LUA_GCSTEP, 1); - return handled; + return hooked; } -// Hook for hurt messages -Red -// The internal name is DeathMsg, but the API name is "HurtMsg". Keep that in mind. (Should this be fixed at some point?) -// @TODO This hook should be fixed to take mobj type at the addHook parameter to compare to inflictor. (I couldn't get this to work without crashing) -boolean LUAh_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source) +// Hook for hurt messages +boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source) { - boolean handled = false; - - if (!gL || !(hooksAvailable[hook_DeathMsg/8] & (1<<(hook_DeathMsg%8)))) + hook_p hookp; + boolean hooked = false; + if (!gL || !(hooksAvailable[hook_HurtMsg/8] & (1<<(hook_HurtMsg%8)))) return false; - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_DeathMsg); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); + lua_pop(gL, -1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); - LUA_PushUserdata(gL, player, META_PLAYER); // Player - LUA_PushUserdata(gL, inflictor, META_MOBJ); // Inflictor - LUA_PushUserdata(gL, source, META_MOBJ); // Source - - lua_pushnil(gL); - - while (lua_next(gL, -5)) { - lua_pushvalue(gL, -5); // player - lua_pushvalue(gL, -5); // inflictor - lua_pushvalue(gL, -5); // source - if (lua_pcall(gL, 3, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_HurtMsg + && (hookp->s.mt == MT_NULL || (inflictor && hookp->s.mt == inflictor->type))) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - handled = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 3); // pop arguments and mobjtype table + + lua_pop(gL, 3); lua_gc(gL, LUA_GCSTEP, 1); - return handled; + return hooked; } #endif diff --git a/src/p_inter.c b/src/p_inter.c index 8eaa4765a..478bd459c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1478,7 +1478,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour return; // Presumably it's obvious what's happening in splitscreen. #ifdef HAVE_BLUA - if (LUAh_DeathMsg(player, inflictor, source)) + if (LUAh_HurtMsg(player, inflictor, source)) return; #endif