From ebb0a95e08137ebd2bdd0ea7d70d25901c2ef3ce Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 24 Sep 2025 18:08:21 +0200 Subject: [PATCH] Support relative directions in transformations closes #256 --- ChatCommands.md | 10 +-- worldedit_commands/test/init.lua | 32 ++++++++ worldedit_commands/transform.lua | 123 ++++++++++++++++--------------- 3 files changed, 101 insertions(+), 64 deletions(-) diff --git a/ChatCommands.md b/ChatCommands.md index c340b90..1f260b0 100644 --- a/ChatCommands.md +++ b/ChatCommands.md @@ -270,7 +270,7 @@ height ``, space between walls ``, composed of ``. //spiral 5 2 1 glass //spiral 7 1 5 mesecons:wire_00000000_off -### `//copy x/y/z/? ` +### `//copy x/y/z/?/up/down/left/right/front/back ` Copy the current WorldEdit region along the given axis by `` nodes. @@ -279,7 +279,7 @@ Copy the current WorldEdit region along the given axis by `` nodes. //copy z +4 //copy ? 8 -### `//move x/y/z/? ` +### `//move x/y/z/?/up/down/left/right/front/back ` Move the current WorldEdit positions and region along the given axis by `` nodes. @@ -288,7 +288,7 @@ Move the current WorldEdit positions and region along the given axis by `` +### `//stack x/y/z/?/up/down/left/right/front/back ` Stack the current WorldEdit region along the given axis `` times. @@ -322,14 +322,14 @@ Transpose the current WorldEdit positions and region along given axes. //transpose y z //transpose ? y -### `//flip x/y/z/?` +### `//flip x/y/z/?/up/down/left/right/front/back` Flip the current WorldEdit region along the given axis. //flip x //flip ? -### `//rotate x/y/z/? ` +### `//rotate x/y/z/?/up/down/left/right/front/back ` Rotate the current WorldEdit positions and region along the given axis by angle `` (90 degree increment). diff --git a/worldedit_commands/test/init.lua b/worldedit_commands/test/init.lua index 0cf6c38..eef477b 100644 --- a/worldedit_commands/test/init.lua +++ b/worldedit_commands/test/init.lua @@ -52,6 +52,35 @@ register_test("//fixedpos", make_parsing_test("fixedpos", { "", })) +register_test("//copy", make_parsing_test("copy", { + "x 10", + "right +1", + "? -4", +}, { + "eee 1", + "up 0", + "", +})) + +register_test("//rotate", make_parsing_test("rotate", { + "z 90", + "left -180", +}, { + "x 0", + "back 77", + "", +})) + +register_test("//flip", make_parsing_test("flip", { + "y", + "down", + "?", +}, { + "1", + "", +})) + + register_test("//inset", make_parsing_test("inset", { "h 1", "v 0", @@ -61,6 +90,7 @@ register_test("//inset", make_parsing_test("inset", { "x 4", "xyz 5", "v foo", + "", })) register_test("//shift", make_parsing_test("shift", { @@ -73,6 +103,7 @@ register_test("//shift", make_parsing_test("shift", { "-z 9", "xx -5", "?? 123", + "", })) register_test("//expand", make_parsing_test("expand", { @@ -86,6 +117,7 @@ register_test("//expand", make_parsing_test("expand", { "x -4", "? 4 -333", "stupid 5 5", + "", })) register_test("//cubeapply", make_parsing_test("cubeapply", { diff --git a/worldedit_commands/transform.lua b/worldedit_commands/transform.lua index ce3d085..3deaa04 100644 --- a/worldedit_commands/transform.lua +++ b/worldedit_commands/transform.lua @@ -1,32 +1,38 @@ local S = minetest.get_translator("worldedit_commands") +local VALID_DIR = worldedit.valid_directions + local function check_region(name) return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) end +local function parse_copylike(param) + local found, _, direction, amount = param:find("^([^%s]+)%s+([+-]?%d+)$") + if found == nil or not VALID_DIR[direction] then + return false + end + if tonumber(amount) == 0 then + return false + end + return true, direction, tonumber(amount) +end worldedit.register_command("copy", { - params = "x/y/z/? ", + params = tostring(VALID_DIR) .. " ", description = S("Copy the current WorldEdit region along the given axis by nodes"), category = S("Transformations"), privs = {worldedit=true}, require_pos = 2, - parse = function(param) - local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$") - if found == nil then - return false - end - return true, axis, tonumber(amount) - end, - nodes_needed = function(name, axis, amount) + parse = parse_copylike, + nodes_needed = function(name, direction, amount) return check_region(name) * 2 end, - func = function(name, axis, amount) - if axis == "?" then - local sign - axis, sign = worldedit.player_axis(name) - amount = amount * sign + func = function(name, direction, amount) + local axis, sign = worldedit.player_direction(name, direction) + if not axis or not sign then + return false, S("Invalid if looking straight up or down") end + amount = amount * sign local count = worldedit.copy(worldedit.pos1[name], worldedit.pos2[name], axis, amount) return true, S("@1 nodes copied", count) @@ -34,27 +40,21 @@ worldedit.register_command("copy", { }) worldedit.register_command("move", { - params = "x/y/z/? ", + params = tostring(VALID_DIR) .. " ", description = S("Move the current WorldEdit region along the given axis by nodes"), category = S("Transformations"), privs = {worldedit=true}, require_pos = 2, - parse = function(param) - local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$") - if found == nil then - return false - end - return true, axis, tonumber(amount) - end, - nodes_needed = function(name, axis, amount) + parse = parse_copylike, + nodes_needed = function(name, direction, amount) return check_region(name) * 2 end, - func = function(name, axis, amount) - if axis == "?" then - local sign - axis, sign = worldedit.player_axis(name) - amount = amount * sign + func = function(name, direction, amount) + local axis, sign = worldedit.player_direction(name, direction) + if not axis or not sign then + return false, S("Invalid if looking straight up or down") end + amount = amount * sign local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local count = worldedit.move(pos1, pos2, axis, amount) @@ -67,27 +67,21 @@ worldedit.register_command("move", { }) worldedit.register_command("stack", { - params = "x/y/z/? ", + params = tostring(VALID_DIR) .. " ", description = S("Stack the current WorldEdit region along the given axis times"), category = S("Transformations"), privs = {worldedit=true}, require_pos = 2, - parse = function(param) - local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$") - if found == nil then - return false - end - return true, axis, tonumber(repetitions) - end, - nodes_needed = function(name, axis, repetitions) + parse = parse_copylike, + nodes_needed = function(name, direction, repetitions) return check_region(name) * math.abs(repetitions) end, - func = function(name, axis, repetitions) - if axis == "?" then - local sign - axis, sign = worldedit.player_axis(name) - repetitions = repetitions * sign + func = function(name, direction, repetitions) + local axis, sign = worldedit.player_direction(name, direction) + if not axis or not sign then + return false, S("Invalid if looking straight up or down") end + repetitions = repetitions * sign local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local count = worldedit.volume(pos1, pos2) * math.abs(repetitions) @@ -149,9 +143,10 @@ worldedit.register_command("stretch", { end, func = function(name, stretchx, stretchy, stretchz) local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] - local count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz) + local count + count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz) - --reset markers to scaled positions + -- reset markers to scaled positions worldedit.pos1[name] = pos1 worldedit.pos2[name] = pos2 worldedit.marker_update(name) @@ -180,9 +175,10 @@ worldedit.register_command("transpose", { local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] if axis1 == "?" then axis1 = worldedit.player_axis(name) end if axis2 == "?" then axis2 = worldedit.player_axis(name) end - local count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2) + local count + count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2) - --reset markers to transposed positions + -- reset markers to transposed positions worldedit.pos1[name] = pos1 worldedit.pos2[name] = pos2 worldedit.marker_update(name) @@ -192,49 +188,58 @@ worldedit.register_command("transpose", { }) worldedit.register_command("flip", { - params = "x/y/z/?", + params = tostring(VALID_DIR), description = S("Flip the current WorldEdit region along the given axis"), category = S("Transformations"), privs = {worldedit=true}, require_pos = 2, parse = function(param) - if param ~= "x" and param ~= "y" and param ~= "z" and param ~= "?" then + if not VALID_DIR[param] then return false end return true, param end, nodes_needed = check_region, func = function(name, param) - if param == "?" then param = worldedit.player_axis(name) end - local count = worldedit.flip(worldedit.pos1[name], worldedit.pos2[name], param) + local axis = worldedit.player_direction(name, param) + if axis == nil then + return false, S("Invalid if looking straight up or down") + end + + local count = worldedit.flip(worldedit.pos1[name], worldedit.pos2[name], axis) return true, S("@1 nodes flipped", count) end, }) worldedit.register_command("rotate", { - params = "x/y/z/? ", + params = tostring(VALID_DIR) .. " ", description = S("Rotate the current WorldEdit region around the given axis by angle (90 degree increment)"), category = S("Transformations"), privs = {worldedit=true}, require_pos = 2, parse = function(param) - local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$") - if found == nil then + local found, _, direction, angle = param:find("^([^%s]+)%s+([+-]?%d+)$") + if found == nil or not VALID_DIR[direction] then return false end angle = tonumber(angle) if angle % 90 ~= 0 or angle % 360 == 0 then return false, S("invalid usage: angle must be multiple of 90") end - return true, axis, angle + return true, direction, angle end, nodes_needed = check_region, - func = function(name, axis, angle) - local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] - if axis == "?" then axis = worldedit.player_axis(name) end - local count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle) + func = function(name, direction, angle) + local axis = worldedit.player_direction(name, direction) + if axis == nil then + return false, S("Invalid if looking straight up or down") + end - --reset markers to rotated positions + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local count + count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle) + + -- reset markers to rotated positions worldedit.pos1[name] = pos1 worldedit.pos2[name] = pos2 worldedit.marker_update(name)