diff --git a/CHANGELOG.md b/CHANGELOG.md index 7979d1f..d5307ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 - 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 - - 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) diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index cd8da59..2c7f8fb 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -225,7 +225,7 @@ Additional examples: //maze3d stone 6 3 3 54321 ``` -## `//bonemeal [ []]` +## `//bonemeal [ [ [ [ ...]]]]` 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. @@ -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.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 //bonemeal //bonemeal 3 25 @@ -247,6 +250,8 @@ Since WorldEditAdditions v1.12, a percentage chance is also supported. This is d //bonemeal 1 10 //bonemeal 2 15 //bonemeal 2 10% +//bonemeal 2 10% dirt +//bonemeal 4 50 ethereal:grove_dirt ``` ## `//walls ` diff --git a/worldeditadditions/lib/bonemeal.lua b/worldeditadditions/lib/bonemeal.lua index 1b7fc7c..31e4682 100644 --- a/worldeditadditions/lib/bonemeal.lua +++ b/worldeditadditions/lib/bonemeal.lua @@ -4,7 +4,8 @@ -- 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) +function worldeditadditions.bonemeal(pos1, pos2, strength, chance, nodename_list) + if not nodename_list then nodename_list = {} end pos1, pos2 = worldedit.sort_pos(pos1, pos2) -- 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" 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 local manip, area = worldedit.manip_helpers.init(pos1, pos2) 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 x = pos2.x, pos1.x, -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 - if math.random(0, chance - 1) == 0 then + if should_bonemeal and math.random(0, chance - 1) == 0 then bonemeal:on_use( { x = x, y = y, z = z }, strength, diff --git a/worldeditadditions_commands/commands/bonemeal.lua b/worldeditadditions_commands/commands/bonemeal.lua index 505ae99..651aaab 100644 --- a/worldeditadditions_commands/commands/bonemeal.lua +++ b/worldeditadditions_commands/commands/bonemeal.lua @@ -6,7 +6,7 @@ local we_c = worldeditadditions_commands -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -- ██████ ██████ ██ ████ ███████ ██ ██ ███████ ██ ██ ███████ worldedit.register_command("bonemeal", { - params = "[ []]", + params = "[ [ [ [ ...]]]]", 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 to be bonemealed; higher values mean a lower chance; default: 1 - 100% chance).", privs = { worldedit = true }, require_pos = 2, @@ -19,15 +19,16 @@ worldedit.register_command("bonemeal", { local strength = 1 local chance = 1 + local node_names = {} -- An empty table means all nodes if #parts >= 1 then - strength = tonumber(parts[1]) + strength = tonumber(table.remove(parts, 1)) if not strength then return false, "Invalid strength value (value must be an integer)" end end if #parts >= 2 then - chance = worldeditadditions.parse.chance(parts[2]) + chance = worldeditadditions.parse.chance(table.remove(parts, 1)) if not chance then return false, "Invalid chance value (must be a positive integer)" 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)" 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 - return true, math.floor(strength), math.floor(chance) + return true, math.floor(strength), math.floor(chance), node_names 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) + func = function(name, strength, chance, node_names) local start_time = worldeditadditions.get_ms_time() - 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 success, nodes_bonemealed, candidates = worldeditadditions.bonemeal( + worldedit.pos1[name], worldedit.pos2[name], + strength, chance, + node_names + ) + -- 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 time_taken = worldeditadditions.get_ms_time() - start_time -- Avoid nan% - since if there aren't any candidates then nodes_bonemealed will be 0 too