//bonmeal: add optional node list constraint

This commit is contained in:
Starbeamrainbowlabs 2021-08-05 01:17:43 +01:00
parent 3338a3fddf
commit 87f84e2482
Signed by: sbrl
GPG key ID: 1BE5172E637709C2
4 changed files with 48 additions and 15 deletions

View file

@ -9,7 +9,8 @@ Note to self: See the bottom of this file for the release template text.
- Add `//airapply` for applying commands only to air nodes in the defined region - Add `//airapply` for applying commands only to air nodes in the defined region
- Use [luacheck](https://github.com/mpeterv/luacheck) to find and fix a large number of bugs and other issues - Use [luacheck](https://github.com/mpeterv/luacheck) to find and fix a large number of bugs and other issues
- Multiple commands: Allow using quotes (`"thing"`, `'thing'`) to quote values when splitting - Multiple commands: Allow using quotes (`"thing"`, `'thing'`) to quote values when splitting
- Add optional slope constraint to `//layers` (inspired by [WorldPainter](https://worldpainter.net/)) - `//layers`: Add optional slope constraint (inspired by [WorldPainter](https://worldpainter.net/))
- `//bonemeal`: Add optional node list contraint
## v1.12: The selection tools update (26th June 2021) ## v1.12: The selection tools update (26th June 2021)

View file

@ -225,7 +225,7 @@ Additional examples:
//maze3d stone 6 3 3 54321 //maze3d stone 6 3 3 54321
``` ```
## `//bonemeal [<strength> [<chance>]]` ## `//bonemeal [<strength> [<chance> [<node_name> [<node_name> ...]]]]`
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 output a message to the server log). Alias: `//flora`. 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 output a message to the server log). Alias: `//flora`.
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. 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.
@ -240,6 +240,9 @@ For example, a chance number of 2 would mean a 50% chance that any given eligibl
Since WorldEditAdditions v1.12, a percentage chance is also supported. This is denoted by suffixing a number with a percent sign (e.g. `//bonemeal 1 25%`). Since WorldEditAdditions v1.12, a percentage chance is also supported. This is denoted by suffixing a number with a percent sign (e.g. `//bonemeal 1 25%`).
Since WorldEditAdditions v1.13, a list of node names is also optionally supported. This will constrain bonemeal operations to be performed only on the node names listed.
```weacmd ```weacmd
//bonemeal //bonemeal
//bonemeal 3 25 //bonemeal 3 25
@ -247,6 +250,8 @@ Since WorldEditAdditions v1.12, a percentage chance is also supported. This is d
//bonemeal 1 10 //bonemeal 1 10
//bonemeal 2 15 //bonemeal 2 15
//bonemeal 2 10% //bonemeal 2 10%
//bonemeal 2 10% dirt
//bonemeal 4 50 ethereal:grove_dirt
``` ```
## `//walls <replace_node>` ## `//walls <replace_node>`

View file

@ -4,7 +4,8 @@
-- strength The strength to apply - see bonemeal:on_use -- strength The strength to apply - see bonemeal:on_use
-- chance Positive integer that represents the chance bonemealing will occur -- chance Positive integer that represents the chance bonemealing will occur
function worldeditadditions.bonemeal(pos1, pos2, strength, chance) function worldeditadditions.bonemeal(pos1, pos2, strength, chance, nodename_list)
if not nodename_list then nodename_list = {} end
pos1, pos2 = worldedit.sort_pos(pos1, pos2) pos1, pos2 = worldedit.sort_pos(pos1, pos2)
-- pos2 will always have the highest co-ordinates now -- pos2 will always have the highest co-ordinates now
@ -14,6 +15,12 @@ function worldeditadditions.bonemeal(pos1, pos2, strength, chance)
return false, "Bonemeal mod not loaded" return false, "Bonemeal mod not loaded"
end end
local node_list = worldeditadditions.table.map(nodename_list, function(nodename)
return minetest.get_content_id(nodename)
end)
local node_list_count = #nodename_list
-- Fetch the nodes in the specified area -- Fetch the nodes in the specified area
local manip, area = worldedit.manip_helpers.init(pos1, pos2) local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data() local data = manip:get_data()
@ -26,10 +33,17 @@ function worldeditadditions.bonemeal(pos1, pos2, strength, chance)
for z = pos2.z, pos1.z, -1 do for z = pos2.z, pos1.z, -1 do
for x = pos2.x, pos1.x, -1 do for x = pos2.x, pos1.x, -1 do
for y = pos2.y, pos1.y, -1 do for y = pos2.y, pos1.y, -1 do
if not worldeditadditions.is_airlike(data[area:index(x, y, z)]) then local i = area:index(x, y, z)
if not worldeditadditions.is_airlike(data[i]) then
local should_bonemeal = true
if node_list_count > 0 and not worldeditadditions.table.contains(node_list, data[i]) then
should_bonemeal = false
end
-- It's not an air node, so let's try to bonemeal it -- It's not an air node, so let's try to bonemeal it
if math.random(0, chance - 1) == 0 then if should_bonemeal and math.random(0, chance - 1) == 0 then
bonemeal:on_use( bonemeal:on_use(
{ x = x, y = y, z = z }, { x = x, y = y, z = z },
strength, strength,

View file

@ -6,7 +6,7 @@ local we_c = worldeditadditions_commands
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██████ ██████ ██ ████ ███████ ██ ██ ███████ ██ ██ ███████ -- ██████ ██████ ██ ████ ███████ ██ ██ ███████ ██ ██ ███████
worldedit.register_command("bonemeal", { worldedit.register_command("bonemeal", {
params = "[<strength> [<chance>]]", params = "[<strength> [<chance> [<node_name> [<node_name> ...]]]]",
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).", 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 }, privs = { worldedit = true },
require_pos = 2, require_pos = 2,
@ -19,15 +19,16 @@ worldedit.register_command("bonemeal", {
local strength = 1 local strength = 1
local chance = 1 local chance = 1
local node_names = {} -- An empty table means all nodes
if #parts >= 1 then if #parts >= 1 then
strength = tonumber(parts[1]) strength = tonumber(table.remove(parts, 1))
if not strength then if not strength then
return false, "Invalid strength value (value must be an integer)" return false, "Invalid strength value (value must be an integer)"
end end
end end
if #parts >= 2 then if #parts >= 2 then
chance = worldeditadditions.parse.chance(parts[2]) chance = worldeditadditions.parse.chance(table.remove(parts, 1))
if not chance then if not chance then
return false, "Invalid chance value (must be a positive integer)" return false, "Invalid chance value (must be a positive integer)"
end end
@ -37,21 +38,33 @@ worldedit.register_command("bonemeal", {
return false, "Error: strength value out of bounds (value must be an integer between 1 and 4 inclusive)" return false, "Error: strength value out of bounds (value must be an integer between 1 and 4 inclusive)"
end end
if #parts > 0 then
for _,nodename in pairs(parts) do
local normalised = worldedit.normalize_nodename(nodename)
if not normalised then return false, "Error: Unknown node name '"..nodename.."'." end
table.insert(node_names, normalised)
end
end
-- We unconditionally math.floor here because when we tried to test for it directly it was unreliable -- 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) return true, math.floor(strength), math.floor(chance), node_names
end, end,
nodes_needed = function(name) -- strength, chance nodes_needed = function(name) -- strength, chance
-- Since every node has to have an air block, in the best-case scenario -- Since every node has to have an air block, in the best-case scenario
-- edit only half the nodes in the selected area -- edit only half the nodes in the selected area
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) / 2 return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) / 2
end, end,
func = function(name, strength, chance) func = function(name, strength, chance, node_names)
local start_time = worldeditadditions.get_ms_time() local start_time = worldeditadditions.get_ms_time()
local success, nodes_bonemealed, candidates = worldeditadditions.bonemeal(worldedit.pos1[name], worldedit.pos2[name], strength, chance) local success, nodes_bonemealed, candidates = worldeditadditions.bonemeal(
if not success then worldedit.pos1[name], worldedit.pos2[name],
-- nodes_bonemealed is an error message here because success == false strength, chance,
return success, nodes_bonemealed node_names
end )
-- nodes_bonemealed is an error message here if success == false
if not success then return success, nodes_bonemealed end
local percentage = worldeditadditions.round((nodes_bonemealed / candidates)*100, 2) local percentage = worldeditadditions.round((nodes_bonemealed / candidates)*100, 2)
local time_taken = worldeditadditions.get_ms_time() - start_time local time_taken = worldeditadditions.get_ms_time() - start_time
-- Avoid nan% - since if there aren't any candidates then nodes_bonemealed will be 0 too -- Avoid nan% - since if there aren't any candidates then nodes_bonemealed will be 0 too