botcmds.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. irc.bot_commands = {}
  2. -- From RFC1459:
  3. -- "Because of IRC’s scandanavian origin, the characters {}| are
  4. -- considered to be the lower case equivalents of the characters
  5. -- []\, respectively."
  6. local irctolower = { ["["]="{", ["\\"]="|", ["]"]="}" }
  7. local function irclower(s)
  8. return (s:lower():gsub("[%[%]\\]", irctolower))
  9. end
  10. local function nickequals(nick1, nick2)
  11. return irclower(nick1) == irclower(nick2)
  12. end
  13. function irc.check_botcmd(msg)
  14. local prefix = irc.config.command_prefix
  15. local nick = irc.conn.nick
  16. local text = msg.args[2]
  17. local nickpart = text:sub(1, #nick)
  18. local suffix = text:sub(#nick+1, #nick+2)
  19. -- First check for a nick prefix
  20. if nickequals(nickpart, nick)
  21. and (suffix == ": " or suffix == ", ") then
  22. irc.bot_command(msg, text:sub(#nick + 3))
  23. return true
  24. -- Then check for the configured prefix
  25. elseif prefix and text:sub(1, #prefix):lower() == prefix:lower() then
  26. irc.bot_command(msg, text:sub(#prefix + 1))
  27. return true
  28. end
  29. return false
  30. end
  31. function irc.bot_command(msg, text)
  32. -- Remove leading whitespace
  33. text = text:match("^%s*(.*)")
  34. if text:sub(1, 1) == "@" then
  35. local _, _, player_to, message = text:find("^.([^%s]+)%s(.+)$")
  36. if not player_to then
  37. return
  38. elseif not minetest.get_player_by_name(player_to) then
  39. irc.reply("User '"..player_to.."' is not in the game.")
  40. return
  41. elseif not irc.joined_players[player_to] then
  42. irc.reply("User '"..player_to.."' is not using IRC.")
  43. return
  44. end
  45. minetest.chat_send_player(player_to,
  46. minetest.colorize(irc.config.pm_color,
  47. "PM from "..msg.user.nick.."@IRC: "..message, false))
  48. irc.reply("Message sent!")
  49. return
  50. end
  51. local pos = text:find(" ", 1, true)
  52. local cmd, args
  53. if pos then
  54. cmd = text:sub(1, pos - 1)
  55. args = text:sub(pos + 1)
  56. else
  57. cmd = text
  58. args = ""
  59. end
  60. if not irc.bot_commands[cmd] then
  61. irc.reply("Unknown command '"..cmd.."'. Try 'help'."
  62. .." Or use @playername <message> to send a private message")
  63. return
  64. end
  65. local _, message = irc.bot_commands[cmd].func(msg.user, args)
  66. if message then
  67. irc.reply(message)
  68. end
  69. end
  70. function irc.register_bot_command(name, def)
  71. if (not def.func) or (type(def.func) ~= "function") then
  72. error("Erroneous bot command definition. def.func missing.", 2)
  73. elseif name:sub(1, 1) == "@" then
  74. error("Erroneous bot command name. Command name begins with '@'.", 2)
  75. end
  76. irc.bot_commands[name] = def
  77. end
  78. irc.register_bot_command("help", {
  79. params = "<command>",
  80. description = "Get help about a command",
  81. func = function(_, args)
  82. if args == "" then
  83. local cmdlist = { }
  84. for name in pairs(irc.bot_commands) do
  85. cmdlist[#cmdlist+1] = name
  86. end
  87. return true, "Available commands: "..table.concat(cmdlist, ", ")
  88. .." -- Use 'help <command name>' to get"
  89. .." help about a specific command."
  90. end
  91. local cmd = irc.bot_commands[args]
  92. if not cmd then
  93. return false, "Unknown command '"..args.."'."
  94. end
  95. return true, ("Usage: %s%s %s -- %s"):format(
  96. irc.config.command_prefix or "",
  97. args,
  98. cmd.params or "<no parameters>",
  99. cmd.description or "<no description>")
  100. end
  101. })
  102. irc.register_bot_command("list", {
  103. params = "",
  104. description = "List available commands.",
  105. func = function()
  106. return false, "The `list` command has been merged into `help`."
  107. .." Use `help` with no arguments to get a list."
  108. end
  109. })
  110. irc.register_bot_command("whereis", {
  111. params = "<player>",
  112. description = "Tell the location of <player>",
  113. func = function(_, args)
  114. if args == "" then
  115. return false, "Player name required."
  116. end
  117. local player = minetest.get_player_by_name(args)
  118. if not player then
  119. return false, "There is no player named '"..args.."'"
  120. end
  121. local fmt = "Player %s is at (%.2f,%.2f,%.2f)"
  122. local pos = player:get_pos()
  123. return true, fmt:format(args, pos.x, pos.y, pos.z)
  124. end
  125. })
  126. local starttime = os.time()
  127. irc.register_bot_command("uptime", {
  128. description = "Tell how much time the server has been up",
  129. func = function()
  130. local cur_time = os.time()
  131. local diff = os.difftime(cur_time, starttime)
  132. local fmt = "Server has been running for %d:%02d:%02d"
  133. return true, fmt:format(
  134. math.floor(diff / 60 / 60),
  135. math.floor(diff / 60) % 60,
  136. math.floor(diff) % 60
  137. )
  138. end
  139. })
  140. irc.register_bot_command("players", {
  141. description = "List the players on the server",
  142. func = function()
  143. local players = minetest.get_connected_players()
  144. local names = {}
  145. for _, player in pairs(players) do
  146. table.insert(names, player:get_player_name())
  147. end
  148. return true, "Connected players: "
  149. ..table.concat(names, ", ")
  150. end
  151. })