From ea05d5f5592042a91071fbc824cd8c0dfb2d13d2 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Tue, 11 May 2021 22:20:29 +0100 Subject: [PATCH 1/8] bonemeal: use wea.parse.chance --- worldeditadditions_commands/commands/bonemeal.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldeditadditions_commands/commands/bonemeal.lua b/worldeditadditions_commands/commands/bonemeal.lua index 4223115..088780f 100644 --- a/worldeditadditions_commands/commands/bonemeal.lua +++ b/worldeditadditions_commands/commands/bonemeal.lua @@ -27,7 +27,7 @@ worldedit.register_command("bonemeal", { end end if #parts >= 2 then - chance = tonumber(parts[2]) + chance = worldeditadditions.parse.chance(parts[2]) if not chance then return false, "Invalid chance value (must be a positive integer)" end From 4e544c555c0be1db87e83781a6e6756de2dd9e01 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Tue, 11 May 2021 22:29:15 +0100 Subject: [PATCH 2/8] replacemix: add support for wea.parse.chance TODO: use wea.parse.weighted_nodes The problem here is that we have a target_node with an optional chance too, so a finite state machine is needed to parse it currently Once we've extracted the target_node and it's optional chance though, we should be able to use wea.parse.weighted_nodes in theory --- .../commands/replacemix.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/worldeditadditions_commands/commands/replacemix.lua b/worldeditadditions_commands/commands/replacemix.lua index 965cd2c..5eaa61a 100644 --- a/worldeditadditions_commands/commands/replacemix.lua +++ b/worldeditadditions_commands/commands/replacemix.lua @@ -1,4 +1,4 @@ -local we_c = worldeditadditions_commands +local wea = worldeditadditions -- ██████ ███████ ██████ ██ █████ ██████ ███████ ███ ███ ██ ██ ██ -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ @@ -15,7 +15,7 @@ worldedit.register_command("replacemix", { return false, "Error: No arguments specified" end - local parts = worldeditadditions.split(params_text, "%s+", false) + local parts = wea.split(params_text, "%s+", false) local target_node = nil local target_node_chance = 1 @@ -30,16 +30,16 @@ worldedit.register_command("replacemix", { return false, "Error: Invalid target_node name" end mode = "target_chance" - elseif mode == "target_chance" and tonumber(part) then - target_node_chance = tonumber(part) + elseif mode == "target_chance" and wea.parse.chance(part) then + target_node_chance = wea.parse.chance(part) mode = "replace_node" - elseif (mode == "target_chance" and not tonumber(part)) or mode == "replace_node" then + elseif (mode == "target_chance" and not wea.parse.chance(part, "weight")) or mode == "replace_node" then mode = "replace_node" - if tonumber(part) then + if wea.parse.chance(part, "weight") then if not last_node_name then return false, "Error: No previous node name was found (this is a probably a bug)." end - replace_nodes[last_node_name] = math.floor(tonumber(part)) + replace_nodes[last_node_name] = math.floor(wea.parse.chance(part, "weight")) else if last_node_name and not replace_nodes[last_node_name] then replace_nodes[last_node_name] = 1 From 8eaa76c75234db5ed8053aa2f09edfbaba97b56d Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Tue, 11 May 2021 22:32:09 +0100 Subject: [PATCH 3/8] Update changelog --- CHANGELOG.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea0d243..0ccacd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,13 @@ Note to self: See the bottom of this file for the release template text. - Add `//spush`, `//spop`, and `//sstack` - `//overlay`: Don't place nodes above water - `//multi`: Improve resilience by handling some edge cases -- Add `//srect` (_select rectangle_), `//scol` (_select column_), `//scube` (_select cube_) - thanks, @VorTechnix! -- Add `//scloud` (_select point cloud_), `//scentre` (_select centre node(s)_), `//srel` (_select relative_) - thanks, @VorTechnix! -- Significantly refactored backend utility functions (more to come in future updates) -- `//bonemeal`: Try bonemealing everything that isn't an air block (#49) + - Add `//srect` (_select rectangle_), `//scol` (_select column_), `//scube` (_select cube_) - thanks, @VorTechnix! + - Add `//scloud` (_select point cloud_), `//scentre` (_select centre node(s)_), `//srel` (_select relative_) - thanks, @VorTechnix! + - Significantly refactored backend utility functions (more to come in future updates) + - `//bonemeal`: Try bonemealing everything that isn't an air block (#49) + - Add new universal chance parsing + - Any `` can now either be a 1-in-N number (e.g. `4`, `10`), or a percentage chance (e.g. `50%`, `10%`). + - Caveat: Percentages are converted to a 1-in-N chance, but additionally that number is rounded down in some places ## v1.11: The big data update (25th January 2021) From 4d080853d42a00735ec5de2143f744abb5a040e4 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Tue, 11 May 2021 22:38:17 +0100 Subject: [PATCH 4/8] reference: add notes about chances --- Chat-Command-Reference.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index 705e8d2..7f0d3aa 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -37,6 +37,7 @@ Note also that columns without any air nodes in them at all are also skipped, so //overlay grass_with_dirt 10 dirt //overlay grass_with_dirt 10 dirt 2 sand 1 //overlay sandstone dirt 2 sand 5 +//overlay dirt 90% stone 10% ``` ## `//layers [ []] [ []] ...` @@ -212,12 +213,15 @@ Also optionally takes a chance number. This is the chance that an eligible node 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%. +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%`). + ``` //bonemeal //bonemeal 3 25 //bonemeal 4 //bonemeal 1 10 //bonemeal 2 15 +//bonemeal 2 10% ``` ## `//walls ` @@ -350,6 +354,14 @@ If we wanted to put all of the above features together into a single command, th The above replaces 1 in 3 `dirt` nodes with a mix of `sandstone`, `dry_dirt`, and `cobble` nodes in the ratio 10:1:2. Awesome! +Since WorldEditAdditions v1.12, you can also use percentages: + +``` +//replacemix dirt 33% sandstone 75% dry_dirt 10% cobble 15% +``` + +Note though that the percentages are internally converted to a 1-in-N chance and rounded down. + Here are all the above examples together: ``` From 3fbfc1fb1563873c5f065a971d220a8ae4458b25 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 15 May 2021 02:00:40 +0100 Subject: [PATCH 5/8] torus: rework to add axes, but it's not finished yet --- worldeditadditions/lib/torus.lua | 15 ++++- .../commands/torus.lua | 67 +++++++++++++------ 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/worldeditadditions/lib/torus.lua b/worldeditadditions/lib/torus.lua index df4734f..22e23f4 100644 --- a/worldeditadditions/lib/torus.lua +++ b/worldeditadditions/lib/torus.lua @@ -1,7 +1,16 @@ --- Overlap command. Places a specified node on top of -- @module worldeditadditions.overlay -function worldeditadditions.torus(position, major_radius, minor_radius, target_node, hollow) +--- Generates a torus shape at the given position with the given parameters. +-- @param position Vector The position at which to generate the torus. +-- @param major_radius number The major radius of the torus - i.e. the distance from the middle to the ring. +-- @param minor_radius number The minor radius of the torus - i.e. the radaius fo the ring itself. +-- @param target_node string The name of the target node to generate the torus with. +-- @param axes=xz string|nil The axes upon which the torus should lay flat. +-- @param hollow=false boolean Whether the generated torus should be hollow or not. +function worldeditadditions.torus(position, major_radius, minor_radius, target_node, axes, hollow) + if type(axes) ~= "string" then axes = "xz" end + -- position = { x, y, z } local total_radius = major_radius + minor_radius local inner_minor_radius = minor_radius - 2 @@ -33,6 +42,10 @@ function worldeditadditions.torus(position, major_radius, minor_radius, target_n for x = -total_radius, total_radius do local x_sq = x*x + if axes == "xz" then + -- TODO: Figure out which 2 axes we need to fiddle here + end + -- (x^2+y^2+z^2-(a^2+b^2))^2-4 a b (b^2-z^2) -- Where: -- (x, y, z) is the point diff --git a/worldeditadditions_commands/commands/torus.lua b/worldeditadditions_commands/commands/torus.lua index 0d6d4a7..2156e32 100644 --- a/worldeditadditions_commands/commands/torus.lua +++ b/worldeditadditions_commands/commands/torus.lua @@ -4,33 +4,58 @@ -- ██ ██ ██ ██ ██ ██ ██ ██ -- ██ ██████ ██ ██ ██████ ███████ local function parse_params_torus(params_text) - local found, _, major_radius, minor_radius, replace_node = params_text:find("([0-9]+)%s+([0-9]+)%s+([a-z:_\\-]+)") + local parts = worldeditadditions.split(params_text, "%s+", false) + print("[DEBUG:torus/parts]") + for i = 1, #parts, 1 do print(parts[i]) end + -- local found, _, major_radius, minor_radius, replace_node, axes = params_text:find("([0-9]+)%s+([0-9]+)%s+([a-z:_\\-]+)%s+([xyz]+)") - if found == nil then - return nil, nil - end + if #parts < 3 then return nil, nil, nil end - major_radius = tonumber(major_radius) - minor_radius = tonumber(minor_radius) - - replace_node = worldedit.normalize_nodename(replace_node) - - if not replace_node then + if #parts < 1 then return false, "Error: Invalid replace_node." end - if not major_radius or major_radius < 1 then + if #parts < 2 then return false, "Error: Invalid major radius (expected integer greater than 0)" end - if not minor_radius or minor_radius < 1 then + if #parts < 3 then return false, "Error: Invalid minor radius (expected integer greater than 0)" end - return true, replace_node, major_radius, minor_radius + local major_radius = tonumber(parts[1]) + local minor_radius = tonumber(parts[2]) + local replace_node = worldedit.normalize_nodename(parts[3]) + local axes + if #parts > 3 then axes = parts[4] end + if not axes then axes = "xy" end + + if major_radius < 1 then + return false, "Error: The major radius must be greater than 0." + end + if minor_radius < 1 then + return false, "Error: The minor radius must be greater than 0." + end + if not replace_node then + return false, "Error: Invalid node name." + end + if axes:find("[^xyz]") then + return false, "Error: The axes may only contain the latters x, y, and z." + end + if #axes ~= 2 then + return false, "Error: Exactly 2 axes must be specified. For example, 'xy' is valid, but 'xyy' is not (both of course without quotes)." + end + + + -- Sort the axis names (this is important to ensure we can identify the direction properly) + if axes == "yx" then axes = "xy" end + if axes == "zx" then axes = "xz" end + if axes == "zy" then axes = "yz" end + + return true, replace_node, major_radius, minor_radius, axes end worldedit.register_command("torus", { - params = " ", - description = "Creates a 3D torus with a major radius of and a minor radius of at pos1, filled with .", + params = " []", + description = "Creates a 3D torus with a major radius of and a minor radius of at pos1, filled with , on axes (i.e. 2 axis names: xz, zy, etc).", privs = { worldedit = true }, require_pos = 1, parse = function(params_text) @@ -40,9 +65,9 @@ worldedit.register_command("torus", { nodes_needed = function(name, target_node, major_radius, minor_radius) return math.ceil(2 * math.pi*math.pi * major_radius * minor_radius*minor_radius) end, - func = function(name, target_node, major_radius, minor_radius) + func = function(name, target_node, major_radius, minor_radius, axes) local start_time = worldeditadditions.get_ms_time() - local replaced = worldeditadditions.torus(worldedit.pos1[name], major_radius, minor_radius, target_node, false) + local replaced = worldeditadditions.torus(worldedit.pos1[name], major_radius, minor_radius, target_node, axes, false) local time_taken = worldeditadditions.get_ms_time() - start_time minetest.log("action", name .. " used //torus at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. replaced .. " nodes in " .. time_taken .. "s") @@ -52,20 +77,20 @@ worldedit.register_command("torus", { -- TODO: This duplicates a lot of code. Perhaps we can trim it down a bit? worldedit.register_command("hollowtorus", { - params = " ", - description = "Creates a 3D hollow torus with a major radius of and a minor radius of at pos1, made out of .", + params = " []", + description = "Creates a 3D hollow torus with a major radius of and a minor radius of at pos1, made out of , on axes (i.e. 2 axis names: xz, zy, etc).", privs = { worldedit = true }, require_pos = 1, parse = function(params_text) local values = {parse_params_torus(params_text)} return unpack(values) end, - nodes_needed = function(name, target_node, major_radius, minor_radius) + nodes_needed = function(name, target_node, major_radius, minor_radius, axes) return math.ceil(2 * math.pi*math.pi * major_radius * minor_radius*minor_radius) end, func = function(name, target_node, major_radius, minor_radius) local start_time = worldeditadditions.get_ms_time() - local replaced = worldeditadditions.torus(worldedit.pos1[name], major_radius, minor_radius, target_node, true) + local replaced = worldeditadditions.torus(worldedit.pos1[name], major_radius, minor_radius, target_node, axes, true) local time_taken = worldeditadditions.get_ms_time() - start_time minetest.log("action", name .. " used //hollowtorus at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. replaced .. " nodes in " .. time_taken .. "s") From 0100725a7ba2eeb13b0b32720790342dc8d7016b Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 15 May 2021 02:09:43 +0100 Subject: [PATCH 6/8] torus: finish rework --- CHANGELOG.md | 1 + Chat-Command-Reference.md | 6 +++++- worldeditadditions/lib/torus.lua | 15 ++++++++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ccacd7..09b4d8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Note to self: See the bottom of this file for the release template text. - Add new universal chance parsing - Any `` can now either be a 1-in-N number (e.g. `4`, `10`), or a percentage chance (e.g. `50%`, `10%`). - Caveat: Percentages are converted to a 1-in-N chance, but additionally that number is rounded down in some places + - `//torus`, `//hollowtorus`: Add optional new axes argument ## v1.11: The big data update (25th January 2021) diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index 7f0d3aa..5dfe97f 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -124,12 +124,15 @@ Creates a hollow ellipsoid at position 1 with the radius `(rx, ry, rz)`. Works t //hollowellipsoid 21 11 41 stone ``` -## `//torus ` +## `//torus []` Creates a solid torus at position 1 with the specified major and minor radii. The major radius is the distance from the centre of the torus to the centre of the circle bit, and the minor radius is the radius of the circle bit. +The optional axes sets the axes upon which the torus will lay flat. Possible values: `xy` (the default), `xz`, `yz`. + ``` //torus 15 5 stone //torus 5 3 meselamp +//hollowtorus 10 6 sandstone xz ``` ## `//hollowtorus ` @@ -138,6 +141,7 @@ Creates a hollow torus at position 1 with the radius major and minor radii. Work ``` //hollowtorus 10 5 glass //hollowtorus 21 11 stone +//hollowtorus 18 6 dirt xz ``` ## `//line [ []]` diff --git a/worldeditadditions/lib/torus.lua b/worldeditadditions/lib/torus.lua index 22e23f4..74f38d4 100644 --- a/worldeditadditions/lib/torus.lua +++ b/worldeditadditions/lib/torus.lua @@ -42,8 +42,13 @@ function worldeditadditions.torus(position, major_radius, minor_radius, target_n for x = -total_radius, total_radius do local x_sq = x*x + local sq = vector.new(x_sq, y_sq, z_sq) + + -- Default: xy if axes == "xz" then - -- TODO: Figure out which 2 axes we need to fiddle here + sq.x, sq.y, sq.z = sq.x, sq.z, sq.y + elseif axes == "yz" then + sq.x, sq.y, sq.z = sq.y, sq.z, sq.x end -- (x^2+y^2+z^2-(a^2+b^2))^2-4 a b (b^2-z^2) @@ -51,8 +56,8 @@ function worldeditadditions.torus(position, major_radius, minor_radius, target_n -- (x, y, z) is the point -- a is the major radius (centre to centre of circle) -- b is the minor radius (radius of circle - local comp_a = (x_sq+y_sq+z_sq - (major_radius_sq+minor_radius_sq)) - local test_value = comp_a*comp_a - 4*major_radius*minor_radius*(minor_radius_sq-z_sq) + local comp_a = (sq.x+sq.y+sq.z - (major_radius_sq+minor_radius_sq)) + local test_value = comp_a*comp_a - 4*major_radius*minor_radius*(minor_radius_sq-sq.z) -- If we're inside the torus, then fill it in if test_value <= 1 then @@ -60,8 +65,8 @@ function worldeditadditions.torus(position, major_radius, minor_radius, target_n if not place_ok then -- It must be hollow! Do some additional calculations. - local inner_comp_a = (x_sq+y_sq+z_sq - (major_radius_sq+inner_minor_radius_sq)) - local inner_test_value = inner_comp_a*inner_comp_a - 4*major_radius*inner_minor_radius*(inner_minor_radius_sq-z_sq) + local inner_comp_a = (sq.x+sq.y+sq.z - (major_radius_sq+inner_minor_radius_sq)) + local inner_test_value = inner_comp_a*inner_comp_a - 4*major_radius*inner_minor_radius*(inner_minor_radius_sq-sq.z) -- It's only ok to place it if it's outside our inner torus place_ok = inner_test_value >= 0 From bf8c847dc190470b976f09eb96dc1d2f3137cecb Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 15 May 2021 02:15:14 +0100 Subject: [PATCH 7/8] torus: fix and improve the error messages --- worldeditadditions_commands/commands/torus.lua | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/worldeditadditions_commands/commands/torus.lua b/worldeditadditions_commands/commands/torus.lua index 2156e32..e9bf88c 100644 --- a/worldeditadditions_commands/commands/torus.lua +++ b/worldeditadditions_commands/commands/torus.lua @@ -5,20 +5,15 @@ -- ██ ██████ ██ ██ ██████ ███████ local function parse_params_torus(params_text) local parts = worldeditadditions.split(params_text, "%s+", false) - print("[DEBUG:torus/parts]") - for i = 1, #parts, 1 do print(parts[i]) end - -- local found, _, major_radius, minor_radius, replace_node, axes = params_text:find("([0-9]+)%s+([0-9]+)%s+([a-z:_\\-]+)%s+([xyz]+)") - - if #parts < 3 then return nil, nil, nil end if #parts < 1 then - return false, "Error: Invalid replace_node." + return false, "Error: No replace_node specified." end if #parts < 2 then - return false, "Error: Invalid major radius (expected integer greater than 0)" + return false, "Error: No major radius specified (expected integer greater than 0)." end if #parts < 3 then - return false, "Error: Invalid minor radius (expected integer greater than 0)" + return false, "Error: No minor radius specified (expected integer greater than 0)." end local major_radius = tonumber(parts[1]) @@ -38,7 +33,7 @@ local function parse_params_torus(params_text) return false, "Error: Invalid node name." end if axes:find("[^xyz]") then - return false, "Error: The axes may only contain the latters x, y, and z." + return false, "Error: The axes may only contain the letters x, y, and z." end if #axes ~= 2 then return false, "Error: Exactly 2 axes must be specified. For example, 'xy' is valid, but 'xyy' is not (both of course without quotes)." From 57ff577694beecdd0748cde6f53fd0412ed07211 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 15 May 2021 02:18:41 +0100 Subject: [PATCH 8/8] torus: add comment --- worldeditadditions/lib/torus.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worldeditadditions/lib/torus.lua b/worldeditadditions/lib/torus.lua index 74f38d4..0ba621d 100644 --- a/worldeditadditions/lib/torus.lua +++ b/worldeditadditions/lib/torus.lua @@ -4,7 +4,7 @@ --- Generates a torus shape at the given position with the given parameters. -- @param position Vector The position at which to generate the torus. -- @param major_radius number The major radius of the torus - i.e. the distance from the middle to the ring. --- @param minor_radius number The minor radius of the torus - i.e. the radaius fo the ring itself. +-- @param minor_radius number The minor radius of the torus - i.e. the radius fo the ring itself. -- @param target_node string The name of the target node to generate the torus with. -- @param axes=xz string|nil The axes upon which the torus should lay flat. -- @param hollow=false boolean Whether the generated torus should be hollow or not. @@ -20,6 +20,7 @@ function worldeditadditions.torus(position, major_radius, minor_radius, target_n -- Fetch the nodes in the specified area -- OPTIMIZE: We should be able to calculate a more efficient box-area here + -- This is complicated by the multiple possible axes though local manip, area = worldedit.manip_helpers.init_radius(position, total_radius) local data = manip:get_data()