Merge branch 'action-super-fix' into 'next'

Make A_Action super act as expected

Closes #718

See merge request STJr/SRB2!1737
This commit is contained in:
sphere 2023-07-19 19:40:42 +00:00
commit 5c87dd52ec
6 changed files with 119 additions and 41 deletions

View file

@ -187,25 +187,31 @@ static inline int lib_freeslot(lua_State *L)
// Arguments: mobj_t actor, int var1, int var2
static int action_call(lua_State *L)
{
//actionf_t *action = lua_touserdata(L,lua_upvalueindex(1));
actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION));
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
var1 = (INT32)luaL_optinteger(L, 3, 0);
var2 = (INT32)luaL_optinteger(L, 4, 0);
if (!actor)
{
return LUA_ErrInvalid(L, "mobj_t");
}
action->acp1(actor);
return 0;
}
// Hardcoded A_Action name to call for super() or NULL if super() would be invalid.
// Set in lua_infolib.
const char *superactions[MAXRECURSION];
UINT8 superstack = 0;
const char *luaactions[MAX_ACTION_RECURSION];
UINT8 luaactionstack = 0;
static int lib_dummysuper(lua_State *L)
{
return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;;
// TODO: Now that the restriction on only being allowed in state changes was lifted,
// it'd be nice to have super extend to Lua A_ functions too :)
return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions!");
}
static void CacheAndPushConstant(lua_State *L, const char *name, lua_Integer value)
@ -606,42 +612,62 @@ static inline int lib_getenum(lua_State *L)
if (!mathlib && fastncmp("A_",word,2)) {
char *caps;
// Try to get a Lua action first.
/// \todo Push a closure that sets superactions[] and superstack.
// Hardcoded actions come first.
// Trying to call them will invoke LUA_CallAction, which will handle super properly.
// Retrieving them from this metatable allows them to be case-insensitive!
for (i = 0; actionpointers[i].name; i++)
{
if (fasticmp(word, actionpointers[i].name))
{
// We push the actionf_t* itself as userdata!
LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION);
return 1;
}
}
// Now try to get Lua actions.
/// \todo Push a closure that sets luaactions[] and luaactionstack.
/// This would be part one of a step to get super functions working for custom A_ functions.
/// Custom functions.
lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS);
// actions are stored in all uppercase.
caps = Z_StrDup(word);
strupr(caps);
lua_getfield(L, -1, caps);
Z_Free(caps);
if (!lua_isnil(L, -1))
{
return 1; // Success! :D That was easy.
}
// Welp, that failed.
lua_pop(L, 2); // pop nil and LREG_ACTIONS
// Hardcoded actions as callable Lua functions!
// Retrieving them from this metatable allows them to be case-insensitive!
for (i = 0; actionpointers[i].name; i++)
if (fasticmp(word, actionpointers[i].name)) {
// We push the actionf_t* itself as userdata!
LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION);
return 1;
}
return 0;
}
else if (!mathlib && fastcmp("super",word))
{
if (!superstack)
if (!luaactionstack)
{
// Not in A_ action routine
lua_pushcfunction(L, lib_dummysuper);
return 1;
}
for (i = 0; actionpointers[i].name; i++)
if (fasticmp(superactions[superstack-1], actionpointers[i].name)) {
{
if (fasticmp(luaactions[luaactionstack-1], actionpointers[i].name))
{
LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION);
return 1;
}
return 0;
}
// Not a hardcoded A_ action.
lua_pushcfunction(L, lib_dummysuper);
return 1;
}
else if ((!mathlib && LUA_PushGlobals(L, word)) || ScanConstants(L, mathlib, word))
return 1;

View file

@ -30,6 +30,7 @@ extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite
memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\
memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\
memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\
memset(actionsoverridden, LUA_REFNIL, sizeof(actionsoverridden));\
}
struct flickytypes_s {

View file

@ -40,9 +40,9 @@ extern boolean gamedataadded;
extern boolean titlechanged;
extern boolean introchanged;
#define MAXRECURSION 30
extern const char *superactions[MAXRECURSION];
extern UINT8 superstack;
#define MAX_ACTION_RECURSION 30
extern const char *luaactions[MAX_ACTION_RECURSION];
extern UINT8 luaactionstack;
// If the dehacked patch does not match this version, we throw a warning
#define PATCHVERSION 220

View file

@ -18,6 +18,7 @@
#include "d_think.h"
#include "sounds.h"
#include "m_fixed.h"
#include "dehacked.h" // MAX_ACTION_RECURSION
// deh_tables.c now has lists for the more named enums! PLEASE keep them up to date!
// For great modding!!
@ -564,7 +565,7 @@ void A_DragonWing();
void A_DragonSegment();
void A_ChangeHeight();
extern boolean actionsoverridden[NUMACTIONS];
extern int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION];
// ratio of states to sprites to mobj types is roughly 6 : 1 : 1
#define NUMMOBJFREESLOTS 512

