X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=worldedit_commands%2Finit.lua;h=1ab8c1953851b149c8ba66c31aef8272f72bd99c;hb=3c61759bae15d8bedc9c54b4e3903479a5f4cf08;hp=b9313cce8c3503976c1bf0840de815aace0824b8;hpb=6e2e2385e90ddc74ad68d129fbb7a94d6ee53a7f;p=worldedit.git diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index b9313cc..1ab8c19 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -12,7 +12,8 @@ end dofile(minetest.get_modpath("worldedit_commands") .. "/cuboid.lua") dofile(minetest.get_modpath("worldedit_commands") .. "/mark.lua") -local safe_region, check_region = dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua") +dofile(minetest.get_modpath("worldedit_commands") .. "/wand.lua") +local safe_region, check_region, reset_pending = dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua") local function get_position(name) --position 1 retrieval function for when not using `safe_region` local pos1 = worldedit.pos1[name] @@ -22,6 +23,7 @@ local function get_position(name) --position 1 retrieval function for when not u return pos1 end +-- normalize_nodename wrapper for convenience purposes local function get_node(name, nodename) local node = worldedit.normalize_nodename(nodename) if not node then @@ -35,26 +37,46 @@ function worldedit.player_notify(name, message) minetest.chat_send_player(name, "WorldEdit -!- " .. message, false) end ---determines whether `nodename` is a valid node name, returning a boolean +local function string_endswith(full, part) + return full:find(part, 1, true) == #full - #part + 1 +end + +-- normalizes node "description" `nodename`, returning a string (or nil) worldedit.normalize_nodename = function(nodename) - nodename = nodename:gsub("^%s*(.-)%s*$", "%1") + nodename = nodename:gsub("^%s*(.-)%s*$", "%1") -- strip spaces if nodename == "" then return nil end - local fullname = ItemStack({name=nodename}):get_name() --resolve aliases of node names to full names - if minetest.registered_nodes[fullname] or fullname == "air" then --directly found node name or alias of nodename + + local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases + if minetest.registered_nodes[fullname] or fullname == "air" then -- full name return fullname end for key, value in pairs(minetest.registered_nodes) do - if key:find(":" .. nodename, 1, true) then --found in mod + if string_endswith(key, ":" .. nodename) then -- matches name (w/o mod part) return key end end - nodename = nodename:lower() --lowercase both for case insensitive comparison + nodename = nodename:lower() -- lowercase both for case insensitive comparison for key, value in pairs(minetest.registered_nodes) do - if value.description:lower() == nodename then --found in description + local desc = value.description:lower() + if desc == nodename then -- matches description + return key + end + if string_endswith(desc, " block") and desc == nodename.." block" then + -- fuzzy description match (e.g. "Steel" == "Steel Block") return key end end - return nil + + local match = nil + for key, value in pairs(minetest.registered_nodes) do + if value.description:lower():find(nodename, 1, true) ~= nil then + if match ~= nil then + return nil + end + match = key -- substring description match (only if no ambiguities) + end + end + return match end -- Determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1) @@ -92,6 +114,56 @@ minetest.register_chatcommand("/about", { end, }) +-- mostly copied from builtin/chatcommands.lua with minor modifications +minetest.register_chatcommand("/help", { + privs = {}, + params = "[all/]", + description = "Get help for WorldEdit commands", + func = function(name, param) + local function is_we_command(cmd) + return cmd:sub(0, 1) == "/" + end + local function format_help_line(cmd, def) + local msg = minetest.colorize("#00ffff", "/"..cmd) + if def.params and def.params ~= "" then + msg = msg .. " " .. def.params + end + if def.description and def.description ~= "" then + msg = msg .. ": " .. def.description + end + return msg + end + + if not minetest.check_player_privs(name, "worldedit") then + return false, "You are not allowed to use any WorldEdit commands." + end + if param == "" then + local msg = "" + local cmds = {} + for cmd, def in pairs(minetest.chatcommands) do + if is_we_command(cmd) and minetest.check_player_privs(name, def.privs) then + cmds[#cmds + 1] = cmd:sub(2) -- strip the / + end + end + table.sort(cmds) + return true, "Available commands: " .. table.concat(cmds, " ") .. "\n" + .. "Use '//help ' to get more information," + .. " or '//help all' to list everything." + elseif param == "all" then + local cmds = {} + for cmd, def in pairs(minetest.chatcommands) do + if is_we_command(cmd) and minetest.check_player_privs(name, def.privs) then + cmds[#cmds + 1] = format_help_line(cmd, def) + end + end + table.sort(cmds) + return true, "Available commands:\n"..table.concat(cmds, "\n") + else + return minetest.chatcommands["help"].func(name, "/" .. param) + end + end, +}) + minetest.register_chatcommand("/inspect", { params = "on/off/1/0/true/false/yes/no/enable/disable/", description = "Enable or disable node inspection", @@ -111,16 +183,28 @@ minetest.register_chatcommand("/inspect", { end, }) +local function get_node_rlight(pos) + local vecs = { -- neighboring nodes + {x= 1, y= 0, z= 0}, + {x=-1, y= 0, z= 0}, + {x= 0, y= 1, z= 0}, + {x= 0, y=-1, z= 0}, + {x= 0, y= 0, z= 1}, + {x= 0, y= 0, z=-1}, + } + local ret = 0 + for _, v in ipairs(vecs) do + ret = math.max(ret, minetest.get_node_light(vector.add(pos, v))) + end + return ret +end + 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 - 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 + local axis, sign = worldedit.player_axis(name) + message = string.format("inspector: %s at %s (param1=%d, param2=%d, received light=%d) punched facing the %s axis", + node.name, minetest.pos_to_string(pos), node.param1, node.param2, get_node_rlight(pos), axis .. (sign > 0 and "+" or "-")) worldedit.player_notify(name, message) end end) @@ -135,6 +219,8 @@ minetest.register_chatcommand("/reset", { worldedit.mark_pos1(name) worldedit.mark_pos2(name) worldedit.set_pos[name] = nil + --make sure the user does not try to confirm an operation after resetting pos: + reset_pending(name) worldedit.player_notify(name, "region reset") end, }) @@ -322,6 +408,25 @@ minetest.register_chatcommand("/set", { end, check_region), }) +minetest.register_chatcommand("/param2", { + params = "", + description = "Set param2 of all nodes in the current WorldEdit region to ", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local param2 = tonumber(param) + if not param2 then + worldedit.player_notify(name, "Invalid or missing param2 argument") + return + elseif param2 < 0 or param2 > 255 then + worldedit.player_notify(name, "Param2 is out of range (must be between 0 and 255 inclusive)!") + return + end + + local count = worldedit.set_param2(worldedit.pos1[name], worldedit.pos2[name], param2) + worldedit.player_notify(name, count .. " nodes altered") + end, check_region), +}) + minetest.register_chatcommand("/mix", { params = " ...", description = "Fill the current WorldEdit region with a random mix of , ...", @@ -390,6 +495,45 @@ minetest.register_chatcommand("/replaceinverse", { end, check_replace), }) +local check_cube = function(name, param) + if worldedit.pos1[name] == nil then + worldedit.player_notify(name, "no position 1 selected") + return nil + end + local found, _, w, h, l, 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 tonumber(w) * tonumber(h) * tonumber(l) +end + +minetest.register_chatcommand("/hollowcube", { + params = " ", + description = "Add a hollow cube with its ground level centered at WorldEdit position 1 with dimensions x x , composed of .", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local found, _, w, h, l, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$") + local node = get_node(name, nodename) + local count = worldedit.cube(worldedit.pos1[name], tonumber(w), tonumber(h), tonumber(l), node, true) + worldedit.player_notify(name, count .. " nodes added") + end, check_cube), +}) + +minetest.register_chatcommand("/cube", { + params = " ", + description = "Add a cube with its ground level centered at WorldEdit position 1 with dimensions x x , composed of .", + privs = {worldedit=true}, + func = safe_region(function(name, param) + local found, _, w, h, l, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$") + local node = get_node(name, nodename) + local count = worldedit.cube(worldedit.pos1[name], tonumber(w), tonumber(h), tonumber(l), node) + worldedit.player_notify(name, count .. " nodes added") + end, check_cube), +}) + local check_sphere = function(name, param) if worldedit.pos1[name] == nil then worldedit.player_notify(name, "no position 1 selected") @@ -473,46 +617,65 @@ local check_cylinder = function(name, param) 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+(.+)$") + -- two radii + local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$") + if found == nil then + -- single radius + found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + radius2 = radius1 + end 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)) + local radius = math.max(tonumber(radius1), tonumber(radius2)) + return math.ceil(math.pi * (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 ", + params = "x/y/z/? [radius2] ", + description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length , base radius (and top radius [radius2]), composed of ", privs = {worldedit=true}, func = safe_region(function(name, param) - local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + -- two radii + local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$") + if found == nil then + -- single radius + found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + radius2 = radius1 + end length = tonumber(length) if axis == "?" then axis, sign = worldedit.player_axis(name) length = length * sign end local node = get_node(name, nodename) - local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius), node, true) + local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius1), tonumber(radius2), node, true) worldedit.player_notify(name, count .. " nodes added") 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 ", + params = "x/y/z/? [radius2] ", + description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length , base radius (and top radius [radius2]), composed of ", privs = {worldedit=true}, func = safe_region(function(name, param) - local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + -- two radii + local found, _, axis, length, radius1, radius2, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(%d+)%s+(.+)$") + if found == nil then + -- single radius + found, _, axis, length, radius1, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+(.+)$") + radius2 = radius1 + end length = tonumber(length) if axis == "?" then axis, sign = worldedit.player_axis(name) length = length * sign end local node = get_node(name, nodename) - local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius), node) + local count = worldedit.cylinder(worldedit.pos1[name], axis, length, tonumber(radius1), tonumber(radius2), node) worldedit.player_notify(name, count .. " nodes added") end, check_cylinder), }) @@ -1058,16 +1221,13 @@ minetest.register_chatcommand("/lua", { description = "Executes as a Lua chunk in the global namespace", privs = {worldedit=true, server=true}, func = function(name, param) - 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") - return - end local err = worldedit.lua(param) if err then worldedit.player_notify(name, "code error: " .. err) + minetest.log("action", name.." tried to execute "..param) else worldedit.player_notify(name, "code successfully executed", false) + minetest.log("action", name.." executed "..param) end end, }) @@ -1077,17 +1237,13 @@ minetest.register_chatcommand("/luatransform", { 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) - 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") - return - end - local err = worldedit.luatransform(worldedit.pos1[name], worldedit.pos2[name], param) if err then worldedit.player_notify(name, "code error: " .. err, false) + minetest.log("action", name.." tried to execute luatransform "..param) else worldedit.player_notify(name, "code successfully executed", false) + minetest.log("action", name.." executed luatransform "..param) end end), })