]> git.lizzy.rs Git - minetest.git/blobdiff - builtin/game/chatcommands.lua
Builtin: Forward old return values
[minetest.git] / builtin / game / chatcommands.lua
index 0b197664081bae00a22916eb40c88be1f3c81482..60d5d4788bf19497752a5ee6aeab04a2fe260e82 100644 (file)
@@ -1,40 +1,28 @@
--- Minetest: builtin/chatcommands.lua
+-- Minetest: builtin/game/chatcommands.lua
 
 --
 -- Chat command handler
 --
 
 
 --
 -- Chat command handler
 --
 
-core.chatcommands = {}
-function core.register_chatcommand(cmd, def)
-       def = def or {}
-       def.params = def.params or ""
-       def.description = def.description or ""
-       def.privs = def.privs or {}
-       def.mod_origin = core.get_current_modname() or "??"
-       core.chatcommands[cmd] = def
-end
-
-if core.setting_getbool("mod_profiling") then
-       local tracefct = profiling_print_log
-       profiling_print_log = nil
-       core.register_chatcommand("save_mod_profile",
-                       {
-                               params      = "",
-                               description = "save mod profiling data to logfile " ..
-                                               "(depends on default loglevel)",
-                               func        = tracefct,
-                               privs       = { server=true }
-                       })
-end
+core.chatcommands = core.registered_chatcommands -- BACKWARDS COMPATIBILITY
 
 core.register_on_chat_message(function(name, message)
 
 core.register_on_chat_message(function(name, message)
+       if message:sub(1,1) ~= "/" then
+               return
+       end
+
        local cmd, param = string.match(message, "^/([^ ]+) *(.*)")
        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
        end
-       local cmd_def = core.chatcommands[cmd]
+
+       param = param or ""
+
+       local cmd_def = core.registered_chatcommands[cmd]
        if not cmd_def then
        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
        end
        local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs)
        if has_privs then
@@ -51,6 +39,12 @@ core.register_on_chat_message(function(name, message)
        return true  -- Handled chat message
 end)
 
        return true  -- Handled chat message
 end)
 
+if core.settings:get_bool("profiler.load") then
+       -- Run after register_chatcommand and its register_on_chat_message
+       -- Before any chatcommands that should be profiled
+       profiler.init_chatcommand()
+end
+
 -- Parses a "range" string in the format of "here (number)" or
 -- "(x1, y1, z1) (x2, y2, z2)", returning two position vectors
 local function parse_range_str(player_name, str)
 -- Parses a "range" string in the format of "here (number)" or
 -- "(x1, y1, z1) (x2, y2, z2)", returning two position vectors
 local function parse_range_str(player_name, str)
