rolling-12
parent
b2b5d3df9f
commit
ae703fb914
7
init.lua
7
init.lua
|
@ -1 +1,6 @@
|
|||
modlib.mod.init("cmdlib")
|
||||
modlib.mod.init("cmdlib")
|
||||
modlib.mod.extend("cmdlib", "override")
|
||||
-- Tests - only uncomment if testing stuff
|
||||
--[[
|
||||
--dofile(modlib.mod.get_resource("cmdlib", "test.lua"))
|
||||
]]
|
196
main.lua
196
main.lua
|
@ -3,25 +3,21 @@ error_format = minetest.get_color_escape_sequence("#FF0000") .. "%s"
|
|||
success_format = minetest.get_color_escape_sequence("#00FF00") .. "%s"
|
||||
function scope_func(scope)
|
||||
return function()
|
||||
return false, "Not a chatcommand, but a category. For a list of subcommands do /help " .. scope .. "."
|
||||
return false,
|
||||
"Not a chatcommand, but a category. For a list of subcommands do /help " ..
|
||||
scope .. "."
|
||||
end
|
||||
end
|
||||
|
||||
chatcommands = trie.new()
|
||||
chatcommand_info = {}
|
||||
error = function(str)
|
||||
return string.format(error_format, str)
|
||||
end
|
||||
success = function(str)
|
||||
return string.format(success_format, str)
|
||||
end
|
||||
format_error = function(str) return string.format(error_format, str) end
|
||||
format_success = function(str) return string.format(success_format, str) end
|
||||
function validate_privs(required, actual)
|
||||
local missing, to_lose = {}, {}
|
||||
for priv, expected in pairs(required) do
|
||||
if expected then
|
||||
if not actual[priv] then
|
||||
table.insert(missing, priv)
|
||||
end
|
||||
if not actual[priv] then table.insert(missing, priv) end
|
||||
elseif actual[priv] then
|
||||
table.insert(to_lose, priv)
|
||||
end
|
||||
|
@ -31,14 +27,10 @@ end
|
|||
function validate_privs_ipairs(required, forbidden, actual)
|
||||
local missing, to_lose = {}, {}
|
||||
for _, priv in ipairs(required) do
|
||||
if not actual[priv] then
|
||||
table.insert(missing, priv)
|
||||
end
|
||||
if not actual[priv] then table.insert(missing, priv) end
|
||||
end
|
||||
for _, priv in ipairs(forbidden) do
|
||||
if actual[priv] then
|
||||
table.insert(to_lose, priv)
|
||||
end
|
||||
if actual[priv] then table.insert(to_lose, priv) end
|
||||
end
|
||||
return missing, to_lose
|
||||
end
|
||||
|
@ -46,13 +38,16 @@ function sufficient_privs(required, playername)
|
|||
local missing, to_lose = validate_privs(required, minetest.get_player_privs(playername))
|
||||
local str
|
||||
if not modlib.table.is_empty(missing) then
|
||||
str = string.format("Missing privilege%s: ", ("s" and #missing > 1) or "") .. table.concat(missing)
|
||||
str = string.format("Missing privilege%s: ",
|
||||
("s" and #missing > 1) or "") ..
|
||||
table.concat(missing)
|
||||
end
|
||||
if not modlib.table.is_empty(to_lose) then
|
||||
str =
|
||||
(str or "") ..
|
||||
string.format("%srivilege%s which need to be lost: ", (str and ", p") or "P", ("s" and #to_lose > 1) or "") ..
|
||||
table.concat(to_lose)
|
||||
str = (str or "") ..
|
||||
string.format("%srivilege%s which need to be lost: ",
|
||||
(str and ", p") or "P",
|
||||
("s" and #to_lose > 1) or "") ..
|
||||
table.concat(to_lose)
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
@ -60,18 +55,21 @@ function build_param_parser(syntax)
|
|||
local params = modlib.text.split_without_limit(syntax, " ")
|
||||
local required_params, optional_params, list_param = {}, {}
|
||||
local i = 1
|
||||
while i <= #params and params[i]:sub(1, 1) == "<" and params[i]:sub(params[i]:len()) == ">" do
|
||||
while i <= #params and params[i]:sub(1, 1) == "<" and
|
||||
params[i]:sub(params[i]:len()) == ">" do
|
||||
table.insert(required_params, params[i]:sub(2, params[i]:len() - 1))
|
||||
i = i + 1
|
||||
end
|
||||
while i <= #params and params[i]:sub(1, 1) == "[" and params[i]:sub(params[i]:len()) == "]" do
|
||||
while i <= #params and params[i]:sub(1, 1) == "[" and
|
||||
params[i]:sub(params[i]:len()) == "]" do
|
||||
table.insert(optional_params, params[i]:sub(2, params[i]:len() - 1))
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if i <= #params then
|
||||
-- check for list param
|
||||
if i == #params and params[i]:sub(1, 1) == "{" and params[i]:sub(params[i]:len()) == "}" then
|
||||
if i == #params and params[i]:sub(1, 1) == "{" and
|
||||
params[i]:sub(params[i]:len()) == "}" then
|
||||
list_param = params[i]:sub(2, params[i]:len() - 1)
|
||||
else
|
||||
return -- Failure
|
||||
|
@ -79,26 +77,20 @@ function build_param_parser(syntax)
|
|||
end
|
||||
|
||||
local limit = #required_params + #optional_params
|
||||
if list_param then
|
||||
limit = nil
|
||||
end
|
||||
if list_param then limit = nil end
|
||||
local minimum = #required_params
|
||||
local paramlist = required_params
|
||||
modlib.table.append(paramlist, optional_params)
|
||||
return function(param)
|
||||
local params = modlib.text.split(param, " ", limit)
|
||||
for i, param in modlib.table.rpairs(params) do
|
||||
if param == "" then
|
||||
table.remove(params, i)
|
||||
end
|
||||
if param == "" then table.remove(params, i) end
|
||||
end
|
||||
if #params < minimum then
|
||||
return "Too few parameters given! At least " ..
|
||||
minimum ..
|
||||
" " ..
|
||||
((minimum == 1 and "is") or "are") ..
|
||||
" required. The following parameters are missing: " ..
|
||||
table.concat({unpack(required_params, #params + 1)})
|
||||
return "Too few parameters given! At least " .. minimum .. " " ..
|
||||
((minimum == 1 and "is") or "are") ..
|
||||
" required. The following parameters are missing: " ..
|
||||
table.concat({unpack(required_params, #params + 1)})
|
||||
end
|
||||
local paramtable = {}
|
||||
for index, name in ipairs(paramlist) do
|
||||
|
@ -115,9 +107,7 @@ function build_func(def)
|
|||
return function(invokername, params)
|
||||
if def.privs then
|
||||
local error = sufficient_privs(def.privs, invokername)
|
||||
if error then
|
||||
return false, error
|
||||
end
|
||||
if error then return false, error end
|
||||
end
|
||||
return def.fnc(invokername, params)
|
||||
end
|
||||
|
@ -125,14 +115,10 @@ function build_func(def)
|
|||
return function(invokername, params)
|
||||
if def.privs then
|
||||
local error = sufficient_privs(def.privs, invokername)
|
||||
if error then
|
||||
return false, error
|
||||
end
|
||||
if error then return false, error end
|
||||
end
|
||||
local error, params = def.param_parser(params)
|
||||
if error then
|
||||
return false, error
|
||||
end
|
||||
if error then return false, error end
|
||||
return def.fnc(invokername, params)
|
||||
end
|
||||
end
|
||||
|
@ -145,9 +131,7 @@ function register_chatcommand(name, def, override)
|
|||
implicit_call = def.implicit_call,
|
||||
fnc = def.func or error("/" .. name .. ": No function given")
|
||||
}
|
||||
if definition.params then
|
||||
definition.implicit_call = true
|
||||
end
|
||||
if definition.params then definition.implicit_call = true end
|
||||
if not definition.custom_syntax then
|
||||
definition.param_parser = build_param_parser(definition.params or "")
|
||||
end
|
||||
|
@ -157,9 +141,13 @@ function register_chatcommand(name, def, override)
|
|||
chatcommand_info[name] = modlib.table.tablecopy(definition)
|
||||
trie.insert(chatcommands, name, definition, override)
|
||||
else
|
||||
local supercommand, super_info = trie.get(chatcommands, scopes[1]), chatcommand_info[scopes[1]]
|
||||
local supercommand, super_info = trie.get(chatcommands, scopes[1]),
|
||||
chatcommand_info[scopes[1]]
|
||||
if not supercommand then
|
||||
supercommand = {subcommands = trie.new(), func = scope_func(scopes[1])}
|
||||
supercommand = {
|
||||
subcommands = trie.new(),
|
||||
func = scope_func(scopes[1])
|
||||
}
|
||||
trie.insert(chatcommands, scopes[1], supercommand)
|
||||
super_info = {subcommands = {}}
|
||||
chatcommand_info[scopes[1]] = super_info
|
||||
|
@ -172,26 +160,63 @@ function register_chatcommand(name, def, override)
|
|||
if not super_info.subcommands then
|
||||
super_info.subcommands = {}
|
||||
end
|
||||
local subcommand = {subcommands = trie.new(), func = scope_func(scopes[1])}
|
||||
local prevval = trie.insert(supercommand.subcommands, scopes[i], subcommand)
|
||||
modlib.table.add_all(inherited_privs, (prevval and prevval.privs) or {})
|
||||
local subcommand = {
|
||||
subcommands = trie.new(),
|
||||
func = scope_func(scopes[1])
|
||||
}
|
||||
local prevval = trie.insert(supercommand.subcommands, scopes[i],
|
||||
subcommand)
|
||||
modlib.table.add_all(inherited_privs,
|
||||
(prevval and prevval.privs) or {})
|
||||
supercommand = prevval or subcommand
|
||||
super_info.subcommands[scopes[i]] = super_info.subcommands[scopes[i]] or {subcommands = {}}
|
||||
super_info.subcommands[scopes[i]] =
|
||||
super_info.subcommands[scopes[i]] or {subcommands = {}}
|
||||
super_info = super_info.subcommands[scopes[i]]
|
||||
end
|
||||
modlib.table.add_all(inherited_privs, def.privs or {})
|
||||
if not supercommand.subcommands then
|
||||
supercommand.subcommands = trie.new()
|
||||
end
|
||||
if not super_info.subcommands then
|
||||
super_info.subcommands = {}
|
||||
end
|
||||
if not super_info.subcommands then super_info.subcommands = {} end
|
||||
definition.privs = next(inherited_privs) and inherited_privs
|
||||
super_info.subcommands[scopes[#scopes]] = modlib.table.tablecopy(definition)
|
||||
trie.insert(supercommand.subcommands, scopes[#scopes], definition, override)
|
||||
super_info.subcommands[scopes[#scopes]] =
|
||||
modlib.table.tablecopy(definition)
|
||||
trie.insert(supercommand.subcommands, scopes[#scopes], definition,
|
||||
override)
|
||||
end
|
||||
end
|
||||
wrap_text = function(text, max)
|
||||
|
||||
local function name_comparator(info, name)
|
||||
return modlib.table.default_comparator(info.name, name)
|
||||
end
|
||||
|
||||
local binary_search_name = modlib.table.binary_search_comparator(name_comparator)
|
||||
function unregister_chatcommand(name)
|
||||
local function get(info, name)
|
||||
return info[(#chatcommand_info ~= 0 and binary_search(info, name)) or name]
|
||||
end
|
||||
local scopes = modlib.text.split_without_limit(name, " ")
|
||||
local super_info = chatcommand_info
|
||||
local super_trie = chatcommands
|
||||
local head_trie = chatcommands
|
||||
local head_info, head_name = chatcommand_info, scopes[1]
|
||||
for i = 2, #scopes do
|
||||
super_info = get(super_info, scopes[i-1]).subcommands
|
||||
super_trie = trie.get(super_trie, scopes[i-1]).subcommands
|
||||
local reset_head = next(super_info, next(super_info)) or super_info.implicit_call
|
||||
if reset_head then
|
||||
head_info, head_name = super_info, scopes[i]
|
||||
head_trie = super_trie
|
||||
end
|
||||
end
|
||||
trie.remove(head_trie, head_name)
|
||||
if #chatcommand_info ~= 0 then
|
||||
head_name = binary_search_name(head_info, head_name)
|
||||
end
|
||||
head_info[head_name] = nil
|
||||
end
|
||||
|
||||
function wrap_text(text, max)
|
||||
max = max or 80
|
||||
local res = {text}
|
||||
while res[#res]:len() > max do
|
||||
|
@ -219,19 +244,21 @@ function handle_chat_message(sendername, message)
|
|||
end
|
||||
cmd, suggestion, _ = trie.search(command_trie, command_name)
|
||||
if not cmd then
|
||||
minetest.chat_send_player(
|
||||
sendername,
|
||||
string.format(
|
||||
error_format,
|
||||
"No such chatcommand. " ..
|
||||
((suggestion and 'Did you mean "' .. message:sub(1, last_space - 1) .. suggestion .. '" ?') or
|
||||
"")
|
||||
)
|
||||
)
|
||||
minetest.chat_send_player(sendername,
|
||||
string.format(error_format,
|
||||
"No such chatcommand. " ..
|
||||
((suggestion and
|
||||
'Did you mean "' ..
|
||||
message:sub(1,
|
||||
last_space -
|
||||
1) ..
|
||||
suggestion ..
|
||||
'" ?') or "")))
|
||||
return true
|
||||
elseif cmd.subcommands and not cmd.implicit_call then
|
||||
command_trie = cmd.subcommands
|
||||
last_space, next_space = next_space + 1, message:find(" ", next_space + 1)
|
||||
last_space, next_space = next_space + 1,
|
||||
message:find(" ", next_space + 1)
|
||||
else
|
||||
last_space = next_space + 1
|
||||
break
|
||||
|
@ -241,9 +268,11 @@ function handle_chat_message(sendername, message)
|
|||
local success, response = cmd.func(sendername, params)
|
||||
if response then
|
||||
if success == true then
|
||||
minetest.chat_send_player(sendername, string.format(success_format, response))
|
||||
minetest.chat_send_player(sendername, string.format(
|
||||
success_format, response))
|
||||
elseif success == false then
|
||||
minetest.chat_send_player(sendername, string.format(error_format, response))
|
||||
minetest.chat_send_player(sendername,
|
||||
string.format(error_format, response))
|
||||
else
|
||||
minetest.chat_send_player(sendername, response)
|
||||
end
|
||||
|
@ -254,11 +283,6 @@ end
|
|||
|
||||
table.insert(core.registered_on_chat_messages, 1, handle_chat_message)
|
||||
|
||||
modlib.mod.extend("cmdlib", "override")
|
||||
-- Tests - only uncomment if testing stuff
|
||||
--[[
|
||||
dofile("test.lua")
|
||||
]]
|
||||
function build_info(chatcommands)
|
||||
local new_info = {}
|
||||
for name, def in pairs(chatcommands) do
|
||||
|
@ -272,6 +296,7 @@ function build_info(chatcommands)
|
|||
table.insert(newforbiddenprivs, priv)
|
||||
end
|
||||
end
|
||||
newdef.implicit_call = def.implicit_call
|
||||
newdef.description = def.description or ""
|
||||
newdef.descriptions = wrap_text(def.description or "", 60)
|
||||
newdef.privs = next(newprivs) and newprivs
|
||||
|
@ -283,18 +308,11 @@ function build_info(chatcommands)
|
|||
newdef.subcommands = build_info(newdef.subcommands)
|
||||
end
|
||||
end
|
||||
table.sort(
|
||||
new_info,
|
||||
function(d1, d2)
|
||||
return d1.name < d2.name
|
||||
end
|
||||
)
|
||||
table.sort(new_info, function(d1, d2) return d1.name < d2.name end)
|
||||
return new_info
|
||||
end
|
||||
|
||||
minetest.register_on_mods_loaded(
|
||||
function()
|
||||
modlib.mod.extend("cmdlib", "help")
|
||||
chatcommand_info = build_info(chatcommand_info)
|
||||
end
|
||||
)
|
||||
minetest.register_on_mods_loaded(function()
|
||||
modlib.mod.extend("cmdlib", "help")
|
||||
chatcommand_info = build_info(chatcommand_info)
|
||||
end)
|
||||
|
|
28
override.lua
28
override.lua
|
@ -1,16 +1,21 @@
|
|||
minetest.original_register_chatcommand = minetest.register_chatcommand
|
||||
minetest.original_override_chatcommand = minetest.override_chatcommand
|
||||
minetest.original_unregister_chatcommand = minetest.unregister_chatcommand
|
||||
|
||||
local minetest_register_chatcommand = function(name, def)
|
||||
register_chatcommand(name, {
|
||||
description = def.description,
|
||||
privs = def.privs,
|
||||
params = def.params,
|
||||
custom_syntax = true,
|
||||
func = def.func
|
||||
})
|
||||
function minetest_register_chatcommand_generator(override)
|
||||
return function(name, def, override)
|
||||
register_chatcommand(name, {
|
||||
description = def.description,
|
||||
privs = def.privs,
|
||||
params = def.params,
|
||||
custom_syntax = true,
|
||||
func = def.func
|
||||
}, override)
|
||||
end
|
||||
end
|
||||
|
||||
local minetest_register_chatcommand = minetest_register_chatcommand_generator()
|
||||
|
||||
for name, def in pairs(minetest.registered_chatcommands) do
|
||||
minetest_register_chatcommand(name, def)
|
||||
end
|
||||
|
@ -20,7 +25,10 @@ minetest.register_chatcommand = function(name, def)
|
|||
minetest.original_register_chatcommand(name, def)
|
||||
end
|
||||
|
||||
local minetest_override_chatcommand = minetest_register_chatcommand_generator(true)
|
||||
minetest.override_chatcommand = function(name, def)
|
||||
minetest_register_chatcommand(name, def)
|
||||
minetest_override_chatcommand(name, def)
|
||||
minetest.original_override_chatcommand(name, def)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.unregister_chatcommand = unregister_chatcommand
|
24
test.lua
24
test.lua
|
@ -6,14 +6,19 @@ function test_format()
|
|||
end
|
||||
|
||||
function test_chatcommands()
|
||||
cmdlib.register_chatcommand("cmdlib_test", {
|
||||
--[[cmdlib.register_chatcommand("cmdlib_test", {
|
||||
params = "<param1>",
|
||||
privs = {fast = true},
|
||||
description = "Test command for cmdlib.",
|
||||
func = function(sendername, params)
|
||||
return true, "You shouted "..(params.param1)
|
||||
end
|
||||
})]]
|
||||
cmdlib.register_chatcommand("this", {
|
||||
params = "<param1>",
|
||||
func = function() end
|
||||
})
|
||||
cmdlib.unregister_chatcommand("this")
|
||||
cmdlib.register_chatcommand("cmdlib_test say", {
|
||||
params = "<param1>",
|
||||
privs = {fast = true, noclip = false},
|
||||
|
@ -22,23 +27,23 @@ function test_chatcommands()
|
|||
return true, "You said "..(params.param1)
|
||||
end
|
||||
})
|
||||
-- TODO fix error when invoking without params (should say params required ?)
|
||||
cmdlib.register_chatcommand("cmdlib_test bark", {
|
||||
cmdlib.register_chatcommand("cmdlib_test repeat", {
|
||||
params = "<param1>",
|
||||
privs = {fast = true},
|
||||
description = "Test command for cmdlib.",
|
||||
func = function(sendername, params)
|
||||
return true, "You barked "..(params.param1)
|
||||
return true, "Param1: "..(params.param1)
|
||||
end
|
||||
})
|
||||
cmdlib.register_chatcommand("cmdlib_test bark loud", {
|
||||
cmdlib.register_chatcommand("cmdlib_test shout loud", {
|
||||
params = "[param1]",
|
||||
privs = {fast = true},
|
||||
description = "Test command : cmdlib.",
|
||||
description = "Test command with a different description.",
|
||||
func = function(sendername, params)
|
||||
return true, "You BARKED "..(params.param1 or "IDK")
|
||||
return true, "You SHOUTED "..(params.param1 or "IDK")
|
||||
end
|
||||
})
|
||||
cmdlib.unregister_chatcommand("cmdlib_test shout loud")
|
||||
end
|
||||
|
||||
function test_trie()
|
||||
|
@ -46,7 +51,6 @@ function test_trie()
|
|||
trie.insert(t, "help")
|
||||
trie.insert(t, "heap")
|
||||
trie.insert(t, "me")
|
||||
--trie.insert(t, "heap")
|
||||
print(trie.search(t, "hewp"))
|
||||
trie.remove(t, "heap")
|
||||
print(trie.search(t, "help"))
|
||||
|
@ -62,6 +66,4 @@ end
|
|||
test_chatcommands()
|
||||
-- test_format()
|
||||
-- test_trie()
|
||||
-- test_info()
|
||||
|
||||
--minetest.register_node("cmdlib:item", {description = minetest.get_color_escape_sequence("#FF0000").."✗ Looks like there's an error !"})
|
||||
-- test_info()
|
Loading…
Reference in New Issue