diff --git a/.gitignore b/.gitignore index 6fd0a37..7ea315e 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ luac.out *.x86_64 *.hex +# Debug Tools (for now) +worldeditadditions_debug/ diff --git a/CHANGELOG.md b/CHANGELOG.md index fe209e9..725f253 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,13 @@ It's about time I started a changelog! This will serve from now on as the main c Note to self: See the bottom of this file for the release template text. -## v1.12 (unreleased) - - Add `//srect` (_select rectangle_), `//scol` (_select column_), `//scube` (_select cube_) - thanks, @VorTechnix! +## v1.12: The selection tools update (unreleased) - Add `//spush`, `//spop`, and `//sstack` - `//overlay`: Don't place nodes above water - `//multi`: Improve resilience by handling some edge cases +### @VorTechnix contributions: +- 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_) ## v1.11: The big data update (25th January 2021) diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index ede42c5..5da8375 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -509,6 +509,31 @@ Short for _select cube_. Sets the pos2 at a set distance along 3 axes from pos1. //scube -z 12 ``` +## `//scloud <0-6|stop|reset>` +Short for _select point cloud_. Sets pos1 and pos2 to include the nodes you punch. Numbers 1-6 designate how many nodes you want to punch before the operation ends. 0 or stop terminate the operation so that any further nodes you punch won't be added to selection. Reset terminates operation if one is running and resets the selection area. + +``` +//scloud 6 +//scloud 5 +//scloud stop +``` + +## `//scentre` +Short for _select center_. Sets pos1 and pos2 to the centre point(s) of the current selection area. 1, 2, 4 or 8 nodes may be selected depending on what parts of the original selection are even in distance. Implementation by @VorTechnix. + +``` +//scentre +``` + +## `//srel [ [ ]]` +Short for _select relative_. Sets the pos2 at set distances along 3 axes relative to pos1. If pos1 is not set it will default to the node directly under the player. The axis arguments accept `x, y, z` as well as `up, down, left, right, front, back`. Left, right, front and back are relative to player facing direction. Negative (`-`) can be applied to the axis, the length or both. Implementation by @VorTechnix. + +``` +//srel front 5 +//srel y 12 right -2 +//srel left 3 up 5 -front 7 +//scube -z 12 -y -2 x -2 +``` ## `//sstack` Displays the contents of your per-user selection stack. This stack can be pushed to and popped from rather like a stack of plates. See also `//spush` (for pushing to the selection stack) and `//spop` (for popping from the selection stack). diff --git a/worldeditadditions/utils/selector_helps.lua b/worldeditadditions/utils/selector_helps.lua index 28e96fc..ee70d44 100644 --- a/worldeditadditions/utils/selector_helps.lua +++ b/worldeditadditions/utils/selector_helps.lua @@ -18,5 +18,21 @@ function worldeditadditions.axis_left(axis,sign) else return true, "x", -sign end end +--- Dehumanize Direction: translates up, down, left, right, front, into xyz based on player orientation. +-- @param name string The name of the player to return facing direction of. +-- @param dir string Relative direction to translate. +-- @return Returns axis name and sign multiplier. +function worldeditadditions.dir_to_xyz(name, dir) + local axfac, drfac = worldeditadditions.player_axis2d(name) + local _, axlft, drlft = worldeditadditions.axis_left(axfac,drfac) + if dir:match("front") or dir:match("back") then + return axfac, dir:match("front") and drfac or -drfac + elseif dir:match("left") or dir:match("right") then + return axlft, dir:match("left") and drlft or -drlft + elseif dir:match("up") or dir:match("down") then + return "y", dir == "down" and -1 or 1 + else return false, "\"" .. dir .. "\" not a recognized direction! Try: (up | down | left | right | front | back)" end +end + -- Tests -- /lua print(unpack(worldeditadditions.player_axis2d(myname))) diff --git a/worldeditadditions/utils/tables.lua b/worldeditadditions/utils/tables.lua index c961a06..e20bd63 100644 --- a/worldeditadditions/utils/tables.lua +++ b/worldeditadditions/utils/tables.lua @@ -46,3 +46,22 @@ function worldeditadditions.table_get_last(tbl, count) math.max(0, (#tbl) - (count - 1)) )} end + +--- Returns the key value pairs in a table as a single string +-- @param tbl table input table +-- @param sep string key value seperator +-- @param new_line string key value pair delimiter +-- @return string concatenated table pairs +function worldeditadditions.table_tostring(tbl, sep, new_line) + if type(sep) ~= "string" then sep = ": " end + if type(new_line) ~= "string" then new_line = ", " end + local ret = {} + if type(tbl) ~= "table" then return "Error: input not table!" end + for key,value in pairs(tbl) do + ret:append(key) + ret:append(sep) + ret:append(value) + ret:append(new_line) + end + return ret:concat("") +end diff --git a/worldeditadditions/utils/vector.lua b/worldeditadditions/utils/vector.lua index 43ee38d..ebcf4c1 100644 --- a/worldeditadditions/utils/vector.lua +++ b/worldeditadditions/utils/vector.lua @@ -42,6 +42,17 @@ function worldeditadditions.vector.floor(v) if v.z then v.z = math.floor(v.z) end end +--- Rounds the values in a vector up. +-- Warning: This MUTATES the given vector! +-- @param v Vector The vector to operate on +function worldeditadditions.vector.ceil(v) + if v.x then v.x = math.ceil(v.x) end + -- Some vectors are 2d, but on the x / z axes + if v.y then v.y = math.ceil(v.y) end + -- Some vectors are 2d + if v.z then v.z = math.ceil(v.z) end +end + --- Determines if the target point is contained within the defined worldedit region. -- @param pos1 Vector pos1 of the defined region. -- @param pos2 Vector pos2 of the defined region. @@ -74,3 +85,11 @@ function worldeditadditions.vector.expand_region(pos1, pos2, target) return pos1, pos2 end + +--- Returns the mean (average) of 2 positions to give you the centre. +-- @param pos1 Vector pos1 of the defined region. +-- @param pos2 Vector pos2 of the defined region. +-- @param target Vector Centre coordinates. +function worldeditadditions.vector.mean(pos1, pos2) + return vector.new((pos1.x + pos2.x)/2, (pos1.y + pos2.y)/2, (pos1.z + pos2.z)/2) +end diff --git a/worldeditadditions_commands/commands/selectors/scentre.lua b/worldeditadditions_commands/commands/selectors/scentre.lua new file mode 100644 index 0000000..20311d9 --- /dev/null +++ b/worldeditadditions_commands/commands/selectors/scentre.lua @@ -0,0 +1,28 @@ +-- ███████ ██████ ███████ ███ ██ ████████ ███████ ██████ +-- ██ ██ ██ ████ ██ ██ ██ ██ ██ +-- ███████ ██ █████ ██ ██ ██ ██ █████ ██████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██████ ███████ ██ ████ ██ ███████ ██ ██ +local wea = worldeditadditions +worldedit.register_command("scentre", { + params = "", + description = "Set WorldEdit region positions 1 and 2 to the centre of the current selection.", + privs = {worldedit=true}, + require_pos = 2, + parse = function(params_text) + return true + end, + func = function(name) + local vecs = {} + vecs.mean = wea.vector.mean(worldedit.pos1[name],worldedit.pos2[name]) + vecs.p1, vecs.p2 = vector.new(vecs.mean), vector.new(vecs.mean) + wea.vector.floor(vecs.p1) + wea.vector.ceil(vecs.p2) + worldedit.pos1[name], worldedit.pos2[name] = vecs.p1, vecs.p2 + worldedit.mark_pos1(name) + worldedit.mark_pos2(name) + return true, "position 1 set to " .. minetest.pos_to_string(vecs.p1) .. ", position 2 set to " .. minetest.pos_to_string(vecs.p2) + end, +}) + +-- lua print(vecs.mean.x..", "..vecs.mean.y..", "..vecs.mean.z) diff --git a/worldeditadditions_commands/commands/selectors/srel.lua b/worldeditadditions_commands/commands/selectors/srel.lua new file mode 100644 index 0000000..cc4b3ce --- /dev/null +++ b/worldeditadditions_commands/commands/selectors/srel.lua @@ -0,0 +1,54 @@ +-- ███████ ██████ ███████ ██ +-- ██ ██ ██ ██ ██ +-- ███████ ██████ █████ ██ +-- ██ ██ ██ ██ ██ +-- ███████ ██ ██ ███████ ███████ +local wea = worldeditadditions +local function parse_with_name(name,args) + local vec, tmp = vector.new(0, 0, 0), {} + local find, _, i = {}, 0, 0 + repeat + _, i, tmp.proc = args:find("([%l%s+-]+%d+)%s*", i) + if tmp.proc:match("[xyz]") then + tmp.ax = tmp.proc:match("[xyz]") + tmp.dir = tonumber(tmp.proc:match("[+-]?%d+")) * (tmp.proc:match("-%l+") and -1 or 1) + else + tmp.ax, _ = wea.dir_to_xyz(name, tmp.proc:match("%l+")) + if not tmp.ax then return false, _ end + tmp.dir = tonumber(tmp.proc:match("[+-]?%d+")) * (tmp.proc:match("-%l+") and -1 or 1) * _ + end + vec[tmp.ax] = tmp.dir + until not args:find("([%l%s+-]+%d+)%s*", i) + return true, vec +end +worldedit.register_command("srel", { + params = " [ [ ]]", + description = "Set WorldEdit region position 2 at set distances along 3 axes.", + privs = { worldedit = true }, + require_pos = 0, + parse = function(params_text) + if params_text:match("([%l%s+-]+%d+)") then return true, params_text + else return false, "No acceptable params found" end + end, + func = function(name, params_text) + local ret = "" + local _, vec = parse_with_name(name,params_text) + if not _ then return false, vec end + + if not worldedit.pos1[name] then + local pos = vector.add(minetest.get_player_by_name(name):get_pos(), vector.new(0.5,-0.5,0.5)) + wea.vector.floor(pos) + worldedit.pos1[name] = pos + worldedit.mark_pos1(name) + ret = "position 1 set to " .. minetest.pos_to_string(pos) .. ", " + end + + local p2 = vector.add(vec,worldedit.pos1[name]) + worldedit.pos2[name] = p2 + worldedit.mark_pos2(name) + return true, ret .. "position 2 set to " .. minetest.pos_to_string(p2) + end, +}) + +-- Tests +-- //srel front 5 left 3 y 2 diff --git a/worldeditadditions_commands/depends.txt b/worldeditadditions_commands/depends.txt index 04e364b..db6f73b 100644 --- a/worldeditadditions_commands/depends.txt +++ b/worldeditadditions_commands/depends.txt @@ -2,4 +2,5 @@ worldeditadditions worldedit_commands worldedit_shortcommands worldedit +worldeditadditions_debug? bonemeal? diff --git a/worldeditadditions_commands/init.lua b/worldeditadditions_commands/init.lua index c17fd9e..f880a9e 100644 --- a/worldeditadditions_commands/init.lua +++ b/worldeditadditions_commands/init.lua @@ -19,20 +19,20 @@ dofile(we_c.modpath.."/player_notify_suppress.lua") -- we_c.safe_region, we_c.check_region, we_c.reset_pending -- = dofile(we_c.modpath.."/safe.lua") -dofile(we_c.modpath.."/commands/floodfill.lua") -dofile(we_c.modpath.."/commands/overlay.lua") -dofile(we_c.modpath.."/commands/layers.lua") -dofile(we_c.modpath.."/commands/fillcaves.lua") -dofile(we_c.modpath.."/commands/ellipsoid.lua") -dofile(we_c.modpath.."/commands/torus.lua") -dofile(we_c.modpath.."/commands/line.lua") -dofile(we_c.modpath.."/commands/walls.lua") -dofile(we_c.modpath.."/commands/maze.lua") -dofile(we_c.modpath.."/commands/replacemix.lua") dofile(we_c.modpath.."/commands/convolve.lua") +dofile(we_c.modpath.."/commands/ellipsoid.lua") dofile(we_c.modpath.."/commands/erode.lua") +dofile(we_c.modpath.."/commands/fillcaves.lua") +dofile(we_c.modpath.."/commands/floodfill.lua") dofile(we_c.modpath.."/commands/hollow.lua") +dofile(we_c.modpath.."/commands/layers.lua") +dofile(we_c.modpath.."/commands/line.lua") +dofile(we_c.modpath.."/commands/maze.lua") +dofile(we_c.modpath.."/commands/overlay.lua") +dofile(we_c.modpath.."/commands/replacemix.lua") dofile(we_c.modpath.."/commands/scale.lua") +dofile(we_c.modpath.."/commands/torus.lua") +dofile(we_c.modpath.."/commands/walls.lua") dofile(we_c.modpath.."/commands/count.lua") @@ -41,13 +41,15 @@ dofile(we_c.modpath.."/commands/meta/many.lua") dofile(we_c.modpath.."/commands/meta/subdivide.lua") dofile(we_c.modpath.."/commands/meta/ellipsoidapply.lua") +dofile(we_c.modpath.."/commands/selectors/srel.lua") +dofile(we_c.modpath.."/commands/selectors/scentre.lua") dofile(we_c.modpath.."/commands/selectors/scloud.lua") dofile(we_c.modpath.."/commands/selectors/scol.lua") -dofile(we_c.modpath.."/commands/selectors/srect.lua") dofile(we_c.modpath.."/commands/selectors/scube.lua") -dofile(we_c.modpath.."/commands/selectors/sstack.lua") -dofile(we_c.modpath.."/commands/selectors/spush.lua") dofile(we_c.modpath.."/commands/selectors/spop.lua") +dofile(we_c.modpath.."/commands/selectors/spush.lua") +dofile(we_c.modpath.."/commands/selectors/srect.lua") +dofile(we_c.modpath.."/commands/selectors/sstack.lua") dofile(we_c.modpath.."/commands/extra/saplingaliases.lua") dofile(we_c.modpath.."/commands/extra/basename.lua") @@ -68,3 +70,5 @@ worldedit.alias_command("naturalise", "layers") worldedit.alias_command("naturalize", "layers") worldedit.alias_command("flora", "bonemeal") + +worldedit.alias_command("mcount", "count")