Optimize field lookups in Lua metatables

This commit is contained in:
Gustaf Alhäll 2023-06-18 18:05:16 +02:00
parent 331c81f32d
commit 2f2de7d3d3
No known key found for this signature in database
GPG key ID: 6C1F67D690CDEDFD
9 changed files with 1597 additions and 537 deletions

View file

@ -566,27 +566,59 @@ static luaL_Reg lib[] = {
{NULL, NULL} {NULL, NULL}
}; };
enum cvar_e
{
cvar_name,
cvar_defaultvalue,
cvar_flags,
cvar_value,
cvar_string,
cvar_changed,
};
static const char *const cvar_opt[] = {
"name",
"defaultvalue",
"flags",
"value",
"string",
"changed",
NULL,
};
static int cvar_fields_ref = LUA_NOREF;
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); enum cvar_e field = Lua_optoption(L, 2, -1, cvar_fields_ref);
if(fastcmp(field,"name")) switch (field)
{
case cvar_name:
lua_pushstring(L, cvar->name); lua_pushstring(L, cvar->name);
else if(fastcmp(field,"defaultvalue")) break;
case cvar_defaultvalue:
lua_pushstring(L, cvar->defaultvalue); lua_pushstring(L, cvar->defaultvalue);
else if(fastcmp(field,"flags")) break;
case cvar_flags:
lua_pushinteger(L, cvar->flags); lua_pushinteger(L, cvar->flags);
else if(fastcmp(field,"value")) break;
case cvar_value:
lua_pushinteger(L, cvar->value); lua_pushinteger(L, cvar->value);
else if(fastcmp(field,"string")) break;
case cvar_string:
lua_pushstring(L, cvar->string); lua_pushstring(L, cvar->string);
else if(fastcmp(field,"changed")) break;
case cvar_changed:
lua_pushboolean(L, cvar->changed); lua_pushboolean(L, cvar->changed);
else if (devparm) break;
default:
if (devparm)
return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field); return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field);
else else
return 0; return 0;
}
return 1; return 1;
} }
@ -598,6 +630,8 @@ int LUA_ConsoleLib(lua_State *L)
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
lua_pop(L,1); lua_pop(L,1);
cvar_fields_ref = Lua_CreateFieldTable(L, cvar_opt);
// Set empty registry tables // Set empty registry tables
lua_newtable(L); lua_newtable(L);
lua_setfield(L, LUA_REGISTRYINDEX, "COM_Command"); lua_setfield(L, LUA_REGISTRYINDEX, "COM_Command");

View file

