diff --git a/mods/MISC/mcl_commands/init.lua b/mods/MISC/mcl_commands/init.lua index 7a9fe4868b..04ff7e6021 100644 --- a/mods/MISC/mcl_commands/init.lua +++ b/mods/MISC/mcl_commands/init.lua @@ -4,6 +4,227 @@ local mod_death_messages = minetest.get_modpath("mcl_death_messages") local modpath = minetest.get_modpath(minetest.get_current_modname()) +mcl_commands = {} + +mcl_commands.types = { + pos = "%(? *(%-?[%d.]+) *, *(%-?[%d.]+) *, *(%-?[%d.]+) *%)?", + text = "(.+)", + number = "(%-?[%d.]+)", + int = "(%-?[%d]+)", + word = "([^ ]+)", + alpha = "([A-Za-z]+)", + modname = "([a-z0-9_]+)", + alphascore = "([A-Za-z_]+)", + alphanumeric = "([A-Za-z0-9]+)", + username = "([A-Za-z0-9-_]+)", --TODO: add json type +} + +function mcl_commands.register_command(name, func, def) + def = def or {} + local cmd = mcl_commands.build(func) + cmd.def = def + def.func = cmd.run + if minetest.registered_chatcommands[name] then + error("[mcl_commands] Failed to register command: ["..name.."] command already existing! Use mcl_commands.overide_command() if you want to overide existing command") + end + minetest.register_chatcommand(name, def) + return cmd +end + +function mcl_commands.overide_command(name, func, def) + def = def or {} + local cmd = mcl_commands.build(func) + cmd.def = def + def.func = cmd.run + if minetest.registered_chatcommands[name] then + minetest.unregister_chatcommand(name) + end + minetest.register_chatcommand(name, def) + return cmd +end + +local STATE_READY = 1 +local STATE_PARAM = 2 +local STATE_PARAM_TYPE = 3 +local bad_chars = {} +bad_chars["("] = true +bad_chars[")"] = true +bad_chars["."] = true +bad_chars["%"] = true +bad_chars["+"] = true +bad_chars["-"] = true +bad_chars["*"] = true +bad_chars["?"] = true +bad_chars["["] = true +bad_chars["^"] = true +bad_chars["$"] = true +local function escape(char) + if bad_chars[char] then + return "%" .. char + else + return char + end +end + +local dprint = function() end + +function mcl_commands.build(func) + local cmd = { + _subs = {} + } + function cmd:sub(route, func, def) + dprint("Parsing " .. route) + + def = def or {} + if string.trim then + route = string.trim(route) + end + + local sub = { + pattern = "^", + params = {}, + func = func + } + + -- End of param reached: add it to the pattern + local param = "" + local param_type = "" + local should_be_eos = false + local function finishParam() + if param ~= "" and param_type ~= "" then + dprint(" - Found param " .. param .. " type " .. param_type) + + local pattern = mcl_commands.types[param_type] + if not pattern then + error("Unrecognised param_type=" .. param_type) + end + + sub.pattern = sub.pattern .. pattern + + table.insert(sub.params, param_type) + + param = "" + param_type = "" + end + end + + -- Iterate through the route to find params + local state = STATE_READY + local catching_space = false + local match_space = " " -- change to "%s" to also catch tabs and newlines + local catch_space = match_space.."+" + for i = 1, #route do + local c = route:sub(i, i) + if should_be_eos then + error("Should be end of string. Nothing is allowed after a param of type text.") + end + + if state == STATE_READY then + if c == ":" then + dprint(" - Found :, entering param") + state = STATE_PARAM + param_type = "word" + catching_space = false + elseif c:match(match_space) then + print(" - Found space") + if not catching_space then + catching_space = true + sub.pattern = sub.pattern .. catch_space + end + else + catching_space = false + sub.pattern = sub.pattern .. escape(c) + end + elseif state == STATE_PARAM then + if c == ":" then + dprint(" - Found :, entering param type") + state = STATE_PARAM_TYPE + param_type = "" + elseif c:match(match_space) then + print(" - Found whitespace, leaving param") + state = STATE_READY + finishParam() + catching_space = true + sub.pattern = sub.pattern .. catch_space + elseif c:match("%W") then + dprint(" - Found nonalphanum, leaving param") + state = STATE_READY + finishParam() + sub.pattern = sub.pattern .. escape(c) + else + param = param .. c + end + elseif state == STATE_PARAM_TYPE then + if c:match(match_space) then + print(" - Found space, leaving param type") + state = STATE_READY + finishParam() + catching_space = true + sub.pattern = sub.pattern .. catch_space + elseif c:match("%W") then + dprint(" - Found nonalphanum, leaving param type") + state = STATE_READY + finishParam() + sub.pattern = sub.pattern .. escape(c) + else + param_type = param_type .. c + end + end + end + dprint(" - End of route") + finishParam() + sub.pattern = sub.pattern .. "$" + dprint("Pattern: " .. sub.pattern) + + table.insert(self._subs, sub) + end + + if func then + func(cmd) + end + + cmd.run = function(name, param) + for i = 1, #cmd._subs do + local sub = cmd._subs[i] + local res = { string.match(param, sub.pattern) } + if #res > 0 then + local pointer = 1 + local params = { name } + for j = 1, #sub.params do + local param = sub.params[j] + if param == "pos" then + local pos = { + x = tonumber(res[pointer]), + y = tonumber(res[pointer + 1]), + z = tonumber(res[pointer + 2]) + } + table.insert(params, pos) + pointer = pointer + 3 + elseif param == "number" or param == "int" then + table.insert(params, tonumber(res[pointer])) + pointer = pointer + 1 + else + table.insert(params, res[pointer]) + pointer = pointer + 1 + end + end + if table.unpack then + -- lua 5.2 or later + return sub.func(table.unpack(params)) + else + -- lua 5.1 or earlier + return sub.func(unpack(params)) + end + end + end + return false, "Invalid command" + end + + return cmd +end + + + dofile(modpath.."/kill.lua") dofile(modpath.."/setblock.lua") dofile(modpath.."/seed.lua") diff --git a/mods/MISC/mcl_commands/kill.lua b/mods/MISC/mcl_commands/kill.lua index 2de69e6a0b..a212bcb45e 100644 --- a/mods/MISC/mcl_commands/kill.lua +++ b/mods/MISC/mcl_commands/kill.lua @@ -41,19 +41,11 @@ local function handle_kill_command(suspect, victim) return true end -if minetest.registered_chatcommands["kill"] then - minetest.unregister_chatcommand("kill") -end -minetest.register_chatcommand("kill", { - params = S("[]"), - description = S("Kill player or yourself"), - privs = {server=true}, - func = function(name, param) - if(param == "") then - -- Selfkill - return handle_kill_command(name, name) - else - return handle_kill_command(name, param) - end - end, -}) \ No newline at end of file +mcl_commands.overide_command("kill", function(cmd) + cmd:sub("", function(name) + return handle_kill_command(name, name) + end) + cmd:sub(":target:username", function(name, target) + return handle_kill_command(name, target) + end) +end) \ No newline at end of file