]> git.lizzy.rs Git - minetest.git/blobdiff - builtin/game/chatcommands.lua
Sounds: Add falling node sounds
[minetest.git] / builtin / game / chatcommands.lua
index 54cd6c3252cd7a8175bd9903182986af60dbedd1..cbfe2fb257bb82412a26fa0228f1116f71e0d352 100644 (file)
@@ -1,46 +1,28 @@
--- Minetest: builtin/chatcommands.lua
+-- Minetest: builtin/game/chatcommands.lua
 
 --
 -- Chat command handler
 --
 
 
 --
 -- Chat command handler
 --
 
-core.registered_chatcommands = {}
 core.chatcommands = core.registered_chatcommands -- BACKWARDS COMPATIBILITY
 core.chatcommands = core.registered_chatcommands -- BACKWARDS COMPATIBILITY
-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.registered_chatcommands[cmd] = def
-end
-
-function core.unregister_chatcommand(name)
-       if core.registered_chatcommands[name] then
-               core.registered_chatcommands[name] = nil
-       else
-               core.log("warning", "Not unregistering chatcommand " ..name..
-                       " because it doesn't exist.")
-       end
-end
 
 
-function core.override_chatcommand(name, redefinition)
-       local chatcommand = core.registered_chatcommands[name]
-       assert(chatcommand, "Attempt to override non-existent chatcommand "..name)
-       for k, v in pairs(redefinition) do
-               rawset(chatcommand, k, v)
+core.register_on_chat_message(function(name, message)
+       if message:sub(1,1) ~= "/" then
+               return
        end
        end
-       core.registered_chatcommands[name] = chatcommand
-end
 
 
-core.register_on_chat_message(function(name, message)
        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
+
+       param = param or ""
+
        local cmd_def = core.registered_chatcommands[cmd]
        if not cmd_def then
        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
        end
        local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs)
        if has_privs then
@@ -57,7 +39,7 @@ core.register_on_chat_message(function(name, message)
        return true  -- Handled chat message
 end)
 
        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
        profiler.init_chatcommand()
        -- Run after register_chatcommand and its register_on_chat_message
        -- Before any chattcommands that should be profiled
        profiler.init_chatcommand()
@@ -100,7 +82,7 @@ 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 = minetest.settings:get("name")
                if admin then
                        return true, "The administrator of this server is "..admin.."."
                else
                if admin then
                        return true, "The administrator of this server is "..admin.."."
                else
@@ -109,63 +91,8 @@ core.register_chatcommand("admin", {
        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 = 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 <cmd>' 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", {
 core.register_chatcommand("privs", {
-       params = "<name>",
+       params = "[<name>]",
        description = "Print privileges of player",
        func = function(caller, param)
                param = param:trim()
        description = "Print privileges of player",
        func = function(caller, param)
                param = param:trim()
@@ -192,7 +119,7 @@ local function handle_grant_command(caller, grantname, grantprivstr)
        local privs = core.get_player_privs(grantname)
        local privs_unknown = ""
        local basic_privs =
        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."
        for priv, _ in pairs(grantprivs) do
                if not basic_privs[priv] and not caller_privs.privs then
                        return false, "Your privileges are insufficient."
@@ -205,6 +132,9 @@ local function handle_grant_command(caller, grantname, grantprivstr)
        if privs_unknown ~= "" then
                return false, privs_unknown
        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.set_player_privs(grantname, privs)
        core.log("action", caller..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
        if grantname ~= caller then
@@ -218,7 +148,7 @@ local function handle_grant_command(caller, grantname, grantprivstr)
 end
 
 core.register_chatcommand("grant", {
 end
 
 core.register_chatcommand("grant", {
-       params = "<name> <privilege>|all",
+       params = "<name> (<privilege> | all)",
        description = "Give privilege to player",
        func = function(name, param)
                local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
        description = "Give privilege to player",
        func = function(name, param)
                local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
@@ -230,7 +160,7 @@ core.register_chatcommand("grant", {
 })
 
 core.register_chatcommand("grantme", {
 })
 
 core.register_chatcommand("grantme", {
-       params = "<privilege>|all",
+       params = "<privilege> | all",
        description = "Grant privileges to yourself",
        func = function(name, param)
                if param == "" then
        description = "Grant privileges to yourself",
        func = function(name, param)
                if param == "" then
@@ -241,7 +171,7 @@ core.register_chatcommand("grantme", {
 })
 
 core.register_chatcommand("revoke", {
 })
 
 core.register_chatcommand("revoke", {
-       params = "<name> <privilege>|all",
+       params = "<name> (<privilege> | all)",
        description = "Remove privilege from player",
        privs = {},
        func = function(name, param)
        description = "Remove privilege from player",
        privs = {},
        func = function(name, param)
@@ -258,7 +188,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 =
                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
                for priv, _ in pairs(revoke_privs) do
                        if not basic_privs[priv] and
                                        not core.check_player_privs(name, {privs=true}) then
@@ -266,12 +196,18 @@ core.register_chatcommand("revoke", {
                        end
                end
                if revoke_priv_str == "all" then
                        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, ', ')
@@ -352,8 +288,33 @@ core.register_chatcommand("auth_reload", {
        end,
 })
 
        end,
 })
 
+core.register_chatcommand("remove_player", {
+       params = "<name>",
+       description = "Remove player 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>",
+       params = "<X>,<Y>,<Z> | <to_name> | (<name> <X>,<Y>,<Z>) | (<name> <to_name>)",
        description = "Teleport to player or position",
        privs = {teleport=true},
        func = function(name, param)
        description = "Teleport to player or position",
        privs = {teleport=true},
        func = function(name, param)
@@ -385,7 +346,7 @@ core.register_chatcommand("teleport", {
                p.y = tonumber(p.y)
                p.z = tonumber(p.z)
                if p.x and p.y and p.z then
                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
                        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
@@ -461,26 +422,26 @@ core.register_chatcommand("teleport", {
 })
 
 core.register_chatcommand("set", {
 })
 
 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)
                local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)")
                if arg and arg == "-n" and setname and setvalue then
        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
                        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
@@ -516,9 +477,9 @@ local function emergeblocks_progress_update(ctx)
 end
 
 core.register_chatcommand("emergeblocks", {
 end
 
 core.register_chatcommand("emergeblocks", {
-       params = "(here [radius]) | (<pos1> <pos2>)",
+       params = "(here [<radius>]) | (<pos1> <pos2>)",
        description = "Load (or, if nonexistent, generate) map blocks "
        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)
        privs = {server=true},
        func = function(name, param)
                local p1, p2 = parse_range_str(name, param)
@@ -542,8 +503,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)
@@ -560,6 +522,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",
@@ -647,6 +629,9 @@ 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 minetest.registered_entities[entityname] then
+                       return false, "Cannot spawn an unknown entity"
+               end
                if p == "" then
                        p = player:getpos()
                else
                if p == "" then
                        p = player:getpos()
                else
@@ -682,21 +667,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]",
+       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)
        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)
-               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 =
@@ -743,11 +728,11 @@ core.register_chatcommand("rollback_check", {
 })
 
 core.register_chatcommand("rollback", {
 })
 
 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)
        description = "Revert actions of a player. Default for <seconds> 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*)")
                        return false, "Rollback functions are disabled."
                end
                local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)")
@@ -835,14 +820,21 @@ core.register_chatcommand("days", {
 })
 
 core.register_chatcommand("shutdown", {
 })
 
 core.register_chatcommand("shutdown", {
-       description = "Shutdown server",
-       params = "[reconnect] [message]",
+       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.chat_send_all("*** Server shutting down (operator request).")
-               local reconnect, message = param:match("([^ ]+)(.*)")
-               core.request_shutdown(message:trim(), minetest.is_yes(reconnect))
+               local delay, reconnect, message = param:match("([^ ][-]?[0-9]+)([^ ]+)(.*)")
+               message = message or ""
+
+               if delay ~= "" then
+                       delay = tonumber(param) or 0
+               else
+                       delay = 0
+                       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,
 })
 
        end,
 })
 
@@ -867,7 +859,7 @@ core.register_chatcommand("ban", {
 })
 
 core.register_chatcommand("unban", {
 })
 
 core.register_chatcommand("unban", {
-       params = "<name/ip>",
+       params = "<name> | <IP_address>",
        description = "Remove IP ban",
        privs = {ban=true},
        func = function(name, param)
        description = "Remove IP ban",
        privs = {ban=true},
        func = function(name, param)
@@ -880,7 +872,7 @@ core.register_chatcommand("unban", {
 })
 
 core.register_chatcommand("kick", {
 })
 
 core.register_chatcommand("kick", {
-       params = "<name> [reason]",
+       params = "<name> [<reason>]",
        description = "Kick a player",
        privs = {kick=true},
        func = function(name, param)
        description = "Kick a player",
        privs = {kick=true},
        func = function(name, param)
@@ -899,7 +891,7 @@ core.register_chatcommand("kick", {
 })
 
 core.register_chatcommand("clearobjects", {
 })
 
 core.register_chatcommand("clearobjects", {
-       params = "[full|quick]",
+       params = "[full | quick]",
        description = "Clear all objects in world",
        privs = {server=true},
        func = function(name, param)
        description = "Clear all objects in world",
        privs = {server=true},
        func = function(name, param)
@@ -945,7 +937,7 @@ core.register_chatcommand("msg", {
 })
 
 core.register_chatcommand("last-login", {
 })
 
 core.register_chatcommand("last-login", {
-       params = "[name]",
+       params = "[<name>]",
        description = "Get the last login time of a player",
        func = function(name, param)
                if param == "" then
        description = "Get the last login time of a player",
        func = function(name, param)
                if param == "" then
@@ -960,3 +952,31 @@ 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 run this command (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,
+})