sbrl / Minetest-WorldEditAdditions

Extra tools and commands to extend WorldEdit for Minetest
https://worldeditadditions.mooncarrot.space/
Mozilla Public License 2.0
16 stars 3 forks source link

Allow specifying an axis and thickness with //floodfill #3

Open LoneWolfHT opened 5 years ago

LoneWolfHT commented 5 years ago

I'd like to be able to select where the marker is and run something like //floodfill dirt 30 y 1 image //floodfill <node> <radius> [<axis> <thickness>]

sbrl commented 5 years ago

That's a really neat idea, @LoneWolfHT!

Currently the algorithm uses simple recursion. I'll have a think about how to implement this - it sounds a bit tricky. Certainly not impossible though - and a great challenge!

Feel free to contribute a pull request if you like :D

LoneWolfHT commented 5 years ago

That's a really neat idea, @LoneWolfHT!

Currently the algorithm uses simple recursion. I'll have a think about how to implement this - it sounds a bit tricky. Certainly not impossible though - and a great challenge!

Feel free to contribute a pull request if you like :D

Hmmm. I had thought your floodfill command used something similar to this function https://gitlab.com/sztest/nodecore/blob/master/mods/nc_api/util_scan_flood.lua If it did it should be very easy to implement this. I would create a PR but I have no idea how the current floodfill code works

sbrl commented 5 years ago

Ah, I see @LoneWolfHT. Does the code you've linked to scan of all the nodes in a cube around the desired area? It's not commented, so I'm a little unsure of how it works.

Re-reading the code behind the //floodfill command here reveals that it doesn't use recursion at all. Now that I've reviewed the code, I remember that I initially implemented a recursive algorithm, because running into nasty infinite-recursion bugs and slow performance, I implemented a queue-based system instead.

Essentially, it's a breath-first search that fans out from a given point. It adds pos1 to the queue, and then as long as the queue has something in it, it loops over the entries in the queue, processes them, and adds their neighbours to the queue also that are further away from pos1 - so long as theya re within range.

I'd be curious to do a speed comparison between the 2 styles. On the one hand, my code should touch any nodes it doesn't need to. On the other, I have the extra overhead of potentially 1000s of calls to a queue.

To clarify, you want to be able to specify the axis on which it floodfills? Or the radius that it floodfills on each axis?

E.g. To specify the radius on different axes, we could have an alternate form of the command like this: //floodfill <node_name> <radius_x> <radius_y> <radius_z>

...or to tell it to floodfill against a different axis - essentially filling in a hole in a wall for example - we could do something like this as an alternate form: //floodfill <node_name> <radius> <axis>.

I wonder if it's possible to combine these 2 syntaxes - then you'd be able to fill a lake from the bottom-up :thinking:

LoneWolfHT commented 5 years ago

To clarify, you want to be able to specify the axis on which it floodfills?

Yes

Ah, I see @LoneWolfHT. Does the code you've linked to scan of all the nodes in a cube around the desired area? It's not commented, so I'm a little unsure of how it works.

I think so. I've asked the modder that coded it. Since it's also a little hard for me to comprehend the code lol

LoneWolfHT commented 5 years ago

Their reply:


it's a flood-fill
It's actually designed to be pretty flexible, via the callback.
The flood-fill stops after a certain depth, so produces a diamond-shaped fill area
it can also be optionally blocked by any criteria you want via the callback.
scan_flood uses queue recursion
i.e. it's a breadth-first scan, and it uses heap space instead of stack space.
Also I think that it processes each outward shell in order, but the nodes within each shell in random order by design.
That way, you can use it for fills that are volume-limited instead of just distance-limited.
For instance, if you want to create an explosion that creates 50 fire nodes, you can set the max depth to 50, but also count the number of nodes you place as you place fire nodes inside the callback.  Once you've used up 50, you just start returning "blocked" from the callback for the rest of the scan and it will quickly stop.
That allows you to create a fixed-volume effect that can be shaped by surrounding terrain, so for instance you could build a pipe to force it to go a much farther distance, or else it will just puff up in a diamond-esque shape around the center when it hits open air.

The reason that function is not documented is probably because the documentation would be harder to maintain and less readable than the code itself.
Oh, right, it looks like if the callback returns truthy, then the whole thing stops and returns that value.  If it returns nil, then it continues on through that node.  If it returns false, then it continues on, but does NOT pass through that node (i.e. it can only reach its neighbors if it goes around).
sbrl commented 5 years ago

Ah, I see. That's a pretty nice implementation there then. A volume-limited search is really nice.

I think it might be possible to refactor our current implementation to support these features & get a similar diamond shape,, whilst still retaining the queue-based system that's already in place. I'm currently quite busy with University work, but I'll have a think and play around with the implementation a bit if I get time.

In the mean-time, PRs are of course welcome if you're impatient bored :P

LoneWolfHT commented 5 years ago

Ah, I see. That's a pretty nice implementation there then. A volume-limited search is really nice.

I think it might be possible to refactor our current implementation to support these features & get a similar diamond shape,, whilst still retaining the queue-based system that's already in place. I'm currently quite busy with University work, but I'll have a think and play around with the implementation a bit if I get time.

In the mean-time, PRs are of course welcome if you're ~impatient~ bored :P

Ok. I'll be a little busy irl for a week or so too. Guess this'll have to wait a while lol