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
This commit is contained in:
Monster Iestyn 2019-09-25 20:27:41 +01:00
parent 73146a8338
commit 75ee3193f4
2 changed files with 36 additions and 21 deletions

View file

@ -411,37 +411,53 @@ static int sector_iterate(lua_State *L)
// sector.lines, i -> sector.lines[i] // sector.lines, i -> sector.lines[i]
// sector.lines.valid, for validity checking // 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) 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 i;
size_t numoflines = 0; size_t numoflines = 0;
lua_settop(L, 2); lua_settop(L, 2);
if (!lua_isnumber(L, 2)) if (!lua_isnumber(L, 2))
{ {
int field = luaL_checkoption(L, 2, NULL, valid_opt); int field = luaL_checkoption(L, 2, NULL, valid_opt);
if (!seclines) if (!seclines || !(*seclines))
{ {
if (field == 0) { if (field == 0) {
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
return 1; 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) { } else if (field == 0) {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
return 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 // 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 // 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????? //return luaL_error(L, "no lines found!"); // no first linedef?????
if (seclines[0]->frontsector->lines == seclines) if ((*seclines)[0]->frontsector->lines == *seclines)
numoflines = seclines[0]->frontsector->linecount; numoflines = (*seclines)[0]->frontsector->linecount;
else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first else if ((*seclines)[0]->backsector && *seclines[0]->backsector->lines == *seclines) // check backsector exists first
numoflines = seclines[0]->backsector->linecount; numoflines = (*seclines)[0]->backsector->linecount;
//if neither sector has it then ??? //if neither sector has it then ???
*/
if (!numoflines) if (!numoflines)
return luaL_error(L, "no lines found!"); 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); i = (size_t)lua_tointeger(L, 2);
if (i >= numoflines) if (i >= numoflines)
return 0; return 0;
LUA_PushUserdata(L, seclines[i], META_LINE); LUA_PushUserdata(L, (*seclines)[i], META_LINE);
return 1; return 1;
} }
// #(sector.lines) -> sector.linecount
static int sectorlines_num(lua_State *L) 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; 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 || !(*seclines))
//if (!seclines[0]) return luaL_error(L, "accessed sector_t.lines doesn't exist anymore.");
//return luaL_error(L, "no lines found!"); // no first linedef?????
if (seclines[0]->frontsector->lines == seclines) // see comments in the _get function above
numoflines = seclines[0]->frontsector->linecount; numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, 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 ???
lua_pushinteger(L, numoflines); lua_pushinteger(L, numoflines);
return 1; return 1;
} }
@ -543,7 +557,7 @@ static int sector_get(lua_State *L)
LUA_PushUserdata(L, &sectors[sector->camsec], META_SECTOR); LUA_PushUserdata(L, &sectors[sector->camsec], META_SECTOR);
return 1; return 1;
case sector_lines: // lines case sector_lines: // lines
LUA_PushUserdata(L, sector->lines, META_SECTORLINES); LUA_PushUserdata(L, &sector->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; return 1;
case sector_ffloors: // ffloors case sector_ffloors: // ffloors
lua_pushcfunction(L, lib_iterateSectorFFloors); lua_pushcfunction(L, lib_iterateSectorFFloors);
@ -579,6 +593,7 @@ static int sector_set(lua_State *L)
case sector_thinglist: // thinglist case sector_thinglist: // thinglist
case sector_heightsec: // heightsec case sector_heightsec: // heightsec
case sector_camsec: // camsec case sector_camsec: // camsec
case sector_lines: // lines
case sector_ffloors: // ffloors case sector_ffloors: // ffloors
#ifdef ESLOPE #ifdef ESLOPE
case sector_fslope: // f_slope case sector_fslope: // f_slope

View file

@ -431,7 +431,7 @@ void LUA_InvalidateLevel(void)
for (i = 0; i < numsectors; i++) for (i = 0; i < numsectors; i++)
{ {
LUA_InvalidateUserdata(&sectors[i]); LUA_InvalidateUserdata(&sectors[i]);
LUA_InvalidateUserdata(sectors[i].lines); LUA_InvalidateUserdata(&sectors[i].lines);
if (sectors[i].ffloors) if (sectors[i].ffloors)
{ {
for (rover = sectors[i].ffloors; rover; rover = rover->next) for (rover = sectors[i].ffloors; rover; rover = rover->next)