diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index 7338b7e..e26d40c 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -13,6 +13,7 @@ if minetest.place_schematic then end dofile(minetest.get_modpath("worldedit_commands") .. "/mark.lua") +dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua") local get_position = function(name) local pos1 = worldedit.pos1[name] @@ -31,71 +32,6 @@ local get_node = function(name, nodename) return node end - ---`callback` is a callback to run when the user confirms ---`nodes_needed` is a function accepting `param`, `pos1`, and `pos2` to calculate the number of nodes needed -local safe_region -do --safe region wrapper function - local safe_region_callback - local safe_region_name - local safe_region_param - safe_region = function(callback, nodes_needed) - nodes_needed = nodes_needed or worldedit.volume - return function(name, param) - --obtain positions - local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] - if pos1 == nil or pos2 == nil then - worldedit.player_notify(name, "no region selected") - return nil - end - - --check volume - local count = nodes_needed(pos1, pos2, name, param) - if not count or count < 10000 then - return callback(name, param, pos1, pos2) - end - - --save callback to call later - safe_region_callback, safe_region_name, safe_region_param = callback, name, param - worldedit.player_notify(name, "WARNING: this operation could affect up to " .. count .. " nodes; type //y to continue or //n to cancel") - end - end - - minetest.register_chatcommand("/y", { - params = "", - description = "Confirm a pending operation", - func = function() - local callback, name, param = safe_region_callback, safe_region_name, safe_region_param - if not callback then - worldedit.player_notify(name, "no operation pending") - return - end - - --obtain positions - local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] - if pos1 == nil or pos2 == nil then - worldedit.player_notify(name, "no region selected") - return - end - - safe_region_callback, safe_region_name, safe_region_param = nil, nil, nil --reset pending operation - callback(name, param, pos1, pos2) - end, - }) - - minetest.register_chatcommand("/n", { - params = "", - description = "Confirm a pending operation", - func = function() - if not safe_region_callback then - worldedit.player_notify(name, "no operation pending") - return - end - safe_region_callback, safe_region_name, safe_region_param = nil, nil, nil - end, - }) -end - worldedit.player_notify = function(name, message) minetest.chat_send_player(name, "WorldEdit -!- " .. message, false) end @@ -135,7 +71,16 @@ worldedit.player_axis = function(name) return "z", dir.z > 0 and 1 or -1 end +local check_region = function(name, param) + --obtain positions + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if pos1 == nil or pos2 == nil then + worldedit.player_notify(name, "no region selected") + return nil + end + return worldedit.volume(pos1, pos2) +end minetest.register_chatcommand("/about", { params = "", @@ -344,259 +289,270 @@ minetest.register_chatcommand("/volume", { end, }) +local check_set = function(name, param) + local node = get_node(name, param) + if not node then return nil end + return check_region(name, param) +end + minetest.register_chatcommand("/set", { params = "", description = "Set the current WorldEdit region to ", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local node = get_node(name, param) - if not node then return end - local count = worldedit.set(pos1, pos2, node) worldedit.player_notify(name, count .. " nodes set") - end), + end, check_set), }) +local check_replace = function(name, param) + local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local newsearchnode = worldedit.normalize_nodename(searchnode) + if not newsearchnode then + worldedit.player_notify(name, "invalid search node name: " .. searchnode) + return nil + end + local newreplacenode = worldedit.normalize_nodename(replacenode) + if not newreplacenode then + worldedit.player_notify(name, "invalid replace node name: " .. replacenode) + return nil + end + return check_region(name, param) +end + minetest.register_chatcommand("/replace", { params = " ", description = "Replace all instances of with in the current WorldEdit region", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end local newsearchnode = worldedit.normalize_nodename(searchnode) - if not newsearchnode then - worldedit.player_notify(name, "invalid search node name: " .. searchnode) - return - end local newreplacenode = worldedit.normalize_nodename(replacenode) - if not newreplacenode then - worldedit.player_notify(name, "invalid replace node name: " .. replacenode) - return - end - local count = worldedit.replace(pos1, pos2, newsearchnode, newreplacenode) worldedit.player_notify(name, count .. " nodes replaced") - end), + end, check_replace), }) minetest.register_chatcommand("/replaceinverse", { params = " ", description = "Replace all nodes other than with in the current WorldEdit region", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end local newsearchnode = worldedit.normalize_nodename(searchnode) - if not newsearchnode then - worldedit.player_notify(name, "invalid search node name: " .. searchnode) - return - end local newreplacenode = worldedit.normalize_nodename(replacenode) - if not newreplacenode then - worldedit.player_notify(name, "invalid replace node name: " .. replacenode) - return - end - local count = worldedit.replaceinverse(pos1, pos2, searchnode, replacenode) worldedit.player_notify(name, count .. " nodes replaced") - end), + end, check_replace), }) +local check_sphere = function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + return math.ceil((4 * math.pi * (tonumber(radius) ^ 3)) / 3) --volume of sphere +end + minetest.register_chatcommand("/hollowsphere", { params = " ", description = "Add hollow sphere centered at WorldEdit position 1 with radius , composed of ", privs = {worldedit=true}, - func = function(name, param) - local pos = get_position(name) - if pos == nil then return end - + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end local node = get_node(name, nodename) - if not node then return end - local count = worldedit.hollow_sphere(pos, tonumber(radius), node) worldedit.player_notify(name, count .. " nodes added") - end, + end, check_sphere), }) minetest.register_chatcommand("/sphere", { params = " ", description = "Add sphere centered at WorldEdit position 1 with radius , composed of ", privs = {worldedit=true}, - func = function(name, param) - local pos = get_position(name) - if pos == nil then return end - + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end local node = get_node(name, nodename) - if not node then return end - local count = worldedit.sphere(pos, tonumber(radius), node) worldedit.player_notify(name, count .. " nodes added") - end, + end, check_sphere), }) +local check_dome = function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + return math.ceil((2 * math.pi * (tonumber(radius) ^ 3)) / 3) --volume of dome +end + minetest.register_chatcommand("/hollowdome", { params = " ", description = "Add hollow dome centered at WorldEdit position 1 with radius , composed of ", privs = {worldedit=true}, - func = function(name, param) - local pos = get_position(name) - if pos == nil then return end - - local found, _, radius, nodename = param:find("^([+-]?%d+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") local node = get_node(name, nodename) - if not node then return end - local count = worldedit.hollow_dome(pos, tonumber(radius), node) worldedit.player_notify(name, count .. " nodes added") - end, + end, check_dome), }) minetest.register_chatcommand("/dome", { params = " ", description = "Add dome centered at WorldEdit position 1 with radius , composed of ", privs = {worldedit=true}, - func = function(name, param) - local pos = get_position(name) - if pos == nil then return end - - local found, _, radius, nodename = param:find("^([+-]?%d+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] + local found, _, radius, nodename = param:find("^(%d+)%s+(.+)$") local node = get_node(name, nodename) - if not node then return end - local count = worldedit.dome(pos, tonumber(radius), node) worldedit.player_notify(name, count .. " nodes added") - end, + end, check_dome), }) +local check_cylinder = function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + return math.ceil(math.pi * (tonumber(radius) ^ 2) * tonumber(length)) +end + minetest.register_chatcommand("/hollowcylinder", { params = "x/y/z/? ", description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length and radius , composed of ", privs = {worldedit=true}, - func = function(name, param) - local pos = get_position(name) - if pos == nil then return end - + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end - length, radius = tonumber(length), tonumber(radius) + length = tonumber(length) if axis == "?" then axis, sign = worldedit.player_axis(name) length = length * sign end local node = get_node(name, nodename) - if not node then return end - - local count = worldedit.hollow_cylinder(pos, axis, length, radius, node) + local count = worldedit.hollow_cylinder(pos, axis, length, tonumber(radius), node) worldedit.player_notify(name, count .. " nodes added") - end, + end, check_cylinder), }) minetest.register_chatcommand("/cylinder", { params = "x/y/z/? ", description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length and radius , composed of ", privs = {worldedit=true}, - func = function(name, param) - local pos = get_position(name) - if pos == nil then return end - + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end - length, radius = tonumber(length), tonumber(radius) + length = tonumber(length) if axis == "?" then axis, sign = worldedit.player_axis(name) length = length * sign end local node = get_node(name, nodename) - if not node then return end - - local count = worldedit.cylinder(pos, axis, length, radius, node) + local count = worldedit.cylinder(pos, axis, length, tonumber(radius), node) worldedit.player_notify(name, count .. " nodes added") - end, + end, check_cylinder), }) minetest.register_chatcommand("/pyramid", { params = "x/y/z/? ", description = "Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height , composed of ", privs = {worldedit=true}, - func = function(name, param) + func = safe_region(function(name, param) local pos = get_position(name) - if pos == nil then return end - local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end height = tonumber(height) if axis == "?" then axis, sign = worldedit.player_axis(name) height = height * sign end local node = get_node(name, nodename) - if not node then return end - local count = worldedit.pyramid(pos, axis, height, node) worldedit.player_notify(name, count .. " nodes added") end, + function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + height = tonumber(height) + return math.ceil(((height * 2 + 1) ^ 2) * height / 3) + end), }) minetest.register_chatcommand("/spiral", { params = " ", description = "Add spiral centered at WorldEdit position 1 with side length , height , space between walls , composed of ", privs = {worldedit=true}, - func = function(name, param) - local pos = get_position(name) - if pos == nil then return end - + func = safe_region(function(name, param) + local pos = worldedit.pos1[name] local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end local node = get_node(name, nodename) - if not node then return end - local count = worldedit.spiral(pos, tonumber(length), tonumber(height), tonumber(space), node) worldedit.player_notify(name, count .. " nodes added") end, + function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + local node = get_node(name, nodename) + if not node then return nil end + return check_region(name, param) + end), }) minetest.register_chatcommand("/copy", { params = "x/y/z/? ", description = "Copy the current WorldEdit region along the x/y/z/? axis by nodes", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$") if found == nil then worldedit.player_notify(name, "invalid usage: " .. param) @@ -610,6 +566,10 @@ minetest.register_chatcommand("/copy", { local count = worldedit.copy(pos1, pos2, axis, amount) worldedit.player_notify(name, count .. " nodes copied") + end, + function(name, param) + local volume = check_region(name, param) + return volume and volume * 2 or volume end), }) @@ -617,7 +577,8 @@ minetest.register_chatcommand("/move", { params = "x/y/z/? ", description = "Move the current WorldEdit region along the x/y/z/? axis by nodes", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$") if found == nil then worldedit.player_notify(name, "invalid usage: " .. param) @@ -636,33 +597,32 @@ minetest.register_chatcommand("/move", { worldedit.mark_pos1(name) worldedit.mark_pos2(name) worldedit.player_notify(name, count .. " nodes moved") - end), + end, check_region), }) minetest.register_chatcommand("/stack", { params = "x/y/z/? ", description = "Stack the current WorldEdit region along the x/y/z/? axis times", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end repetitions = tonumber(repetitions) if axis == "?" then axis, sign = worldedit.player_axis(name) repetitions = repetitions * sign end - local count = worldedit.stack(pos1, pos2, axis, repetitions) worldedit.player_notify(name, count .. " nodes stacked") end, - function(pos1, pos2, name, param) + function(name, param) local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$") - if found then - return tonumber(repetitions) * worldedit.volume(pos1, pos2) + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) end + local count = check_region(name, param) + if count then return (tonumber(repetitions) + 1) * count end + return nil end), }) @@ -670,17 +630,10 @@ 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 = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] 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 factors: " .. param) - end - local count, pos1, pos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz) --reset markers to scaled positions @@ -691,11 +644,19 @@ minetest.register_chatcommand("/stretch", { worldedit.player_notify(name, count .. " nodes stretched") end, - function(pos1, pos2, name, param) + function(name, param) local found, _, stretchx, stretchy, stretchz = param:find("^(%d+)%s+(%d+)%s+(%d+)$") - if found then - return tonumber(stretchx) * tonumber(stretchy) * tonumber(stretchz) * worldedit.volume(pos1, pos2) + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil 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 factors: " .. param) + end + local count = check_region(name, param) + if count then return tonumber(stretchx) * tonumber(stretchy) * tonumber(stretchz) * count end + return nil end), }) @@ -703,23 +664,11 @@ minetest.register_chatcommand("/transpose", { params = "x/y/z/? x/y/z/?", description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end - if axis1 == "?" then - axis1 = worldedit.player_axis(name) - end - if axis2 == "?" then - axis2 = worldedit.player_axis(name) - end - if axis1 == axis2 then - worldedit.player_notify(name, "invalid usage: axes must be different") - return - end - + 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) --reset markers to transposed positions @@ -729,6 +678,18 @@ minetest.register_chatcommand("/transpose", { worldedit.mark_pos2(name) worldedit.player_notify(name, count .. " nodes transposed") + end, + function(name, param) + local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + if axis1 == axis2 then + worldedit.player_notify(name, "invalid usage: axes must be different") + return nil + end + return check_region(name, param) end), }) @@ -736,17 +697,18 @@ minetest.register_chatcommand("/flip", { params = "x/y/z/?", description = "Flip the current WorldEdit region along the x/y/z/? axis", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) - if param == "?" then - param = worldedit.player_axis(name) - end - if param ~= "x" and param ~= "y" and param ~= "z" then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end - + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if param == "?" then param = worldedit.player_axis(name) end local count = worldedit.flip(pos1, pos2, param) worldedit.player_notify(name, count .. " nodes flipped") + end, + function(name, param) + if param ~= "x" and param ~= "y" and param ~= "z" and param ~= "?" then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + return check_region(name, param) end), }) @@ -754,20 +716,10 @@ minetest.register_chatcommand("/rotate", { params = " ", description = "Rotate the current WorldEdit region around the axis by angle (90 degree increment)", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$") - if found == nil then - worldedit.player_notify(name, "invalid usage: " .. param) - return - end - if axis == "?" then - axis = worldedit.player_axis(name) - end - if angle % 90 ~= 0 then - worldedit.player_notify(name, "invalid usage: angle must be multiple of 90") - return - end - + if axis == "?" then axis = worldedit.player_axis(name) end local count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle) --reset markers to rotated positions @@ -777,6 +729,18 @@ minetest.register_chatcommand("/rotate", { worldedit.mark_pos2(name) worldedit.player_notify(name, count .. " nodes rotated") + end, + function(name, param) + local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$") + if found == nil then + worldedit.player_notify(name, "invalid usage: " .. param) + return nil + end + if angle % 90 ~= 0 then + worldedit.player_notify(name, "invalid usage: angle must be multiple of 90") + return nil + end + return check_region(name, param) end), }) @@ -784,20 +748,23 @@ minetest.register_chatcommand("/orient", { params = "", description = "Rotate oriented nodes in the current WorldEdit region around the Y axis by angle (90 degree increment)", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + local found, _, angle = param:find("^([+-]?%d+)$") + local count = worldedit.orient(pos1, pos2, angle) + worldedit.player_notify(name, count .. " nodes oriented") + end, + function(name, param) local found, _, angle = param:find("^([+-]?%d+)$") if found == nil then worldedit.player_notify(name, "invalid usage: " .. param) - return + return nil end if angle % 90 ~= 0 then worldedit.player_notify(name, "invalid usage: angle must be multiple of 90") - return + return nil end - - local count = worldedit.orient(pos1, pos2, angle) - - worldedit.player_notify(name, count .. " nodes oriented") + return check_region(name, param) end), }) @@ -805,7 +772,8 @@ minetest.register_chatcommand("/fixlight", { params = "", description = "Fix the lighting in the current WorldEdit region", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local count = worldedit.fixlight(pos1, pos2) worldedit.player_notify(name, count .. " nodes updated") end), @@ -815,7 +783,8 @@ minetest.register_chatcommand("/hide", { params = "", description = "Hide all nodes in the current WorldEdit region non-destructively", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local count = worldedit.hide(pos1, pos2) worldedit.player_notify(name, count .. " nodes hidden") end), @@ -825,33 +794,32 @@ minetest.register_chatcommand("/suppress", { params = "", description = "Suppress all in the current WorldEdit region non-destructively", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local node = get_node(name, param) - if not node then return end - local count = worldedit.suppress(pos1, pos2, node) worldedit.player_notify(name, count .. " nodes suppressed") - end), + end, check_set), }) minetest.register_chatcommand("/highlight", { params = "", description = "Highlight in the current WorldEdit region by hiding everything else non-destructively", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local node = get_node(name, param) - if not node then return end - local count = worldedit.highlight(pos1, pos2, node) worldedit.player_notify(name, count .. " nodes highlighted") - end), + end, check_set), }) minetest.register_chatcommand("/restore", { params = "", description = "Restores nodes hidden with WorldEdit in the current WorldEdit region", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local count = worldedit.restore(pos1, pos2) worldedit.player_notify(name, count .. " nodes restored") end), @@ -861,7 +829,8 @@ minetest.register_chatcommand("/save", { params = "", description = "Save the current WorldEdit region to \"(world folder)/schems/.we\"", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] if param == "" then worldedit.player_notify(name, "invalid usage: " .. param) return @@ -1002,7 +971,8 @@ minetest.register_chatcommand("/luatransform", { params = "", description = "Executes as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region", privs = {worldedit=true, server=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local admin = minetest.setting_get("name") if not admin or not name == admin then worldedit.player_notify(name, "this command can only be run by the server administrator") @@ -1022,7 +992,8 @@ minetest.register_chatcommand("/mtschemcreate", { params = "", description = "Save the current WorldEdit region using the Minetest Schematic format to \"(world folder)/schems/.mts\"", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] if param == nil then worldedit.player_notify(name, "No filename specified") return @@ -1111,7 +1082,8 @@ minetest.register_chatcommand("/clearobjects", { params = "", description = "Clears all objects within the WorldEdit region", privs = {worldedit=true}, - func = safe_region(function(name, param, pos1, pos2) + func = safe_region(function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local count = worldedit.clearobjects(pos1, pos2) worldedit.player_notify(name, count .. " objects cleared") end), diff --git a/worldedit_commands/safe.lua b/worldedit_commands/safe.lua new file mode 100644 index 0000000..6f83078 --- /dev/null +++ b/worldedit_commands/safe.lua @@ -0,0 +1,57 @@ +local safe_region_callback +local safe_region_name +local safe_region_param + +--`callback` is a callback to run when the user confirms +--`nodes_needed` is a function accepting `param`, `pos1`, and `pos2` to calculate the number of nodes needed +safe_region = function(callback, nodes_needed) + --default node volume calculation + nodes_needed = nodes_needed or check_region + + return function(name, param) + --check if the operation applies to a safe number of nodes + local count = nodes_needed(name, param) + if count == nil then return end --invalid command + if count < 10000 then + return callback(name, param) + end + + --save callback to call later + safe_region_callback, safe_region_name, safe_region_param = callback, name, param + worldedit.player_notify(name, "WARNING: this operation could affect up to " .. count .. " nodes; type //y to continue or //n to cancel") + end +end + +minetest.register_chatcommand("/y", { + params = "", + description = "Confirm a pending operation", + func = function() + local callback, name, param = safe_region_callback, safe_region_name, safe_region_param + if not callback then + worldedit.player_notify(name, "no operation pending") + return + end + + --obtain positions + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if pos1 == nil or pos2 == nil then + worldedit.player_notify(name, "no region selected") + return + end + + safe_region_callback, safe_region_name, safe_region_param = nil, nil, nil --reset pending operation + callback(name, param, pos1, pos2) + end, +}) + +minetest.register_chatcommand("/n", { + params = "", + description = "Confirm a pending operation", + func = function() + if not safe_region_callback then + worldedit.player_notify(name, "no operation pending") + return + end + safe_region_callback, safe_region_name, safe_region_param = nil, nil, nil + end, +})