Add after_destruct and cache the existence of on_construct, on_destruct and after_des...
authorPerttu Ahola <celeron55@gmail.com>
Tue, 5 Jun 2012 20:51:37 +0000 (23:51 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 5 Jun 2012 20:51:37 +0000 (23:51 +0300)
doc/lua_api.txt
games/minimal/mods/experimental/init.lua
src/nodedef.cpp
src/nodedef.h
src/scriptapi.cpp
src/scriptapi.h

index 5e0f2f1185ce8327ea9614d170d14bcdd131fe22..e6e24b90a032decffdc9ffee1cfce4734341c9eb 100644 (file)
@@ -1150,15 +1150,18 @@ Node definition (register_node)
     on_destruct = func(pos),
     ^ Node destructor; always called before removing node
     ^ default: nil
+    after_destruct = func(pos, oldnode),
+    ^ Node destructor; always called after removing node
+    ^ default: nil
 
     after_place_node = func(pos, placer),
     ^ Called after constructing node when node was placed using
-      minetest.item_place_node
+      minetest.item_place_node / minetest.env:place_node
     ^ default: nil
     after_dig_node = func(pos, oldnode, oldmetadata, digger),
     ^ oldmetadata is in table format
     ^ Called after destructing node when node was dug using
-      minetest.node_dig
+      minetest.node_dig / minetest.env:dig_node
     ^ default: nil
     can_dig = function(pos,player)
     ^ returns true if node can be dug, or false if not
index ea11e6d3b8fcd80fcaff38b675f209780d6755f0..c8ffb25de36254d937b49f93b17b4ad151f98160 100644 (file)
@@ -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)..")")
        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)
                experimental.print_to_everything("experimental:tester_node_1:after_dig_node("..minetest.pos_to_string(pos)..")")
        end,
index 2feec04f8faa8735ae38e699800a59ede391e5ad..eaf0612873083b6a88d51e5d5939f11e90283dad 100644 (file)
@@ -117,6 +117,9 @@ void ContentFeatures::reset()
        visual_solidness = 0;
        backface_culling = true;
 #endif
+       has_on_construct = false;
+       has_on_destruct = false;
+       has_after_destruct = false;
        /*
                Actual data
                
index 681606fd8f9fac4398c1d5b2318436b1f31bb70e..04f375043c745280c85a54cefb11b5dcef236b61 100644 (file)
@@ -144,6 +144,11 @@ struct ContentFeatures
        bool backface_culling;
 #endif
 
+       // Server-side cached callback existence for fast skipping
+       bool has_on_construct;
+       bool has_on_destruct;
+       bool has_after_destruct;
+
        /*
                Actual data
        */
index 5091216dc2f5c23d0799512e7e4b62c19d7f6918..f53355f640dfde1ae004e16244fa4c92bb341154 100644 (file)
@@ -994,6 +994,18 @@ static ContentFeatures read_content_features(lua_State *L, int index)
                index = lua_gettop(L) + 1 + index;
 
        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 */
        getstringfield(L, index, "name", f.name);
 
@@ -3024,20 +3036,26 @@ private:
                EnvRef *o = checkobject(L, 1);
                ServerEnvironment *env = o->m_env;
                if(env == NULL) return 0;
-               // pos
+               INodeDefManager *ndef = env->getGameDef()->ndef();
+               // parameters
                v3s16 pos = read_v3s16(L, 2);
-               // content
-               MapNode n = readnode(L, 3, env->getGameDef()->ndef());
+               MapNode n = readnode(L, 3, ndef);
                // Do it
-               // Call destructor
                MapNode n_old = env->getMap().getNodeNoEx(pos);
-               scriptapi_node_on_destruct(L, pos, n_old);
+               // Call destructor
+               if(ndef->get(n_old).has_on_destruct)
+                       scriptapi_node_on_destruct(L, pos, n_old);
                // Replace node
                bool succeeded = env->getMap().addNodeWithEvent(pos, n);
+               if(succeeded){
+                       // Call post-destructor
+                       if(ndef->get(n_old).has_after_destruct)
+                               scriptapi_node_after_destruct(L, pos, n_old);
+                       // Call constructor
+                       if(ndef->get(n).has_on_construct)
+                               scriptapi_node_on_construct(L, pos, n);
+               }
                lua_pushboolean(L, succeeded);
-               // Call constructor
-               if(succeeded)
-                       scriptapi_node_on_construct(L, pos, n);
                return 1;
        }
 
@@ -3053,14 +3071,22 @@ private:
                EnvRef *o = checkobject(L, 1);
                ServerEnvironment *env = o->m_env;
                if(env == NULL) return 0;
+               INodeDefManager *ndef = env->getGameDef()->ndef();
+               // parameters
                v3s16 pos = read_v3s16(L, 2);
                // Do it
+               MapNode n_old = env->getMap().getNodeNoEx(pos);
                // Call destructor
-               MapNode n = env->getMap().getNodeNoEx(pos);
-               scriptapi_node_on_destruct(L, pos, n);
+               if(ndef->get(n_old).has_on_destruct)
+                       scriptapi_node_on_destruct(L, pos, n_old);
                // Replace with air
                // This is slightly optimized compared to addNodeWithEvent(air)
                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);
                // Air doesn't require constructor
                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));
 }
 
+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,
                const std::string &formname,
                const std::map<std::string, std::string> &fields,
index 7b0bffdb5e73b64c3f6dcd4a58311980b115bc69..59daa3aa094fbd7e7ec4ebcaeb6b1f60fcdb73e2 100644 (file)
@@ -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);
 // Node destructor
 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
 void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
                const std::string &formname,