Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add on_flood() callback. #5619

Closed
wants to merge 1 commit into from
Closed

Add on_flood() callback. #5619

wants to merge 1 commit into from

Conversation

sofar
Copy link
Contributor

@sofar sofar commented Apr 20, 2017

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.

@sofar sofar added @ Script API @ Server / Client / Env. Feature ✨ PRs that add or enhance a feature labels Apr 20, 2017
@sofar sofar added this to the 0.4.16 milestone Apr 20, 2017
@sofar
Copy link
Contributor Author

sofar commented Apr 20, 2017

Parts of this PR came from #4130

@raymoo
Copy link
Contributor

raymoo commented Apr 20, 2017

Will lava still be able to be cooled by water that is below it with this?

@sofar
Copy link
Contributor Author

sofar commented Apr 20, 2017

lava flowing on top of water floods the water node below the lava. The water doesn't magically jump up one node.

@raymoo
Copy link
Contributor

raymoo commented Apr 20, 2017

Oh, I see, I was only thinking of water doing the flooding.

src/map.cpp Outdated
@@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ServerEnv should be passed as pointer like everywhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha.

Copy link
Member

@nerzhul nerzhul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one change, else perfect shipit

@Desour
Copy link
Member

Desour commented Apr 20, 2017

A pointflooded_thing could be useful to know from where the liquid comes.

@raymoo
Copy link
Contributor

raymoo commented Apr 20, 2017

@DS-Minetest That wouldn't make sense since there isn't any pointing involved, but I guess the callback could receive a flooder position argument too.

doc/lua_api.txt Outdated
@@ -3974,6 +3974,12 @@ 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should make clear it is called only for non-air nodes.

Copy link
Contributor

@paramat paramat Apr 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps mention 'floodable = true' here, "called for non-air nodes with 'floodable = true'".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

@paramat
Copy link
Contributor

paramat commented Apr 20, 2017

Good to see this being done at last.
Could you explain the usage of 'return true' stopping the node being flooded? I can only see this causing unending repeated callbacks, which should be avoided, how would we avoid this if the node is not flooded?

@paramat
Copy link
Contributor

paramat commented Apr 20, 2017

No need for flooder pos, this should be as simple as possible.

@Ekdohibs
Copy link
Member

@paramat it causes repeated callbacks, but only 1/s and this is really not that much, except if you really have lots of nodes preventing flooding that way. If we had some nodetimer-based system or something like that based on node updates, it would avoid those repeated callbacks as well as allowing to make the water flow faster as was requested in another issue, for instance.

Copy link
Member

@Ekdohibs Ekdohibs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise, looks good!

src/map.cpp Outdated

// on_flood() the node
if (floodable_node != CONTENT_AIR) {
if (env.getScriptIface()->node_on_flood(p0, n0, new_node_content))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callback is called after n0.param2 is modified. That means that the param2 of n0 will already be the new param2, which can cause problems with coloured nodes, for instance (like the node dropping with a different colour than it should).

@paramat
Copy link
Contributor

paramat commented Apr 20, 2017

it causes repeated callbacks, but only 1/s and this is really not that much,

I agree, but it seems to cause a never-ending series of calls, which is a bad idea even if only 1 per second. So i'm wondering if this should not be encouraged / allowed. However there may be a good reason to allow this.

@sofar
Copy link
Contributor Author

sofar commented Apr 20, 2017

One reason to allow cancellation is that it could permit a security mod to effectively and retroactively mop up a hostile liquid spill.

This mopping up requires us to stop the flooding. If we don't stop flooding the node, then the callback here will require hacks like minetest.after(0, ...set_node, oldnode) or similar tricks depending on timing workarounds to avoid the flooding. That will turn out to be very fragile and problematic in itself.

With the return value honored, we can allow protection mods to delete vertical columns of lava or water relatively safely and not cause performance spikes.

You could also use this feature to safely change the liquid into a "non-flooding" liquid that just stops right there as well.

So even though it won't be used much, or shouldn't be used much, it serves a useful purpose.

@sofar
Copy link
Contributor Author

sofar commented Apr 20, 2017

I'm gonna try and see if I can replace n0 with e.g. n00 in the call and get the proper param2 in place here, but it'll have to wait until tonight when I can test (->WIP)

@raymoo
Copy link
Contributor

raymoo commented Apr 20, 2017

@sofar For that particular case you could make the on_flood callback be called after the flooding, and then it would be a good time to put the security node back in, so no need for minetest.after. It might cause problems if a node has metadata that should be preserved, though.

@paramat
Copy link
Contributor

paramat commented Apr 20, 2017

Ok i'm neutral on the return true behaviour.
Very keen on removing the lava ABM.

@sofar
Copy link
Contributor Author

sofar commented Apr 20, 2017

@raymoo right, that's why I don't want to wait until the metadata is destroyed.

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.
@sofar
Copy link
Contributor Author

sofar commented Apr 21, 2017

Pushed what I feel should be the final update.

@Ekdohibs what seems to happen is that the param2 of every node that gets newly flooded is by definition 0, until later the engine raises the liquid level to a higher value in subsequent liquidtransform calls and the liquid becomes stable.

So, per definition the param2 of newnode will always be zero.

Because of the ambiguity of the liquid direction, I think it's false to try and include a liquid direction. If one needs to see if the node above equals the liquid in newnode, one could just do a quick get_node and decide based on that, which would be relatively quick.

@Ekdohibs
Copy link
Member

@sofar n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK); for me it looks like the param2 is not always zero... however, any behaviour is fine with me as long as it is properly documented.

@sofar
Copy link
Contributor Author

sofar commented Apr 21, 2017

@Ekdohibs I think that case only happens if the liquid will be flowing down through the node entirely, like a waterfall. I have not been able to confirm that, and in all my testing of flooding e.g. flowers and other stuff, I was only ever getting 0.

@Ekdohibs
Copy link
Member

@sofar well, as long as the param2 given is the one that is used to flood, I think it is ok, regardless of what it is.

@sofar
Copy link
Contributor Author

sofar commented Apr 21, 2017

@Ekdohibs right, that's why I'm convinced that this patch is correct as-is.

@paramat paramat dismissed nerzhul’s stale review April 21, 2017 19:20

env pointer seems done.

@paramat
Copy link
Contributor

paramat commented Apr 21, 2017

@Ekdohibs seems to be +1?

@paramat
Copy link
Contributor

paramat commented Apr 21, 2017

Docs are ok for me now.

@paramat
Copy link
Contributor

paramat commented Apr 22, 2017

cca58fe

@paramat paramat closed this Apr 22, 2017
@paramat paramat mentioned this pull request Apr 22, 2017
@sofar sofar deleted the on_flood branch April 24, 2017 18:00
@nerzhul nerzhul added this to Done in Minetest 0.4.16 Apr 29, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

6 participants