Add lua object references

Whenever a lua script references a core struct obj, increment a counter
in the obj struct. Core code will not free the obj, if there are any
lua references pointing to it, just makes it free-floating.
When lua script ends, the lua gc will free the free-floating objects.

Also exposes u.inventory to lua.

Breaks save and bones compat.
This commit is contained in:
Pasi Kallinen
2019-12-26 18:43:39 +02:00
parent 7ea7058c01
commit 6d8d3a9557
7 changed files with 30 additions and 4 deletions

View File

@@ -1675,6 +1675,7 @@ E int FDECL(l_selection_register, (lua_State *));
/* ### nhlobj.c ### */
#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET)
E void FDECL(nhl_push_obj, (lua_State *, struct obj *));
E int FDECL(l_obj_register, (lua_State *));
#endif

View File

@@ -119,6 +119,7 @@ struct obj {
unsigned oeaten; /* nutrition left in food, if partly eaten */
long age; /* creation date */
long owornmask;
unsigned lua_ref_cnt; /* # of lua script references for this object */
struct oextra *oextra; /* pointer to oextra struct */
};

View File

@@ -14,7 +14,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files.
*/
#define EDITLEVEL 5
#define EDITLEVEL 6
#define COPYRIGHT_BANNER_A "NetHack, Copyright 1985-2019"
#define COPYRIGHT_BANNER_B \

View File

@@ -444,6 +444,7 @@ long num;
obj->owt = weight(obj);
otmp->quan = num;
otmp->owt = weight(otmp); /* -= obj->owt ? */
otmp->lua_ref_cnt = 0;
g.context.objsplit.parent_oid = obj->o_id;
g.context.objsplit.child_oid = otmp->o_id;
@@ -797,6 +798,7 @@ boolean artif;
otmp->lknown = 0;
otmp->cknown = 0;
otmp->corpsenm = NON_PM;
otmp->lua_ref_cnt = 0;
if (init) {
switch (let) {
@@ -2178,8 +2180,10 @@ struct obj *obj;
* list must track all objects that can have a light source
* attached to it (and also requires lamplit to be set).
*/
if (obj_sheds_light(obj))
if (obj_sheds_light(obj)) {
del_light_source(LS_OBJECT, obj_to_any(obj));
obj->lamplit = 0;
}
if (obj == g.thrownobj)
g.thrownobj = 0;
@@ -2188,6 +2192,8 @@ struct obj *obj;
if (obj->oextra)
dealloc_oextra(obj);
if (obj->lua_ref_cnt)
return; /* obj is referenced from a lua script, let lua gc free it */
free((genericptr_t) obj);
}

View File

@@ -43,8 +43,10 @@ lua_State *L;
struct _lua_obj *lo = l_obj_check(L, 1);
if (lo && lo->obj) {
/* free-floating objects are deallocated */
if (lo->obj->where == OBJ_FREE) {
if (lo->obj->lua_ref_cnt > 0)
lo->obj->lua_ref_cnt--;
/* free-floating objects with no other refs are deallocated. */
if (lo->obj->where == OBJ_FREE && !lo->obj->lua_ref_cnt) {
if (Has_contents(lo->obj)) {
struct obj *otmp;
while ((otmp = lo->obj->cobj) != 0) {
@@ -71,10 +73,20 @@ struct obj *otmp;
lo->state = 0;
lo->obj = otmp;
if (otmp)
otmp->lua_ref_cnt++;
return lo;
}
void
nhl_push_obj(L, otmp)
lua_State *L;
struct obj *otmp;
{
(void) l_obj_push(L, otmp);
}
/* local o = obj.new("large chest");
local cobj = o:contents(); */
static int

View File

@@ -839,6 +839,11 @@ lua_State *L;
return nhl_push_anything(L, ustruct[i].type, ustruct[i].ptr);
}
if (!strcmp(tkey, "inventory")) {
nhl_push_obj(L, g.invent);
return 1;
}
nhl_error(L, "Unknown u table index");
return 0;
}

View File

@@ -201,6 +201,7 @@ struct obj *otmp;
if (nhfp->structlevel)
mread(nhfp->fd, (genericptr_t) otmp, sizeof(struct obj));
otmp->lua_ref_cnt = 0;
/* next object pointers are invalid; otmp->cobj needs to be left
as is--being non-null is key to restoring container contents */
otmp->nobj = otmp->nexthere = (struct obj *) 0;