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.

This commit is contained in:
Uberi 2013-12-20 18:41:13 -05:00
parent 3767ea84d2
commit 674d6473e4
6 changed files with 61 additions and 30 deletions

View File

@ -22,6 +22,7 @@ Enable or disable node inspection.
//inspect no //inspect no
//inspect enable //inspect enable
//inspect disable //inspect disable
//inspect
### //reset ### //reset

View File

@ -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 <player name> worldedit`. This privelege can later be removed using the following chat command: `/revoke <player name> worldedit`. 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 <player name> worldedit`. This privelege can later be removed using the following chat command: `/revoke <player name> 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 <command name>` in the chat. For example, to learn more about the `//copy` command, simply type `/help /copy` to display information relevant to copying a region. For in-game information about these commands, type `/help <command name>` in the chat. For example, to learn more about the `//copy` command, simply type `/help /copy` to display information relevant to copying a region.

View File

@ -57,11 +57,11 @@ Duplicates the region defined by positions `pos1` and `pos2` along the `axis` ax
Returns the number of nodes stacked. 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) ### count, newpos1, newpos2 = worldedit.transpose(pos1, pos2, axis1, axis2)

View File

@ -18,3 +18,6 @@ worldedit.metaload = function(originpos, filename)
local data = file:read("*a") local data = file:read("*a")
return worldedit.deserialize(originpos, data) return worldedit.deserialize(originpos, data)
end end
worldedit.scale = function(pos1, pos2, factor)
return worldedit.stretch(pos1, pos2, factor, factor, factor)
end

View File

@ -109,7 +109,7 @@ worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode)
return count return count
end 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) local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if amount == 0 then if amount == 0 then
@ -291,24 +291,28 @@ worldedit.stack = function(pos1, pos2, axis, count)
return worldedit.volume(pos1, pos2) * count return worldedit.volume(pos1, pos2) * count
end 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 --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.scale = function(pos1, pos2, factor) worldedit.stretch = function(pos1, pos2, stretchx, stretchy, stretchz) --wip: test this
local pos1, pos2 = worldedit.sort_pos(pos1, pos2) local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
--prepare schematic of large node --prepare schematic of large node
local get_node, get_meta, place_schematic = minetest.get_node, minetest.get_meta, minetest.place_schematic 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 placeholder_node = {name="", param1=255, param2=0}
local nodes = {} local nodes = {}
for i = 1, factor ^ 3 do for i = 1, stretchx * stretchy * stretchz do
nodes[i] = placeholder_node nodes[i] = placeholder_node
end 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 --make area stay loaded
local manip = minetest.get_voxel_manip() 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) manip:read_from_map(pos1, new_pos2)
local pos = {x=pos2.x, y=0, z=0} 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 node = get_node(pos) --obtain current node
local meta = get_meta(pos):to_table() --get meta of current node local meta = get_meta(pos):to_table() --get meta of current node
local value = pos[axis] --store current position --calculate far corner of the big node
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 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 --create large node
placeholder_node.name = node.name placeholder_node.name = node.name
@ -331,10 +337,10 @@ worldedit.scale = function(pos1, pos2, factor)
place_schematic(bigpos, schematic) place_schematic(bigpos, schematic)
--fill in large node meta --fill in large node meta
if next(meta.fields) ~= nil and next(meta.inventory) ~= nil then --node has meta fields if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then --node has meta fields
for x = 0, size do for x = 0, sizex do
for y = 0, size do for y = 0, sizey do
for z = 0, size do for z = 0, sizez do
bigpos.x, bigpos.y, bigpos.z = posx + x, posy + y, posz + z bigpos.x, bigpos.y, bigpos.z = posx + x, posy + y, posz + z
get_meta(bigpos):from_table(meta) --set metadata of new node get_meta(bigpos):from_table(meta) --set metadata of new node
end end
@ -347,7 +353,7 @@ worldedit.scale = function(pos1, pos2, factor)
end end
pos.x = pos.x - 1 pos.x = pos.x - 1
end end
return worldedit.volume(pos1, pos2) * (factor ^ 3), pos1, new_pos2 return worldedit.volume(pos1, pos2) * stretchx * stretchy * stretchz, pos1, new_pos2
end 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 --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

View File

@ -61,16 +61,18 @@ minetest.register_chatcommand("/about", {
}) })
minetest.register_chatcommand("/inspect", { 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/<blank>",
description = "Enable or disable node inspection", description = "Enable or disable node inspection",
privs = {worldedit=true}, privs = {worldedit=true},
func = function(name, param) 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.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 elseif param == "off" or param == "0" or param == "false" or param == "no" or param == "disable" then
worldedit.inspect[name] = nil worldedit.inspect[name] = nil
worldedit.player_notify(name, "node inspection disabled") worldedit.player_notify(name, "inspector: inspection disabled")
else else
worldedit.player_notify(name, "invalid usage: " .. param) worldedit.player_notify(name, "invalid usage: " .. param)
end end
@ -81,7 +83,9 @@ minetest.register_on_punchnode(function(pos, node, puncher)
local name = puncher:get_player_name() local name = puncher:get_player_name()
if worldedit.inspect[name] then if worldedit.inspect[name] then
if minetest.check_player_privs(name, {worldedit=true}) 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 else
message = "inspector: worldedit privileges required" message = "inspector: worldedit privileges required"
end end
@ -658,9 +662,9 @@ minetest.register_chatcommand("/stack", {
end, end,
}) })
minetest.register_chatcommand("/scale", { minetest.register_chatcommand("/stretch", {
params = "<factor>", params = "<stretchx> <stretchy> <stretchz>",
description = "Scale the current WorldEdit positions and region by a factor of positive integer <factor> with position 1 as the origin", description = "Scale the current WorldEdit positions and region by a factor of <stretchx>, <stretchy>, <stretchz> along the X, Y, and Z axes, repectively, with position 1 as the origin",
privs = {worldedit=true}, privs = {worldedit=true},
func = function(name, param) func = function(name, param)
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
@ -669,12 +673,17 @@ minetest.register_chatcommand("/scale", {
return return
end end
local factor = tonumber(param) local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$")
if not factor or factor ~= math.floor(factor) or factor <= 0 then 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) worldedit.player_notify(name, "invalid scaling factor: " .. param)
end 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 --reset markers to scaled positions
worldedit.pos1[name] = pos1 worldedit.pos1[name] = pos1
@ -682,7 +691,7 @@ minetest.register_chatcommand("/scale", {
worldedit.mark_pos1(name) worldedit.mark_pos1(name)
worldedit.mark_pos2(name) worldedit.mark_pos2(name)
worldedit.player_notify(name, count .. " nodes scaled") worldedit.player_notify(name, count .. " nodes stretched")
end, end,
}) })
@ -919,6 +928,10 @@ minetest.register_chatcommand("/save", {
worldedit.player_notify(name, "invalid usage: " .. param) worldedit.player_notify(name, "invalid usage: " .. param)
return return
end 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) local result, count = worldedit.serialize(pos1, pos2)
@ -953,6 +966,10 @@ minetest.register_chatcommand("/allocate", {
worldedit.player_notify(name, "invalid usage: " .. param) worldedit.player_notify(name, "invalid usage: " .. param)
return return
end 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 filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we"
local file, err = io.open(filename, "rb") local file, err = io.open(filename, "rb")
@ -993,6 +1010,10 @@ minetest.register_chatcommand("/load", {
worldedit.player_notify(name, "invalid usage: " .. param) worldedit.player_notify(name, "invalid usage: " .. param)
return return
end 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 --find the file in the world path
local testpaths = { local testpaths = {