mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-03-22 10:52:23 +00:00
Lua tag lists
Index and take length of tag lists like a table, 1-indexed. There are three methods which may be used on tag lists: list:iterate() - returns an iterator over the tags in the list list:has(tag) - returns a boolean whether the tag is in the list list.shares(list2) - returns whether two lists share a tag "find" is also an alias to "has". Each method may be accessed from the global taglist library too, e.g. taglist.iterate(list) Tag lists may be compared with an equality operator too. This will tell you if the two lists are composed of identical tags. Accessible from sector.taglist, line.taglist and mapthing.taglist.
This commit is contained in:
parent
c2217bb426
commit
314fd2783a
6 changed files with 183 additions and 0 deletions
|
@ -184,12 +184,15 @@ static const struct {
|
|||
{META_CVAR, "consvar_t"},
|
||||
|
||||
{META_SECTORLINES, "sector_t.lines"},
|
||||
{META_SECTORTAGLIST, "sector_t.taglist"},
|
||||
{META_SIDENUM, "line_t.sidenum"},
|
||||
{META_LINEARGS, "line_t.args"},
|
||||
{META_LINESTRINGARGS, "line_t.stringargs"},
|
||||
{META_LINETAGLIST, "line_t.taglist"},
|
||||
|
||||
{META_THINGARGS, "mapthing.args"},
|
||||
{META_THINGSTRINGARGS, "mapthing.stringargs"},
|
||||
{META_THINGTAGLIST, "mapthing_t.taglist"},
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
{META_NODEBBOX, "node_t.bbox"},
|
||||
{META_NODECHILDREN, "node_t.children"},
|
||||
|
|
|
@ -56,11 +56,14 @@ extern lua_State *gL;
|
|||
#define META_CVAR "CONSVAR_T*"
|
||||
|
||||
#define META_SECTORLINES "SECTOR_T*LINES"
|
||||
#define META_SECTORTAGLIST "SECTOR_T*TAGLIST"
|
||||
#define META_SIDENUM "LINE_T*SIDENUM"
|
||||
#define META_LINEARGS "LINE_T*ARGS"
|
||||
#define META_LINESTRINGARGS "LINE_T*STRINGARGS"
|
||||
#define META_LINETAGLIST "LINE_T*TAGLIST"
|
||||
#define META_THINGARGS "MAPTHING_T*ARGS"
|
||||
#define META_THINGSTRINGARGS "MAPTHING_T*STRINGARGS"
|
||||
#define META_THINGTAGLIST "THING_T*TAGLIST"
|
||||
#define META_POLYOBJVERTICES "POLYOBJ_T*VERTICES"
|
||||
#define META_POLYOBJLINES "POLYOBJ_T*LINES"
|
||||
#ifdef HAVE_LUA_SEGS
|
||||
|
|
|
@ -37,6 +37,7 @@ enum sector_e {
|
|||
sector_lightlevel,
|
||||
sector_special,
|
||||
sector_tag,
|
||||
sector_taglist,
|
||||
sector_thinglist,
|
||||
sector_heightsec,
|
||||
sector_camsec,
|
||||
|
@ -55,6 +56,7 @@ static const char *const sector_opt[] = {
|
|||
"lightlevel",
|
||||
"special",
|
||||
"tag",
|
||||
"taglist",
|
||||
"thinglist",
|
||||
"heightsec",
|
||||
"camsec",
|
||||
|
@ -89,6 +91,7 @@ enum line_e {
|
|||
line_flags,
|
||||
line_special,
|
||||
line_tag,
|
||||
line_taglist,
|
||||
line_args,
|
||||
line_stringargs,
|
||||
line_sidenum,
|
||||
|
@ -113,6 +116,7 @@ static const char *const line_opt[] = {
|
|||
"flags",
|
||||
"special",
|
||||
"tag",
|
||||
"taglist",
|
||||
"args",
|
||||
"stringargs",
|
||||
"sidenum",
|
||||
|
@ -581,6 +585,9 @@ static int sector_get(lua_State *L)
|
|||
case sector_tag:
|
||||
lua_pushinteger(L, Tag_FGet(§or->tags));
|
||||
return 1;
|
||||
case sector_taglist:
|
||||
LUA_PushUserdata(L, §or->tags, META_SECTORTAGLIST);
|
||||
return 1;
|
||||
case sector_thinglist: // thinglist
|
||||
lua_pushcfunction(L, lib_iterateSectorThinglist);
|
||||
LUA_PushUserdata(L, sector->thinglist, META_MOBJ);
|
||||
|
@ -682,6 +689,8 @@ static int sector_set(lua_State *L)
|
|||
case sector_tag:
|
||||
Tag_SectorFSet((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3));
|
||||
break;
|
||||
case sector_taglist:
|
||||
return LUA_ErrSetDirectly(L, "sector_t", "taglist");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -821,6 +830,9 @@ static int line_get(lua_State *L)
|
|||
case line_tag:
|
||||
lua_pushinteger(L, Tag_FGet(&line->tags));
|
||||
return 1;
|
||||
case line_taglist:
|
||||
LUA_PushUserdata(L, &line->tags, META_LINETAGLIST);
|
||||
return 1;
|
||||
case line_args:
|
||||
LUA_PushUserdata(L, line->args, META_LINEARGS);
|
||||
return 1;
|
||||
|
|
|
@ -902,6 +902,11 @@ static int mapthing_get(lua_State *L)
|
|||
number = mt->extrainfo;
|
||||
else if(fastcmp(field,"tag"))
|
||||
number = Tag_FGet(&mt->tags);
|
||||
else if(fastcmp(field,"taglist"))
|
||||
{
|
||||
LUA_PushUserdata(L, &mt->tags, META_THINGTAGLIST);
|
||||
return 1;
|
||||
}
|
||||
else if(fastcmp(field,"args"))
|
||||
{
|
||||
LUA_PushUserdata(L, mt->args, META_THINGARGS);
|
||||
|
@ -964,6 +969,8 @@ static int mapthing_set(lua_State *L)
|
|||
}
|
||||
else if (fastcmp(field,"tag"))
|
||||
Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3));
|
||||
else if (fastcmp(field,"taglist"))
|
||||
return LUA_ErrSetDirectly(L, "mapthing_t", "taglist");
|
||||
else if(fastcmp(field,"mobj"))
|
||||
mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
|
||||
else
|
||||
|
|
|
@ -102,6 +102,8 @@ void COM_Lua_f(void);
|
|||
|
||||
#define LUA_ErrInvalid(L, type) luaL_error(L, "accessed " type " doesn't exist anymore, please check 'valid' before using " type ".");
|
||||
|
||||
#define LUA_ErrSetDirectly(L, type, field) luaL_error(L, type " field " LUA_QL(field) " cannot be set directly.")
|
||||
|
||||
// Deprecation warnings
|
||||
// Shows once upon use. Then doesn't show again.
|
||||
#define LUA_Deprecated(L,this_func,use_instead)\
|
||||
|
|
156
src/lua_taglib.c
156
src/lua_taglib.c
|
@ -150,6 +150,137 @@ static int lib_numTaggroupElements(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void push_taglist(lua_State *L, int idx)
|
||||
{
|
||||
lua_getmetatable(L, idx);
|
||||
lua_pushliteral(L, "taglist");
|
||||
lua_rawget(L, -2);
|
||||
lua_remove(L, -2);
|
||||
}
|
||||
|
||||
static int has_valid_field(lua_State *L)
|
||||
{
|
||||
int equal;
|
||||
lua_pushliteral(L, "valid");
|
||||
equal = lua_rawequal(L, 2, -1);
|
||||
lua_pop(L, 1);
|
||||
return equal;
|
||||
}
|
||||
|
||||
static taglist_t * valid_taglist(lua_State *L, int idx, boolean getting)
|
||||
{
|
||||
taglist_t *list = *(taglist_t **)lua_touserdata(L, idx);
|
||||
|
||||
if (list == NULL)
|
||||
{
|
||||
if (getting && has_valid_field(L))
|
||||
lua_pushboolean(L, 0);
|
||||
else
|
||||
LUA_ErrInvalid(L, "taglist_t");/* doesn't actually return */
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return list;
|
||||
}
|
||||
|
||||
static taglist_t * check_taglist(lua_State *L, int idx)
|
||||
{
|
||||
luaL_checktype(L, idx, LUA_TUSERDATA);
|
||||
push_taglist(L, idx);
|
||||
luaL_argcheck(L, lua_toboolean(L, -1), idx, "must be a tag list");
|
||||
return valid_taglist(L, idx, false);
|
||||
}
|
||||
|
||||
static int taglist_get(lua_State *L)
|
||||
{
|
||||
const taglist_t *list = valid_taglist(L, 1, true);
|
||||
|
||||
if (list == NULL)/* valid check */
|
||||
return 1;
|
||||
|
||||
if (lua_isnumber(L, 2))
|
||||
{
|
||||
const size_t i = lua_tonumber(L, 2);
|
||||
|
||||
if (list && i <= list->count)
|
||||
{
|
||||
lua_pushnumber(L, list->tags[i - 1]);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if (has_valid_field(L))
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
push_taglist(L, 1);
|
||||
lua_replace(L, 1);
|
||||
lua_rawget(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int taglist_len(lua_State *L)
|
||||
{
|
||||
const taglist_t *list = valid_taglist(L, 1, false);
|
||||
lua_pushnumber(L, list->count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int taglist_equal(lua_State *L)
|
||||
{
|
||||
const taglist_t *lhs = check_taglist(L, 1);
|
||||
const taglist_t *rhs = check_taglist(L, 2);
|
||||
lua_pushboolean(L, Tag_Compare(lhs, rhs));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int taglist_iterator(lua_State *L)
|
||||
{
|
||||
const taglist_t *list = valid_taglist(L, 1, false);
|
||||
const size_t i = 1 + lua_tonumber(L, lua_upvalueindex(1));
|
||||
if (i <= list->count)
|
||||
{
|
||||
lua_pushnumber(L, list->tags[i - 1]);
|
||||
/* watch me exploit an upvalue as a control because
|
||||
I want to use the control as the value */
|
||||
lua_pushnumber(L, i);
|
||||
lua_replace(L, lua_upvalueindex(1));
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int taglist_iterate(lua_State *L)
|
||||
{
|
||||
check_taglist(L, 1);
|
||||
lua_pushnumber(L, 0);
|
||||
lua_pushcclosure(L, taglist_iterator, 1);
|
||||
lua_pushvalue(L, 1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int taglist_find(lua_State *L)
|
||||
{
|
||||
const taglist_t *list = check_taglist(L, 1);
|
||||
const mtag_t tag = luaL_checknumber(L, 2);
|
||||
lua_pushboolean(L, Tag_Find(list, tag));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int taglist_shares(lua_State *L)
|
||||
{
|
||||
const taglist_t *lhs = check_taglist(L, 1);
|
||||
const taglist_t *rhs = check_taglist(L, 2);
|
||||
lua_pushboolean(L, Tag_Share(lhs, rhs));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LUA_InsertTaggroupIterator
|
||||
( lua_State *L,
|
||||
taggroup_t *garray[],
|
||||
|
@ -179,6 +310,13 @@ void LUA_InsertTaggroupIterator
|
|||
lua_setfield(L, -2, "tagged");
|
||||
}
|
||||
|
||||
static luaL_Reg taglist_lib[] = {
|
||||
{"iterate", taglist_iterate},
|
||||
{"find", taglist_find},
|
||||
{"shares", taglist_shares},
|
||||
{0}
|
||||
};
|
||||
|
||||
int LUA_TagLib(lua_State *L)
|
||||
{
|
||||
lua_newuserdata(L, 0);
|
||||
|
@ -193,5 +331,23 @@ int LUA_TagLib(lua_State *L)
|
|||
lua_setmetatable(L, -2);
|
||||
lua_setglobal(L, "tags");
|
||||
|
||||
luaL_newmetatable(L, META_THINGTAGLIST);
|
||||
luaL_register(L, "taglist", taglist_lib);
|
||||
lua_getfield(L, -1, "find");
|
||||
lua_setfield(L, -2, "has");
|
||||
lua_setfield(L, -2, "taglist");
|
||||
|
||||
lua_pushcfunction(L, taglist_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, taglist_len);
|
||||
lua_setfield(L, -2, "__len");
|
||||
|
||||
lua_pushcfunction(L, taglist_equal);
|
||||
lua_setfield(L, -2, "__eq");
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, META_LINETAGLIST);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, META_SECTORTAGLIST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue