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:55 +02:00
parent 2ae7cf02ea
commit 7e07cef197
5 changed files with 58 additions and 30 deletions

View File

@@ -66,7 +66,8 @@ struct obj {
#define OBJ_MIGRATING 5 /* object sent off to another level */
#define OBJ_BURIED 6 /* object buried */
#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 */
Bitfield(cursed, 1);

View File

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

View File

@@ -1969,6 +1969,7 @@ struct monst *mtmp;
* OBJ_MIGRATING migrating chain
* OBJ_BURIED level.buriedobjs chain
* OBJ_ONBILL on g.billobjs chain
* OBJ_LUAFREE obj is dealloc'd from core, but still used by lua
*/
void
obj_extract_self(obj)
@@ -1976,6 +1977,7 @@ struct obj *obj;
{
switch (obj->where) {
case OBJ_FREE:
case OBJ_LUAFREE:
break;
case OBJ_FLOOR:
remove_object(obj);
@@ -2161,7 +2163,7 @@ void
dealloc_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");
if (obj->nobj)
panic("dealloc_obj with nobj");
@@ -2192,8 +2194,11 @@ 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 */
if (obj->lua_ref_cnt) {
/* obj is referenced from a lua script, let lua gc free it */
obj->where = OBJ_LUAFREE;
return;
}
free((genericptr_t) obj);
}
@@ -2430,7 +2435,8 @@ const char *mesg;
static const char *obj_state_names[NOBJ_STATES] = { "free", "floor",
"contained", "invent",
"minvent", "migrating",
"buried", "onbill" };
"buried", "onbill",
"luafree" };
static const char *
where_name(obj)

View File

@@ -22,6 +22,8 @@ struct _lua_obj {
struct obj *obj;
};
#define lobj_is_ok(lo) ((lo) && (lo)->obj && (lo)->obj->where != OBJ_LUAFREE)
struct _lua_obj *
l_obj_check(L, index)
lua_State *L;
@@ -46,7 +48,8 @@ lua_State *L;
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 (!lo->obj->lua_ref_cnt
&& (lo->obj->where == OBJ_FREE || lo->obj->where == OBJ_LUAFREE)) {
if (Has_contents(lo->obj)) {
struct obj *otmp;
while ((otmp = lo->obj->cobj) != 0) {
@@ -98,13 +101,12 @@ lua_State *L;
if (!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);
return 1;
}
/* Puts object inside another object. */
/* local box = obj.new("large chest");
box.addcontent(obj.new("rock"));
*/
@@ -115,19 +117,21 @@ lua_State *L;
struct _lua_obj *lobox = l_obj_check(L, 1);
struct _lua_obj *lo = l_obj_check(L, 2);
struct obj *otmp;
int refs;
if (!lo->obj || !lobox->obj)
nhl_error(L, "l_obj_add_to_container: no obj");
if (!lobj_is_ok(lo) || !lobj_is_ok(lobox))
return 0;
if (!Is_container(lobox->obj))
nhl_error(L, "l_obj_add_to_container: not a container");
refs = lo->obj->lua_ref_cnt;
obj_extract_self(lo->obj);
otmp = add_to_container(lobox->obj, lo->obj);
/* was lo->obj merged? FIXME: causes problems if both lo->obj and
the one it merged with are handled by lua. Use lo->state? */
if (otmp != lo->obj)
/* was lo->obj merged? */
if (otmp != lo->obj) {
lo->obj->lua_ref_cnt += refs;
lo->obj = otmp;
}
return 0;
}
@@ -135,6 +139,7 @@ lua_State *L;
/* Get a table of object class data. */
/* local odata = obj.class(otbl.otyp); */
/* local odata = obj.class(obj.new("rock")); */
/* local odata = o:class(); */
static int
l_obj_objects_to_table(L)
lua_State *L;
@@ -217,7 +222,7 @@ lua_State *L;
lua_newtable(L);
if (!obj) {
if (!obj || obj->where == OBJ_LUAFREE) {
nhl_add_table_entry_int(L, "NO_OBJ", 1);
return 1;
}
@@ -352,20 +357,19 @@ lua_State *L;
{
int argc = lua_gettop(L);
struct _lua_obj *lo = l_obj_check(L, 1);
int x, y;
if (argc != 3)
nhl_error(L, "l_obj_placeobj: Wrong args");
if (lo && lo->obj) {
int x, y;
x = (int) luaL_checkinteger(L, 2);
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);
} else
nhl_error(L, "l_obj_placeobj: Wrong args");
}
return 0;
}
@@ -393,11 +397,10 @@ lua_State *L;
{
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);
return 1;
}
(void) l_obj_push(L, NULL);
else
(void) l_obj_push(L, NULL);
return 1;
}
@@ -409,7 +412,7 @@ lua_State *L;
{
struct _lua_obj *lo = l_obj_check(L, 1);
lua_pushboolean(L, lo && lo->obj);
lua_pushboolean(L, lobj_is_ok(lo));
return 1;
}

View File

@@ -64,3 +64,21 @@ end
if (oc3.class ~= "*") then
error("object class is not *, part 3");
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"));