mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-26 09:03:01 +00:00
Add //bonemeal command
This commit is contained in:
parent
238ef7c810
commit
5f7a64702a
6 changed files with 178 additions and 11 deletions
41
README.md
41
README.md
|
@ -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)
|
- [`//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)
|
- [`//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-)
|
- [`//multi <command_a> <command_b> .....`](#multi-command_a-command_b-command_c-)
|
||||||
- [`//yy`](#yy)
|
- [`//y`](#y)
|
||||||
- [`//nn`](#nn)
|
- [`//n`](#n)
|
||||||
|
|
||||||
### `//floodfill [<replace_node> [<radius>]]`
|
### `//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).
|
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
|
//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> .....`
|
### `//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!
|
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
|
//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`
|
### `//y`
|
||||||
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.
|
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`
|
### `//n`
|
||||||
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.
|
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
|
## Troubleshooting
|
||||||
|
|
61
worldeditadditions/bonemeal.lua
Normal file
61
worldeditadditions/bonemeal.lua
Normal 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
|
|
@ -14,3 +14,5 @@ dofile(minetest.get_modpath("worldeditadditions") .. "/ellipsoid.lua")
|
||||||
dofile(minetest.get_modpath("worldeditadditions") .. "/torus.lua")
|
dofile(minetest.get_modpath("worldeditadditions") .. "/torus.lua")
|
||||||
dofile(minetest.get_modpath("worldeditadditions") .. "/maze2d.lua")
|
dofile(minetest.get_modpath("worldeditadditions") .. "/maze2d.lua")
|
||||||
dofile(minetest.get_modpath("worldeditadditions") .. "/maze3d.lua")
|
dofile(minetest.get_modpath("worldeditadditions") .. "/maze3d.lua")
|
||||||
|
|
||||||
|
dofile(minetest.get_modpath("worldeditadditions") .. "/bonemeal.lua")
|
||||||
|
|
61
worldeditadditions_commands/commands/bonemeal.lua
Normal file
61
worldeditadditions_commands/commands/bonemeal.lua
Normal 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
|
||||||
|
})
|
|
@ -10,14 +10,25 @@ local we_c = worldeditadditions_commands
|
||||||
|
|
||||||
we_c.modpath = minetest.get_modpath("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")
|
dofile(we_c.modpath.."/multi.lua")
|
||||||
|
|
||||||
we_c.safe_region, we_c.check_region, we_c.reset_pending
|
-- We no longer need our own implementation of safe_region thanks to @sfan5's
|
||||||
= dofile(we_c.modpath.."/safe.lua")
|
-- 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/floodfill.lua")
|
||||||
dofile(we_c.modpath.."/commands/overlay.lua")
|
dofile(we_c.modpath.."/commands/overlay.lua")
|
||||||
dofile(we_c.modpath.."/commands/ellipsoid.lua")
|
dofile(we_c.modpath.."/commands/ellipsoid.lua")
|
||||||
dofile(we_c.modpath.."/commands/torus.lua")
|
dofile(we_c.modpath.."/commands/torus.lua")
|
||||||
dofile(we_c.modpath.."/commands/maze.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
|
||||||
|
|
7
worldeditadditions_commands/utils/numbers.lua
Normal file
7
worldeditadditions_commands/utils/numbers.lua
Normal 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
|
Loading…
Reference in a new issue