View file

@ -66,7 +66,7 @@ const char *const sfxinfo_wopt[] = {
"caption",
NULL};
boolean actionsoverridden[NUMACTIONS] = {false};
int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION];
//
// Sprite Names
@ -645,8 +645,8 @@ static void A_Lua(mobj_t *actor)
if (lua_rawequal(gL, -1, -4))
{
found = true;
superactions[superstack] = lua_tostring(gL, -2); // "A_ACTION"
++superstack;
luaactions[luaactionstack] = lua_tostring(gL, -2); // "A_ACTION"
++luaactionstack;
lua_pop(gL, 2); // pop the name and function
break;
}
@ -661,8 +661,8 @@ static void A_Lua(mobj_t *actor)
if (found)
{
--superstack;
superactions[superstack] = NULL;
--luaactionstack;
luaactions[luaactionstack] = NULL;
}
}
@ -812,22 +812,54 @@ boolean LUA_SetLuaAction(void *stv, const char *action)
return true; // action successfully set.
}
static UINT8 superstack[NUMACTIONS];
boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor)
{
I_Assert(actor != NULL);
if (!actionsoverridden[actionnum]) // The action is not overriden,
return false; // action not called.
if (actionsoverridden[actionnum][0] == LUA_REFNIL)
{
// The action was not overridden at all,
// so just call the hardcoded version.
return false;
}
if (superstack && fasticmp(actionpointers[actionnum].name, superactions[superstack-1])) // the action is calling itself,
return false; // let it call the hardcoded function instead.
if (luaactionstack && fasticmp(actionpointers[actionnum].name, luaactions[luaactionstack-1]))
{
// The action is calling itself,
// so look up the next Lua reference in its stack.
// 0 is just the reference to the one we're calling,
// so we increment here.
superstack[actionnum]++;
if (superstack[actionnum] >= MAX_ACTION_RECURSION)
{
CONS_Alert(CONS_WARNING, "Max Lua super recursion reached! Cool it on calling super!\n");
superstack[actionnum] = 0;
return false;
}
}
if (actionsoverridden[actionnum][superstack[actionnum]] == LUA_REFNIL)
{
// No Lua reference beyond this point.
// Let it call the hardcoded function instead.
if (superstack[actionnum])
{
// Decrement super stack
superstack[actionnum]--;
}
return false;
}
// Push error function
lua_pushcfunction(gL, LUA_GetErrorMessage);
// grab function by uppercase name.
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS);
lua_getfield(gL, -1, actionpointers[actionnum].name);
lua_remove(gL, -2); // pop LREG_ACTIONS
// Push function by reference.
lua_getref(gL, actionsoverridden[actionnum][superstack[actionnum]]);
if (lua_isnil(gL, -1)) // no match
{
@ -835,7 +867,7 @@ boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor)
return false; // action not called.
}
if (superstack == MAXRECURSION)
if (luaactionstack >= MAX_ACTION_RECURSION)
{
CONS_Alert(CONS_WARNING, "Max Lua Action recursion reached! Cool it on the calling A_Action functions from inside A_Action functions!\n");
lua_pop(gL, 2); // pop function and error handler
@ -849,14 +881,20 @@ boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor)
lua_pushinteger(gL, var1);
lua_pushinteger(gL, var2);
superactions[superstack] = actionpointers[actionnum].name;
++superstack;
luaactions[luaactionstack] = actionpointers[actionnum].name;
++luaactionstack;
LUA_Call(gL, 3, 0, -(2 + 3));
lua_pop(gL, -1); // Error handler
--superstack;
superactions[superstack] = NULL;
if (superstack[actionnum])
{
// Decrement super stack
superstack[actionnum]--;
}
--luaactionstack;
luaactions[luaactionstack] = NULL;
return true; // action successfully called.
}

View file

@ -501,7 +501,19 @@ static int setglobals(lua_State *L)
actionnum = LUA_GetActionNumByName(name);
if (actionnum < NUMACTIONS)
actionsoverridden[actionnum] = true;
{
int i;
for (i = MAX_ACTION_RECURSION-1; i > 0; i--)
{
// Move other references deeper.
actionsoverridden[actionnum][i] = actionsoverridden[actionnum][i - 1];
}
// Add the new reference.
lua_pushvalue(L, 2);
actionsoverridden[actionnum][0] = luaL_ref(L, LUA_REGISTRYINDEX);
}
Z_Free(name);
return 0;