// 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 0; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_LinedefExecute && !strcmp(hookp->s.funcname, line->text)) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, sector, META_SECTOR); } 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_settop(gL, 0); return hooked; }
void LUAh_NetArchiveHook(lua_CFunction archFunc) { hook_p hookp; if (!gL || !(hooksAvailable[hook_NetVars/8] & (1<<(hook_NetVars%8)))) return; // stack: tables I_Assert(lua_gettop(gL) > 0); I_Assert(lua_istable(gL, -1)); // tables becomes an upvalue of archFunc lua_pushvalue(gL, -1); lua_pushcclosure(gL, archFunc, 1); // stack: tables, archFunc for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_NetVars) { lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -2); // archFunc LUA_Call(gL, 1); } lua_pop(gL, 1); // pop archFunc // stack: tables }
void LUAh_ScoresHUD(void) { if (!gL || !(hudAvailable & (1<<hudhook_scores))) return; hud_running = true; lua_pop(gL, -1); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -1, 3); // HUD[3] = rendering funcs I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD lua_pushnil(gL); while (lua_next(gL, -3) != 0) { lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1); } lua_pop(gL, -1); lua_gc(gL, LUA_GCCOLLECT, 0); hud_running = false; }
// Hook for HUD rendering void LUAh_GameHUD(player_t *stplyr) { if (!gL || !(hudAvailable & (1<<hudhook_game))) return; hud_running = true; lua_pop(gL, -1); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -1, 2); // HUD[2] = rendering funcs I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD LUA_PushUserdata(gL, stplyr, META_PLAYER); lua_pushnil(gL); while (lua_next(gL, -4) != 0) { lua_pushvalue(gL, -4); // graphics library (HUD[1]) lua_pushvalue(gL, -4); // stplyr LUA_Call(gL, 2); } lua_pop(gL, -1); lua_gc(gL, LUA_GCCOLLECT, 0); hud_running = false; }
boolean LUA_CallAction(const char *csaction, mobj_t *actor) { I_Assert(csaction != NULL); I_Assert(actor != NULL); if (!gL) // Lua isn't loaded, return false; // action not called. if (superstack && fasticmp(csaction, superactions[superstack-1])) // the action is calling itself, return false; // let it call the hardcoded function instead. // grab function by uppercase name. lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); { char *action = Z_StrDup(csaction); strupr(action); lua_getfield(gL, -1, action); Z_Free(action); } lua_remove(gL, -2); // pop LREG_ACTIONS if (lua_isnil(gL, -1)) // no match { lua_pop(gL, 1); // pop nil return false; // action not called. } if (superstack == MAXRECURSION) { CONS_Alert(CONS_WARNING, "Max Lua Action recursion reached! Cool it on the calling A_Action functions from inside A_Action functions!\n"); return true; } // Found a function. // Call it with (actor, var1, var2) I_Assert(lua_isfunction(gL, -1)); LUA_PushUserdata(gL, actor, META_MOBJ); lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); superactions[superstack] = csaction; ++superstack; LUA_Call(gL, 3); --superstack; superactions[superstack] = NULL; return true; // action successfully called. }
// Uses astate to determine which state is calling it // Then looks up which Lua action is assigned to that state and calls it static void A_Lua(mobj_t *actor) { boolean found = false; I_Assert(actor != NULL); // get the action for this state lua_getfield(gL, LUA_REGISTRYINDEX, LREG_STATEACTION); I_Assert(lua_istable(gL, -1)); lua_pushlightuserdata(gL, astate); lua_rawget(gL, -2); I_Assert(lua_isfunction(gL, -1)); lua_remove(gL, -2); // pop LREG_STATEACTION // get the name for this action, if possible. lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); lua_pushnil(gL); while (lua_next(gL, -2)) { if (lua_rawequal(gL, -1, -4)) { found = true; superactions[superstack] = lua_tostring(gL, -2); // "A_ACTION" ++superstack; lua_pop(gL, 2); // pop the name and function break; } lua_pop(gL, 1); } lua_pop(gL, 1); // pop LREG_ACTION LUA_PushUserdata(gL, actor, META_MOBJ); lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); LUA_Call(gL, 3); if (found) { --superstack; superactions[superstack] = NULL; } 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_settop(gL, 0); lua_pushinteger(gL, playernum); 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_settop(gL, 0); }
// Hook for map load void LUAh_MapLoad(void) { hook_p hookp; if (!gL || !(hooksAvailable[hook_MapLoad/8] & (1<<(hook_MapLoad%8)))) return; lua_settop(gL, 0); lua_pushinteger(gL, gamemap); 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_settop(gL, 0); }
static void Lua_OnChange(void) { I_Assert(gL != NULL); I_Assert(cvname != NULL); /// \todo Network this! XD_LUAVAR // From CV_OnChange registry field, get the function for this cvar by name. lua_getfield(gL, LUA_REGISTRYINDEX, "CV_OnChange"); I_Assert(lua_istable(gL, -1)); lua_getfield(gL, -1, cvname); // get function // From the CV_Vars registry field, get the cvar's userdata by name. lua_getfield(gL, LUA_REGISTRYINDEX, "CV_Vars"); I_Assert(lua_istable(gL, -1)); lua_getfield(gL, -1, cvname); // get consvar_t* userdata. lua_remove(gL, -2); // pop the CV_Vars table. LUA_Call(gL, 1); // call function(cvar) lua_pop(gL, 1); // pop CV_OnChange table }
static void NetArchiveHook(lua_CFunction archFunc) { int TABLESINDEX; if (!gL) return; TABLESINDEX = lua_gettop(gL); lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -1, hook_NetVars); lua_remove(gL, -2); I_Assert(lua_istable(gL, -1)); lua_pushvalue(gL, TABLESINDEX); lua_pushcclosure(gL, archFunc, 1); lua_pushnil(gL); while (lua_next(gL, -3) != 0) { lua_pushvalue(gL, -3); // function LUA_Call(gL, 1); } lua_pop(gL, 2); }
// Wrapper for COM_AddCommand commands void COM_Lua_f(void) { char *buf, *p; UINT8 i, flags; UINT16 len; INT32 playernum = consoleplayer; I_Assert(gL != NULL); lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command I_Assert(lua_istable(gL, -1)); // use buf temporarily -- must use lowercased string buf = Z_StrDup(COM_Argv(0)); strlwr(buf); lua_getfield(gL, -1, buf); // push command info table I_Assert(lua_istable(gL, -1)); lua_remove(gL, -2); // pop COM_Command Z_Free(buf); lua_rawgeti(gL, -1, 2); // push flags from command info table if (lua_isboolean(gL, -1)) flags = (lua_toboolean(gL, -1) ? 1 : 0); else flags = (UINT8)lua_tointeger(gL, -1); lua_pop(gL, 1); // pop flags if (flags & 2) // flag 2: splitscreen player command. { if (!splitscreen) { lua_pop(gL, 1); // pop command info table return; // can't execute splitscreen command without player 2! } playernum = secondarydisplayplayer; } if (netgame) { // Send the command through the network UINT8 argc; lua_pop(gL, 1); // pop command info table if (flags & 1 && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command. { CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); return; } if (COM_Argc() > UINT8_MAX) argc = UINT8_MAX; else argc = (UINT8)COM_Argc(); if (argc == UINT8_MAX) len = UINT16_MAX; else len = (argc+1)*256; buf = malloc(len); p = buf; WRITEUINT8(p, argc); for (i = 0; i < argc; i++) WRITESTRINGN(p, COM_Argv(i), 255); if (flags & 2) SendNetXCmd2(XD_LUACMD, buf, p-buf); else SendNetXCmd(XD_LUACMD, buf, p-buf); free(buf); return; } // Do the command locally, NetXCmds don't go through outside of GS_LEVEL || GS_INTERMISSION lua_rawgeti(gL, -1, 1); // push function from command info table I_Assert(lua_isfunction(gL, -1)); lua_remove(gL, -2); // pop command info table LUA_PushUserdata(gL, &players[playernum], META_PLAYER); for (i = 1; i < COM_Argc(); i++) lua_pushstring(gL, COM_Argv(i)); LUA_Call(gL, (int)COM_Argc()); // COM_Argc is 1-based, so this will cover the player we passed too. }
void Got_Luacmd(UINT8 **cp, INT32 playernum) { UINT8 i, argc, flags; char buf[256]; // don't use I_Assert here, goto the deny code below // to clean up and kick people who try nefarious exploits // like sending random junk lua commands to crash the server if (!gL) goto deny; lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command if (!lua_istable(gL, -1)) goto deny; argc = READUINT8(*cp); READSTRINGN(*cp, buf, 255); strlwr(buf); // must lowercase buffer lua_getfield(gL, -1, buf); // push command info table if (!lua_istable(gL, -1)) goto deny; lua_remove(gL, -2); // pop COM_Command lua_rawgeti(gL, -1, 2); // push flags from command info table if (lua_isboolean(gL, -1)) flags = (lua_toboolean(gL, -1) ? 1 : 0); else flags = (UINT8)lua_tointeger(gL, -1); lua_pop(gL, 1); // pop flags // requires server/admin and the player is not one of them if ((flags & 1) && playernum != serverplayer && !IsPlayerAdmin(playernum)) goto deny; lua_rawgeti(gL, -1, 1); // push function from command info table // although honestly this should be true anyway // BUT GODDAMNIT I SAID NO I_ASSERTS SO NO I_ASSERTS IT IS if (!lua_isfunction(gL, -1)) goto deny; lua_remove(gL, -2); // pop command info table LUA_PushUserdata(gL, &players[playernum], META_PLAYER); for (i = 1; i < argc; i++) { READSTRINGN(*cp, buf, 255); lua_pushstring(gL, buf); } LUA_Call(gL, (int)argc); // argc is 1-based, so this will cover the player we passed too. return; deny: //must be hacked/buggy client if (gL) // check if Lua is actually turned on first, you dummmy -- Monster Iestyn 04/07/18 lua_settop(gL, 0); // clear stack CONS_Alert(CONS_WARNING, M_GetText("Illegal lua command received from %s\n"), player_names[playernum]); if (server) { XBOXSTATIC UINT8 bufn[2]; bufn[0] = (UINT8)playernum; bufn[1] = KICK_MSG_CON_FAIL; SendNetXCmd(XD_KICK, &bufn, 2); } }