local S = minetest.get_translator("worldedit_commands") local function check_region(name) return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) end worldedit.register_command("deleteblocks", { params = "", description = S("Remove all MapBlocks (16x16x16) containing the selected area from the map"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, nodes_needed = check_region, func = function(name) local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local success = minetest.delete_area(pos1, pos2) if success then return true, S("Area deleted.") else return false, S("There was an error during deletion of the area.") end end, }) worldedit.register_command("clearobjects", { params = "", description = S("Clears all objects within the WorldEdit region"), category = S("Node manipulation"), -- not really, but it doesn't fit anywhere else privs = {worldedit=true}, require_pos = 2, nodes_needed = check_region, func = function(name) local count = worldedit.clear_objects(worldedit.pos1[name], worldedit.pos2[name]) return true, S("@1 objects cleared", count) end, }) worldedit.register_command("set", { params = "", description = S("Set the current WorldEdit region to "), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, parse = function(param) local node = worldedit.normalize_nodename(param) if not node then return false, S("invalid node name: @1", param) end return true, node end, nodes_needed = check_region, func = function(name, node) local count = worldedit.set(worldedit.pos1[name], worldedit.pos2[name], node) return true, S("@1 nodes set", count) end, }) worldedit.register_command("param2", { params = "", description = S("Set param2 of all nodes in the current WorldEdit region to "), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, parse = function(param) local param2 = tonumber(param) if not param2 then return false elseif param2 < 0 or param2 > 255 then return false, S("Param2 is out of range (must be between 0 and 255 inclusive!)") end return true, param2 end, nodes_needed = check_region, func = function(name, param2) local count = worldedit.set_param2(worldedit.pos1[name], worldedit.pos2[name], param2) return true, S("@1 nodes altered", count) end, }) worldedit.register_command("mix", { params = " [count1] [count2] ...", description = S("Fill the current WorldEdit region with a random mix of , ..."), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, parse = function(param) local nodes = {} for nodename in param:gmatch("[^%s]+") do if tonumber(nodename) ~= nil and #nodes > 0 then local last_node = nodes[#nodes] for i = 1, tonumber(nodename) do nodes[#nodes + 1] = last_node end else local node = worldedit.normalize_nodename(nodename) if not node then return false, S("invalid node name: @1", nodename) end nodes[#nodes + 1] = node end end if #nodes == 0 then return false end return true, nodes end, nodes_needed = check_region, func = function(name, nodes) local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] local count = worldedit.set(pos1, pos2, nodes) return true, S("@1 nodes set", count) end, }) local check_replace = function(param) local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+(.+)$") if found == nil then return false end local newsearchnode = worldedit.normalize_nodename(searchnode) if not newsearchnode then return false, S("invalid search node name: @1", searchnode) end local newreplacenode = worldedit.normalize_nodename(replacenode) if not newreplacenode then return false, S("invalid replace node name: @1", replacenode) end return true, newsearchnode, newreplacenode end worldedit.register_command("replace", { params = " ", description = S("Replace all instances of with in the current WorldEdit region"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, parse = check_replace, nodes_needed = check_region, func = function(name, search_node, replace_node) local count = worldedit.replace(worldedit.pos1[name], worldedit.pos2[name], search_node, replace_node) return true, S("@1 nodes replaced", count) end, }) worldedit.register_command("replaceinverse", { params = " ", description = S("Replace all nodes other than with in the current WorldEdit region"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, parse = check_replace, nodes_needed = check_region, func = function(name, search_node, replace_node) local count = worldedit.replace(worldedit.pos1[name], worldedit.pos2[name], search_node, replace_node, true) return true, S("@1 nodes replaced", count) end, }) worldedit.register_command("fixlight", { params = "", description = S("Fix the lighting in the current WorldEdit region"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, nodes_needed = check_region, func = function(name) local count = worldedit.fixlight(worldedit.pos1[name], worldedit.pos2[name]) return true, S("@1 nodes updated", count) end, }) local drain_cache local function drain(pos1, pos2) if drain_cache == nil then drain_cache = {} for name, d in pairs(minetest.registered_nodes) do if d.drawtype == "liquid" or d.drawtype == "flowingliquid" then drain_cache[name] = true end end end pos1, pos2 = worldedit.sort_pos(pos1, pos2) local count = 0 local get_node, remove_node = minetest.get_node, minetest.remove_node for x = pos1.x, pos2.x do for y = pos1.y, pos2.y do for z = pos1.z, pos2.z do local p = vector.new(x, y, z) local n = get_node(p).name if drain_cache[n] then remove_node(p) count = count + 1 end end end end return count end worldedit.register_command("drain", { params = "", description = S("Remove any fluid node within the current WorldEdit region"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, nodes_needed = check_region, func = function(name) local count = drain(worldedit.pos1[name], worldedit.pos2[name]) return true, S("@1 nodes updated", count) end, }) local clearcut_cache local function clearcut(pos1, pos2) -- decide which nodes we consider plants if clearcut_cache == nil then clearcut_cache = {} for name, def in pairs(minetest.registered_nodes) do local groups = def.groups or {} if ( -- the groups say so groups.flower or groups.grass or groups.flora or groups.plant or groups.leaves or groups.tree or groups.leafdecay or groups.sapling or -- drawtype heuristic (def.is_ground_content and def.buildable_to and (def.sunlight_propagates or not def.walkable) and def.drawtype == "plantlike") or -- if it's flammable, it probably needs to go too (def.is_ground_content and not def.walkable and groups.flammable) ) then clearcut_cache[name] = true end end end local plants = clearcut_cache local count = 0 local prev, any local get_node, remove_node = minetest.get_node, minetest.remove_node for x = pos1.x, pos2.x do for z = pos1.z, pos2.z do prev = false any = false -- first pass: remove floating nodes that would be left over for y = pos1.y, pos2.y do local pos = vector.new(x, y, z) local n = get_node(pos).name if plants[n] then prev = true any = true elseif prev then local def = minetest.registered_nodes[n] or {} local groups = def.groups or {} if groups.attached_node or (def.buildable_to and groups.falling_node) then remove_node(pos) count = count + 1 else prev = false end end end -- second pass: remove plants, top-to-bottom to avoid item drops if any then for y = pos2.y, pos1.y, -1 do local pos = vector.new(x, y, z) local n = get_node(pos).name if plants[n] then remove_node(pos) count = count + 1 end end end end end return count end worldedit.register_command("clearcut", { params = "", description = S("Remove any plant, tree or foliage-like nodes in the selected region"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, nodes_needed = check_region, func = function(name) local pos1, pos2 = worldedit.sort_pos(worldedit.pos1[name], worldedit.pos2[name]) local count = clearcut(pos1, pos2) return true, S("@1 nodes removed", count) end, }) worldedit.register_command("hide", { params = "", description = S("Hide all nodes in the current WorldEdit region non-destructively"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, nodes_needed = check_region, func = function(name) local count = worldedit.hide(worldedit.pos1[name], worldedit.pos2[name]) return true, S("@1 nodes hidden", count) end, }) worldedit.register_command("suppress", { params = "", description = S("Suppress all in the current WorldEdit region non-destructively"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, parse = function(param) local node = worldedit.normalize_nodename(param) if not node then return false, S("invalid node name: @1", param) end return true, node end, nodes_needed = check_region, func = function(name, node) local count = worldedit.suppress(worldedit.pos1[name], worldedit.pos2[name], node) return true, S("@1 nodes suppressed", count) end, }) worldedit.register_command("highlight", { params = "", description = S("Highlight in the current WorldEdit region by hiding everything else non-destructively"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, parse = function(param) local node = worldedit.normalize_nodename(param) if not node then return false, S("invalid node name: @1", param) end return true, node end, nodes_needed = check_region, func = function(name, node) local count = worldedit.highlight(worldedit.pos1[name], worldedit.pos2[name], node) return true, S("@1 nodes highlighted", count) end, }) worldedit.register_command("restore", { params = "", description = S("Restores nodes hidden with WorldEdit in the current WorldEdit region"), category = S("Node manipulation"), privs = {worldedit=true}, require_pos = 2, nodes_needed = check_region, func = function(name) local count = worldedit.restore(worldedit.pos1[name], worldedit.pos2[name]) return true, S("@1 nodes restored", count) end, })