@ -95,6 +95,8 @@ static const char *const patch_opt[] = {
"topoffset", "topoffset",
NULL}; NULL};
static int patch_fields_ref = LUA_NOREF;
// alignment types for v.drawString // alignment types for v.drawString
enum align { enum align {
align_left = 0, align_left = 0,
@ -196,6 +198,8 @@ static const char *const camera_opt[] = {
"momz", "momz",
NULL}; NULL};
static int camera_fields_ref = LUA_NOREF;
static int lib_getHudInfo(lua_State *L) static int lib_getHudInfo(lua_State *L)
{ {
UINT32 i; UINT32 i;
@ -276,7 +280,7 @@ static int colormap_get(lua_State *L)
static int patch_get(lua_State *L) static int patch_get(lua_State *L)
{ {
patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH));
enum patch field = luaL_checkoption(L, 2, NULL, patch_opt); enum patch field = Lua_optoption(L, 2, -1, patch_fields_ref);
// patches are invalidated when switching renderers // patches are invalidated when switching renderers
if (!patch) { if (!patch) {
@ -316,7 +320,7 @@ static int patch_set(lua_State *L)
static int camera_get(lua_State *L) static int camera_get(lua_State *L)
{ {
camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA));
enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt); enum cameraf field = Lua_optoption(L, 2, -1, camera_fields_ref);
// cameras should always be valid unless I'm a nutter // cameras should always be valid unless I'm a nutter
I_Assert(cam != NULL); I_Assert(cam != NULL);
@ -372,7 +376,7 @@ static int camera_get(lua_State *L)
static int camera_set(lua_State *L) static int camera_set(lua_State *L)
{ {
camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA));
enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt); enum cameraf field = Lua_optoption(L, 2, -1, camera_fields_ref);
I_Assert(cam != NULL); I_Assert(cam != NULL);
@ -1444,6 +1448,8 @@ int LUA_HudLib(lua_State *L)
lua_setfield(L, -2, "__newindex"); lua_setfield(L, -2, "__newindex");
lua_pop(L,1); lua_pop(L,1);
patch_fields_ref = Lua_CreateFieldTable(L, patch_opt);
luaL_newmetatable(L, META_CAMERA); luaL_newmetatable(L, META_CAMERA);
lua_pushcfunction(L, camera_get); lua_pushcfunction(L, camera_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -1452,6 +1458,8 @@ int LUA_HudLib(lua_State *L)
lua_setfield(L, -2, "__newindex"); lua_setfield(L, -2, "__newindex");
lua_pop(L,1); lua_pop(L,1);
camera_fields_ref = Lua_CreateFieldTable(L, camera_opt);
luaL_register(L, "hud", lib_hud); luaL_register(L, "hud", lib_hud);
return 0; return 0;
} }

View file

@ -1106,75 +1106,161 @@ static int lib_mobjinfolen(lua_State *L)
return 1; return 1;
} }
enum mobjinfo_e
{
mobjinfo_doomednum,
mobjinfo_spawnstate,
mobjinfo_spawnhealth,
mobjinfo_seestate,
mobjinfo_seesound,
mobjinfo_reactiontime,
mobjinfo_attacksound,
mobjinfo_painstate,
mobjinfo_painchance,
mobjinfo_painsound,
mobjinfo_meleestate,
mobjinfo_missilestate,
mobjinfo_deathstate,
mobjinfo_xdeathstate,
mobjinfo_deathsound,
mobjinfo_speed,
mobjinfo_radius,
mobjinfo_height,
mobjinfo_dispoffset,
mobjinfo_mass,
mobjinfo_damage,
mobjinfo_activesound,
mobjinfo_flags,
mobjinfo_raisestate,
};
const char *const mobjinfo_opt[] = {
"doomednum",
"spawnstate",
"spawnhealth",
"seestate",
"seesound",
"reactiontime",
"attacksound",
"painstate",
"painchance",
"painsound",
"meleestate",
"missilestate",
"deathstate",
"xdeathstate",
"deathsound",
"speed",
"radius",
"height",
"dispoffset",
"mass",
"damage",
"activesound",
"flags",
"raisestate",
NULL,
};
static int mobjinfo_fields_ref = LUA_NOREF;
// mobjinfo_t *, field -> number // mobjinfo_t *, field -> number
static int mobjinfo_get(lua_State *L) static int mobjinfo_get(lua_State *L)
{ {
mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO)); mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO));
const char *field = luaL_checkstring(L, 2); enum mobjinfo_e field = luaL_checkoption(L, 2, mobjinfo_opt[0], mobjinfo_opt);
I_Assert(info != NULL); I_Assert(info != NULL);
I_Assert(info >= mobjinfo); I_Assert(info >= mobjinfo);
if (fastcmp(field,"doomednum")) switch (field)
{
case mobjinfo_doomednum:
lua_pushinteger(L, info->doomednum); lua_pushinteger(L, info->doomednum);
else if (fastcmp(field,"spawnstate")) break;
case mobjinfo_spawnstate:
lua_pushinteger(L, info->spawnstate); lua_pushinteger(L, info->spawnstate);
else if (fastcmp(field,"spawnhealth")) break;
case mobjinfo_spawnhealth:
lua_pushinteger(L, info->spawnhealth); lua_pushinteger(L, info->spawnhealth);
else if (fastcmp(field,"seestate")) break;
case mobjinfo_seestate:
lua_pushinteger(L, info->seestate); lua_pushinteger(L, info->seestate);
else if (fastcmp(field,"seesound")) break;
case mobjinfo_seesound:
lua_pushinteger(L, info->seesound); lua_pushinteger(L, info->seesound);
else if (fastcmp(field,"reactiontime")) break;
case mobjinfo_reactiontime:
lua_pushinteger(L, info->reactiontime); lua_pushinteger(L, info->reactiontime);
else if (fastcmp(field,"attacksound")) break;
case mobjinfo_attacksound:
lua_pushinteger(L, info->attacksound); lua_pushinteger(L, info->attacksound);
else if (fastcmp(field,"painstate")) break;
case mobjinfo_painstate:
lua_pushinteger(L, info->painstate); lua_pushinteger(L, info->painstate);
else if (fastcmp(field,"painchance")) break;
case mobjinfo_painchance:
lua_pushinteger(L, info->painchance); lua_pushinteger(L, info->painchance);
else if (fastcmp(field,"painsound")) break;
case mobjinfo_painsound:
lua_pushinteger(L, info->painsound); lua_pushinteger(L, info->painsound);
else if (fastcmp(field,"meleestate")) break;
case mobjinfo_meleestate:
lua_pushinteger(L, info->meleestate); lua_pushinteger(L, info->meleestate);
else if (fastcmp(field,"missilestate")) break;
case mobjinfo_missilestate:
lua_pushinteger(L, info->missilestate); lua_pushinteger(L, info->missilestate);
else if (fastcmp(field,"deathstate")) break;
case mobjinfo_deathstate:
lua_pushinteger(L, info->deathstate); lua_pushinteger(L, info->deathstate);
else if (fastcmp(field,"xdeathstate")) break;
case mobjinfo_xdeathstate:
lua_pushinteger(L, info->xdeathstate); lua_pushinteger(L, info->xdeathstate);
else if (fastcmp(field,"deathsound")) break;
case mobjinfo_deathsound:
lua_pushinteger(L, info->deathsound); lua_pushinteger(L, info->deathsound);
else if (fastcmp(field,"speed")) break;
case mobjinfo_speed:
lua_pushinteger(L, info->speed); // sometimes it's fixed_t, sometimes it's not... lua_pushinteger(L, info->speed); // sometimes it's fixed_t, sometimes it's not...
else if (fastcmp(field,"radius")) break;
case mobjinfo_radius:
lua_pushfixed(L, info->radius); lua_pushfixed(L, info->radius);
else if (fastcmp(field,"height")) break;
case mobjinfo_height:
lua_pushfixed(L, info->height); lua_pushfixed(L, info->height);
else if (fastcmp(field,"dispoffset")) break;
case mobjinfo_dispoffset:
lua_pushinteger(L, info->dispoffset); lua_pushinteger(L, info->dispoffset);
else if (fastcmp(field,"mass")) break;
case mobjinfo_mass:
lua_pushinteger(L, info->mass); lua_pushinteger(L, info->mass);
else if (fastcmp(field,"damage")) break;
case mobjinfo_damage:
lua_pushinteger(L, info->damage); lua_pushinteger(L, info->damage);
else if (fastcmp(field,"activesound")) break;
case mobjinfo_activesound:
lua_pushinteger(L, info->activesound); lua_pushinteger(L, info->activesound);
else if (fastcmp(field,"flags")) break;
case mobjinfo_flags:
lua_pushinteger(L, info->flags); lua_pushinteger(L, info->flags);
else if (fastcmp(field,"raisestate")) break;
case mobjinfo_raisestate:
lua_pushinteger(L, info->raisestate); lua_pushinteger(L, info->raisestate);
else { break;
default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1)); I_Assert(lua_istable(L, -1));
lua_pushlightuserdata(L, info); lua_pushlightuserdata(L, info);
lua_rawget(L, -2); lua_rawget(L, -2);
if (!lua_istable(L, -1)) { // no extra values table if (!lua_istable(L, -1)) { // no extra values table
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field); CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", lua_tostring(L, 2));
return 0; return 0;
} }
lua_getfield(L, -1, field); lua_pushvalue(L, 2); // field name
lua_gettable(L, -2);
if (lua_isnil(L, -1)) // no value for this field if (lua_isnil(L, -1)) // no value for this field
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field); CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", lua_tostring(L, 2));
break;
} }
return 1; return 1;
} }
@ -1183,7 +1269,7 @@ static int mobjinfo_get(lua_State *L)
static int mobjinfo_set(lua_State *L) static int mobjinfo_set(lua_State *L)
{ {
mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO)); mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO));
const char *field = luaL_checkstring(L, 2); enum mobjinfo_e field = Lua_optoption(L, 2, -1, mobjinfo_fields_ref);
if (hud_running) if (hud_running)
return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!"); return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!");
@ -1193,55 +1279,81 @@ static int mobjinfo_set(lua_State *L)
I_Assert(info != NULL); I_Assert(info != NULL);
I_Assert(info >= mobjinfo); I_Assert(info >= mobjinfo);
if (fastcmp(field,"doomednum")) switch (field)
{
case mobjinfo_doomednum:
info->doomednum = (INT32)luaL_checkinteger(L, 3); info->doomednum = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"spawnstate")) break;
case mobjinfo_spawnstate:
info->spawnstate = luaL_checkinteger(L, 3); info->spawnstate = luaL_checkinteger(L, 3);
else if (fastcmp(field,"spawnhealth")) break;
case mobjinfo_spawnhealth:
info->spawnhealth = (INT32)luaL_checkinteger(L, 3); info->spawnhealth = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"seestate")) break;
case mobjinfo_seestate:
info->seestate = luaL_checkinteger(L, 3); info->seestate = luaL_checkinteger(L, 3);
else if (fastcmp(field,"seesound")) break;
case mobjinfo_seesound:
info->seesound = luaL_checkinteger(L, 3); info->seesound = luaL_checkinteger(L, 3);
else if (fastcmp(field,"reactiontime")) break;
case mobjinfo_reactiontime:
info->reactiontime = (INT32)luaL_checkinteger(L, 3); info->reactiontime = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"attacksound")) break;
case mobjinfo_attacksound:
info->attacksound = luaL_checkinteger(L, 3); info->attacksound = luaL_checkinteger(L, 3);
else if (fastcmp(field,"painstate")) break;
case mobjinfo_painstate:
info->painstate = luaL_checkinteger(L, 3); info->painstate = luaL_checkinteger(L, 3);
else if (fastcmp(field,"painchance")) break;
case mobjinfo_painchance:
info->painchance = (INT32)luaL_checkinteger(L, 3); info->painchance = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"painsound")) break;
case mobjinfo_painsound:
info->painsound = luaL_checkinteger(L, 3); info->painsound = luaL_checkinteger(L, 3);
else if (fastcmp(field,"meleestate")) break;
case mobjinfo_meleestate:
info->meleestate = luaL_checkinteger(L, 3); info->meleestate = luaL_checkinteger(L, 3);
else if (fastcmp(field,"missilestate")) break;
case mobjinfo_missilestate:
info->missilestate = luaL_checkinteger(L, 3); info->missilestate = luaL_checkinteger(L, 3);
else if (fastcmp(field,"deathstate")) break;
case mobjinfo_deathstate:
info->deathstate = luaL_checkinteger(L, 3); info->deathstate = luaL_checkinteger(L, 3);
else if (fastcmp(field,"xdeathstate")) break;
case mobjinfo_xdeathstate:
info->xdeathstate = luaL_checkinteger(L, 3); info->xdeathstate = luaL_checkinteger(L, 3);
else if (fastcmp(field,"deathsound")) break;
case mobjinfo_deathsound:
info->deathsound = luaL_checkinteger(L, 3); info->deathsound = luaL_checkinteger(L, 3);
else if (fastcmp(field,"speed")) break;
case mobjinfo_speed:
info->speed = luaL_checkfixed(L, 3); info->speed = luaL_checkfixed(L, 3);
else if (fastcmp(field,"radius")) break;
case mobjinfo_radius:
info->radius = luaL_checkfixed(L, 3); info->radius = luaL_checkfixed(L, 3);
else if (fastcmp(field,"height")) break;
case mobjinfo_height:
info->height = luaL_checkfixed(L, 3); info->height = luaL_checkfixed(L, 3);
else if (fastcmp(field,"dispoffset")) break;
case mobjinfo_dispoffset:
info->dispoffset = (INT32)luaL_checkinteger(L, 3); info->dispoffset = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"mass")) break;
case mobjinfo_mass:
info->mass = (INT32)luaL_checkinteger(L, 3); info->mass = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"damage")) break;
case mobjinfo_damage:
info->damage = (INT32)luaL_checkinteger(L, 3); info->damage = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"activesound")) break;
case mobjinfo_activesound:
info->activesound = luaL_checkinteger(L, 3); info->activesound = luaL_checkinteger(L, 3);
else if (fastcmp(field,"flags")) break;
case mobjinfo_flags:
info->flags = (INT32)luaL_checkinteger(L, 3); info->flags = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"raisestate")) break;
case mobjinfo_raisestate:
info->raisestate = luaL_checkinteger(L, 3); info->raisestate = luaL_checkinteger(L, 3);
else { break;
default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1)); I_Assert(lua_istable(L, -1));
lua_pushlightuserdata(L, info); lua_pushlightuserdata(L, info);
@ -1249,18 +1361,17 @@ static int mobjinfo_set(lua_State *L)
if (lua_isnil(L, -1)) { if (lua_isnil(L, -1)) {
// This index doesn't have a table for extra values yet, let's make one. // This index doesn't have a table for extra values yet, let's make one.
lua_pop(L, 1); lua_pop(L, 1);
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", field); CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", lua_tostring(L, 2));
lua_newtable(L); lua_newtable(L);
lua_pushlightuserdata(L, info); lua_pushlightuserdata(L, info);
lua_pushvalue(L, -2); // ext value table lua_pushvalue(L, -2); // ext value table
lua_rawset(L, -4); // LREG_EXTVARS table lua_rawset(L, -4); // LREG_EXTVARS table
} }
lua_pushvalue(L, 2); // key
lua_pushvalue(L, 3); // value to store lua_pushvalue(L, 3); // value to store
lua_setfield(L, -2, field); lua_settable(L, -3);
lua_pop(L, 2); lua_pop(L, 2);
} }
//else
//return luaL_error(L, LUA_QL("mobjinfo_t") " has no field named " LUA_QS, field);
return 0; return 0;
} }
@ -1788,6 +1899,8 @@ int LUA_InfoLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
mobjinfo_fields_ref = Lua_CreateFieldTable(L, mobjinfo_opt);
luaL_newmetatable(L, META_SKINCOLOR); luaL_newmetatable(L, META_SKINCOLOR);
lua_pushcfunction(L, skincolor_get); lua_pushcfunction(L, skincolor_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");

View file

@ -88,6 +88,8 @@ static const char *const sector_opt[] = {
"gravity", "gravity",
NULL}; NULL};
static int sector_fields_ref = LUA_NOREF;
enum subsector_e { enum subsector_e {
subsector_valid = 0, subsector_valid = 0,
subsector_sector, subsector_sector,
@ -104,6 +106,8 @@ static const char *const subsector_opt[] = {
"polyList", "polyList",
NULL}; NULL};
static int subsector_fields_ref = LUA_NOREF;
enum line_e { enum line_e {
line_valid = 0, line_valid = 0,
line_v1, line_v1,
@ -156,6 +160,8 @@ static const char *const line_opt[] = {
"callcount", "callcount",
NULL}; NULL};
static int line_fields_ref = LUA_NOREF;
enum side_e { enum side_e {
side_valid = 0, side_valid = 0,
side_textureoffset, side_textureoffset,
@ -184,6 +190,8 @@ static const char *const side_opt[] = {
"text", "text",
NULL}; NULL};
static int side_fields_ref = LUA_NOREF;
enum vertex_e { enum vertex_e {
vertex_valid = 0, vertex_valid = 0,
vertex_x, vertex_x,
@ -204,6 +212,8 @@ static const char *const vertex_opt[] = {
"ceilingzset", "ceilingzset",
NULL}; NULL};
static int vertex_fields_ref = LUA_NOREF;
enum ffloor_e { enum ffloor_e {
ffloor_valid = 0, ffloor_valid = 0,
ffloor_topheight, ffloor_topheight,
@ -256,6 +266,8 @@ static const char *const ffloor_opt[] = {
"bouncestrength", "bouncestrength",
NULL}; NULL};
static int ffloor_fields_ref = LUA_NOREF;
#ifdef HAVE_LUA_SEGS #ifdef HAVE_LUA_SEGS
enum seg_e { enum seg_e {
seg_valid = 0, seg_valid = 0,
@ -285,6 +297,8 @@ static const char *const seg_opt[] = {
"polyseg", "polyseg",
NULL}; NULL};
static int seg_fields_ref = LUA_NOREF;
enum node_e { enum node_e {
node_valid = 0, node_valid = 0,
node_x, node_x,
@ -305,6 +319,8 @@ static const char *const node_opt[] = {
"children", "children",
NULL}; NULL};
static int node_fields_ref = LUA_NOREF;
enum nodechild_e { enum nodechild_e {
nodechild_valid = 0, nodechild_valid = 0,
nodechild_right, nodechild_right,
@ -356,6 +372,8 @@ static const char *const slope_opt[] = {
"flags", "flags",
NULL}; NULL};
static int slope_fields_ref = LUA_NOREF;
// shared by both vector2_t and vector3_t // shared by both vector2_t and vector3_t
enum vector_e { enum vector_e {
vector_x = 0, vector_x = 0,
@ -575,7 +593,7 @@ static int sectorlines_num(lua_State *L)
static int sector_get(lua_State *L) static int sector_get(lua_State *L)
{ {
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref);
INT16 i; INT16 i;
if (!sector) if (!sector)
@ -697,7 +715,7 @@ static int sector_get(lua_State *L)
static int sector_set(lua_State *L) static int sector_set(lua_State *L)
{ {
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref);
if (!sector) if (!sector)
return luaL_error(L, "accessed sector_t doesn't exist anymore."); return luaL_error(L, "accessed sector_t doesn't exist anymore.");
@ -814,7 +832,7 @@ static int sector_num(lua_State *L)
static int subsector_get(lua_State *L) static int subsector_get(lua_State *L)
{ {
subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)); subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR));
enum subsector_e field = luaL_checkoption(L, 2, subsector_opt[0], subsector_opt); enum subsector_e field = Lua_optoption(L, 2, subsector_valid, subsector_fields_ref);
if (!subsector) if (!subsector)
{ {
@ -898,7 +916,7 @@ static int linestringargs_len(lua_State *L)
static int line_get(lua_State *L) static int line_get(lua_State *L)
{ {
line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE)); line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE));
enum line_e field = luaL_checkoption(L, 2, line_opt[0], line_opt); enum line_e field = Lua_optoption(L, 2, line_valid, line_fields_ref);
if (!line) if (!line)
{ {
@ -1057,7 +1075,7 @@ static int sidenum_get(lua_State *L)
static int side_get(lua_State *L) static int side_get(lua_State *L)
{ {
side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt); enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref);
if (!side) if (!side)
{ {
@ -1110,7 +1128,7 @@ static int side_get(lua_State *L)
static int side_set(lua_State *L) static int side_set(lua_State *L)
{ {
side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt); enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref);
if (!side) if (!side)
{ {
@ -1166,7 +1184,7 @@ static int side_num(lua_State *L)
static int vertex_get(lua_State *L) static int vertex_get(lua_State *L)
{ {
vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX)); vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX));
enum vertex_e field = luaL_checkoption(L, 2, vertex_opt[0], vertex_opt); enum vertex_e field = Lua_optoption(L, 2, vertex_valid, vertex_fields_ref);
if (!vertex) if (!vertex)
{ {
@ -1220,7 +1238,7 @@ static int vertex_num(lua_State *L)
static int seg_get(lua_State *L) static int seg_get(lua_State *L)
{ {
seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG)); seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG));
enum seg_e field = luaL_checkoption(L, 2, seg_opt[0], seg_opt); enum seg_e field = Lua_optoption(L, 2, seg_valid, seg_fields_ref);
if (!seg) if (!seg)
{ {
@ -1284,7 +1302,7 @@ static int seg_num(lua_State *L)
static int node_get(lua_State *L) static int node_get(lua_State *L)
{ {
node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE)); node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE));
enum node_e field = luaL_checkoption(L, 2, node_opt[0], node_opt); enum node_e field = Lua_optoption(L, 2, node_valid, node_fields_ref);
if (!node) if (!node)
{ {
@ -1920,7 +1938,7 @@ static INT32 P_GetOldFOFFlags(ffloor_t *fflr)
static int ffloor_get(lua_State *L) static int ffloor_get(lua_State *L)
{ {
ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref);
INT16 i; INT16 i;
if (!ffloor) if (!ffloor)
@ -2102,7 +2120,7 @@ static void P_SetOldFOFFlags(ffloor_t *fflr, oldffloortype_e oldflags)
static int ffloor_set(lua_State *L) static int ffloor_set(lua_State *L)
{ {
ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref);
if (!ffloor) if (!ffloor)
return luaL_error(L, "accessed ffloor_t doesn't exist anymore."); return luaL_error(L, "accessed ffloor_t doesn't exist anymore.");
@ -2197,7 +2215,7 @@ static int ffloor_set(lua_State *L)
static int slope_get(lua_State *L) static int slope_get(lua_State *L)
{ {
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt); enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref);
if (!slope) if (!slope)
{ {
@ -2241,7 +2259,7 @@ static int slope_get(lua_State *L)
static int slope_set(lua_State *L) static int slope_set(lua_State *L)
{ {
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt); enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref);
if (!slope) if (!slope)
return luaL_error(L, "accessed pslope_t doesn't exist anymore."); return luaL_error(L, "accessed pslope_t doesn't exist anymore.");
@ -2405,110 +2423,258 @@ static int lib_nummapheaders(lua_State *L)
// mapheader_t // // mapheader_t //
///////////////// /////////////////
enum mapheaderinfo_e
{
mapheaderinfo_lvlttl,
mapheaderinfo_subttl,
mapheaderinfo_actnum,
mapheaderinfo_typeoflevel,
mapheaderinfo_nextlevel,
mapheaderinfo_marathonnext,
mapheaderinfo_keywords,
mapheaderinfo_musname,
mapheaderinfo_mustrack,
mapheaderinfo_muspos,
mapheaderinfo_musinterfadeout,
mapheaderinfo_musintername,
mapheaderinfo_muspostbossname,
mapheaderinfo_muspostbosstrack,
mapheaderinfo_muspostbosspos,
mapheaderinfo_muspostbossfadein,
mapheaderinfo_musforcereset,
mapheaderinfo_forcecharacter,
mapheaderinfo_weather,
mapheaderinfo_skynum,
mapheaderinfo_skybox_scalex,
mapheaderinfo_skybox_scaley,
mapheaderinfo_skybox_scalez,
mapheaderinfo_interscreen,
mapheaderinfo_runsoc,
mapheaderinfo_scriptname,
mapheaderinfo_precutscenenum,
mapheaderinfo_cutscenenum,
mapheaderinfo_countdown,
mapheaderinfo_palette,
mapheaderinfo_numlaps,
mapheaderinfo_unlockrequired,
mapheaderinfo_levelselect,
mapheaderinfo_bonustype,
mapheaderinfo_ltzzpatch,
mapheaderinfo_ltzztext,
mapheaderinfo_ltactdiamond,
mapheaderinfo_maxbonuslives,
mapheaderinfo_levelflags,
mapheaderinfo_menuflags,
mapheaderinfo_selectheading,
mapheaderinfo_startrings,
mapheaderinfo_sstimer,
mapheaderinfo_ssspheres,
mapheaderinfo_gravity,
};
static const char *const mapheaderinfo_opt[] = {
"lvlttl",
"subttl",
"actnum",
"typeoflevel",
"nextlevel",
"marathonnext",
"keywords",
"musname",
"mustrack",
"muspos",
"musinterfadeout",
"musintername",
"muspostbossname",
"muspostbosstrack",
"muspostbosspos",
"muspostbossfadein",
"musforcereset",
"forcecharacter",
"weather",
"skynum",
"skybox_scalex",
"skybox_scaley",
"skybox_scalez",
"interscreen",
"runsoc",
"scriptname",
"precutscenenum",
"cutscenenum",
"countdown",
"palette",
"numlaps",
"unlockrequired",
"levelselect",
"bonustype",
"ltzzpatch",
"ltzztext",
"ltactdiamond",
"maxbonuslives",
"levelflags",
"menuflags",
"selectheading",
"startrings",
"sstimer",
"ssspheres",
"gravity",
NULL,
};
static int mapheaderinfo_fields_ref = LUA_NOREF;
static int mapheaderinfo_get(lua_State *L) static int mapheaderinfo_get(lua_State *L)
{ {
mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER)); mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER));
const char *field = luaL_checkstring(L, 2); enum mapheaderinfo_e field = Lua_optoption(L, 2, -1, mapheaderinfo_fields_ref);
INT16 i; INT16 i;
if (fastcmp(field,"lvlttl"))
switch (field)
{
case mapheaderinfo_lvlttl:
lua_pushstring(L, header->lvlttl); lua_pushstring(L, header->lvlttl);
else if (fastcmp(field,"subttl")) break;
case mapheaderinfo_subttl:
lua_pushstring(L, header->subttl); lua_pushstring(L, header->subttl);
else if (fastcmp(field,"actnum")) break;
case mapheaderinfo_actnum:
lua_pushinteger(L, header->actnum); lua_pushinteger(L, header->actnum);
else if (fastcmp(field,"typeoflevel")) break;
case mapheaderinfo_typeoflevel:
lua_pushinteger(L, header->typeoflevel); lua_pushinteger(L, header->typeoflevel);
else if (fastcmp(field,"nextlevel")) break;
case mapheaderinfo_nextlevel:
lua_pushinteger(L, header->nextlevel); lua_pushinteger(L, header->nextlevel);
else if (fastcmp(field,"marathonnext")) break;
case mapheaderinfo_marathonnext:
lua_pushinteger(L, header->marathonnext); lua_pushinteger(L, header->marathonnext);
else if (fastcmp(field,"keywords")) break;
case mapheaderinfo_keywords:
lua_pushstring(L, header->keywords); lua_pushstring(L, header->keywords);
else if (fastcmp(field,"musname")) break;
case mapheaderinfo_musname:
lua_pushstring(L, header->musname); lua_pushstring(L, header->musname);
else if (fastcmp(field,"mustrack")) break;
case mapheaderinfo_mustrack:
lua_pushinteger(L, header->mustrack); lua_pushinteger(L, header->mustrack);
else if (fastcmp(field,"muspos")) break;
case mapheaderinfo_muspos:
lua_pushinteger(L, header->muspos); lua_pushinteger(L, header->muspos);
else if (fastcmp(field,"musinterfadeout")) break;
case mapheaderinfo_musinterfadeout:
lua_pushinteger(L, header->musinterfadeout); lua_pushinteger(L, header->musinterfadeout);
else if (fastcmp(field,"musintername")) break;
case mapheaderinfo_musintername:
lua_pushstring(L, header->musintername); lua_pushstring(L, header->musintername);
else if (fastcmp(field,"muspostbossname")) break;
case mapheaderinfo_muspostbossname:
lua_pushstring(L, header->muspostbossname); lua_pushstring(L, header->muspostbossname);
else if (fastcmp(field,"muspostbosstrack")) break;
case mapheaderinfo_muspostbosstrack:
lua_pushinteger(L, header->muspostbosstrack); lua_pushinteger(L, header->muspostbosstrack);
else if (fastcmp(field,"muspostbosspos")) break;
case mapheaderinfo_muspostbosspos:
lua_pushinteger(L, header->muspostbosspos); lua_pushinteger(L, header->muspostbosspos);
else if (fastcmp(field,"muspostbossfadein")) break;
case mapheaderinfo_muspostbossfadein:
lua_pushinteger(L, header->muspostbossfadein); lua_pushinteger(L, header->muspostbossfadein);
else if (fastcmp(field,"musforcereset")) break;
case mapheaderinfo_musforcereset:
lua_pushinteger(L, header->musforcereset); lua_pushinteger(L, header->musforcereset);
else if (fastcmp(field,"forcecharacter")) break;
case mapheaderinfo_forcecharacter:
lua_pushstring(L, header->forcecharacter); lua_pushstring(L, header->forcecharacter);
else if (fastcmp(field,"weather")) break;
case mapheaderinfo_weather:
lua_pushinteger(L, header->weather); lua_pushinteger(L, header->weather);
else if (fastcmp(field,"skynum")) break;
case mapheaderinfo_skynum:
lua_pushinteger(L, header->skynum); lua_pushinteger(L, header->skynum);
else if (fastcmp(field,"skybox_scalex")) break;
case mapheaderinfo_skybox_scalex:
lua_pushinteger(L, header->skybox_scalex); lua_pushinteger(L, header->skybox_scalex);
else if (fastcmp(field,"skybox_scaley")) break;
case mapheaderinfo_skybox_scaley:
lua_pushinteger(L, header->skybox_scaley); lua_pushinteger(L, header->skybox_scaley);
else if (fastcmp(field,"skybox_scalez")) break;
case mapheaderinfo_skybox_scalez:
lua_pushinteger(L, header->skybox_scalez); lua_pushinteger(L, header->skybox_scalez);
else if (fastcmp(field,"interscreen")) { break;
case mapheaderinfo_interscreen:
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
if (!header->interscreen[i]) if (!header->interscreen[i])
break; break;
lua_pushlstring(L, header->interscreen, i); lua_pushlstring(L, header->interscreen, i);
} else if (fastcmp(field,"runsoc")) break;
case mapheaderinfo_runsoc:
lua_pushstring(L, header->runsoc); lua_pushstring(L, header->runsoc);
else if (fastcmp(field,"scriptname")) break;
case mapheaderinfo_scriptname:
lua_pushstring(L, header->scriptname); lua_pushstring(L, header->scriptname);
else if (fastcmp(field,"precutscenenum")) break;
case mapheaderinfo_precutscenenum:
lua_pushinteger(L, header->precutscenenum); lua_pushinteger(L, header->precutscenenum);
else if (fastcmp(field,"cutscenenum")) break;
case mapheaderinfo_cutscenenum:
lua_pushinteger(L, header->cutscenenum); lua_pushinteger(L, header->cutscenenum);
else if (fastcmp(field,"countdown")) break;
case mapheaderinfo_countdown:
lua_pushinteger(L, header->countdown); lua_pushinteger(L, header->countdown);
else if (fastcmp(field,"palette")) break;
case mapheaderinfo_palette:
lua_pushinteger(L, header->palette); lua_pushinteger(L, header->palette);
else if (fastcmp(field,"numlaps")) break;
case mapheaderinfo_numlaps:
lua_pushinteger(L, header->numlaps); lua_pushinteger(L, header->numlaps);
else if (fastcmp(field,"unlockrequired")) break;
case mapheaderinfo_unlockrequired:
lua_pushinteger(L, header->unlockrequired); lua_pushinteger(L, header->unlockrequired);
else if (fastcmp(field,"levelselect")) break;
case mapheaderinfo_levelselect:
lua_pushinteger(L, header->levelselect); lua_pushinteger(L, header->levelselect);
else if (fastcmp(field,"bonustype")) break;
case mapheaderinfo_bonustype:
lua_pushinteger(L, header->bonustype); lua_pushinteger(L, header->bonustype);
else if (fastcmp(field,"ltzzpatch")) break;
case mapheaderinfo_ltzzpatch:
lua_pushstring(L, header->ltzzpatch); lua_pushstring(L, header->ltzzpatch);
else if (fastcmp(field,"ltzztext")) break;
case mapheaderinfo_ltzztext:
lua_pushstring(L, header->ltzztext); lua_pushstring(L, header->ltzztext);
else if (fastcmp(field,"ltactdiamond")) break;
case mapheaderinfo_ltactdiamond:
lua_pushstring(L, header->ltactdiamond); lua_pushstring(L, header->ltactdiamond);
else if (fastcmp(field,"maxbonuslives")) break;
case mapheaderinfo_maxbonuslives:
lua_pushinteger(L, header->maxbonuslives); lua_pushinteger(L, header->maxbonuslives);
else if (fastcmp(field,"levelflags")) break;
case mapheaderinfo_levelflags:
lua_pushinteger(L, header->levelflags); lua_pushinteger(L, header->levelflags);
else if (fastcmp(field,"menuflags")) break;
case mapheaderinfo_menuflags:
lua_pushinteger(L, header->menuflags); lua_pushinteger(L, header->menuflags);
else if (fastcmp(field,"selectheading")) break;
case mapheaderinfo_selectheading:
lua_pushstring(L, header->selectheading); lua_pushstring(L, header->selectheading);
else if (fastcmp(field,"startrings")) break;
case mapheaderinfo_startrings:
lua_pushinteger(L, header->startrings); lua_pushinteger(L, header->startrings);
else if (fastcmp(field, "sstimer")) break;
case mapheaderinfo_sstimer:
lua_pushinteger(L, header->sstimer); lua_pushinteger(L, header->sstimer);
else if (fastcmp(field, "ssspheres")) break;
case mapheaderinfo_ssspheres:
lua_pushinteger(L, header->ssspheres); lua_pushinteger(L, header->ssspheres);
else if (fastcmp(field, "gravity")) break;
case mapheaderinfo_gravity:
lua_pushfixed(L, header->gravity); lua_pushfixed(L, header->gravity);
break;
// TODO add support for reading numGradedMares and grades // TODO add support for reading numGradedMares and grades
else { default:
// Read custom vars now // Read custom vars now
// (note: don't include the "LUA." in your lua scripts!) // (note: don't include the "LUA." in your lua scripts!)
UINT8 j = 0; UINT8 j = 0;
for (;j < header->numCustomOptions && !fastcmp(field, header->customopts[j].option); ++j); for (;j < header->numCustomOptions && !fastcmp(lua_tostring(L, 2), header->customopts[j].option); ++j);
if(j < header->numCustomOptions) if(j < header->numCustomOptions)
lua_pushstring(L, header->customopts[j].value); lua_pushstring(L, header->customopts[j].value);
@ -2539,6 +2705,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
sector_fields_ref = Lua_CreateFieldTable(L, sector_opt);
luaL_newmetatable(L, META_SUBSECTOR); luaL_newmetatable(L, META_SUBSECTOR);
lua_pushcfunction(L, subsector_get); lua_pushcfunction(L, subsector_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -2547,6 +2715,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
subsector_fields_ref = Lua_CreateFieldTable(L, subsector_opt);
luaL_newmetatable(L, META_LINE); luaL_newmetatable(L, META_LINE);
lua_pushcfunction(L, line_get); lua_pushcfunction(L, line_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -2555,6 +2725,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
line_fields_ref = Lua_CreateFieldTable(L, line_opt);
luaL_newmetatable(L, META_LINEARGS); luaL_newmetatable(L, META_LINEARGS);
lua_pushcfunction(L, lineargs_get); lua_pushcfunction(L, lineargs_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -2587,6 +2759,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
side_fields_ref = Lua_CreateFieldTable(L, side_opt);
luaL_newmetatable(L, META_VERTEX); luaL_newmetatable(L, META_VERTEX);
lua_pushcfunction(L, vertex_get); lua_pushcfunction(L, vertex_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -2595,6 +2769,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
vertex_fields_ref = Lua_CreateFieldTable(L, vertex_opt);
luaL_newmetatable(L, META_FFLOOR); luaL_newmetatable(L, META_FFLOOR);
lua_pushcfunction(L, ffloor_get); lua_pushcfunction(L, ffloor_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -2603,6 +2779,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__newindex"); lua_setfield(L, -2, "__newindex");
lua_pop(L, 1); lua_pop(L, 1);
ffloor_fields_ref = Lua_CreateFieldTable(L, ffloor_opt);
#ifdef HAVE_LUA_SEGS #ifdef HAVE_LUA_SEGS
luaL_newmetatable(L, META_SEG); luaL_newmetatable(L, META_SEG);
lua_pushcfunction(L, seg_get); lua_pushcfunction(L, seg_get);
@ -2612,6 +2790,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
seg_fields_ref = Lua_CreateFieldTable(L, seg_opt);
luaL_newmetatable(L, META_NODE); luaL_newmetatable(L, META_NODE);
lua_pushcfunction(L, node_get); lua_pushcfunction(L, node_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -2620,6 +2800,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
node_fields_ref = Lua_CreateFieldTable(L, node_opt);
luaL_newmetatable(L, META_NODEBBOX); luaL_newmetatable(L, META_NODEBBOX);
//lua_pushcfunction(L, nodebbox_get); //lua_pushcfunction(L, nodebbox_get);
//lua_setfield(L, -2, "__index"); //lua_setfield(L, -2, "__index");
@ -2646,6 +2828,8 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__newindex"); lua_setfield(L, -2, "__newindex");
lua_pop(L, 1); lua_pop(L, 1);
slope_fields_ref = Lua_CreateFieldTable(L, slope_opt);
luaL_newmetatable(L, META_VECTOR2); luaL_newmetatable(L, META_VECTOR2);
lua_pushcfunction(L, vector2_get); lua_pushcfunction(L, vector2_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -2664,6 +2848,8 @@ int LUA_MapLib(lua_State *L)
//lua_setfield(L, -2, "__len"); //lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
mapheaderinfo_fields_ref = Lua_CreateFieldTable(L, mapheaderinfo_opt);
LUA_PushTaggableObjectArray(L, "sectors", LUA_PushTaggableObjectArray(L, "sectors",
lib_iterateSectors, lib_iterateSectors,
lib_getSector, lib_getSector,

View file

@ -179,10 +179,12 @@ static const char *const mobj_opt[] = {
#define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field]) #define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
static int mobj_fields_ref = LUA_NOREF;
static int mobj_get(lua_State *L) static int mobj_get(lua_State *L)
{ {
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
enum mobj_e field = Lua_optoption(L, 2, NULL, mobj_opt); enum mobj_e field = Lua_optoption(L, 2, -1, mobj_fields_ref);
lua_settop(L, 2); lua_settop(L, 2);
if (!mo || !ISINLEVEL) { if (!mo || !ISINLEVEL) {
@ -467,7 +469,7 @@ static int mobj_get(lua_State *L)
static int mobj_set(lua_State *L) static int mobj_set(lua_State *L)
{ {
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
enum mobj_e field = Lua_optoption(L, 2, mobj_opt[0], mobj_opt); enum mobj_e field = Lua_optoption(L, 2, mobj_valid, mobj_fields_ref);
lua_settop(L, 3); lua_settop(L, 3);
INLEVEL INLEVEL
@ -876,14 +878,55 @@ static int thingstringargs_len(lua_State *L)
return 1; return 1;
} }
enum mapthing_e {
mapthing_valid = 0,
mapthing_x,
mapthing_y,
mapthing_angle,
mapthing_pitch,
mapthing_roll,
mapthing_type,
mapthing_options,
mapthing_scale,
mapthing_z,
mapthing_extrainfo,
mapthing_tag,
mapthing_taglist,
mapthing_args,
mapthing_stringargs,
mapthing_mobj,
};
const char *const mapthing_opt[] = {
"valid",
"x",
"y",
"angle",
"pitch",
"roll",
"type",
"options",
"scale",
"z",
"extrainfo",
"tag",
"taglist",
"args",
"stringargs",
"mobj",
NULL,
};
static int mapthing_fields_ref = LUA_NOREF;
static int mapthing_get(lua_State *L) static int mapthing_get(lua_State *L)
{ {
mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)); mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING));
const char *field = luaL_checkstring(L, 2); enum mapthing_e field = Lua_optoption(L, 2, -1, mapthing_fields_ref);
lua_Integer number; lua_settop(L, 2);
if (!mt) { if (!mt) {
if (fastcmp(field,"valid")) { if (field == mapthing_valid) {
lua_pushboolean(L, false); lua_pushboolean(L, false);
return 1; return 1;
} }
@ -892,62 +935,71 @@ static int mapthing_get(lua_State *L)
return 0; return 0;
} }
if (fastcmp(field,"valid")) { switch (field)
{
case mapthing_valid:
lua_pushboolean(L, true); lua_pushboolean(L, true);
return 1; break;
} else if(fastcmp(field,"x")) case mapthing_x:
number = mt->x; lua_pushinteger(L, mt->x);
else if(fastcmp(field,"y")) break;
number = mt->y; case mapthing_y:
else if(fastcmp(field,"angle")) lua_pushinteger(L, mt->y);
number = mt->angle; break;
else if(fastcmp(field,"pitch")) case mapthing_angle:
number = mt->pitch; lua_pushinteger(L, mt->angle);
else if(fastcmp(field,"roll")) break;
number = mt->roll; case mapthing_pitch:
else if(fastcmp(field,"type")) lua_pushinteger(L, mt->pitch);
number = mt->type; break;
else if(fastcmp(field,"options")) case mapthing_roll:
number = mt->options; lua_pushinteger(L, mt->roll);
else if(fastcmp(field,"scale")) break;
number = mt->scale; case mapthing_type:
else if(fastcmp(field,"z")) lua_pushinteger(L, mt->type);
number = mt->z; break;
else if(fastcmp(field,"extrainfo")) case mapthing_options:
number = mt->extrainfo; lua_pushinteger(L, mt->options);
else if(fastcmp(field,"tag")) break;
number = Tag_FGet(&mt->tags); case mapthing_scale:
else if(fastcmp(field,"taglist")) lua_pushinteger(L, mt->scale);
{ break;
case mapthing_z:
lua_pushinteger(L, mt->z);
break;
case mapthing_extrainfo:
lua_pushinteger(L, mt->extrainfo);
break;
case mapthing_tag:
lua_pushinteger(L, Tag_FGet(&mt->tags));
break;
case mapthing_taglist:
LUA_PushUserdata(L, &mt->tags, META_TAGLIST); LUA_PushUserdata(L, &mt->tags, META_TAGLIST);
return 1; break;
} case mapthing_args:
else if(fastcmp(field,"args"))
{
LUA_PushUserdata(L, mt->args, META_THINGARGS); LUA_PushUserdata(L, mt->args, META_THINGARGS);
return 1; break;
} case mapthing_stringargs:
else if(fastcmp(field,"stringargs"))
{
LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS); LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS);
return 1; break;
} case mapthing_mobj:
else if(fastcmp(field,"mobj")) {
LUA_PushUserdata(L, mt->mobj, META_MOBJ); LUA_PushUserdata(L, mt->mobj, META_MOBJ);
return 1; break;
} else if (devparm) default:
if (devparm)
return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field);
else else
return 0; return 0;
}
lua_pushinteger(L, number);
return 1; return 1;
} }
static int mapthing_set(lua_State *L) static int mapthing_set(lua_State *L)
{ {
mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)); mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING));
const char *field = luaL_checkstring(L, 2); enum mapthing_e field = Lua_optoption(L, 2, -1, mapthing_fields_ref);
lua_settop(L, 3);
if (!mt) if (!mt)
return luaL_error(L, "accessed mapthing_t doesn't exist anymore."); return luaL_error(L, "accessed mapthing_t doesn't exist anymore.");
@ -957,39 +1009,52 @@ static int mapthing_set(lua_State *L)
if (hook_cmd_running) if (hook_cmd_running)
return luaL_error(L, "Do not alter mapthing_t in CMD building code!"); return luaL_error(L, "Do not alter mapthing_t in CMD building code!");
if(fastcmp(field,"x")) switch (field)
mt->x = (INT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"y"))
mt->y = (INT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"angle"))
mt->angle = (INT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"pitch"))
mt->pitch = (INT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"roll"))
mt->roll = (INT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"type"))
mt->type = (UINT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"options"))
mt->options = (UINT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"scale"))
mt->scale = luaL_checkfixed(L, 3);
else if(fastcmp(field,"z"))
mt->z = (INT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"extrainfo"))
{ {
case mapthing_x:
mt->x = (INT16)luaL_checkinteger(L, 3);
break;
case mapthing_y:
mt->y = (INT16)luaL_checkinteger(L, 3);
break;
case mapthing_angle:
mt->angle = (INT16)luaL_checkinteger(L, 3);
break;
case mapthing_pitch:
mt->pitch = (INT16)luaL_checkinteger(L, 3);
break;
case mapthing_roll:
mt->roll = (INT16)luaL_checkinteger(L, 3);
break;
case mapthing_type:
mt->type = (UINT16)luaL_checkinteger(L, 3);
break;
case mapthing_options:
mt->options = (UINT16)luaL_checkinteger(L, 3);
break;
case mapthing_scale:
mt->scale = luaL_checkfixed(L, 3);
break;
case mapthing_z:
mt->z = (INT16)luaL_checkinteger(L, 3);
break;
case mapthing_extrainfo:
INT32 extrainfo = luaL_checkinteger(L, 3); INT32 extrainfo = luaL_checkinteger(L, 3);
if (extrainfo & ~15) if (extrainfo & ~15)
return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15); return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15);
mt->extrainfo = (UINT8)extrainfo; mt->extrainfo = (UINT8)extrainfo;
} break;
else if (fastcmp(field,"tag")) case mapthing_tag:
Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3));
else if (fastcmp(field,"taglist")) break;
case mapthing_taglist:
return LUA_ErrSetDirectly(L, "mapthing_t", "taglist"); return LUA_ErrSetDirectly(L, "mapthing_t", "taglist");
else if(fastcmp(field,"mobj")) case mapthing_mobj:
mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
else break;
default:
return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field);
}
return 0; return 0;
} }
@ -1051,6 +1116,8 @@ int LUA_MobjLib(lua_State *L)
lua_setfield(L, -2, "__newindex"); lua_setfield(L, -2, "__newindex");
lua_pop(L,1); lua_pop(L,1);
mobj_fields_ref = Lua_CreateFieldTable(L, mobj_opt);
luaL_newmetatable(L, META_THINGARGS); luaL_newmetatable(L, META_THINGARGS);
lua_pushcfunction(L, thingargs_get); lua_pushcfunction(L, thingargs_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -1078,6 +1145,8 @@ int LUA_MobjLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L,1); lua_pop(L,1);
mapthing_fields_ref = Lua_CreateFieldTable(L, mapthing_opt);
LUA_PushTaggableObjectArray(L, "mapthings", LUA_PushTaggableObjectArray(L, "mapthings",
lib_iterateMapthings, lib_iterateMapthings,
lib_getMapthing, lib_getMapthing,

File diff suppressed because it is too large Load diff

View file

@ -1729,17 +1729,39 @@ void LUA_UnArchive(void)
} }
// For mobj_t, player_t, etc. to take custom variables. // For mobj_t, player_t, etc. to take custom variables.
int Lua_optoption(lua_State *L, int narg, int Lua_optoption(lua_State *L, int narg, int def, int list_ref)
const char *def, const char *const lst[])
{ {
const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); if (lua_isnoneornil(L, narg))
int i; return def;
for (i=0; lst[i]; i++)
if (fastcmp(lst[i], name)) I_Assert(lua_checkstack(L, 2));
return i; luaL_checkstring(L, narg);
lua_rawgeti(L, LUA_REGISTRYINDEX, list_ref);
I_Assert(lua_istable(L, -1));
lua_pushvalue(L, narg);
lua_rawget(L, -2);
if (lua_isnumber(L, -1))
return lua_tointeger(L, -1);
return -1; return -1;
} }
int Lua_CreateFieldTable(lua_State *L, const char *const lst[])
{
int i;
lua_newtable(L);
for (i = 0; lst[i] != NULL; i++)
{
lua_pushstring(L, lst[i]);
lua_pushinteger(L, i);
lua_settable(L, -3);
}
return luaL_ref(L, LUA_REGISTRYINDEX);
}
void LUA_PushTaggableObjectArray void LUA_PushTaggableObjectArray
( lua_State *L, ( lua_State *L,
const char *field, const char *field,

View file

@ -57,8 +57,8 @@ 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(void *cvar); // 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, int def, int list_ref);
const char *def, const char *const lst[]); int Lua_CreateFieldTable(lua_State *L, const char *const lst[]);
void LUA_HookNetArchive(lua_CFunction archFunc); void LUA_HookNetArchive(lua_CFunction archFunc);
void LUA_PushTaggableObjectArray void LUA_PushTaggableObjectArray

View file

@ -55,6 +55,7 @@ enum skin {
skin_soundsid, skin_soundsid,
skin_sprites skin_sprites
}; };
static const char *const skin_opt[] = { static const char *const skin_opt[] = {
"valid", "valid",
"name", "name",
@ -95,10 +96,12 @@ static const char *const skin_opt[] = {
#define UNIMPLEMENTED luaL_error(L, LUA_QL("skin_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", skin_opt[field]) #define UNIMPLEMENTED luaL_error(L, LUA_QL("skin_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", skin_opt[field])
static int skin_fields_ref = LUA_NOREF;
static int skin_get(lua_State *L) static int skin_get(lua_State *L)
{ {
skin_t *skin = *((skin_t **)luaL_checkudata(L, 1, META_SKIN)); skin_t *skin = *((skin_t **)luaL_checkudata(L, 1, META_SKIN));
enum skin field = luaL_checkoption(L, 2, NULL, skin_opt); enum skin field = Lua_optoption(L, 2, -1, skin_fields_ref);
// skins are always valid, only added, never removed // skins are always valid, only added, never removed
I_Assert(skin != NULL); I_Assert(skin != NULL);
@ -376,6 +379,8 @@ int LUA_SkinLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L,1); lua_pop(L,1);
skin_fields_ref = Lua_CreateFieldTable(L, skin_opt);
luaL_newmetatable(L, META_SOUNDSID); luaL_newmetatable(L, META_SOUNDSID);
lua_pushcfunction(L, soundsid_get); lua_pushcfunction(L, soundsid_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");