X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=builtin%2Fgame%2Fchatcommands.lua;h=60d5d4788bf19497752a5ee6aeab04a2fe260e82;hb=3ad9a8f3a978b41a88ebf8a88690ad658cd132c7;hp=745b012e6f03be15bcd7af59bef960c3387afcf5;hpb=d7bc346981e189851e490f2417ed015a38bca79b;p=minetest.git diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua index 745b012e6..60d5d4788 100644 --- a/builtin/game/chatcommands.lua +++ b/builtin/game/chatcommands.lua @@ -7,13 +7,22 @@ core.chatcommands = core.registered_chatcommands -- BACKWARDS COMPATIBILITY core.register_on_chat_message(function(name, message) + if message:sub(1,1) ~= "/" then + return + end + local cmd, param = string.match(message, "^/([^ ]+) *(.*)") - if not param then - param = "" + if not cmd then + core.chat_send_player(name, "-!- Empty command") + return true end + + param = param or "" + local cmd_def = core.registered_chatcommands[cmd] if not cmd_def then - return false + core.chat_send_player(name, "-!- Invalid command: " .. cmd) + return true end local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs) if has_privs then @@ -30,9 +39,9 @@ core.register_on_chat_message(function(name, message) return true -- Handled chat message end) -if core.setting_getbool("profiler.load") then +if core.settings:get_bool("profiler.load") then -- Run after register_chatcommand and its register_on_chat_message - -- Before any chattcommands that should be profiled + -- Before any chatcommands that should be profiled profiler.init_chatcommand() end @@ -62,7 +71,7 @@ end -- core.register_chatcommand("me", { params = "", - description = "Display chat action (e.g., '/me orders a pizza' displays" + description = "Show chat action (e.g., '/me orders a pizza' displays" .. " ' orders a pizza')", privs = {shout=true}, func = function(name, param) @@ -73,84 +82,57 @@ core.register_chatcommand("me", { core.register_chatcommand("admin", { description = "Show the name of the server owner", func = function(name) - local admin = minetest.setting_get("name") + local admin = core.settings:get("name") if admin then - return true, "The administrator of this server is "..admin.."." + return true, "The administrator of this server is " .. admin .. "." else return false, "There's no administrator named in the config file." end end, }) -core.register_chatcommand("help", { - privs = {}, - params = "[all/privs/]", - description = "Get help for commands or list privileges", - func = function(name, param) - local function format_help_line(cmd, def) - local msg = core.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 param == "" then - local msg = "" - local cmds = {} - for cmd, def in pairs(core.registered_chatcommands) do - if core.check_player_privs(name, def.privs) then - cmds[#cmds + 1] = cmd - 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(core.registered_chatcommands) do - if core.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") - elseif param == "privs" then - local privs = {} - for priv, def in pairs(core.registered_privileges) do - privs[#privs + 1] = priv .. ": " .. def.description - end - table.sort(privs) - return true, "Available privileges:\n"..table.concat(privs, "\n") - else - local cmd = param - local def = core.registered_chatcommands[cmd] - if not def then - return false, "Command not available: "..cmd - else - return true, format_help_line(cmd, def) - end - end - end, -}) - core.register_chatcommand("privs", { - params = "", - description = "Print privileges of player", + params = "[]", + description = "Show privileges of yourself or another player", func = function(caller, param) param = param:trim() local name = (param ~= "" and param or caller) + if not core.player_exists(name) then + return false, "Player " .. name .. " does not exist." + end return true, "Privileges of " .. name .. ": " .. core.privs_to_string( core.get_player_privs(name), ' ') end, }) +core.register_chatcommand("haspriv", { + params = "", + description = "Return list of all online players with privilege.", + privs = {basic_privs = true}, + func = function(caller, param) + param = param:trim() + if param == "" then + return false, "Invalid parameters (see /help haspriv)" + end + if not core.registered_privileges[param] then + return false, "Unknown privilege!" + end + local privs = core.string_to_privs(param) + local players_with_priv = {} + for _, player in pairs(core.get_connected_players()) do + local player_name = player:get_player_name() + if core.check_player_privs(player_name, privs) then + table.insert(players_with_priv, player_name) + end + end + return true, "Players online with the \"" .. param .. "\" privilege: " .. + table.concat(players_with_priv, ", ") + end +}) + local function handle_grant_command(caller, grantname, grantprivstr) - local caller_privs = minetest.get_player_privs(caller) + local caller_privs = core.get_player_privs(caller) if not (caller_privs.privs or caller_privs.basic_privs) then return false, "Your privileges are insufficient." end @@ -165,7 +147,7 @@ local function handle_grant_command(caller, grantname, grantprivstr) local privs = core.get_player_privs(grantname) local privs_unknown = "" local basic_privs = - core.string_to_privs(core.setting_get("basic_privs") or "interact,shout") + core.string_to_privs(core.settings:get("basic_privs") or "interact,shout") for priv, _ in pairs(grantprivs) do if not basic_privs[priv] and not caller_privs.privs then return false, "Your privileges are insufficient." @@ -178,6 +160,9 @@ local function handle_grant_command(caller, grantname, grantprivstr) if privs_unknown ~= "" then return false, privs_unknown end + for priv, _ in pairs(grantprivs) do + core.run_priv_callbacks(grantname, priv, caller, "grant") + end core.set_player_privs(grantname, privs) core.log("action", caller..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname) if grantname ~= caller then @@ -191,8 +176,8 @@ local function handle_grant_command(caller, grantname, grantprivstr) end core.register_chatcommand("grant", { - params = " |all", - description = "Give privilege to player", + params = " ( | all)", + description = "Give privileges to player", func = function(name, param) local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)") if not grantname or not grantprivstr then @@ -203,7 +188,7 @@ core.register_chatcommand("grant", { }) core.register_chatcommand("grantme", { - params = "|all", + params = " | all", description = "Grant privileges to yourself", func = function(name, param) if param == "" then @@ -214,8 +199,8 @@ core.register_chatcommand("grantme", { }) core.register_chatcommand("revoke", { - params = " |all", - description = "Remove privilege from player", + params = " ( | all)", + description = "Remove privileges from player", privs = {}, func = function(name, param) if not core.check_player_privs(name, {privs=true}) and @@ -231,7 +216,7 @@ core.register_chatcommand("revoke", { local revoke_privs = core.string_to_privs(revoke_priv_str) local privs = core.get_player_privs(revoke_name) local basic_privs = - core.string_to_privs(core.setting_get("basic_privs") or "interact,shout") + core.string_to_privs(core.settings:get("basic_privs") or "interact,shout") for priv, _ in pairs(revoke_privs) do if not basic_privs[priv] and not core.check_player_privs(name, {privs=true}) then @@ -239,12 +224,18 @@ core.register_chatcommand("revoke", { end end if revoke_priv_str == "all" then + revoke_privs = privs privs = {} else for priv, _ in pairs(revoke_privs) do privs[priv] = nil end end + + for priv, _ in pairs(revoke_privs) do + core.run_priv_callbacks(revoke_name, priv, name, "revoke") + end + core.set_player_privs(revoke_name, privs) core.log("action", name..' revoked (' ..core.privs_to_string(revoke_privs, ', ') @@ -300,7 +291,7 @@ core.register_chatcommand("setpassword", { core.register_chatcommand("clearpassword", { params = "", - description = "Set empty password", + description = "Set empty password for a player", privs = {password=true}, func = function(name, param) local toname = param @@ -325,9 +316,34 @@ core.register_chatcommand("auth_reload", { end, }) +core.register_chatcommand("remove_player", { + params = "", + description = "Remove a player's data", + privs = {server=true}, + func = function(name, param) + local toname = param + if toname == "" then + return false, "Name field required" + end + + local rc = core.remove_player(toname) + + if rc == 0 then + core.log("action", name .. " removed player data of " .. toname .. ".") + return true, "Player \"" .. toname .. "\" removed." + elseif rc == 1 then + return true, "No such player \"" .. toname .. "\" to remove." + elseif rc == 2 then + return true, "Player \"" .. toname .. "\" is connected, cannot remove." + end + + return false, "Unhandled remove_player return code " .. rc .. "" + end, +}) + core.register_chatcommand("teleport", { - params = ",, | | ,, | ", - description = "Teleport to player or position", + params = ",, | | ( ,,) | ( )", + description = "Teleport to position or player", privs = {teleport=true}, func = function(name, param) -- Returns (pos, true) if found, otherwise (pos, false) @@ -358,13 +374,13 @@ core.register_chatcommand("teleport", { p.y = tonumber(p.y) p.z = tonumber(p.z) if p.x and p.y and p.z then - local lm = tonumber(minetest.setting_get("map_generation_limit") or 31000) + local lm = 31000 if p.x < -lm or p.x > lm or p.y < -lm or p.y > lm or p.z < -lm or p.z > lm then return false, "Cannot teleport out of map bounds!" end teleportee = core.get_player_by_name(name) if teleportee then - teleportee:setpos(p) + teleportee:set_pos(p) return true, "Teleporting to "..core.pos_to_string(p) end end @@ -377,12 +393,12 @@ core.register_chatcommand("teleport", { if target_name then local target = core.get_player_by_name(target_name) if target then - p = target:getpos() + p = target:get_pos() end end if teleportee and p then p = find_free_position_near(p) - teleportee:setpos(p) + teleportee:set_pos(p) return true, "Teleporting to " .. target_name .. " at "..core.pos_to_string(p) end @@ -401,7 +417,7 @@ core.register_chatcommand("teleport", { teleportee = core.get_player_by_name(teleportee_name) end if teleportee and p.x and p.y and p.z then - teleportee:setpos(p) + teleportee:set_pos(p) return true, "Teleporting " .. teleportee_name .. " to " .. core.pos_to_string(p) end @@ -417,12 +433,12 @@ core.register_chatcommand("teleport", { if target_name then local target = core.get_player_by_name(target_name) if target then - p = target:getpos() + p = target:get_pos() end end if teleportee and p then p = find_free_position_near(p) - teleportee:setpos(p) + teleportee:set_pos(p) return true, "Teleporting " .. teleportee_name .. " to " .. target_name .. " at " .. core.pos_to_string(p) @@ -434,26 +450,26 @@ core.register_chatcommand("teleport", { }) core.register_chatcommand("set", { - params = "[-n] | ", + params = "([-n] ) | ", description = "Set or read server configuration setting", privs = {server=true}, func = function(name, param) local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)") if arg and arg == "-n" and setname and setvalue then - core.setting_set(setname, setvalue) + core.settings:set(setname, setvalue) return true, setname .. " = " .. setvalue end local setname, setvalue = string.match(param, "([^ ]+) (.+)") if setname and setvalue then - if not core.setting_get(setname) then + if not core.settings:get(setname) then return false, "Failed. Use '/set -n ' to create a new setting." end - core.setting_set(setname, setvalue) + core.settings:set(setname, setvalue) return true, setname .. " = " .. setvalue end local setname = string.match(param, "([^ ]+)") if setname then - local setvalue = core.setting_get(setname) + local setvalue = core.settings:get(setname) if not setvalue then setvalue = "" end @@ -489,9 +505,9 @@ local function emergeblocks_progress_update(ctx) end core.register_chatcommand("emergeblocks", { - params = "(here [radius]) | ( )", + params = "(here []) | ( )", description = "Load (or, if nonexistent, generate) map blocks " - .. "contained in area pos1 to pos2", + .. "contained in area pos1 to pos2 ( and must be in parentheses)", privs = {server=true}, func = function(name, param) local p1, p2 = parse_range_str(name, param) @@ -515,8 +531,9 @@ core.register_chatcommand("emergeblocks", { }) core.register_chatcommand("deleteblocks", { - params = "(here [radius]) | ( )", - description = "Delete map blocks contained in area pos1 to pos2", + params = "(here []) | ( )", + description = "Delete map blocks contained in area pos1 to pos2 " + .. "( and must be in parentheses)", privs = {server=true}, func = function(name, param) local p1, p2 = parse_range_str(name, param) @@ -533,6 +550,26 @@ core.register_chatcommand("deleteblocks", { end, }) +core.register_chatcommand("fixlight", { + params = "(here []) | ( )", + description = "Resets lighting in the area between pos1 and pos2 " + .. "( and must be in parentheses)", + privs = {server = true}, + func = function(name, param) + local p1, p2 = parse_range_str(name, param) + if p1 == false then + return false, p2 + end + + if core.fix_light(p1, p2) then + return true, "Successfully reset light in the area ranging from " .. + core.pos_to_string(p1, 1) .. " to " .. core.pos_to_string(p2, 1) + else + return false, "Failed to load one or more blocks in area" + end + end, +}) + core.register_chatcommand("mods", { params = "", description = "List mods installed on the server", @@ -548,8 +585,11 @@ local function handle_give_command(cmd, giver, receiver, stackstring) local itemstack = ItemStack(stackstring) if itemstack:is_empty() then return false, "Cannot give an empty item" - elseif not itemstack:is_known() then + elseif (not itemstack:is_known()) or (itemstack:get_name() == "unknown") then return false, "Cannot give an unknown item" + -- Forbid giving 'ignore' due to unwanted side effects + elseif itemstack:get_name() == "ignore" then + return false, "Giving 'ignore' is not allowed" end local receiverref = core.get_player_by_name(receiver) if receiverref == nil then @@ -568,18 +608,18 @@ local function handle_give_command(cmd, giver, receiver, stackstring) -- entered (e.g. big numbers are always interpreted as 2^16-1). stackstring = itemstack:to_string() if giver == receiver then - return true, ("%q %sadded to inventory.") - :format(stackstring, partiality) + local msg = "%q %sadded to inventory." + return true, msg:format(stackstring, partiality) else core.chat_send_player(receiver, ("%q %sadded to inventory.") :format(stackstring, partiality)) - return true, ("%q %sadded to %s's inventory.") - :format(stackstring, partiality, receiver) + local msg = "%q %sadded to %s's inventory." + return true, msg:format(stackstring, partiality, receiver) end end core.register_chatcommand("give", { - params = " ", + params = " [ []]", description = "Give item to player", privs = {give=true}, func = function(name, param) @@ -592,7 +632,7 @@ core.register_chatcommand("give", { }) core.register_chatcommand("giveme", { - params = "", + params = " [ []]", description = "Give item to yourself", privs = {give=true}, func = function(name, param) @@ -620,8 +660,11 @@ core.register_chatcommand("spawnentity", { core.log("error", "Unable to spawn entity, player is nil") return false, "Unable to spawn entity, player is nil" end + if not core.registered_entities[entityname] then + return false, "Cannot spawn an unknown entity" + end if p == "" then - p = player:getpos() + p = player:get_pos() else p = core.string_to_pos(p) if p == nil then @@ -643,10 +686,13 @@ core.register_chatcommand("pulverize", { core.log("error", "Unable to pulverize, no player.") return false, "Unable to pulverize, no player." end - if player:get_wielded_item():is_empty() then + local wielded_item = player:get_wielded_item() + if wielded_item:is_empty() then return false, "Unable to pulverize, no item in hand." end - player:set_wielded_item(nil) + core.log("action", name .. " pulverized \"" .. + wielded_item:get_name() .. " " .. wielded_item:get_count() .. "\"") + player:set_wielded_item(nil) return true, "An item was pulverized." end, }) @@ -655,21 +701,21 @@ core.register_chatcommand("pulverize", { core.rollback_punch_callbacks = {} core.register_on_punchnode(function(pos, node, puncher) - local name = puncher:get_player_name() - if core.rollback_punch_callbacks[name] then + local name = puncher and puncher:get_player_name() + if name and core.rollback_punch_callbacks[name] then core.rollback_punch_callbacks[name](pos, node, puncher) core.rollback_punch_callbacks[name] = nil end end) core.register_chatcommand("rollback_check", { - params = "[] [] [limit]", + params = "[] [] []", description = "Check who last touched a node or a node near it" .. " within the time specified by . Default: range = 0," .. " seconds = 86400 = 24h, limit = 5", privs = {rollback=true}, func = function(name, param) - if not core.setting_getbool("enable_rollback_recording") then + if not core.settings:get_bool("enable_rollback_recording") then return false, "Rollback functions are disabled." end local range, seconds, limit = @@ -716,11 +762,11 @@ core.register_chatcommand("rollback_check", { }) core.register_chatcommand("rollback", { - params = " [] | : []", + params = "( []) | (: [])", description = "Revert actions of a player. Default for is 60", privs = {rollback=true}, func = function(name, param) - if not core.setting_getbool("enable_rollback_recording") then + if not core.settings:get_bool("enable_rollback_recording") then return false, "Rollback functions are disabled." end local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)") @@ -754,15 +800,19 @@ core.register_chatcommand("rollback", { }) core.register_chatcommand("status", { - description = "Print server status", + description = "Show server status", func = function(name, param) - return true, core.get_server_status() + local status = core.get_server_status(name, false) + if status and status ~= "" then + return true, status + end + return false, "This command was disabled by a mod or game" end, }) core.register_chatcommand("time", { - params = "<0..23>:<0..59> | <0..24000>", - description = "Set time of day", + params = "[<0..23>:<0..59> | <0..24000>]", + description = "Show or set time of day", privs = {}, func = function(name, param) if param == "" then @@ -801,32 +851,45 @@ core.register_chatcommand("time", { }) core.register_chatcommand("days", { - description = "Display day count", + description = "Show day count since world creation", func = function(name, param) return true, "Current day is " .. core.get_day_count() end }) core.register_chatcommand("shutdown", { - description = "Shutdown server", - params = "[reconnect] [message]", + params = "[ | -1] [reconnect] []", + description = "Shutdown server (-1 cancels a delayed shutdown)", privs = {server=true}, func = function(name, param) - core.log("action", name .. " shuts down server") - core.chat_send_all("*** Server shutting down (operator request).") - local reconnect, message = param:match("([^ ]+)(.*)") - message = message or "" - core.request_shutdown(message:trim(), core.is_yes(reconnect)) + local delay, reconnect, message + delay, param = param:match("^%s*(%S+)(.*)") + if param then + reconnect, param = param:match("^%s*(%S+)(.*)") + end + message = param and param:match("^%s*(.+)") or "" + delay = tonumber(delay) or 0 + + if delay == 0 then + core.log("action", name .. " shuts down server") + core.chat_send_all("*** Server shutting down (operator request).") + end + core.request_shutdown(message:trim(), core.is_yes(reconnect), delay) end, }) core.register_chatcommand("ban", { - params = "", - description = "Ban IP of player", + params = "[ | ]", + description = "Ban player or show ban list", privs = {ban=true}, func = function(name, param) if param == "" then - return true, "Ban list: " .. core.get_ban_list() + local ban_list = core.get_ban_list() + if ban_list == "" then + return true, "The ban list is empty." + else + return true, "Ban list: " .. ban_list + end end if not core.get_player_by_name(param) then return false, "No such player." @@ -841,8 +904,8 @@ core.register_chatcommand("ban", { }) core.register_chatcommand("unban", { - params = "", - description = "Remove IP ban", + params = " | ", + description = "Remove player ban", privs = {ban=true}, func = function(name, param) if not core.unban_player_or_ip(param) then @@ -854,7 +917,7 @@ core.register_chatcommand("unban", { }) core.register_chatcommand("kick", { - params = " [reason]", + params = " []", description = "Kick a player", privs = {kick=true}, func = function(name, param) @@ -873,15 +936,15 @@ core.register_chatcommand("kick", { }) core.register_chatcommand("clearobjects", { - params = "[full|quick]", + params = "[full | quick]", description = "Clear all objects in world", privs = {server=true}, func = function(name, param) local options = {} - if param == "" or param == "full" then - options.mode = "full" - elseif param == "quick" then + if param == "" or param == "quick" then options.mode = "quick" + elseif param == "full" then + options.mode = "full" else return false, "Invalid usage, see /help clearobjects." end @@ -919,8 +982,8 @@ core.register_chatcommand("msg", { }) core.register_chatcommand("last-login", { - params = "[name]", - description = "Get the last login time of a player", + params = "[]", + description = "Get the last login time of a player or yourself", func = function(name, param) if param == "" then param = name @@ -934,3 +997,62 @@ core.register_chatcommand("last-login", { return false, "Last login time is unknown" end, }) + +core.register_chatcommand("clearinv", { + params = "[]", + description = "Clear the inventory of yourself or another player", + func = function(name, param) + local player + if param and param ~= "" and param ~= name then + if not core.check_player_privs(name, {server=true}) then + return false, "You don't have permission" + .. " to clear another player's inventory (missing privilege: server)" + end + player = core.get_player_by_name(param) + core.chat_send_player(param, name.." cleared your inventory.") + else + player = core.get_player_by_name(name) + end + + if player then + player:get_inventory():set_list("main", {}) + player:get_inventory():set_list("craft", {}) + player:get_inventory():set_list("craftpreview", {}) + core.log("action", name.." clears "..player:get_player_name().."'s inventory") + return true, "Cleared "..player:get_player_name().."'s inventory." + else + return false, "Player must be online to clear inventory!" + end + end, +}) + +local function handle_kill_command(killer, victim) + if core.settings:get_bool("enable_damage") == false then + return false, "Players can't be killed, damage has been disabled." + end + local victimref = core.get_player_by_name(victim) + if victimref == nil then + return false, string.format("Player %s is not online.", victim) + elseif victimref:get_hp() <= 0 then + if killer == victim then + return false, "You are already dead." + else + return false, string.format("%s is already dead.", victim) + end + end + if not killer == victim then + core.log("action", string.format("%s killed %s", killer, victim)) + end + -- Kill victim + victimref:set_hp(0) + return true, string.format("%s has been killed.", victim) +end + +core.register_chatcommand("kill", { + params = "[]", + description = "Kill player or yourself", + privs = {server=true}, + func = function(name, param) + return handle_kill_command(name, param == "" and name or param) + end, +})