Skip to content

Commit

Permalink
Add on_flood() callback.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sofar authored and paramat committed Apr 22, 2017
1 parent 8464da7 commit cca58fe
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 3 deletions.
7 changes: 7 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -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 ]]

This comment has been minimized.

Copy link
@HybridDog

HybridDog Apr 22, 2017

Contributor

Does on_flood also work if l add it to liquid nodes, e.g. flowing water?

This comment has been minimized.

Copy link
@paramat

paramat Apr 22, 2017

Contributor

No, liquids are not 'floodable', if they were they would continuously remove themselves in every liquid node, overloading the liquid queue, very bad idea.


after_place_node = func(pos, placer, itemstack, pointed_thing) --[[
^ Called after constructing node when node was placed using
Expand Down
12 changes: 11 additions & 1 deletion src/map.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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()");
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/map.h
Expand Up @@ -266,7 +266,8 @@ class Map /*: public NodeContainer*/
// 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
Expand Down
21 changes: 21 additions & 0 deletions src/script/cpp_api/s_node.cpp
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/script/cpp_api/s_node.h
Expand Up @@ -42,6 +42,7 @@ class ScriptApiNode
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,
Expand Down
2 changes: 1 addition & 1 deletion src/server.cpp
Expand Up @@ -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
Expand Down

0 comments on commit cca58fe

Please sign in to comment.