Replace LUA_PushLightUserdata with LUA_PushUserdata

See 7df6a309 and 83a87042. I didn't realize that light
userdata's metatable is shared--like numbers or strings.
So it cannot be paired with a metatable.

I also made a few minor tweaks to Lua cvars, other than
accounting for the double pointer in the userdata.
This commit is contained in:
James R 2021-05-02 21:59:23 -07:00
parent ed5a7f51e8
commit aee963f4e9
4 changed files with 23 additions and 57 deletions

View file

@ -1577,7 +1577,7 @@ finish:
} }
var->flags |= CV_MODIFIED; var->flags |= CV_MODIFIED;
// raise 'on change' code // raise 'on change' code
LUA_CVarChanged(var->name); // let consolelib know what cvar this is. LUA_CVarChanged(var); // let consolelib know what cvar this is.
if (var->flags & CV_CALL && !stealth) if (var->flags & CV_CALL && !stealth)
var->func(); var->func();

View file

@ -28,7 +28,7 @@ return luaL_error(L, "HUD rendering code should not call this function!");
#define NOHOOK if (!lua_lumploading)\ #define NOHOOK if (!lua_lumploading)\
return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
static const char *cvname = NULL; static consvar_t *this_cvar;
void Got_Luacmd(UINT8 **cp, INT32 playernum) void Got_Luacmd(UINT8 **cp, INT32 playernum)
{ {
@ -273,16 +273,13 @@ static int lib_comBufInsertText(lua_State *L)
return 0; return 0;
} }
void LUA_CVarChanged(const char *name) void LUA_CVarChanged(void *cvar)
{ {
cvname = name; this_cvar = cvar;
} }
static void Lua_OnChange(void) static void Lua_OnChange(void)
{ {
I_Assert(gL != NULL);
I_Assert(cvname != NULL);
/// \todo Network this! XD_LUAVAR /// \todo Network this! XD_LUAVAR
lua_pushcfunction(gL, LUA_GetErrorMessage); lua_pushcfunction(gL, LUA_GetErrorMessage);
@ -291,13 +288,10 @@ static void Lua_OnChange(void)
// From CV_OnChange registry field, get the function for this cvar by name. // From CV_OnChange registry field, get the function for this cvar by name.
lua_getfield(gL, LUA_REGISTRYINDEX, "CV_OnChange"); lua_getfield(gL, LUA_REGISTRYINDEX, "CV_OnChange");
I_Assert(lua_istable(gL, -1)); I_Assert(lua_istable(gL, -1));
lua_getfield(gL, -1, cvname); // get function lua_pushlightuserdata(gL, this_cvar);
lua_rawget(gL, -2); // get function
// From the CV_Vars registry field, get the cvar's userdata by name. LUA_RawPushUserdata(gL, this_cvar);
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, 0, 1); // call function(cvar) LUA_Call(gL, 1, 0, 1); // call function(cvar)
lua_pop(gL, 1); // pop CV_OnChange table lua_pop(gL, 1); // pop CV_OnChange table
@ -312,15 +306,12 @@ static int lib_cvRegisterVar(lua_State *L)
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one. lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
NOHOOK NOHOOK
cvar = lua_newuserdata(L, sizeof(consvar_t)); cvar = ZZ_Calloc(sizeof(consvar_t));
luaL_getmetatable(L, META_CVAR); LUA_PushUserdata(L, cvar, META_CVAR);
lua_setmetatable(L, -2);
#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("CV_RegisterVar") " (%s)", e); #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("CV_RegisterVar") " (%s)", e);
#define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1)))
memset(cvar, 0x00, sizeof(consvar_t)); // zero everything by default
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, 1)) { while (lua_next(L, 1)) {
// stack: cvar table, cvar userdata, key/index, value // stack: cvar table, cvar userdata, key/index, value
@ -369,7 +360,7 @@ static int lib_cvRegisterVar(lua_State *L)
lua_getfield(L, LUA_REGISTRYINDEX, "CV_PossibleValue"); lua_getfield(L, LUA_REGISTRYINDEX, "CV_PossibleValue");
I_Assert(lua_istable(L, 5)); I_Assert(lua_istable(L, 5));
lua_pushvalue(L, 2); // cvar userdata lua_pushlightuserdata(L, cvar);
cvpv = lua_newuserdata(L, sizeof(CV_PossibleValue_t) * (count+1)); cvpv = lua_newuserdata(L, sizeof(CV_PossibleValue_t) * (count+1));
lua_rawset(L, 5); lua_rawset(L, 5);
lua_pop(L, 1); // pop CV_PossibleValue registry table lua_pop(L, 1); // pop CV_PossibleValue registry table
@ -397,8 +388,9 @@ static int lib_cvRegisterVar(lua_State *L)
TYPEERROR("func", LUA_TFUNCTION) TYPEERROR("func", LUA_TFUNCTION)
lua_getfield(L, LUA_REGISTRYINDEX, "CV_OnChange"); lua_getfield(L, LUA_REGISTRYINDEX, "CV_OnChange");
I_Assert(lua_istable(L, 5)); I_Assert(lua_istable(L, 5));
lua_pushlightuserdata(L, cvar);
lua_pushvalue(L, 4); lua_pushvalue(L, 4);
lua_setfield(L, 5, cvar->name); lua_rawset(L, 5);
lua_pop(L, 1); lua_pop(L, 1);
cvar->func = Lua_OnChange; cvar->func = Lua_OnChange;
} }
@ -415,19 +407,6 @@ static int lib_cvRegisterVar(lua_State *L)
if ((cvar->flags & CV_CALL) && !cvar->func) if ((cvar->flags & CV_CALL) && !cvar->func)
return luaL_error(L, M_GetText("Variable %s has CV_CALL without a function\n"), cvar->name); return luaL_error(L, M_GetText("Variable %s has CV_CALL without a function\n"), cvar->name);
// stack: cvar table, cvar userdata
lua_getfield(L, LUA_REGISTRYINDEX, "CV_Vars");
I_Assert(lua_istable(L, 3));
lua_getfield(L, 3, cvar->name);
if (lua_type(L, -1) != LUA_TNIL)
return luaL_error(L, M_GetText("Variable %s is already defined\n"), cvar->name);
lua_pop(L, 1);
lua_pushvalue(L, 2);
lua_setfield(L, 3, cvar->name);
lua_pop(L, 1);
// actually time to register it to the console now! Finally! // actually time to register it to the console now! Finally!
cvar->flags |= CV_MODIFIED; cvar->flags |= CV_MODIFIED;
CV_RegisterVar(cvar); CV_RegisterVar(cvar);
@ -440,22 +419,9 @@ static int lib_cvRegisterVar(lua_State *L)
static int lib_cvFindVar(lua_State *L) static int lib_cvFindVar(lua_State *L)
{ {
consvar_t *cv; const char *name = luaL_checkstring(L, 1);
if (( cv = CV_FindVar(luaL_checkstring(L,1)) )) LUA_PushUserdata(L, CV_FindVar(name), META_CVAR);
{
lua_settop(L,1);/* We only want one argument in the stack. */
lua_pushlightuserdata(L, cv);/* Now the second value on stack. */
luaL_getmetatable(L, META_CVAR);
/*
The metatable is the last value on the stack, so this
applies it to the second value, which is the cvar.
*/
lua_setmetatable(L,2);
lua_pushvalue(L,2);
return 1; return 1;
}
else
return 0;
} }
static int CVarSetFunction static int CVarSetFunction
@ -464,7 +430,7 @@ static int CVarSetFunction
void (*Set)(consvar_t *, const char *), void (*Set)(consvar_t *, const char *),
void (*SetValue)(consvar_t *, INT32) void (*SetValue)(consvar_t *, INT32)
){ ){
consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR);
if (cvar->flags & CV_NOLUA) if (cvar->flags & CV_NOLUA)
return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name); return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name);
@ -496,7 +462,7 @@ static int lib_cvStealthSet(lua_State *L)
static int lib_cvAddValue(lua_State *L) static int lib_cvAddValue(lua_State *L)
{ {
consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR);
if (cvar->flags & CV_NOLUA) if (cvar->flags & CV_NOLUA)
return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name); return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name);
@ -555,7 +521,7 @@ static luaL_Reg lib[] = {
static int cvar_get(lua_State *L) static int cvar_get(lua_State *L)
{ {
consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR);
const char *field = luaL_checkstring(L, 2); const char *field = luaL_checkstring(L, 2);
if(fastcmp(field,"name")) if(fastcmp(field,"name"))

View file

@ -56,7 +56,7 @@ void LUA_UnArchive(void);
int LUA_PushGlobals(lua_State *L, const char *word); int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_CheckGlobals(lua_State *L, const char *word); int LUA_CheckGlobals(lua_State *L, const char *word);
void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
void LUA_CVarChanged(const char *name); // lua_consolelib.c void LUA_CVarChanged(void *cvar); // lua_consolelib.c
int Lua_optoption(lua_State *L, int narg, int Lua_optoption(lua_State *L, int narg,
const char *def, const char *const lst[]); const char *def, const char *const lst[]);
void LUAh_NetArchiveHook(lua_CFunction archFunc); void LUAh_NetArchiveHook(lua_CFunction archFunc);

View file

@ -213,7 +213,7 @@ static int skin_get(lua_State *L)
lua_pushinteger(L, skin->availability); lua_pushinteger(L, skin->availability);
break; break;
case skin_sprites: case skin_sprites:
LUA_PushLightUserdata(L, skin->sprites, META_SKINSPRITES); LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
break; break;
} }
return 1; return 1;
@ -336,13 +336,13 @@ static const char *const sprites_opt[] = {
// skin.sprites[i] -> sprites[i] // skin.sprites[i] -> sprites[i]
static int lib_getSkinSprite(lua_State *L) static int lib_getSkinSprite(lua_State *L)
{ {
spritedef_t *sprites = (spritedef_t *)luaL_checkudata(L, 1, META_SKINSPRITES); spritedef_t *sprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES);
playersprite_t i = luaL_checkinteger(L, 2); playersprite_t i = luaL_checkinteger(L, 2);
if (i < 0 || i >= NUMPLAYERSPRITES*2) if (i < 0 || i >= NUMPLAYERSPRITES*2)
return luaL_error(L, LUA_QL("skin_t") " field 'sprites' index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1); return luaL_error(L, LUA_QL("skin_t") " field 'sprites' index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1);
LUA_PushLightUserdata(L, &sprites[i], META_SKINSPRITESLIST); LUA_PushUserdata(L, &sprites[i], META_SKINSPRITESLIST);
return 1; return 1;
} }
@ -355,7 +355,7 @@ static int lib_numSkinsSprites(lua_State *L)
static int sprite_get(lua_State *L) static int sprite_get(lua_State *L)
{ {
spritedef_t *sprite = (spritedef_t *)luaL_checkudata(L, 1, META_SKINSPRITESLIST); spritedef_t *sprite = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESLIST);
enum spritesopt field = luaL_checkoption(L, 2, NULL, sprites_opt); enum spritesopt field = luaL_checkoption(L, 2, NULL, sprites_opt);
switch (field) switch (field)