Add //bonemeal command

This commit is contained in:
Starbeamrainbowlabs 2020-05-11 02:02:02 +01:00
parent 238ef7c810
commit 5f7a64702a
Signed by: sbrl
GPG Key ID: 1BE5172E637709C2
6 changed files with 178 additions and 11 deletions

View File

@ -17,8 +17,8 @@ If you can dream of it, it probably belongs here!
- [`//maze <replace_node> [<path_length> [<path_width> [<seed>]]]`](#maze-replace_node-seed)
- [`//maze3d <replace_node> [<path_length> [<path_width> [<path_depth> [<seed>]]]]`](#maze3d-replace_node-seed)
- [`//multi <command_a> <command_b> .....`](#multi-command_a-command_b-command_c-)
- [`//yy`](#yy)
- [`//nn`](#nn)
- [`//y`](#y)
- [`//n`](#n)
### `//floodfill [<replace_node> [<radius>]]`
Floods all connected nodes of the same type starting at _pos1_ with <replace_node> (which defaults to `water_source`), in a sphere with a radius of <radius> (which defaults to 50).
@ -108,6 +108,27 @@ The optional `path_depth` parameter defaults to `1` and allows customisation of
//maze3d stone 6 3 3 54321
```
### `//bonemeal [<strength> [<chance>]]`
Requires the [`bonemeal`](https://content.minetest.net/packages/TenPlus1/bonemeal/) ([repo](https://notabug.org/TenPlus1/bonemeal/)) mod (otherwise _WorldEditAdditions_ will not register this command and outut a message to the server log).
Bonemeals all eligible nodes in the current region. An eligible node is one that has an air node directly above it - note that just because a node is eligible doesn't mean to say that something will actually happen when the `bonemeal` mod bonemeals it.
Optionally takes a strength value (that's passed to `bonemeal:on_use()`, the method in the `bonemeal` mod that is called to actually do the bonemealing). The strength value is a positive integer from 1 to 4 (i.e. 1, 2, 3, or 4) - the default is 1 (the lowest strength).
I observe that a higher strength value gives a higher chance that something will actually grow. In the case of soil or sand nodes, I observe that it increases the area of effect of a single bonemeal action (thus at higher strengths generally you'll probably want a higher chance number - see below). See the [`bonemeal` mod README](https://notabug.org/TenPlus1/bonemeal) for more information.
Also optionally takes a chance number. This is the chance that an eligible node will actually get bonemealed, and is a positive integer that defaults to 1. The chance number represents a 1-in-{number} chance to bonemeal any given eligible node, where {number} is the chance number. In other words, the higher the chance number the lower the chance that a node will be bonemealed.
For example, a chance number of 2 would mean a 50% chance that any given eligible node will get bonemealed. A chance number of 16 would be a 6.25% chance, and a chance number of 25 would be 2%.
```
//bonemeal
//bonemeal 3 25
//bonemeal 4
//bonemeal 1 10
//bonemeal 2 15
```
### `//multi <command_a> <command_b> <command_c> .....`
Executes multi chat commands in sequence. Intended for _WorldEdit_ commands, but does work with others too. Don't forget a space between commands!
@ -117,18 +138,22 @@ Executes multi chat commands in sequence. Intended for _WorldEdit_ commands, but
//multi /time 7:00 //1 //outset h 20 //outset v 5 //overlay dirt_with_grass //1 //2 //sphere 8 air //shift down 1 //floodfill //reset
```
### `//yy`
Confirms the execution of a command if it could potentially affect a large number of nodes and take a while. Equivalent to _WorldEdit_'s `//y`, but because of security sandboxing issues it's not really possible to hook into WorldEdit's existing command.
### `//y`
Confirms the execution of a command if it could potentially affect a large number of nodes and take a while. This is a regular WorldEdit command.
<!-- Equivalent to _WorldEdit_'s `//y`, but because of security sandboxing issues it's not really possible to hook into WorldEdit's existing command. -->
```
//yy
//y
```
### `//nn`
Prevents the execution of a command if it could potentially affect a large number of nodes and take a while. Equivalent to _WorldEdit_'s `//y`, but because of security sandboxing issues it's not really possible to hook into WorldEdit's existing command.
### `//n`
Prevents the execution of a command if it could potentially affect a large number of nodes and take a while. This is a regular WorldEdit command.
<!-- Equivalent to _WorldEdit_'s `//y`, but because of security sandboxing issues it's not really possible to hook into WorldEdit's existing command. -->
```
//nn
//n
```
## Troubleshooting

View File

@ -0,0 +1,61 @@
--- Bonemeal command.
-- Applies bonemeal to all notes
-- @module worldeditadditions.overlay
-- strength The strength to apply - see bonemeal:on_use
-- chance Positive integer that represents the chance bonemealing will occur
function worldeditadditions.bonemeal(pos1, pos2, strength, chance)
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
-- This command requires the bonemeal mod to be installed
-- We check here too because other mods might call this function directly and bypass the chat command system
if not minetest.get_modpath("bonemeal") then
return false, "Bonemeal mod not loaded"
end
-- Fetch the nodes in the specified area
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data()
local node_id_air = minetest.get_content_id("air")
-- z y x is the preferred loop order (because CPU cache I'd guess), but that isn't really possible here
local nodes_bonemealed = 0
local candidates = 0
for z = pos2.z, pos1.z, -1 do
for x = pos2.x, pos1.x, -1 do
local found_air = false
for y = pos2.y, pos1.y, -1 do
if data[area:index(x, y, z)] ~= node_id_air then
if found_air then
-- We've found an air block previously, so this node definitely has air above it
if math.random(0, chance - 1) == 0 then
bonemeal:on_use(
{ x = x, y = y, z = z },
strength,
nil
)
nodes_bonemealed = nodes_bonemealed + 1
end
candidates = candidates + 1
found_air = false
end
else
found_air = true
end
end
end
end
-- Save the modified nodes back to disk & return
-- Note that we do NOT save it back to disk here, because we haven't actually changed anything
-- We just grabbed the data via manip to allow for rapid node name lookups
-- worldedit.manip_helpers.finish(manip, data)
return true, nodes_bonemealed, candidates
end

View File

@ -14,3 +14,5 @@ dofile(minetest.get_modpath("worldeditadditions") .. "/ellipsoid.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/torus.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/maze2d.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/maze3d.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/bonemeal.lua")

View File

@ -0,0 +1,61 @@
local we_c = worldeditadditions_commands
-- ██████ ██████ ███ ██ ███████ ███ ███ ███████ █████ ██
-- ██ ██ ██ ██ ████ ██ ██ ████ ████ ██ ██ ██ ██
-- ██████ ██ ██ ██ ██ ██ █████ ██ ████ ██ █████ ███████ ██
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██████ ██████ ██ ████ ███████ ██ ██ ███████ ██ ██ ███████
worldedit.register_command("bonemeal", {
params = "[<strength> [<chance>]]",
description = "Bonemeals everything that's bonemeal-able that has an air node directly above it. Optionally takes a strength value to use (default: 1, maximum: 4), and a chance to actually bonemeal an eligible node (positive integer; nodes have a 1-in-<chance> chance to be bonemealed; higher values mean a lower chance; default: 1 - 100% chance).",
privs = { worldedit = true },
require_pos = 2,
parse = function(params_text)
if not params_text or params_text == "" then
params_text = "1"
end
local parts = we_c.split(params_text, "%s+", false)
local strength = 1
local chance = 1
if #parts >= 1 then
strength = tonumber(parts[1])
if not strength then
return false, "Invalid strength value (value must be an integer)"
end
end
if #parts >= 2 then
chance = tonumber(parts[2])
if not chance then
return false, "Invalid chance value (must be a positive integer)"
end
end
if strength < 1 or strength > 4 then
return false, "Error: strength value out of bounds (value must be an integer between 1 and 4 inclusive)"
end
-- We unconditionally math.floor here because when we tried to test for it directly it was unreliable
return true, math.floor(strength), math.floor(chance)
end,
nodes_needed = function(name) -- strength, chance
-- Since every node has to have an air block, in the best-case scenario
-- edit only half the nodes in the selected area
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) / 2
end,
func = function(name, strength, chance)
local start_time = os.clock()
local success, nodes_bonemealed, candidates = worldeditadditions.bonemeal(worldedit.pos1[name], worldedit.pos2[name], strength, chance)
if not success then
-- nodes_bonemealed is an error message here because success == false
return success, nodes_bonemealed
end
local percentage = we_c.round((nodes_bonemealed / candidates)*100, 2)
local time_taken = os.clock() - start_time
minetest.log("action", name .. " used //bonemeal at "..worldeditadditions.vector.tostring(worldedit.pos1[name]).." - "..worldeditadditions.vector.tostring(worldedit.pos2[name])..", bonemealing " .. nodes_bonemealed.." nodes (out of "..candidates.." nodes) at strength "..strength.." in "..time_taken.."s")
return true, nodes_bonemealed.." out of "..candidates.." (~"..percentage.."%) candidates bonemealed in "..time_taken.."s"
end
})

View File

@ -10,14 +10,25 @@ local we_c = worldeditadditions_commands
we_c.modpath = minetest.get_modpath("worldeditadditions_commands")
dofile(we_c.modpath.."/utils/strings.lua")
dofile(we_c.modpath.."/utils/numbers.lua")
dofile(we_c.modpath.."/multi.lua")
we_c.safe_region, we_c.check_region, we_c.reset_pending
= dofile(we_c.modpath.."/safe.lua")
-- We no longer need our own implementation of safe_region thanks to @sfan5's
-- suggestion in issue #5 - yay!
-- we_c.safe_region, we_c.check_region, we_c.reset_pending
-- = dofile(we_c.modpath.."/safe.lua")
dofile(we_c.modpath.."/utils/strings.lua")
dofile(we_c.modpath.."/commands/floodfill.lua")
dofile(we_c.modpath.."/commands/overlay.lua")
dofile(we_c.modpath.."/commands/ellipsoid.lua")
dofile(we_c.modpath.."/commands/torus.lua")
dofile(we_c.modpath.."/commands/maze.lua")
-- Don't registry the //bonemeal command if the bonemeal mod isn't present
if minetest.get_modpath("bonemeal") then
dofile(we_c.modpath.."/commands/bonemeal.lua")
else
minetest.log("action", "[WorldEditAdditions] bonemeal mod not detected: //bonemeal command not registered")
end

View File

@ -0,0 +1,7 @@
local we_c = worldeditadditions_commands
-- From http://lua-users.org/wiki/SimpleRound
function we_c.round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end