@@ -77,7 +71,8 @@ end
 --
 core.register_chatcommand("me", {
        params = "<action>",
 --
 core.register_chatcommand("me", {
        params = "<action>",
-       description = "chat action (eg. /me orders a pizza)",
+       description = "Show chat action (e.g., '/me orders a pizza' displays"
+                       .. " '<player name> orders a pizza')",
        privs = {shout=true},
        func = function(name, param)
                core.chat_send_all("* " .. name .. " " .. param)
        privs = {shout=true},
        func = function(name, param)
                core.chat_send_all("* " .. name .. " " .. param)
@@ -87,128 +82,125 @@ core.register_chatcommand("me", {
 core.register_chatcommand("admin", {
        description = "Show the name of the server owner",
        func = function(name)
 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
                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,
 })
 
                else
                        return false, "There's no administrator named in the config file."
                end
        end,
 })
 
-core.register_chatcommand("help", {
-       privs = {},
-       params = "[all/privs/<cmd>]",
-       description = "Get help for commands or list privileges",
-       func = function(name, param)
-               local function format_help_line(cmd, def)
-                       local msg = "/"..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.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 <cmd>' to get more information,"
-                                       .. " or '/help all' to list everything."
-               elseif param == "all" then
-                       local cmds = {}
-                       for cmd, def in pairs(core.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.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", {
 core.register_chatcommand("privs", {
-       params = "<name>",
-       description = "print out privileges of player",
-       func = function(name, param)
-               param = (param ~= "" and param or name)
-               return true, "Privileges of " .. param .. ": "
+       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.privs_to_string(
-                               core.get_player_privs(param), ' ')
+                               core.get_player_privs(name), ' ')
        end,
 })
        end,
 })
-core.register_chatcommand("grant", {
-       params = "<name> <privilege>|all",
-       description = "Give privilege to player",
-       func = function(name, param)
-               if not core.check_player_privs(name, {privs=true}) and
-                               not core.check_player_privs(name, {basic_privs=true}) then
+
+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 = core.get_player_privs(caller)
+       if not (caller_privs.privs or caller_privs.basic_privs) then
+               return false, "Your privileges are insufficient."
+       end
+
+       if not core.get_auth_handler().get_auth(grantname) then
+               return false, "Player " .. grantname .. " does not exist."
+       end
+       local grantprivs = core.string_to_privs(grantprivstr)
+       if grantprivstr == "all" then
+               grantprivs = core.registered_privileges
+       end
+       local privs = core.get_player_privs(grantname)
+       local privs_unknown = ""
+       local basic_privs =
+               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."
                end
                        return false, "Your privileges are insufficient."
                end
+               if not core.registered_privileges[priv] then
+                       privs_unknown = privs_unknown .. "Unknown privilege: " .. priv .. "\n"
+               end
+               privs[priv] = true
+       end
+       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
+               core.chat_send_player(grantname, caller
+                               .. " granted you privileges: "
+                               .. core.privs_to_string(grantprivs, ' '))
+       end
+       return true, "Privileges of " .. grantname .. ": "
+               .. core.privs_to_string(
+                       core.get_player_privs(grantname), ' ')
+end
+
+core.register_chatcommand("grant", {
+       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
                        return false, "Invalid parameters (see /help grant)"
                local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
                if not grantname or not grantprivstr then
                        return false, "Invalid parameters (see /help grant)"
-               elseif not core.auth_table[grantname] then
-                       return false, "Player " .. grantname .. " does not exist."
-               end
-               local grantprivs = core.string_to_privs(grantprivstr)
-               if grantprivstr == "all" then
-                       grantprivs = core.registered_privileges
-               end
-               local privs = core.get_player_privs(grantname)
-               local privs_unknown = ""
-               for priv, _ in pairs(grantprivs) do
-                       if priv ~= "interact" and priv ~= "shout" and
-                                       not core.check_player_privs(name, {privs=true}) then
-                               return false, "Your privileges are insufficient."
-                       end
-                       if not core.registered_privileges[priv] then
-                               privs_unknown = privs_unknown .. "Unknown privilege: " .. priv .. "\n"
-                       end
-                       privs[priv] = true
                end
                end
-               if privs_unknown ~= "" then
-                       return false, privs_unknown
-               end
-               core.set_player_privs(grantname, privs)
-               core.log("action", name..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
-               if grantname ~= name then
-                       core.chat_send_player(grantname, name
-                                       .. " granted you privileges: "
-                                       .. core.privs_to_string(grantprivs, ' '))
+               return handle_grant_command(name, grantname, grantprivstr)
+       end,
+})
+
+core.register_chatcommand("grantme", {
+       params = "<privilege> | all",
+       description = "Grant privileges to yourself",
+       func = function(name, param)
+               if param == "" then
+                       return false, "Invalid parameters (see /help grantme)"
                end
                end
-               return true, "Privileges of " .. grantname .. ": "
-                       .. core.privs_to_string(
-                               core.get_player_privs(grantname), ' ')
+               return handle_grant_command(name, name, param)
        end,
 })
        end,
 })
+
 core.register_chatcommand("revoke", {
 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
        privs = {},
        func = function(name, param)
                if not core.check_player_privs(name, {privs=true}) and
@@ -218,24 +210,32 @@ core.register_chatcommand("revoke", {
                local revoke_name, revoke_priv_str = string.match(param, "([^ ]+) (.+)")
                if not revoke_name or not revoke_priv_str then
                        return false, "Invalid parameters (see /help revoke)"
                local revoke_name, revoke_priv_str = string.match(param, "([^ ]+) (.+)")
                if not revoke_name or not revoke_priv_str then
                        return false, "Invalid parameters (see /help revoke)"
-               elseif not core.auth_table[revoke_name] then
+               elseif not core.get_auth_handler().get_auth(revoke_name) then
                        return false, "Player " .. revoke_name .. " does not exist."
                end
                local revoke_privs = core.string_to_privs(revoke_priv_str)
                local privs = core.get_player_privs(revoke_name)
                        return false, "Player " .. revoke_name .. " does not exist."
                end
                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.settings:get("basic_privs") or "interact,shout")
                for priv, _ in pairs(revoke_privs) do
                for priv, _ in pairs(revoke_privs) do
-                       if priv ~= "interact" and priv ~= "shout" and
+                       if not basic_privs[priv] and
                                        not core.check_player_privs(name, {privs=true}) then
                                return false, "Your privileges are insufficient."
                        end
                end
                if revoke_priv_str == "all" then
                                        not core.check_player_privs(name, {privs=true}) then
                                return false, "Your privileges are insufficient."
                        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
                        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, ', ')
                core.set_player_privs(revoke_name, privs)
                core.log("action", name..' revoked ('
                                ..core.privs_to_string(revoke_privs, ', ')
@@ -253,7 +253,7 @@ core.register_chatcommand("revoke", {
 
 core.register_chatcommand("setpassword", {
        params = "<name> <password>",
 
 core.register_chatcommand("setpassword", {
        params = "<name> <password>",
-       description = "set given password",
+       description = "Set player's password",
        privs = {password=true},
        func = function(name, param)
                local toname, raw_password = string.match(param, "^([^ ]+) +(.+)$")
        privs = {password=true},
        func = function(name, param)
                local toname, raw_password = string.match(param, "^([^ ]+) +(.+)$")
@@ -291,7 +291,7 @@ core.register_chatcommand("setpassword", {
 
 core.register_chatcommand("clearpassword", {
        params = "<name>",
 
 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
        privs = {password=true},
        func = function(name, param)
                local toname = param
@@ -308,7 +308,7 @@ core.register_chatcommand("clearpassword", {
 
 core.register_chatcommand("auth_reload", {
        params = "",
 
 core.register_chatcommand("auth_reload", {
        params = "",
-       description = "reload authentication data",
+       description = "Reload authentication data",
        privs = {server=true},
        func = function(name, param)
                local done = core.auth_reload()
        privs = {server=true},
        func = function(name, param)
                local done = core.auth_reload()
@@ -316,9 +316,34 @@ core.register_chatcommand("auth_reload", {
        end,
 })
 
        end,
 })
 
+core.register_chatcommand("remove_player", {
+       params = "<name>",
+       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", {
 core.register_chatcommand("teleport", {
-       params = "<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>",
-       description = "teleport to given 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)
        privs = {teleport=true},
        func = function(name, param)
                -- Returns (pos, true) if found, otherwise (pos, false)
@@ -348,10 +373,16 @@ core.register_chatcommand("teleport", {
                p.x = tonumber(p.x)
                p.y = tonumber(p.y)
                p.z = tonumber(p.z)
                p.x = tonumber(p.x)
                p.y = tonumber(p.y)
                p.z = tonumber(p.z)
-               teleportee = core.get_player_by_name(name)
-               if teleportee and p.x and p.y and p.z then
-                       teleportee:setpos(p)
-                       return true, "Teleporting to "..core.pos_to_string(p)
+               if p.x and p.y and p.z then
+                       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:set_pos(p)
+                               return true, "Teleporting to "..core.pos_to_string(p)
+                       end
                end
 
                local teleportee = nil
                end
 
                local teleportee = nil
@@ -362,12 +393,12 @@ core.register_chatcommand("teleport", {
                if target_name then
                        local target = core.get_player_by_name(target_name)
                        if target then
                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)
                        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
                        return true, "Teleporting to " .. target_name
                                        .. " at "..core.pos_to_string(p)
                end
@@ -386,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 = 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
                        return true, "Teleporting " .. teleportee_name
                                        .. " to " .. core.pos_to_string(p)
                end
@@ -402,12 +433,12 @@ core.register_chatcommand("teleport", {
                if target_name then
                        local target = core.get_player_by_name(target_name)
                        if target then
                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)
                        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)
                        return true, "Teleporting " .. teleportee_name
                                        .. " to " .. target_name
                                        .. " at " .. core.pos_to_string(p)
@@ -419,26 +450,26 @@ core.register_chatcommand("teleport", {
 })
 
 core.register_chatcommand("set", {
 })
 
 core.register_chatcommand("set", {
-       params = "[-n] <name> <value> | <name>",
-       description = "set or read server configuration setting",
+       params = "([-n] <name> <value>) | <name>",
+       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
        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
                        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 <name> <value>' to create a new setting."
                        end
                                return false, "Failed. Use '/set -n <name> <value>' 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
                        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 = "<not set>"
                        end
                        if not setvalue then
                                setvalue = "<not set>"
                        end
@@ -474,9 +505,9 @@ local function emergeblocks_progress_update(ctx)
 end
 
 core.register_chatcommand("emergeblocks", {
 end
 
 core.register_chatcommand("emergeblocks", {
-       params = "(here [radius]) | (<pos1> <pos2>)",
-       description = "starts loading (or generating, if inexistent) map blocks "
-               .. "contained in area pos1 to pos2",
+       params = "(here [<radius>]) | (<pos1> <pos2>)",
+       description = "Load (or, if nonexistent, generate) 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)
        privs = {server=true},
        func = function(name, param)
                local p1, p2 = parse_range_str(name, param)
@@ -500,8 +531,9 @@ core.register_chatcommand("emergeblocks", {
 })
 
 core.register_chatcommand("deleteblocks", {
 })
 
 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)
        privs = {server=true},
        func = function(name, param)
                local p1, p2 = parse_range_str(name, param)
@@ -518,6 +550,26 @@ core.register_chatcommand("deleteblocks", {
        end,
 })
 
        end,
 })
 
+core.register_chatcommand("fixlight", {
+       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)
+               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",
 core.register_chatcommand("mods", {
        params = "",
        description = "List mods installed on the server",
@@ -533,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"
        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"
                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
        end
        local receiverref = core.get_player_by_name(receiver)
        if receiverref == nil then
@@ -553,19 +608,19 @@ 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
        -- 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))
        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", {
        end
 end
 
 core.register_chatcommand("give", {
-       params = "<name> <ItemString>",
-       description = "give item to player",
+       params = "<name> <ItemString> [<count> [<wear>]]",
+       description = "Give item to player",
        privs = {give=true},
        func = function(name, param)
                local toname, itemstring = string.match(param, "^([^ ]+) +(.+)$")
        privs = {give=true},
        func = function(name, param)
                local toname, itemstring = string.match(param, "^([^ ]+) +(.+)$")
@@ -577,8 +632,8 @@ core.register_chatcommand("give", {
 })
 
 core.register_chatcommand("giveme", {
 })
 
 core.register_chatcommand("giveme", {
-       params = "<ItemString>",
-       description = "give item to yourself",
+       params = "<ItemString> [<count> [<wear>]]",
+       description = "Give item to yourself",
        privs = {give=true},
        func = function(name, param)
                local itemstring = string.match(param, "(.+)$")
        privs = {give=true},
        func = function(name, param)
                local itemstring = string.match(param, "(.+)$")
@@ -605,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
                        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
                if p == "" then
-                       p = player:getpos()
+                       p = player:get_pos()
                else
                        p = core.string_to_pos(p)
                        if p == nil then
                else
                        p = core.string_to_pos(p)
                        if p == nil then
@@ -628,10 +686,13 @@ core.register_chatcommand("pulverize", {
                        core.log("error", "Unable to pulverize, no player.")
                        return false, "Unable to pulverize, no player."
                end
                        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
                        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,
 })
                return true, "An item was pulverized."
        end,
 })
@@ -640,21 +701,21 @@ core.register_chatcommand("pulverize", {
 core.rollback_punch_callbacks = {}
 
 core.register_on_punchnode(function(pos, node, puncher)
 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", {
                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]",
-       description = "Check who has last touched a node or near it,"
-                       .. " max. <seconds> ago (default range=0,"
-                       .. " seconds=86400=24h, limit=5)",
+       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",
        privs = {rollback=true},
        func = function(name, param)
        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 =
                        return false, "Rollback functions are disabled."
                end
                local range, seconds, limit =
@@ -701,11 +762,11 @@ core.register_chatcommand("rollback_check", {
 })
 
 core.register_chatcommand("rollback", {
 })
 
 core.register_chatcommand("rollback", {
-       params = "<player name> [<seconds>] | :<actor> [<seconds>]",
-       description = "revert actions of a player; default for <seconds> is 60",
+       params = "(<name> [<seconds>]) | (:<actor> [<seconds>])",
+       description = "Revert actions of a player. Default for <seconds> is 60",
        privs = {rollback=true},
        func = function(name, param)
        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*)")
                        return false, "Rollback functions are disabled."
                end
                local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)")
@@ -739,15 +800,19 @@ core.register_chatcommand("rollback", {
 })
 
 core.register_chatcommand("status", {
 })
 
 core.register_chatcommand("status", {
-       description = "Print server status",
+       description = "Show server status",
        func = function(name, param)
        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", {
        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
        privs = {},
        func = function(name, param)
                if param == "" then
@@ -786,29 +851,45 @@ core.register_chatcommand("time", {
 })
 
 core.register_chatcommand("days", {
 })
 
 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", {
        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> | -1] [reconnect] [<message>]",
+       description = "Shutdown server (-1 cancels a delayed shutdown)",
        privs = {server=true},
        func = function(name, param)
        privs = {server=true},
        func = function(name, param)
-               core.log("action", name .. " shuts down server")
-               core.request_shutdown()
-               core.chat_send_all("*** Server shutting down (operator request).")
+               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", {
        end,
 })
 
 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
        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."
                end
                if not core.get_player_by_name(param) then
                        return false, "No such player."
@@ -823,8 +904,8 @@ core.register_chatcommand("ban", {
 })
 
 core.register_chatcommand("unban", {
 })
 
 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
        privs = {ban=true},
        func = function(name, param)
                if not core.unban_player_or_ip(param) then
@@ -836,8 +917,8 @@ core.register_chatcommand("unban", {
 })
 
 core.register_chatcommand("kick", {
 })
 
 core.register_chatcommand("kick", {
-       params = "<name> [reason]",
-       description = "kick a player",
+       params = "<name> [<reason>]",
+       description = "Kick a player",
        privs = {kick=true},
        func = function(name, param)
                local tokick, reason = param:match("([^ ]+) (.+)")
        privs = {kick=true},
        func = function(name, param)
                local tokick, reason = param:match("([^ ]+) (.+)")
@@ -855,15 +936,15 @@ core.register_chatcommand("kick", {
 })
 
 core.register_chatcommand("clearobjects", {
 })
 
 core.register_chatcommand("clearobjects", {
-       params = "[full|quick]",
-       description = "clear all objects in world",
+       params = "[full | quick]",
+       description = "Clear all objects in world",
        privs = {server=true},
        func = function(name, param)
        privs = {server=true},
        func = function(name, param)
-               options = {}
-               if param == "" or param == "full" then
-                       options.mode = "full"
-               elseif param == "quick" then
+               local options = {}
+               if param == "" or param == "quick" then
                        options.mode = "quick"
                        options.mode = "quick"
+               elseif param == "full" then
+                       options.mode = "full"
                else
                        return false, "Invalid usage, see /help clearobjects."
                end
                else
                        return false, "Invalid usage, see /help clearobjects."
                end
@@ -901,8 +982,8 @@ core.register_chatcommand("msg", {
 })
 
 core.register_chatcommand("last-login", {
 })
 
 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
        func = function(name, param)
                if param == "" then
                        param = name
@@ -916,3 +997,62 @@ core.register_chatcommand("last-login", {
                return false, "Last login time is unknown"
        end,
 })
                return false, "Last login time is unknown"
        end,
 })
+
+core.register_chatcommand("clearinv", {
+       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 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 = "[<name>]",
+       description = "Kill player or yourself",
+       privs = {server=true},
+       func = function(name, param)
+               return handle_kill_command(name, param == "" and name or param)
+       end,
+})