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:
@@ -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);
|
||||
|
||||
@@ -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 \
|
||||
|
||||
14
src/mkobj.c
14
src/mkobj.c
@@ -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)
|
||||
|
||||
51
src/nhlobj.c
51
src/nhlobj.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"));
|
||||
|
||||
Reference in New Issue
Block a user