Add on_flood() callback.
authorAuke Kok <sofar@foo-projects.org>
Thu, 20 Apr 2017 06:10:39 +0000 (23:10 -0700)
committerparamat <mat.gregory@virginmedia.com>
Sat, 22 Apr 2017 00:23:51 +0000 (01:23 +0100)
This callback is called if a liquid definitely floods a non-air
node on the map. The callback arguments are (pos, oldnode, newnode)
and can return a `bool` value indicating whether flooding the
node should be cancelled (`return true` will prevent the node
from flooding).

Documentation is added, the callback function was tested with a
modified minetest_game.

Note that `return true` will likely cause the node's `on_flood()`
callback to be called every second until the node gets removed,
so care must be taken to prevent many callbacks from using this
return value. The current default liquid update interval is 1.0
seconds, which isn't unmanageable.

The larger aim of this patch is to remove the lava cooling ABM,
which is a significant cost to idle servers that have lava on their
map. This callback will be much more efficient.

doc/lua_api.txt
src/map.cpp
src/map.h
src/script/cpp_api/s_node.cpp
src/script/cpp_api/s_node.h
src/server.cpp

index 4e328ac765a293a23441051d406bdf9fe137bd3f..774b1e992dd4f51d2c2ae4b61b9f21ed7078bd21 100644 (file)
@@ -4002,6 +4002,13 @@ Definition tables
         ^ Node destructor; called after removing node
         ^ Not called for bulk node placement (i.e. schematics and VoxelManip)
         ^ default: nil ]]
+        on_flood = func(pos, oldnode, newnode), --[[
+        ^ Called when a liquid (newnode) is about to flood oldnode, if
+        ^ it has `floodable = true` in the nodedef. Not called for bulk
+        ^ node placement (i.e. schematics and VoxelManip) or air nodes. If
+        ^ return true the node is not flooded, but on_flood callback will
+        ^ most likely be called over and over again every liquid update
+        ^ interval. Default: nil ]]
 
         after_place_node = func(pos, placer, itemstack, pointed_thing) --[[
         ^ Called after constructing node when node was placed using
index 8754813dd685d90d8610ed772d0c18ca9973d16b..75dcee350dff91d6e236b726e47287b17aeee6fd 100644 (file)
@@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "database.h"
 #include "database-dummy.h"
 #include "database-sqlite3.h"
+#include "script/serverscripting.h"
 #include <deque>
 #include <queue>
 #if USE_LEVELDB
@@ -637,7 +638,8 @@ s32 Map::transforming_liquid_size() {
         return m_transforming_liquid.size();
 }
 
-void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
+void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks,
+               ServerEnvironment *env)
 {
        DSTACK(FUNCTION_NAME);
        //TimeTaker timer("transformLiquids()");
@@ -897,8 +899,16 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
                        // set the liquid level and flow bit to 0
                        n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
                }
+
+               // change the node.
                n0.setContent(new_node_content);
 
+               // on_flood() the node
+               if (floodable_node != CONTENT_AIR) {
+                       if (env->getScriptIface()->node_on_flood(p0, n00, n0))
+                               continue;
+               }
+
                // Ignore light (because calling voxalgo::update_lighting_nodes)
                n0.setLight(LIGHTBANK_DAY, 0, m_nodedef);
                n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
index 739cdb59b5ec448cbe1f8ba9f7800873b4e9d591..4d7079823d99f9fc60d85e34589bc7d0561ea62d 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -266,7 +266,8 @@ public:
        // For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: "
        virtual void PrintInfo(std::ostream &out);
 
-       void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks);
+       void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks,
+                       ServerEnvironment *env);
 
        /*
                Node metadata
index adad01e453389b3c5814055614ab7bb98d7752c6..2723f84e19fc83cafad6f6b432de3558b039f945 100644 (file)
@@ -178,6 +178,27 @@ void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
        lua_pop(L, 1);  // Pop error handler
 }
 
+bool ScriptApiNode::node_on_flood(v3s16 p, MapNode node, MapNode newnode)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       int error_handler = PUSH_ERROR_HANDLER(L);
+
+       INodeDefManager *ndef = getServer()->ndef();
+
+       // Push callback function on stack
+       if (!getItemCallback(ndef->get(node).name.c_str(), "on_flood"))
+               return false;
+
+       // Call function
+       push_v3s16(L, p);
+       pushnode(L, node, ndef);
+       pushnode(L, newnode, ndef);
+       PCALL_RES(lua_pcall(L, 3, 1, error_handler));
+       lua_remove(L, error_handler);
+       return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
+}
+
 void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
 {
        SCRIPTAPI_PRECHECKHEADER
index fe1180cb3b3eb7ce2c111566ba6d6d8f49426455..eb127909d724e36145fb40d01767faa68fc1b7a6 100644 (file)
@@ -42,6 +42,7 @@ public:
                        ServerActiveObject *digger);
        void node_on_construct(v3s16 p, MapNode node);
        void node_on_destruct(v3s16 p, MapNode node);
+       bool node_on_flood(v3s16 p, MapNode node, MapNode newnode);
        void node_after_destruct(v3s16 p, MapNode node);
        bool node_on_timer(v3s16 p, MapNode node, f32 dtime);
        void node_on_receive_fields(v3s16 p,
index a921423d281b0475b4e9de040587205ee9853c25..ac6265d09d0029e2635680604e326f4d39530143 100644 (file)
@@ -599,7 +599,7 @@ void Server::AsyncRunStep(bool initial_step)
                ScopeProfiler sp(g_profiler, "Server: liquid transform");
 
                std::map<v3s16, MapBlock*> modified_blocks;
-               m_env->getMap().transformLiquids(modified_blocks);
+               m_env->getMap().transformLiquids(modified_blocks, m_env);
 #if 0
                /*
                        Update lighting