From 75ee3193f42524b80a8ebd26dee4d801a8106053 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Wed, 25 Sep 2019 20:27:41 +0100 Subject: [PATCH] Write a new hack for getting sector->linecount from sector->lines in Lua, to put my mind at rest about it at last. 1) In sector_get, actually push the memory address of the lines array within sector_t, rather than push the value of "lines" itself (essentially, we we want a pointer to a double pointer, or rather a TRIPLE pointer haha) 2) In the sectorlines_* functions, use offsetof to shift the memory address so we can obtain the value of linecount within the sector_t struct, and dereference the result to obtain the value of linecount itself 3) ??? profit Untested and uncompiled atm, but I have some confidence this might work --- src/lua_maplib.c | 55 ++++++++++++++++++++++++++++++------------------ src/lua_script.c | 2 +- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/lua_maplib.c b/src/lua_maplib.c index dbb69b7e2..1da232efa 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -411,37 +411,53 @@ static int sector_iterate(lua_State *L) // sector.lines, i -> sector.lines[i] // sector.lines.valid, for validity checking +// +// 25/9/19 Monster Iestyn +// Modified this and _num to use triple pointers, to allow for a new hack of mine involving offsetof +// this way we don't need to check frontsector or backsector of line #0 in the array +// static int sectorlines_get(lua_State *L) { - line_t **seclines = *((line_t ***)luaL_checkudata(L, 1, META_SECTORLINES)); + line_t ***seclines = *((line_t ****)luaL_checkudata(L, 1, META_SECTORLINES)); size_t i; size_t numoflines = 0; lua_settop(L, 2); if (!lua_isnumber(L, 2)) { int field = luaL_checkoption(L, 2, NULL, valid_opt); - if (!seclines) + if (!seclines || !(*seclines)) { if (field == 0) { lua_pushboolean(L, 0); return 1; } - return luaL_error(L, "accessed sector_t doesn't exist anymore."); + return luaL_error(L, "accessed sector_t.lines doesn't exist anymore."); } else if (field == 0) { lua_pushboolean(L, 1); return 1; } } +/* a snip from sector_t struct in r_defs.h, for reference + size_t linecount; + struct line_s **lines; // [linecount] size +*/ + // get the "linecount" by shifting our retrieved memory address of "lines" to where "linecount" is in the sector_t, then dereferencing the result + // we need this to determine the array's actual size, and therefore also the maximum value allowed as an index + // this only works if seclines is actually a pointer to a sector's lines member in memory, oh boy + numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount)))); + +/* OLD HACK // check first linedef to figure which of its sectors owns this sector->lines pointer // then check that sector's linecount to get a maximum index - //if (!seclines[0]) + //if (!(*seclines)[0]) //return luaL_error(L, "no lines found!"); // no first linedef????? - if (seclines[0]->frontsector->lines == seclines) - numoflines = seclines[0]->frontsector->linecount; - else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first - numoflines = seclines[0]->backsector->linecount; + if ((*seclines)[0]->frontsector->lines == *seclines) + numoflines = (*seclines)[0]->frontsector->linecount; + else if ((*seclines)[0]->backsector && *seclines[0]->backsector->lines == *seclines) // check backsector exists first + numoflines = (*seclines)[0]->backsector->linecount; //if neither sector has it then ??? +*/ if (!numoflines) return luaL_error(L, "no lines found!"); @@ -449,23 +465,21 @@ static int sectorlines_get(lua_State *L) i = (size_t)lua_tointeger(L, 2); if (i >= numoflines) return 0; - LUA_PushUserdata(L, seclines[i], META_LINE); + LUA_PushUserdata(L, (*seclines)[i], META_LINE); return 1; } +// #(sector.lines) -> sector.linecount static int sectorlines_num(lua_State *L) { - line_t **seclines = *((line_t ***)luaL_checkudata(L, 1, META_SECTORLINES)); + line_t ***seclines = *((line_t ****)luaL_checkudata(L, 1, META_SECTORLINES)); size_t numoflines = 0; - // check first linedef to figure which of its sectors owns this sector->lines pointer - // then check that sector's linecount to get a maximum index - //if (!seclines[0]) - //return luaL_error(L, "no lines found!"); // no first linedef????? - if (seclines[0]->frontsector->lines == seclines) - numoflines = seclines[0]->frontsector->linecount; - else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first - numoflines = seclines[0]->backsector->linecount; - //if neither sector has it then ??? + + if (!seclines || !(*seclines)) + return luaL_error(L, "accessed sector_t.lines doesn't exist anymore."); + + // see comments in the _get function above + numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount)))); lua_pushinteger(L, numoflines); return 1; } @@ -543,7 +557,7 @@ static int sector_get(lua_State *L) LUA_PushUserdata(L, §ors[sector->camsec], META_SECTOR); return 1; case sector_lines: // lines - LUA_PushUserdata(L, sector->lines, META_SECTORLINES); + LUA_PushUserdata(L, §or->lines, META_SECTORLINES); // push the address of the "lines" member in the struct, to allow our hacks in sectorlines_get/_num to work return 1; case sector_ffloors: // ffloors lua_pushcfunction(L, lib_iterateSectorFFloors); @@ -579,6 +593,7 @@ static int sector_set(lua_State *L) case sector_thinglist: // thinglist case sector_heightsec: // heightsec case sector_camsec: // camsec + case sector_lines: // lines case sector_ffloors: // ffloors #ifdef ESLOPE case sector_fslope: // f_slope diff --git a/src/lua_script.c b/src/lua_script.c index deb644dc0..a161368b8 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -431,7 +431,7 @@ void LUA_InvalidateLevel(void) for (i = 0; i < numsectors; i++) { LUA_InvalidateUserdata(§ors[i]); - LUA_InvalidateUserdata(sectors[i].lines); + LUA_InvalidateUserdata(§ors[i].lines); if (sectors[i].ffloors) { for (rover = sectors[i].ffloors; rover; rover = rover->next)