From 674d6473e4b13676aa6bc9e45a4113e3bca89078 Mon Sep 17 00:00:00 2001 From: Uberi Date: Fri, 20 Dec 2013 18:41:13 -0500 Subject: [PATCH] Improve node inspector to show player axis, replace //scale with //stretch, which supports per-axis stretching (full backwards compatibility retained), and secure schematic file loading functions. --- Chat Commands.md | 1 + README.md | 2 +- WorldEdit API.md | 6 ++--- worldedit/compatibility.lua | 3 +++ worldedit/manipulations.lua | 34 ++++++++++++++++------------ worldedit_commands/init.lua | 45 +++++++++++++++++++++++++++---------- 6 files changed, 61 insertions(+), 30 deletions(-) diff --git a/Chat Commands.md b/Chat Commands.md index 1524dfe..04c8116 100644 --- a/Chat Commands.md +++ b/Chat Commands.md @@ -22,6 +22,7 @@ Enable or disable node inspection. //inspect no //inspect enable //inspect disable + //inspect ### //reset diff --git a/README.md b/README.md index 9827e07..e94bcdf 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ WorldEdit works primarily through the WorldEdit GUI and chat commands. Depending WorldEdit has a huge potential for abuse by untrusted players. Therefore, users will not be able to use WorldEdit unless they have the `worldedit` privelege. This is available by default in single player, but in multiplayer the permission must be explicitly given by someone with the right credentials, using the follwoing chat command: `/grant worldedit`. This privelege can later be removed using the following chat command: `/revoke worldedit`. -Certain functions/commands such as WorldEdit GUI's "Run Lua" (equivalent to the `//lua` chat command) additionally require the `server` privilege. This is because it is extremely dangerous to give access to these commands to untrusted players, since they essentially are able to control the computer the server is running on. Give this privilege only to people you trust with your computer. +Certain functions/commands such as WorldEdit GUI's "Run Lua" function (equivalent to the `//lua` and `//luatransform` chat command) additionally require the `server` privilege. This is because it is extremely dangerous to give access to these commands to untrusted players, since they essentially are able to control the computer the server is running on. Give this privilege only to people you trust with your computer. For in-game information about these commands, type `/help ` in the chat. For example, to learn more about the `//copy` command, simply type `/help /copy` to display information relevant to copying a region. diff --git a/WorldEdit API.md b/WorldEdit API.md index 4169cbe..c05958e 100644 --- a/WorldEdit API.md +++ b/WorldEdit API.md @@ -57,11 +57,11 @@ Duplicates the region defined by positions `pos1` and `pos2` along the `axis` ax Returns the number of nodes stacked. -### count, newpos1, newpos2 = worldedit.scale(pos1, pos2, factor) +### count, newpos1, newpos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz) -Scales the region defined by positions `pos1` and `pos2` by an factor of positive integer `factor` with `pos1` as the origin. +Stretches the region defined by positions `pos1` and `pos2` by an factor of positive integers `stretchx`, `stretchy`. and `stretchz` along the X, Y, and Z axes, respectively, with `pos1` as the origin. -Returns the number of nodes scaled, the new scaled position 1, and the new scaled position 2. +Returns the number of nodes stretched, the new scaled position 1, and the new scaled position 2. ### count, newpos1, newpos2 = worldedit.transpose(pos1, pos2, axis1, axis2) diff --git a/worldedit/compatibility.lua b/worldedit/compatibility.lua index eb81eea..ff3447f 100644 --- a/worldedit/compatibility.lua +++ b/worldedit/compatibility.lua @@ -18,3 +18,6 @@ worldedit.metaload = function(originpos, filename) local data = file:read("*a") return worldedit.deserialize(originpos, data) end +worldedit.scale = function(pos1, pos2, factor) + return worldedit.stretch(pos1, pos2, factor, factor, factor) +end \ No newline at end of file diff --git a/worldedit/manipulations.lua b/worldedit/manipulations.lua index eee0bb8..1d4c6dc 100644 --- a/worldedit/manipulations.lua +++ b/worldedit/manipulations.lua @@ -109,7 +109,7 @@ worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode) return count end -worldedit.copy = function(pos1, pos2, axis, amount) +worldedit.copy = function(pos1, pos2, axis, amount) --wip: replace the old version below local pos1, pos2 = worldedit.sort_pos(pos1, pos2) if amount == 0 then @@ -291,24 +291,28 @@ worldedit.stack = function(pos1, pos2, axis, count) return worldedit.volume(pos1, pos2) * count end ---scales the region defined by positions `pos1` and `pos2` by an factor of positive integer `factor` with `pos1` as the origin, returning the number of nodes scaled, the new scaled position 1, and the new scaled position 2 -worldedit.scale = function(pos1, pos2, factor) +--stretches the region defined by positions `pos1` and `pos2` by an factor of positive integers `stretchx`, `stretchy`. and `stretchz` along the X, Y, and Z axes, respectively, with `pos1` as the origin, returning the number of nodes scaled, the new scaled position 1, and the new scaled position 2 +worldedit.stretch = function(pos1, pos2, stretchx, stretchy, stretchz) --wip: test this local pos1, pos2 = worldedit.sort_pos(pos1, pos2) --prepare schematic of large node local get_node, get_meta, place_schematic = minetest.get_node, minetest.get_meta, minetest.place_schematic local placeholder_node = {name="", param1=255, param2=0} local nodes = {} - for i = 1, factor ^ 3 do + for i = 1, stretchx * stretchy * stretchz do nodes[i] = placeholder_node end - local schematic = {size={x=factor, y=factor, z=factor}, data=nodes} + local schematic = {size={x=stretchx, y=stretchy, z=stretchz}, data=nodes} - local size = factor - 1 + local sizex, sizey, sizez = stretchx - 1, stretchy - 1, stretchz - 1 --make area stay loaded local manip = minetest.get_voxel_manip() - local new_pos2 = {x=pos1.x + (pos2.x - pos1.x) * factor + size, y=pos1.y + (pos2.y - pos1.y) * factor + size, z=pos1.z + (pos2.z - pos1.z) * factor + size} + local new_pos2 = { + x=pos1.x + (pos2.x - pos1.x) * stretchx + sizex, + y=pos1.y + (pos2.y - pos1.y) * stretchy + sizey, + z=pos1.z + (pos2.z - pos1.z) * stretchz + sizez, + } manip:read_from_map(pos1, new_pos2) local pos = {x=pos2.x, y=0, z=0} @@ -321,8 +325,10 @@ worldedit.scale = function(pos1, pos2, factor) local node = get_node(pos) --obtain current node local meta = get_meta(pos):to_table() --get meta of current node - local value = pos[axis] --store current position - local posx, posy, posz = pos1.x + (pos.x - pos1.x) * factor, pos1.y + (pos.y - pos1.y) * factor, pos1.z + (pos.z - pos1.z) * factor + --calculate far corner of the big node + local posx = pos1.x + (pos.x - pos1.x) * stretchx + local posy = pos1.y + (pos.y - pos1.y) * stretchy + local posz = pos1.z + (pos.z - pos1.z) * stretchz --create large node placeholder_node.name = node.name @@ -331,10 +337,10 @@ worldedit.scale = function(pos1, pos2, factor) place_schematic(bigpos, schematic) --fill in large node meta - if next(meta.fields) ~= nil and next(meta.inventory) ~= nil then --node has meta fields - for x = 0, size do - for y = 0, size do - for z = 0, size do + if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then --node has meta fields + for x = 0, sizex do + for y = 0, sizey do + for z = 0, sizez do bigpos.x, bigpos.y, bigpos.z = posx + x, posy + y, posz + z get_meta(bigpos):from_table(meta) --set metadata of new node end @@ -347,7 +353,7 @@ worldedit.scale = function(pos1, pos2, factor) end pos.x = pos.x - 1 end - return worldedit.volume(pos1, pos2) * (factor ^ 3), pos1, new_pos2 + return worldedit.volume(pos1, pos2) * stretchx * stretchy * stretchz, pos1, new_pos2 end --transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed, the new transposed position 1, and the new transposed position 2 diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index f2bd118..ab58572 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -61,16 +61,18 @@ minetest.register_chatcommand("/about", { }) minetest.register_chatcommand("/inspect", { - params = "on/off/1/0/true/false/yes/no/enable/disable", + params = "on/off/1/0/true/false/yes/no/enable/disable/", description = "Enable or disable node inspection", privs = {worldedit=true}, func = function(name, param) - if param == "on" or param == "1" or param == "true" or param == "yes" or param == "enable" then + if param == "on" or param == "1" or param == "true" or param == "yes" or param == "enable" or param == "" then worldedit.inspect[name] = true - worldedit.player_notify(name, "node inspection enabled") + local axis, sign = worldedit.player_axis(name) + worldedit.player_notify(name, string.format("inspector: inspection enabled for %s, currently facing the %s axis", + name, axis .. (sign > 0 and "+" or "-"))) elseif param == "off" or param == "0" or param == "false" or param == "no" or param == "disable" then worldedit.inspect[name] = nil - worldedit.player_notify(name, "node inspection disabled") + worldedit.player_notify(name, "inspector: inspection disabled") else worldedit.player_notify(name, "invalid usage: " .. param) end @@ -81,7 +83,9 @@ minetest.register_on_punchnode(function(pos, node, puncher) local name = puncher:get_player_name() if worldedit.inspect[name] then if minetest.check_player_privs(name, {worldedit=true}) then - message = "inspector: " .. node.name .. " at " .. minetest.pos_to_string(pos) .. " (param1=" .. node.param1 .. ", param2=" .. node.param2 .. ")" + local axis, sign = worldedit.player_axis(name) + message = string.format("inspector: %s at %s (param1=%d, param2=%d) punched by %s facing the %s axis", + node.name, minetest.pos_to_string(pos), node.param1, node.param2, name, axis .. (sign > 0 and "+" or "-")) else message = "inspector: worldedit privileges required" end @@ -658,9 +662,9 @@ minetest.register_chatcommand("/stack", { end, }) -minetest.register_chatcommand("/scale", { - params = "", - description = "Scale the current WorldEdit positions and region by a factor of positive integer with position 1 as the origin", +minetest.register_chatcommand("/stretch", { + params = " ", + description = "Scale the current WorldEdit positions and region by a factor of , , along the X, Y, and Z axes, repectively, with position 1 as the origin", privs = {worldedit=true}, func = function(name, param) local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] @@ -669,12 +673,17 @@ minetest.register_chatcommand("/scale", { return end - local factor = tonumber(param) - if not factor or factor ~= math.floor(factor) or factor <= 0 then + local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return + end + stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz) + if stretchx == 0 or stretchy == 0 or stretchz == 0 then worldedit.player_notify(name, "invalid scaling factor: " .. param) end - local count, pos1, pos2 = worldedit.scale(pos1, pos2, factor) + local count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz) --reset markers to scaled positions worldedit.pos1[name] = pos1 @@ -682,7 +691,7 @@ minetest.register_chatcommand("/scale", { worldedit.mark_pos1(name) worldedit.mark_pos2(name) - worldedit.player_notify(name, count .. " nodes scaled") + worldedit.player_notify(name, count .. " nodes stretched") end, }) @@ -919,6 +928,10 @@ minetest.register_chatcommand("/save", { worldedit.player_notify(name, "invalid usage: " .. param) return end + if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then + worldedit.player_notify(name, "invalid file name: " .. param) + return + end local result, count = worldedit.serialize(pos1, pos2) @@ -953,6 +966,10 @@ minetest.register_chatcommand("/allocate", { worldedit.player_notify(name, "invalid usage: " .. param) return end + if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then + worldedit.player_notify(name, "invalid file name: " .. param) + return + end local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we" local file, err = io.open(filename, "rb") @@ -993,6 +1010,10 @@ minetest.register_chatcommand("/load", { worldedit.player_notify(name, "invalid usage: " .. param) return end + if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then + worldedit.player_notify(name, "invalid file name: " .. param) + return + end --find the file in the world path local testpaths = {