Add after_destruct and cache the existence of on_construct, on_destruct and after_destruct for quick skipping when a node does not have them

This commit is contained in:
Perttu Ahola 2012-06-05 23:51:37 +03:00
parent c3658e7c79
commit 3a0562bebc
6 changed files with 74 additions and 12 deletions

@ -1150,15 +1150,18 @@ Node definition (register_node)
on_destruct = func(pos), on_destruct = func(pos),
^ Node destructor; always called before removing node ^ Node destructor; always called before removing node
^ default: nil ^ default: nil
after_destruct = func(pos, oldnode),
^ Node destructor; always called after removing node
^ default: nil
after_place_node = func(pos, placer), after_place_node = func(pos, placer),
^ Called after constructing node when node was placed using ^ Called after constructing node when node was placed using
minetest.item_place_node minetest.item_place_node / minetest.env:place_node
^ default: nil ^ default: nil
after_dig_node = func(pos, oldnode, oldmetadata, digger), after_dig_node = func(pos, oldnode, oldmetadata, digger),
^ oldmetadata is in table format ^ oldmetadata is in table format
^ Called after destructing node when node was dug using ^ Called after destructing node when node was dug using
minetest.node_dig minetest.node_dig / minetest.env:dig_node
^ default: nil ^ default: nil
can_dig = function(pos,player) can_dig = function(pos,player)
^ returns true if node can be dug, or false if not ^ returns true if node can be dug, or false if not

@ -468,6 +468,10 @@ minetest.register_node("experimental:tester_node_1", {
experimental.print_to_everything("experimental:tester_node_1:on_destruct("..minetest.pos_to_string(pos)..")") experimental.print_to_everything("experimental:tester_node_1:on_destruct("..minetest.pos_to_string(pos)..")")
end, end,
after_destruct = function(pos)
experimental.print_to_everything("experimental:tester_node_1:after_destruct("..minetest.pos_to_string(pos)..")")
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger) after_dig_node = function(pos, oldnode, oldmetadata, digger)
experimental.print_to_everything("experimental:tester_node_1:after_dig_node("..minetest.pos_to_string(pos)..")") experimental.print_to_everything("experimental:tester_node_1:after_dig_node("..minetest.pos_to_string(pos)..")")
end, end,

@ -117,6 +117,9 @@ void ContentFeatures::reset()
visual_solidness = 0; visual_solidness = 0;
backface_culling = true; backface_culling = true;
#endif #endif
has_on_construct = false;
has_on_destruct = false;
has_after_destruct = false;
/* /*
Actual data Actual data

@ -144,6 +144,11 @@ struct ContentFeatures
bool backface_culling; bool backface_culling;
#endif #endif
// Server-side cached callback existence for fast skipping
bool has_on_construct;
bool has_on_destruct;
bool has_after_destruct;
/* /*
Actual data Actual data
*/ */

@ -994,6 +994,18 @@ static ContentFeatures read_content_features(lua_State *L, int index)
index = lua_gettop(L) + 1 + index; index = lua_gettop(L) + 1 + index;
ContentFeatures f; ContentFeatures f;
/* Cache existence of some callbacks */
lua_getfield(L, index, "on_construct");
if(!lua_isnil(L, -1)) f.has_on_construct = true;
lua_pop(L, 1);
lua_getfield(L, index, "on_destruct");
if(!lua_isnil(L, -1)) f.has_on_destruct = true;
lua_pop(L, 1);
lua_getfield(L, index, "after_destruct");
if(!lua_isnil(L, -1)) f.has_after_destruct = true;
lua_pop(L, 1);
/* Name */ /* Name */
getstringfield(L, index, "name", f.name); getstringfield(L, index, "name", f.name);
@ -3024,20 +3036,26 @@ private:
EnvRef *o = checkobject(L, 1); EnvRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env; ServerEnvironment *env = o->m_env;
if(env == NULL) return 0; if(env == NULL) return 0;
// pos INodeDefManager *ndef = env->getGameDef()->ndef();
// parameters
v3s16 pos = read_v3s16(L, 2); v3s16 pos = read_v3s16(L, 2);
// content MapNode n = readnode(L, 3, ndef);
MapNode n = readnode(L, 3, env->getGameDef()->ndef());
// Do it // Do it
// Call destructor
MapNode n_old = env->getMap().getNodeNoEx(pos); MapNode n_old = env->getMap().getNodeNoEx(pos);
// Call destructor
if(ndef->get(n_old).has_on_destruct)
scriptapi_node_on_destruct(L, pos, n_old); scriptapi_node_on_destruct(L, pos, n_old);
// Replace node // Replace node
bool succeeded = env->getMap().addNodeWithEvent(pos, n); bool succeeded = env->getMap().addNodeWithEvent(pos, n);
lua_pushboolean(L, succeeded); if(succeeded){
// Call post-destructor
if(ndef->get(n_old).has_after_destruct)
scriptapi_node_after_destruct(L, pos, n_old);
// Call constructor // Call constructor
if(succeeded) if(ndef->get(n).has_on_construct)
scriptapi_node_on_construct(L, pos, n); scriptapi_node_on_construct(L, pos, n);
}
lua_pushboolean(L, succeeded);
return 1; return 1;
} }
@ -3053,14 +3071,22 @@ private:
EnvRef *o = checkobject(L, 1); EnvRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env; ServerEnvironment *env = o->m_env;
if(env == NULL) return 0; if(env == NULL) return 0;
INodeDefManager *ndef = env->getGameDef()->ndef();
// parameters
v3s16 pos = read_v3s16(L, 2); v3s16 pos = read_v3s16(L, 2);
// Do it // Do it
MapNode n_old = env->getMap().getNodeNoEx(pos);
// Call destructor // Call destructor
MapNode n = env->getMap().getNodeNoEx(pos); if(ndef->get(n_old).has_on_destruct)
scriptapi_node_on_destruct(L, pos, n); scriptapi_node_on_destruct(L, pos, n_old);
// Replace with air // Replace with air
// This is slightly optimized compared to addNodeWithEvent(air) // This is slightly optimized compared to addNodeWithEvent(air)
bool succeeded = env->getMap().removeNodeWithEvent(pos); bool succeeded = env->getMap().removeNodeWithEvent(pos);
if(succeeded){
// Call post-destructor
if(ndef->get(n_old).has_after_destruct)
scriptapi_node_after_destruct(L, pos, n_old);
}
lua_pushboolean(L, succeeded); lua_pushboolean(L, succeeded);
// Air doesn't require constructor // Air doesn't require constructor
return 1; return 1;
@ -5143,6 +5169,25 @@ void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node)
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L, "error: %s", lua_tostring(L, -1));
} }
void scriptapi_node_after_destruct(lua_State *L, v3s16 p, MapNode node)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
INodeDefManager *ndef = get_server(L)->ndef();
// Push callback function on stack
if(!get_item_callback(L, ndef->get(node).name.c_str(), "after_destruct"))
return;
// Call function
push_v3s16(L, p);
pushnode(L, node, ndef);
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p, void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
const std::string &formname, const std::string &formname,
const std::map<std::string, std::string> &fields, const std::map<std::string, std::string> &fields,

@ -86,6 +86,8 @@ bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node); void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node);
// Node destructor // Node destructor
void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node); void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node);
// Node post-destructor
void scriptapi_node_after_destruct(lua_State *L, v3s16 p, MapNode node);
// Called when a metadata form returns values // Called when a metadata form returns values
void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p, void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
const std::string &formname, const std::string &formname,