]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - builtin/game/chatcommands.lua
Fix core.download_file() creating empty files on HTTP error
[dragonfireclient.git] / builtin / game / chatcommands.lua
index 3dfc29ffa6010e08137ae954b1ab8a95c4516e11..60d5d4788bf19497752a5ee6aeab04a2fe260e82 100644 (file)
@@ -41,7 +41,7 @@ end)
 
 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
 
@@ -71,7 +71,7 @@ end
 --
 core.register_chatcommand("me", {
        params = "<action>",
-       description = "Display chat action (e.g., '/me orders a pizza' displays"
+       description = "Show chat action (e.g., '/me orders a pizza' displays"
                        .. " '<player name> orders a pizza')",
        privs = {shout=true},
        func = function(name, param)
@@ -82,9 +82,9 @@ core.register_chatcommand("me", {
 core.register_chatcommand("admin", {
        description = "Show the name of the server owner",
        func = function(name)
-               local admin = minetest.settings: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
@@ -92,19 +92,47 @@ core.register_chatcommand("admin", {
 })
 
 core.register_chatcommand("privs", {
-       params = "<name>",
-       description = "Print privileges of player",
+       params = "[<name>]",
+       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 = "<privilege>",
+       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
@@ -132,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
@@ -145,8 +176,8 @@ local function handle_grant_command(caller, grantname, grantprivstr)
 end
 
 core.register_chatcommand("grant", {
-       params = "<name> <privilege>|all",
-       description = "Give privilege to player",
+       params = "<name> (<privilege> | all)",
+       description = "Give privileges to player",
        func = function(name, param)
                local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
                if not grantname or not grantprivstr then
@@ -157,7 +188,7 @@ core.register_chatcommand("grant", {
 })
 
 core.register_chatcommand("grantme", {
-       params = "<privilege>|all",
+       params = "<privilege> | all",
        description = "Grant privileges to yourself",
        func = function(name, param)
                if param == "" then
@@ -168,8 +199,8 @@ core.register_chatcommand("grantme", {
 })
 
 core.register_chatcommand("revoke", {
-       params = "<name> <privilege>|all",
-       description = "Remove privilege from player",
+       params = "<name> (<privilege> | all)",
+       description = "Remove privileges from player",
        privs = {},
        func = function(name, param)
                if not core.check_player_privs(name, {privs=true}) and
@@ -193,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, ', ')
@@ -254,7 +291,7 @@ core.register_chatcommand("setpassword", {
 
 core.register_chatcommand("clearpassword", {
        params = "<name>",
-       description = "Set empty password",
+       description = "Set empty password for a player",
        privs = {password=true},
        func = function(name, param)
                local toname = param
@@ -281,7 +318,7 @@ core.register_chatcommand("auth_reload", {
 
 core.register_chatcommand("remove_player", {
        params = "<name>",
-       description = "Remove player data",
+       description = "Remove a player's data",
        privs = {server=true},
        func = function(name, param)
                local toname = param
@@ -305,8 +342,8 @@ core.register_chatcommand("remove_player", {
 })
 
 core.register_chatcommand("teleport", {
-       params = "<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>",
-       description = "Teleport to player or position",
+       params = "<X>,<Y>,<Z> | <to_name> | (<name> <X>,<Y>,<Z>) | (<name> <to_name>)",
+       description = "Teleport to position or player",
        privs = {teleport=true},
        func = function(name, param)
                -- Returns (pos, true) if found, otherwise (pos, false)
@@ -343,7 +380,7 @@ core.register_chatcommand("teleport", {
                        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
@@ -356,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
@@ -380,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
@@ -396,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)
@@ -413,7 +450,7 @@ core.register_chatcommand("teleport", {
 })
 
 core.register_chatcommand("set", {
-       params = "[-n] <name> <value> | <name>",
+       params = "([-n] <name> <value>) | <name>",
        description = "Set or read server configuration setting",
        privs = {server=true},
        func = function(name, param)
@@ -468,9 +505,9 @@ local function emergeblocks_progress_update(ctx)
 end
 
 core.register_chatcommand("emergeblocks", {
-       params = "(here [radius]) | (<pos1> <pos2>)",
+       params = "(here [<radius>]) | (<pos1> <pos2>)",
        description = "Load (or, if nonexistent, generate) map blocks "
-               .. "contained in area pos1 to pos2",
+               .. "contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)",
        privs = {server=true},
        func = function(name, param)
                local p1, p2 = parse_range_str(name, param)
@@ -494,8 +531,9 @@ core.register_chatcommand("emergeblocks", {
 })
 
 core.register_chatcommand("deleteblocks", {
-       params = "(here [radius]) | (<pos1> <pos2>)",
-       description = "Delete map blocks contained in area pos1 to pos2",
+       params = "(here [<radius>]) | (<pos1> <pos2>)",
+       description = "Delete map blocks contained in area pos1 to pos2 "
+               .. "(<pos1> and <pos2> must be in parentheses)",
        privs = {server=true},
        func = function(name, param)
                local p1, p2 = parse_range_str(name, param)
@@ -513,8 +551,9 @@ core.register_chatcommand("deleteblocks", {
 })
 
 core.register_chatcommand("fixlight", {
-       params = "(here [radius]) | (<pos1> <pos2>)",
-       description = "Resets lighting in the area between pos1 and pos2",
+       params = "(here [<radius>]) | (<pos1> <pos2>)",
+       description = "Resets lighting in the area between pos1 and pos2 "
+               .. "(<pos1> and <pos2> must be in parentheses)",
        privs = {server = true},
        func = function(name, param)
                local p1, p2 = parse_range_str(name, param)
@@ -546,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
@@ -566,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 = "<name> <ItemString>",
+       params = "<name> <ItemString> [<count> [<wear>]]",
        description = "Give item to player",
        privs = {give=true},
        func = function(name, param)
@@ -590,7 +632,7 @@ core.register_chatcommand("give", {
 })
 
 core.register_chatcommand("giveme", {
-       params = "<ItemString>",
+       params = "<ItemString> [<count> [<wear>]]",
        description = "Give item to yourself",
        privs = {give=true},
        func = function(name, param)
@@ -618,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
@@ -641,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,
 })
@@ -653,15 +701,15 @@ 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 = "[<range>] [<seconds>] [limit]",
+       params = "[<range>] [<seconds>] [<limit>]",
        description = "Check who last touched a node or a node near it"
                        .. " within the time specified by <seconds>. Default: range = 0,"
                        .. " seconds = 86400 = 24h, limit = 5",
@@ -714,7 +762,7 @@ core.register_chatcommand("rollback_check", {
 })
 
 core.register_chatcommand("rollback", {
-       params = "<player name> [<seconds>] | :<actor> [<seconds>]",
+       params = "(<name> [<seconds>]) | (:<actor> [<seconds>])",
        description = "Revert actions of a player. Default for <seconds> is 60",
        privs = {rollback=true},
        func = function(name, param)
@@ -752,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
@@ -799,24 +851,26 @@ 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 = "[delay_in_seconds (non-negative number, or -1 to cancel)] [reconnect] [message]",
+       params = "[<delay_in_seconds> | -1] [reconnect] [<message>]",
+       description = "Shutdown server (-1 cancels a delayed shutdown)",
        privs = {server=true},
        func = function(name, param)
-               local delay, reconnect, message = param:match("([^ ][-]?[0-9]+)([^ ]+)(.*)")
-               message = message or ""
+               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 ~= "" then
-                       delay = tonumber(param) or 0
-               else
-                       delay = 0
+               if delay == 0 then
                        core.log("action", name .. " shuts down server")
                        core.chat_send_all("*** Server shutting down (operator request).")
                end
@@ -825,12 +879,17 @@ core.register_chatcommand("shutdown", {
 })
 
 core.register_chatcommand("ban", {
-       params = "<name>",
-       description = "Ban IP of player",
+       params = "[<name> | <IP_address>]",
+       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."
@@ -845,8 +904,8 @@ core.register_chatcommand("ban", {
 })
 
 core.register_chatcommand("unban", {
-       params = "<name/ip>",
-       description = "Remove IP ban",
+       params = "<name> | <IP_address>",
+       description = "Remove player ban",
        privs = {ban=true},
        func = function(name, param)
                if not core.unban_player_or_ip(param) then
@@ -858,7 +917,7 @@ core.register_chatcommand("unban", {
 })
 
 core.register_chatcommand("kick", {
-       params = "<name> [reason]",
+       params = "<name> [<reason>]",
        description = "Kick a player",
        privs = {kick=true},
        func = function(name, param)
@@ -877,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
@@ -923,8 +982,8 @@ core.register_chatcommand("msg", {
 })
 
 core.register_chatcommand("last-login", {
-       params = "[name]",
-       description = "Get the last login time of a player",
+       params = "[<name>]",
+       description = "Get the last login time of a player or yourself",
        func = function(name, param)
                if param == "" then
                        param = name
@@ -940,14 +999,14 @@ core.register_chatcommand("last-login", {
 })
 
 core.register_chatcommand("clearinv", {
-       params = "[name]",
+       params = "[<name>]",
        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 run this command (missing privilege: server)"
+                                               .. " 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.")
@@ -966,3 +1025,34 @@ core.register_chatcommand("clearinv", {
                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 = "[<name>]",
+       description = "Kill player or yourself",
+       privs = {server=true},
+       func = function(name, param)
+               return handle_kill_command(name, param == "" and name or param)
+       end,
+})