660 lines
16 KiB
Lua
660 lines
16 KiB
Lua
|
|
--- Cleaner Chat Commands
|
|
--
|
|
-- @topic commands
|
|
|
|
|
|
local S = core.get_translator(cleaner.modname)
|
|
|
|
|
|
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
|
|
|
local function pos_list(ppos, radius)
|
|
local plist = {}
|
|
|
|
for x = ppos.x - radius, ppos.x + radius, 1 do
|
|
for y = ppos.y - radius, ppos.y + radius, 1 do
|
|
for z = ppos.z - radius, ppos.z + radius, 1 do
|
|
table.insert(plist, {x=x, y=y, z=z})
|
|
end
|
|
end
|
|
end
|
|
|
|
return plist
|
|
end
|
|
|
|
local param_def = {
|
|
radius = {name=S("radius"), desc=S("Search radius.")},
|
|
entity = {name=S("entity"), desc=S("Entity technical name.")},
|
|
node = {name=S("node"), desc=S("Node technical name.")},
|
|
old_node = {name=S("old_node"), desc=S("Technical name of node to be replaced.")},
|
|
new_node = {name=S("new_node"), desc=S("Technical name of node to be used in place.")},
|
|
old_item = {name=S("old_item"), desc=S("Technical name of item to be replaced.")},
|
|
new_item = {name=S("new_item"), desc=S("Technical name of item to be used in place.")},
|
|
ore = {name=S("ore"), desc=S("Ore technical name.")},
|
|
action = {name=S("action"),
|
|
desc=S('Action to execute. Can be one of "@1", "@2", or "@3".', "status", "setmode", "setnode")},
|
|
value = {name=S("value"), desc=S('Mode or node to be set for tool (not required for "@1" action).', "status")},
|
|
}
|
|
|
|
local cmd_repo = {
|
|
entity = {
|
|
cmd = "remove_entities",
|
|
params = {"entity"},
|
|
oparams = {radius=100},
|
|
},
|
|
rem_node = {
|
|
cmd = "remove_nodes",
|
|
params = {"node"},
|
|
oparams = {radius=5},
|
|
},
|
|
rep_node = {
|
|
cmd = "replace_nodes",
|
|
params = {"old_node", "new_node"},
|
|
oparams = {radius=5},
|
|
},
|
|
find_node = {
|
|
cmd = "find_unknown_nodes",
|
|
oparams = {radius=100},
|
|
},
|
|
near_node = {
|
|
cmd = "find_nearby_nodes",
|
|
oparams = {radius=5},
|
|
},
|
|
item = {
|
|
cmd = "replace_items",
|
|
params = {"old_item", "new_item"},
|
|
},
|
|
ore = {
|
|
cmd = "remove_ores",
|
|
params = {"ore"},
|
|
},
|
|
tool = {
|
|
cmd = "ctool",
|
|
params = {"action", "value"},
|
|
},
|
|
param = {
|
|
missing = S("Missing parameter."),
|
|
excess = S("Too many parameters."),
|
|
mal_radius = S("Radius must be a number."),
|
|
},
|
|
}
|
|
|
|
for k, def in pairs(cmd_repo) do
|
|
if k ~= "param" then
|
|
local cmd_help = {
|
|
param_string = "",
|
|
usage_string = "/" .. def.cmd,
|
|
}
|
|
|
|
if def.params or def.oparams then
|
|
if def.params then
|
|
local params = {}
|
|
for _, p in ipairs(def.params) do
|
|
-- translate
|
|
table.insert(params, S(p))
|
|
end
|
|
|
|
cmd_help.param_string = "<" .. table.concat(params, "> <") .. ">"
|
|
end
|
|
end
|
|
|
|
if def.oparams then
|
|
for k, v in pairs(def.oparams) do
|
|
local op = k
|
|
if type(op) == "number" then
|
|
op = v
|
|
end
|
|
|
|
cmd_help.param_string = cmd_help.param_string .. " [" .. S(op) .. "]"
|
|
end
|
|
end
|
|
|
|
if cmd_help.param_string ~= "" then
|
|
cmd_help.usage_string = cmd_help.usage_string .. " " .. cmd_help.param_string
|
|
end
|
|
|
|
cmd_repo[k].help = cmd_help
|
|
end
|
|
end
|
|
|
|
local function get_cmd_def(cmd)
|
|
for k, v in pairs(cmd_repo) do
|
|
if v.cmd == cmd then return v end
|
|
end
|
|
end
|
|
|
|
local function format_usage(cmd)
|
|
local def = get_cmd_def(cmd)
|
|
if def then
|
|
return S("Usage:") .. "\n " .. def.help.usage_string
|
|
end
|
|
end
|
|
|
|
local function format_params(cmd)
|
|
local def = get_cmd_def(cmd)
|
|
|
|
local param_count
|
|
local all_params = {}
|
|
if def.params then
|
|
for k, v in ipairs(def.params) do
|
|
table.insert(all_params, p)
|
|
end
|
|
end
|
|
if def.oparams then
|
|
for k, v in pairs(def.oparams) do
|
|
|
|
end
|
|
end
|
|
|
|
local retval = ""
|
|
local p_count = 0
|
|
|
|
if def.params then
|
|
for _, p in ipairs(def.params) do
|
|
if p_count == 0 then
|
|
retval = retval .. S("Params:")
|
|
end
|
|
|
|
retval = retval .. "\n " .. S(p) .. ": " .. param_def[p].desc
|
|
|
|
p_count = p_count + 1
|
|
end
|
|
end
|
|
|
|
if def.oparams then
|
|
for k, v in pairs(def.oparams) do
|
|
if p_count == 0 then
|
|
retval = retval .. S("Params:")
|
|
end
|
|
|
|
local p = k
|
|
local dvalue = v
|
|
if type(p) == "number" then
|
|
p = v
|
|
dvalue = nil
|
|
end
|
|
|
|
retval = retval .. "\n " .. S(p) .. ": " .. param_def[p].desc
|
|
if dvalue then
|
|
retval = retval .. " (" .. S("default: @1", dvalue) .. ")"
|
|
end
|
|
|
|
p_count = p_count + 1
|
|
end
|
|
end
|
|
|
|
return retval
|
|
end
|
|
|
|
local function format_help(cmd)
|
|
return format_usage(cmd) .. "\n\n" .. format_params(cmd)
|
|
end
|
|
|
|
|
|
local function check_radius(radius, pname)
|
|
local is_admin = core.check_player_privs(pname, {server=true})
|
|
|
|
if not is_admin and radius > 10 then
|
|
radius = 10
|
|
return radius, S("You do not have permission to set radius that high. Reduced to @1.", radius)
|
|
end
|
|
|
|
if radius > 100 then
|
|
radius = 100
|
|
return radius, S("Radius is too high. Reduced to @1.", radius)
|
|
end
|
|
|
|
return radius
|
|
end
|
|
|
|
|
|
--- Removes nearby entities.
|
|
--
|
|
-- @chatcmd remove_entities
|
|
-- @param entity Entity technical name.
|
|
-- @tparam[opt] int radius Search radius (default: 100).
|
|
-- @priv server
|
|
-- @usage
|
|
-- # remove all mobs:horse entities within a radius of 10 nodes
|
|
-- /remove_entities mobs:horse 10
|
|
core.register_chatcommand(cmd_repo.entity.cmd, {
|
|
privs = {server=true},
|
|
description = S("Remove an entity from game.") .. "\n\n"
|
|
.. format_params(cmd_repo.entity.cmd),
|
|
params = cmd_repo.entity.help.param_string,
|
|
func = function(name, param)
|
|
local entity
|
|
local radius = cmd_repo.entity.oparams.radius
|
|
if param:find(" ") then
|
|
entity = param:split(" ")
|
|
radius = tonumber(entity[2])
|
|
entity = entity[1]
|
|
else
|
|
entity = param
|
|
end
|
|
|
|
local err
|
|
if not entity or entity:trim() == "" then
|
|
err = cmd_repo.param.missing
|
|
elseif not radius then
|
|
err = cmd_repo.param.mal_radius
|
|
end
|
|
|
|
local radius, msg = check_radius(radius, name)
|
|
if msg then
|
|
core.chat_send_player(name, msg)
|
|
end
|
|
|
|
if err then
|
|
return false, err .. "\n\n" .. format_help(cmd_repo.entity.cmd)
|
|
end
|
|
|
|
local player = core.get_player_by_name(name)
|
|
|
|
local total_removed = 0
|
|
for _, object in ipairs(core.get_objects_inside_radius(player:get_pos(), radius)) do
|
|
local lent = object:get_luaentity()
|
|
|
|
if lent then
|
|
if lent.name == entity then
|
|
object:remove()
|
|
total_removed = total_removed + 1
|
|
end
|
|
else
|
|
if object:get_properties().infotext == entity then
|
|
object:remove()
|
|
total_removed = total_removed + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
return true, S("Removed @1 entities.", total_removed)
|
|
end,
|
|
})
|
|
|
|
--- Removes nearby nodes.
|
|
--
|
|
-- @chatcmd remove_nodes
|
|
-- @param node Node technical name.
|
|
-- @tparam[opt] int radius Search radius (default: 5).
|
|
-- @priv server
|
|
-- @usage
|
|
-- # remove all default:dirt nodes within a radius of 10
|
|
-- /remove_nodes default:dirt 10
|
|
core.register_chatcommand(cmd_repo.rem_node.cmd, {
|
|
privs = {server=true},
|
|
description = S("Remove a node from game.") .. "\n\n"
|
|
.. format_params(cmd_repo.rem_node.cmd),
|
|
params = cmd_repo.rem_node.help.param_string,
|
|
func = function(name, param)
|
|
local nname
|
|
local radius = cmd_repo.rem_node.oparams.radius
|
|
if param:find(" ") then
|
|
nname = param:split(" ")
|
|
radius = tonumber(nname[2])
|
|
nname = nname[1]
|
|
else
|
|
nname = param
|
|
end
|
|
|
|
local err
|
|
if not nname or nname:trim() == "" then
|
|
err = cmd_repo.param.missing
|
|
elseif not radius then
|
|
err = cmd_repo.param.mal_radius
|
|
end
|
|
|
|
local radius, msg = check_radius(radius, name)
|
|
if msg then
|
|
core.chat_send_player(name, msg)
|
|
end
|
|
|
|
if err then
|
|
return false, err .. "\n\n" .. format_help(cmd_repo.rem_node.cmd)
|
|
end
|
|
|
|
local ppos = core.get_player_by_name(name):get_pos()
|
|
|
|
local total_removed = 0
|
|
for _, npos in ipairs(pos_list(ppos, radius)) do
|
|
local node = core.get_node_or_nil(npos)
|
|
if node and node.name == nname then
|
|
core.remove_node(npos)
|
|
total_removed = total_removed + 1
|
|
end
|
|
end
|
|
|
|
return true, S("Removed @1 nodes.", total_removed)
|
|
end,
|
|
})
|
|
|
|
--- Replaces an item.
|
|
--
|
|
-- @chatcmd replace_items
|
|
-- @param old_item Technical name of item to replace.
|
|
-- @param new_item Technical name of item to be used in place.
|
|
-- @priv server
|
|
-- @usage
|
|
-- # replace default:sword_wood with default:sword_mese
|
|
-- /replace_items default:sword_wood default:sword_mese
|
|
core.register_chatcommand(cmd_repo.item.cmd, {
|
|
privs = {server=true},
|
|
description = S("Replace an item in game.") .. "\n\n"
|
|
.. format_params(cmd_repo.item.cmd),
|
|
params = cmd_repo.item.help.param_string,
|
|
func = function(name, param)
|
|
if not param:find(" ") then
|
|
return false, cmd_repo.param.missing .. "\n\n" .. format_help(cmd_repo.item.cmd)
|
|
end
|
|
|
|
local src = param:split(" ")
|
|
local tgt = src[2]
|
|
src = src[1]
|
|
|
|
local retval, msg = cleaner.replace_item(src, tgt, true)
|
|
if not retval then
|
|
return false, msg
|
|
end
|
|
|
|
return true, S("Success!")
|
|
end,
|
|
})
|
|
|
|
--- Replaces nearby nodes.
|
|
--
|
|
-- @chatcmd replace_nodes
|
|
-- @param old_node Technical name of node to replace.
|
|
-- @param new_node Technical name of node to be used in place.
|
|
-- @tparam[opt] int radius Search radius (default: 5).
|
|
-- @priv server
|
|
-- @usage
|
|
-- # replace all default:dirt nodes with default:cobble within a radius of 10
|
|
-- /replace_nodes default:dirt default:cobble 10
|
|
core.register_chatcommand(cmd_repo.rep_node.cmd, {
|
|
privs = {server=true},
|
|
description = S("Replace a node in game.") .. "\n\n"
|
|
.. format_params(cmd_repo.rep_node.cmd),
|
|
params = cmd_repo.rep_node.help.param_string,
|
|
func = function(name, param)
|
|
local help = format_help(cmd_repo.rep_node.cmd)
|
|
|
|
if not param:find(" ") then
|
|
return false, cmd_repo.param.missing .. "\n\n" .. help
|
|
end
|
|
|
|
local radius = cmd_repo.rep_node.oparams.radius
|
|
local params = param:split(" ")
|
|
|
|
local src = params[1]
|
|
local tgt = tostring(params[2])
|
|
if #params > 2 then
|
|
radius = tonumber(params[3])
|
|
end
|
|
|
|
if not radius then
|
|
return false, cmd_repo.param.mal_radius .. "\n\n" .. help
|
|
end
|
|
|
|
local radius, msg = check_radius(radius, name)
|
|
if msg then
|
|
core.chat_send_player(name, msg)
|
|
end
|
|
|
|
if not core.registered_nodes[tgt] then
|
|
return false, S('Cannot use unknown node "@1" as replacement.', tgt)
|
|
end
|
|
|
|
local total_replaced = 0
|
|
local ppos = core.get_player_by_name(name):get_pos()
|
|
for _, npos in ipairs(pos_list(ppos, radius)) do
|
|
local node = core.get_node_or_nil(npos)
|
|
if node and node.name == src then
|
|
if core.swap_node(npos, {name=tgt}) then
|
|
total_replaced = total_replaced + 1
|
|
else
|
|
cleaner.log("error", "could not replace node at " .. core.pos_to_string(npos, 0))
|
|
end
|
|
end
|
|
end
|
|
|
|
return true, S("Replaced @1 nodes.", total_replaced)
|
|
end,
|
|
})
|
|
|
|
--- Checks for nearby unknown nodes.
|
|
--
|
|
-- @chatcmd find_unknown_nodes
|
|
-- @tparam[opt] int radius Search radius (default: 100).
|
|
-- @priv server
|
|
-- @usage
|
|
-- # print names of all unknown nodes within radius of 10
|
|
-- /find_unknown_nodes 10
|
|
core.register_chatcommand(cmd_repo.find_node.cmd, {
|
|
privs = {server=true},
|
|
description = S("Find names of unknown nodes.") .. "\n\n"
|
|
.. format_params(cmd_repo.find_node.cmd),
|
|
params = cmd_repo.find_node.help.param_string,
|
|
func = function(name, param)
|
|
local help = format_help(cmd_repo.find_node.cmd)
|
|
|
|
if param:find(" ") then
|
|
return false, cmd_repo.param.excess .. "\n\n" .. help
|
|
end
|
|
|
|
local radius = cmd_repo.find_node.oparams.radius
|
|
if param and param:trim() ~= "" then
|
|
radius = tonumber(param)
|
|
end
|
|
|
|
if not radius then
|
|
return false, cmd_repo.param.mal_radius .. "\n\n" .. help
|
|
end
|
|
|
|
local radius, msg = check_radius(radius, name)
|
|
if msg then
|
|
core.chat_send_player(name, msg)
|
|
end
|
|
|
|
local ppos = core.get_player_by_name(name):get_pos()
|
|
|
|
local checked_nodes = {}
|
|
local unknown_nodes = {}
|
|
for _, npos in ipairs(pos_list(ppos, radius)) do
|
|
local node = core.get_node_or_nil(npos)
|
|
if node and not checked_nodes[node.name] then
|
|
if not core.registered_nodes[node.name] then
|
|
table.insert(unknown_nodes, node.name)
|
|
end
|
|
|
|
checked_nodes[node.name] = true
|
|
end
|
|
end
|
|
|
|
local node_count = #unknown_nodes
|
|
if node_count > 0 then
|
|
msg = S("Found unknown nodes: @1", node_count) .. "\n " .. table.concat(unknown_nodes, ", ")
|
|
else
|
|
msg = S("No unknown nodes found.")
|
|
end
|
|
|
|
return true, msg
|
|
end,
|
|
})
|
|
|
|
--- Finds names of nearby nodes.
|
|
--
|
|
-- @chatcmd find_nearby_nodes
|
|
-- @tparam[opt] int radius Search radius (default: 5).
|
|
-- @priv server
|
|
-- @usage
|
|
-- # print names of all node types found within radius of 10
|
|
-- /find_nearby_nodes 10
|
|
core.register_chatcommand(cmd_repo.near_node.cmd, {
|
|
privs = {server=true},
|
|
description = S("Find names of nearby nodes.") .. "\n\n"
|
|
.. format_params(cmd_repo.near_node.cmd),
|
|
params = cmd_repo.near_node.help.param_string,
|
|
func = function(name, param)
|
|
local help = format_help(cmd_repo.near_node.cmd)
|
|
|
|
if param:find(" ") then
|
|
return false, cmd_repo.param.excess .. "\n\n" .. help
|
|
end
|
|
|
|
local radius = cmd_repo.near_node.oparams.radius
|
|
if param and param:trim() ~= "" then
|
|
radius = tonumber(param)
|
|
end
|
|
|
|
if not radius then
|
|
return false, cmd_repo.param.mal_radius .. "\n\n" .. help
|
|
end
|
|
|
|
local radius, msg = check_radius(radius, name)
|
|
if msg then
|
|
core.chat_send_player(name, msg)
|
|
end
|
|
|
|
local ppos = core.get_player_by_name(name):get_pos()
|
|
|
|
local node_names = {}
|
|
for _, npos in ipairs(pos_list(ppos, radius)) do
|
|
local node = core.get_node_or_nil(npos)
|
|
if node and not node_names[node.name] then
|
|
node_names[node.name] = true
|
|
end
|
|
end
|
|
|
|
local found_nodes = {}
|
|
for k, _ in pairs(node_names) do
|
|
table.insert(found_nodes, k)
|
|
end
|
|
|
|
local msg
|
|
local node_count = #found_nodes
|
|
if node_count > 0 then
|
|
msg = S("Nearby nodes: @1", node_count) .. "\n " .. table.concat(found_nodes, ", ")
|
|
else
|
|
msg = S("No nearby nodes found.")
|
|
end
|
|
|
|
return true, msg
|
|
end,
|
|
})
|
|
|
|
|
|
--- Unsafe Commands.
|
|
--
|
|
-- Enabled with [cleaner.unsafe](settings.html#cleaner.unsafe) setting.
|
|
--
|
|
-- @section unsafe
|
|
|
|
|
|
if cleaner.unsafe then
|
|
--- Registers an ore to be removed.
|
|
--
|
|
-- @chatcmd remove_ores
|
|
-- @param ore Ore technical name.
|
|
-- @priv server
|
|
-- @note This action is reverted after server restart. To make changes permanent,
|
|
-- use the [cleaner.json](config.html#cleaner.json) config.
|
|
-- @usage
|
|
-- # remove all registered ores that add default:stone_with_iron to world
|
|
-- /remove_ores default:stone_with_iron
|
|
core.register_chatcommand(cmd_repo.ore.cmd, {
|
|
privs = {server=true},
|
|
description = S("Remove an ore from game.") .. "\n\n"
|
|
.. format_params(cmd_repo.ore.cmd),
|
|
params = cmd_repo.ore.help.param_string,
|
|
func = function(name, param)
|
|
local err
|
|
if not param or param:trim() == "" then
|
|
err = cmd_repo.param.missing
|
|
elseif param:find(" ") then
|
|
err = cmd_repo.param.excess
|
|
end
|
|
|
|
if err then
|
|
return false, err .. "\n\n" .. format_help(cmd_repo.ore.cmd)
|
|
end
|
|
|
|
local success = false
|
|
local msg
|
|
local registered, total_removed = cleaner.remove_ore(param)
|
|
|
|
if not registered then
|
|
msg = S('Ore "@1" not found, not unregistering.', param)
|
|
else
|
|
msg = S("Unregistered @1 ores (this will be undone after server restart).", total_removed)
|
|
success = true
|
|
end
|
|
|
|
return success, msg
|
|
end
|
|
})
|
|
end
|
|
|
|
--- @section end
|
|
|
|
|
|
--- Manages settings for wielded [cleaner tool](tools.html).
|
|
--
|
|
-- <h3>Required Privileges:</h3>
|
|
--
|
|
-- - server
|
|
--
|
|
-- @chatcmd ctool
|
|
-- @param action Action to execute. Can be "status", "setmode", or "setnode".
|
|
-- @param value Mode or node to be set for tool (not required for "status" action).
|
|
-- @usage
|
|
-- # while cleaner:pencil is wielded, configure to place default:dirt node when used
|
|
-- /ctool setmode write
|
|
-- /ctool setnode default:dirt
|
|
core.register_chatcommand(cmd_repo.tool.cmd, {
|
|
privs = {server=true},
|
|
description = S("Manage settings for wielded cleaner tool.") .. "\n\n"
|
|
.. format_params(cmd_repo.tool.cmd),
|
|
params = cmd_repo.tool.help.param_string,
|
|
func = function(name, param)
|
|
local action, value = param
|
|
local idx = param:find(" ")
|
|
if idx then
|
|
param = string.split(param, " ")
|
|
action = param[1]
|
|
value = param[2]
|
|
end
|
|
|
|
local help = format_help(cmd_repo.tool.cmd)
|
|
|
|
local player = core.get_player_by_name(name)
|
|
local stack = player:get_wielded_item()
|
|
local iname = aux.tool:format_name(stack)
|
|
local imeta = stack:get_meta()
|
|
|
|
if iname ~= "cleaner:pencil" then
|
|
return false, S("Unrecognized wielded item: @1", iname) .. "\n\n" .. help
|
|
end
|
|
|
|
if action == "status" then
|
|
core.chat_send_player(name, iname .. ": " .. S("mode") .. "=" .. imeta:get_string("mode")
|
|
.. ", " .. S("node") .. "=" .. imeta:get_string("node"))
|
|
return true
|
|
end
|
|
|
|
if not action or not value then
|
|
return false, S("Missing parameter.") .. "\n\n" .. help
|
|
end
|
|
|
|
if action == "setmode" then
|
|
stack = aux.tool:set_mode(stack, value, name)
|
|
elseif action == "setnode" then
|
|
stack = aux.tool:set_node(stack, value, name)
|
|
else
|
|
return false, S("Unrecognized action: @1", action) .. "\n\n" .. help
|
|
end
|
|
|
|
return player:set_wielded_item(stack)
|
|
end,
|
|
})
|