Lua struct obj improvements

If the core frees the obj struct referred by lua, don't free it,
just mark it as OBJ_LUAFREE - lua will free it in gc once all
the references to it are gone.
This commit is contained in:
Pasi Kallinen
2020-01-01 13:25:59 +02:00
parent 2ae7cf02ea
commit 7e07cef197
5 changed files with 58 additions and 30 deletions
+2 -1
View File
@@ -66,7 +66,8 @@ struct obj {
#define OBJ_MIGRATING 5 /* object sent off to another level */ #define OBJ_MIGRATING 5 /* object sent off to another level */
#define OBJ_BURIED 6 /* object buried */ #define OBJ_BURIED 6 /* object buried */
#define OBJ_ONBILL 7 /* object on shk bill */ #define OBJ_ONBILL 7 /* object on shk bill */
#define NOBJ_STATES 8 #define OBJ_LUAFREE 8 /* object has been dealloc'd, but is ref'd by lua */
#define NOBJ_STATES 9
xchar timed; /* # of fuses (timers) attached to this obj */ xchar timed; /* # of fuses (timers) attached to this obj */
Bitfield(cursed, 1); Bitfield(cursed, 1);
+1 -1
View File
@@ -14,7 +14,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones * Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files. * and save files.
*/ */
#define EDITLEVEL 7 #define EDITLEVEL 8
#define COPYRIGHT_BANNER_A "NetHack, Copyright 1985-2019" #define COPYRIGHT_BANNER_A "NetHack, Copyright 1985-2019"
#define COPYRIGHT_BANNER_B \ #define COPYRIGHT_BANNER_B \
+10 -4
View File
@@ -1969,6 +1969,7 @@ struct monst *mtmp;
* OBJ_MIGRATING migrating chain * OBJ_MIGRATING migrating chain
* OBJ_BURIED level.buriedobjs chain * OBJ_BURIED level.buriedobjs chain
* OBJ_ONBILL on g.billobjs chain * OBJ_ONBILL on g.billobjs chain
* OBJ_LUAFREE obj is dealloc'd from core, but still used by lua
*/ */
void void
obj_extract_self(obj) obj_extract_self(obj)
@@ -1976,6 +1977,7 @@ struct obj *obj;
{ {
switch (obj->where) { switch (obj->where) {
case OBJ_FREE: case OBJ_FREE:
case OBJ_LUAFREE:
break; break;
case OBJ_FLOOR: case OBJ_FLOOR:
remove_object(obj); remove_object(obj);
@@ -2161,7 +2163,7 @@ void
dealloc_obj(obj) dealloc_obj(obj)
struct obj *obj; struct obj *obj;
{ {
if (obj->where != OBJ_FREE) if (obj->where != OBJ_FREE && obj->where != OBJ_LUAFREE)
panic("dealloc_obj: obj not free"); panic("dealloc_obj: obj not free");
if (obj->nobj) if (obj->nobj)
panic("dealloc_obj with nobj"); panic("dealloc_obj with nobj");
@@ -2192,8 +2194,11 @@ struct obj *obj;
if (obj->oextra) if (obj->oextra)
dealloc_oextra(obj); dealloc_oextra(obj);
if (obj->lua_ref_cnt) if (obj->lua_ref_cnt) {
return; /* obj is referenced from a lua script, let lua gc free it */ /* obj is referenced from a lua script, let lua gc free it */
obj->where = OBJ_LUAFREE;
return;
}
free((genericptr_t) obj); free((genericptr_t) obj);
} }
@@ -2430,7 +2435,8 @@ const char *mesg;
static const char *obj_state_names[NOBJ_STATES] = { "free", "floor", static const char *obj_state_names[NOBJ_STATES] = { "free", "floor",
"contained", "invent", "contained", "invent",
"minvent", "migrating", "minvent", "migrating",
"buried", "onbill" }; "buried", "onbill",
"luafree" };
static const char * static const char *
where_name(obj) where_name(obj)
+27 -24
View File
@@ -22,6 +22,8 @@ struct _lua_obj {
struct obj *obj; struct obj *obj;
}; };
#define lobj_is_ok(lo) ((lo) && (lo)->obj && (lo)->obj->where != OBJ_LUAFREE)
struct _lua_obj * struct _lua_obj *
l_obj_check(L, index) l_obj_check(L, index)
lua_State *L; lua_State *L;
@@ -46,7 +48,8 @@ lua_State *L;
if (lo->obj->lua_ref_cnt > 0) if (lo->obj->lua_ref_cnt > 0)
lo->obj->lua_ref_cnt--; lo->obj->lua_ref_cnt--;
/* free-floating objects with no other refs are deallocated. */ /* free-floating objects with no other refs are deallocated. */
if (lo->obj->where == OBJ_FREE && !lo->obj->lua_ref_cnt) { if (!lo->obj->lua_ref_cnt
&& (lo->obj->where == OBJ_FREE || lo->obj->where == OBJ_LUAFREE)) {
if (Has_contents(lo->obj)) { if (Has_contents(lo->obj)) {
struct obj *otmp; struct obj *otmp;
while ((otmp = lo->obj->cobj) != 0) { while ((otmp = lo->obj->cobj) != 0) {
@@ -98,13 +101,12 @@ lua_State *L;
if (!obj) if (!obj)
nhl_error(L, "l_obj_getcontents: no obj"); nhl_error(L, "l_obj_getcontents: no obj");
if (!obj->cobj)
nhl_error(L, "l_obj_getcontents: no cobj");
(void) l_obj_push(L, obj->cobj); (void) l_obj_push(L, obj->cobj);
return 1; return 1;
} }
/* Puts object inside another object. */
/* local box = obj.new("large chest"); /* local box = obj.new("large chest");
box.addcontent(obj.new("rock")); box.addcontent(obj.new("rock"));
*/ */
@@ -115,19 +117,21 @@ lua_State *L;
struct _lua_obj *lobox = l_obj_check(L, 1); struct _lua_obj *lobox = l_obj_check(L, 1);
struct _lua_obj *lo = l_obj_check(L, 2); struct _lua_obj *lo = l_obj_check(L, 2);
struct obj *otmp; struct obj *otmp;
int refs;
if (!lo->obj || !lobox->obj) if (!lobj_is_ok(lo) || !lobj_is_ok(lobox))
nhl_error(L, "l_obj_add_to_container: no obj"); return 0;
if (!Is_container(lobox->obj)) refs = lo->obj->lua_ref_cnt;
nhl_error(L, "l_obj_add_to_container: not a container");
obj_extract_self(lo->obj);
otmp = add_to_container(lobox->obj, lo->obj); otmp = add_to_container(lobox->obj, lo->obj);
/* was lo->obj merged? FIXME: causes problems if both lo->obj and /* was lo->obj merged? */
the one it merged with are handled by lua. Use lo->state? */ if (otmp != lo->obj) {
if (otmp != lo->obj) lo->obj->lua_ref_cnt += refs;
lo->obj = otmp; lo->obj = otmp;
}
return 0; return 0;
} }
@@ -135,6 +139,7 @@ lua_State *L;
/* Get a table of object class data. */ /* Get a table of object class data. */
/* local odata = obj.class(otbl.otyp); */ /* local odata = obj.class(otbl.otyp); */
/* local odata = obj.class(obj.new("rock")); */ /* local odata = obj.class(obj.new("rock")); */
/* local odata = o:class(); */
static int static int
l_obj_objects_to_table(L) l_obj_objects_to_table(L)
lua_State *L; lua_State *L;
@@ -217,7 +222,7 @@ lua_State *L;
lua_newtable(L); lua_newtable(L);
if (!obj) { if (!obj || obj->where == OBJ_LUAFREE) {
nhl_add_table_entry_int(L, "NO_OBJ", 1); nhl_add_table_entry_int(L, "NO_OBJ", 1);
return 1; return 1;
} }
@@ -352,20 +357,19 @@ lua_State *L;
{ {
int argc = lua_gettop(L); int argc = lua_gettop(L);
struct _lua_obj *lo = l_obj_check(L, 1); struct _lua_obj *lo = l_obj_check(L, 1);
int x, y;
if (argc != 3) if (argc != 3)
nhl_error(L, "l_obj_placeobj: Wrong args"); nhl_error(L, "l_obj_placeobj: Wrong args");
if (lo && lo->obj) { x = (int) luaL_checkinteger(L, 2);
int x, y; y = (int) luaL_checkinteger(L, 3);
lua_pop(L, 3);
x = (int) luaL_checkinteger(L, 2);
y = (int) luaL_checkinteger(L, 3);
lua_pop(L, 3);
if (lobj_is_ok(lo)) {
obj_extract_self(lo->obj);
place_object(lo->obj, x, y); place_object(lo->obj, x, y);
} else }
nhl_error(L, "l_obj_placeobj: Wrong args");
return 0; return 0;
} }
@@ -393,11 +397,10 @@ lua_State *L;
{ {
struct _lua_obj *lo = l_obj_check(L, 1); struct _lua_obj *lo = l_obj_check(L, 1);
if (lo && lo->obj && lo->obj->where == OBJ_CONTAINED) { if (lo && lo->obj && lo->obj->where == OBJ_CONTAINED)
(void) l_obj_push(L, lo->obj->ocontainer); (void) l_obj_push(L, lo->obj->ocontainer);
return 1; else
} (void) l_obj_push(L, NULL);
(void) l_obj_push(L, NULL);
return 1; return 1;
} }
@@ -409,7 +412,7 @@ lua_State *L;
{ {
struct _lua_obj *lo = l_obj_check(L, 1); struct _lua_obj *lo = l_obj_check(L, 1);
lua_pushboolean(L, lo && lo->obj); lua_pushboolean(L, lobj_is_ok(lo));
return 1; return 1;
} }
+18
View File
@@ -64,3 +64,21 @@ end
if (oc3.class ~= "*") then if (oc3.class ~= "*") then
error("object class is not *, part 3"); error("object class is not *, part 3");
end end
local oc4 = o:class();
if (oc4.name ~= "rock") then
error("object class is not rock, part 4");
end
if (oc4.class ~= "*") then
error("object class is not *, part 4");
end
-- placing obj into container even when obj is somewhere else already
local o5 = obj.new("dagger");
o5:placeobj(u.ux, u.uy);
box:addcontent(o5);
local o6 = obj.new("statue");
o6:addcontent(obj.new("spellbook"));