├── .github └── workflows │ └── check-release.yml ├── .gitignore ├── .gitmodules ├── .luacheckrc ├── API.md ├── LICENSE.txt ├── README.md ├── botcmds.lua ├── callback.lua ├── chatcmds.lua ├── config.lua ├── hooks.lua ├── init.lua ├── messages.lua ├── mod.conf ├── player_part.lua └── settingtypes.txt /.github/workflows/check-release.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: Check & Release 3 | jobs: 4 | lint: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@master 8 | - name: lint 9 | uses: Roang-zero1/factorio-mod-luacheck@master 10 | with: 11 | luacheckrc_url: https://raw.githubusercontent.com/minetest-mods/irc/master/.luacheckrc 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/LuaIRC"] 2 | path = irc 3 | url = https://github.com/ShadowNinja/LuaIRC.git 4 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | 2 | allow_defined_top = true 3 | 4 | read_globals = { 5 | "minetest" 6 | } 7 | 8 | exclude_files = { 9 | "irc/*", 10 | } 11 | 12 | globals = { 13 | "irc", 14 | } 15 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | IRC Mod API 2 | =========== 3 | 4 | This file documents the Minetest IRC mod API. 5 | 6 | Basics 7 | ------ 8 | 9 | In order to allow your mod to interface with this mod, you must add `irc` 10 | to your mod's `depends.txt` file. 11 | 12 | 13 | Reference 14 | --------- 15 | 16 | irc.say([name,] message) 17 | Sends to either the channel (if is nil or not specified), 18 | or to the given user (if is specified). 19 | Example: 20 | irc.say("Hello, Channel!") 21 | irc.say("john1234", "How are you?") 22 | 23 | irc.register_bot_command(name, cmdDef) 24 | Registers a new bot command named . 25 | When an user sends a private message to the bot with the command name, the 26 | command's function is called. 27 | Here's the format of a command definition (): 28 | cmdDef = { 29 | params = " ...", -- A description of the command's parameters 30 | description = "My command", -- A description of what the command does. (one-liner) 31 | func = function(user, args) 32 | -- This function gets called when the command is invoked. 33 | -- is a user table for the user that ran the command. 34 | -- (See the LuaIRC documentation for details.) 35 | -- It contains fields such as 'nick' and 'ident' 36 | -- is a string of arguments to the command (may be "") 37 | -- This function should return boolean success and a message. 38 | end, 39 | }; 40 | Example: 41 | irc.register_bot_command("hello", { 42 | params = "", 43 | description = "Greet user", 44 | func = function(user, param) 45 | return true, "Hello!" 46 | end, 47 | }); 48 | 49 | irc.joined_players[name] 50 | This table holds the players who are currently on the channel (may be less 51 | than the players in the game). It is modified by the /part and /join chat 52 | commands. 53 | Example: 54 | if irc.joined_players["joe"] then 55 | -- Joe is talking on IRC 56 | end 57 | 58 | irc.register_hook(name, func) 59 | Registers a function to be called when an event happens. is the name 60 | of the event, and is the function to be called. See HOOKS below 61 | for more information 62 | Example: 63 | irc.register_hook("OnSend", function(line) 64 | print("SEND: "..line) 65 | end) 66 | 67 | This mod also supplies some utility functions: 68 | 69 | string.expandvars(string, vars) 70 | Expands all occurrences of the pattern "$(varname)" with the value of 71 | 'varname' in the table. Variable names not found on the table 72 | are left verbatim in the string. 73 | Example: 74 | local tpl = "$(foo) $(bar) $(baz)" 75 | local s = tpl:expandvars({foo=1, bar="Hello"}) 76 | assert(s == "1 Hello $(baz)") 77 | 78 | In addition, all the configuration options decribed in `README.txt` are 79 | available to other mods, though they should be considered read-only. Do 80 | not modify these settings at runtime or you might crash the server! 81 | 82 | 83 | Hooks 84 | ----- 85 | 86 | The `irc.register_hook` function can register functions to be called 87 | when some events happen. The events supported are the same as the LuaIRC 88 | ones with a few added (mostly for internal use). 89 | See src/LuaIRC/doc/irc.luadoc for more information. 90 | 91 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Diego Martinez (kaeza) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | - Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 13 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 16 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 19 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 20 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 21 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://github.com/minetest-mods/irc/workflows/Check%20&%20Release/badge.svg)](https://github.com/minetest-mods/irc/actions) 2 | 3 | IRC Mod for Minetest 4 | ==================== 5 | 6 | Introduction 7 | ------------ 8 | 9 | This mod is just a glue between IRC and Minetest. It provides two-way 10 | communication between the in-game chat, and an arbitrary IRC channel. 11 | 12 | The forum topic is [here][forum]. 13 | 14 | [forum]: https://forum.minetest.net/viewtopic.php?f=11&t=3905 15 | 16 | 17 | Installing 18 | ---------- 19 | 20 | Quick one line install for Linux: 21 | 22 | cd && git clone --recursive https://github.com/minetest-mods/irc.git 23 | 24 | Please change `` to fit your installation of Minetest. 25 | For more information, see [the wiki][wiki]. 26 | 27 | The IRC mod's git repository uses submodules, therefore you will have to run 28 | `git submodule init` when first installing the mod (unless you used 29 | `--recursive` as above), and `git submodule update` every time that a submodule 30 | is updated. These steps can be combined into `git submodule update --init`. 31 | 32 | You'll need to install LuaSocket. You can do so with your package manager on 33 | many distributions, for example: 34 | 35 | # # On Arch Linux: 36 | # pacman -S lua51-socket 37 | # # On Debian/Ubuntu: 38 | # # Debian/Ubuntu's LuaSocket packages are broken, so use LuaRocks. 39 | # apt-get install luarocks 40 | # luarocks install luasocket 41 | 42 | You will also need to add IRC to your trusted mods if you haven't disabled mod 43 | security. Here's an example configuration line: 44 | 45 | secure.trusted_mods = irc 46 | 47 | [wiki]: https://wiki.minetest.net/Installing_mods 48 | 49 | 50 | Settings 51 | -------- 52 | 53 | All settings are changed in `minetest.conf`. If any of these settings 54 | are not set, the default value is used. 55 | 56 | * `irc.server` (string): 57 | The address of the IRC server to connect to. 58 | 59 | * `irc.channel` (string): 60 | The IRC channel to join. 61 | 62 | * `irc.interval` (number, default 2.0): 63 | This prevents the server from flooding. It should be at 64 | least 2.0 but can be higher. After four messages this much 65 | time must pass between folowing messages. 66 | 67 | * `irc.nick` (string): 68 | Nickname the server uses when it connects to IRC. 69 | 70 | * `irc.password` (string, default nil): 71 | Password to use when connecting to the server. 72 | 73 | * `irc.NSPass` (string, default nil): 74 | NickServ password. Don't set this if you use SASL authentication. 75 | 76 | * `irc.sasl.pass` (string, default nil): 77 | SASL password, same as nickserv password. 78 | You should use this instead of NickServ authentication 79 | if the server supports it. 80 | 81 | * `irc.sasl.user` (string, default `irc.nick`): 82 | The SASL username. This should normaly be set to your 83 | NickServ account name. 84 | 85 | * `irc.debug` (boolean, default false): 86 | Whether to output debug information. 87 | 88 | * `irc.disable_auto_connect` (boolean, default false): 89 | If false, the bot is connected by default. If true, a player with 90 | the 'irc_admin' privilege has to use the `/irc_connect` command to 91 | connect to the server. 92 | 93 | * `irc.disable_auto_join` (boolean, default false): 94 | If false, players join the channel automatically upon entering the 95 | game. If true, each user must manually use the `/join` command to 96 | join the channel. In any case, the players may use the `/part` 97 | command to opt-out of being in the channel. 98 | 99 | * `irc.send_join_part` (boolean, default true): 100 | Determines whether to send player join and part messages to the channel. 101 | 102 | 103 | Usage 104 | ----- 105 | 106 | Once the game is connected to the IRC channel, chatting in-game will send 107 | messages to the channel, and will be visible by anyone. Also, messages sent 108 | to the channel will be visible in-game. 109 | 110 | Messages that begin with `[off]` from in-game or IRC are not sent to the 111 | other side. 112 | 113 | This mod also adds a few chat commands: 114 | 115 | * `/irc_msg `: 116 | Send a private message to a IRC user. 117 | 118 | * `/join`: 119 | Join the IRC chat. 120 | 121 | * `/part`: 122 | Part the IRC chat. 123 | 124 | * `/irc_connect`: 125 | Connect the bot manually to the IRC network. 126 | 127 | * `/irc_disconnect`: 128 | Disconnect the bot manually from the IRC network (this does not 129 | shutdown the game). 130 | 131 | * `/irc_reconnect`: 132 | Equivalent to `/irc_disconnect` followed by `/irc_connect`. 133 | 134 | You can also send private messages from IRC to in-game players 135 | by sending a private message to the bot (set with the `irc.nick` 136 | option above), in the following format: 137 | 138 | @playername message 139 | 140 | For example, if there's a player named `mtuser`, you can send him/her 141 | a private message from IRC with: 142 | 143 | /msg server_nick @mtuser Hello! 144 | 145 | The bot also supports some basic commands, which are invoked by saying 146 | the bot name followed by either a colon or a comma and the command, or 147 | sending a private message to it. For example: `ServerBot: help whereis`. 148 | 149 | * `help []`: 150 | Prints help about a command, or a list of supported commands if no 151 | command is given. 152 | 153 | * `uptime`: 154 | Prints the server's running time. 155 | 156 | * `whereis `: 157 | Prints the coordinates of the given player. 158 | 159 | * `players`: 160 | Lists players currently in the server. 161 | 162 | 163 | Thanks 164 | ------ 165 | 166 | I'd like to thank the users who supported this mod both on the Minetest 167 | Forums and on the `#minetest` channel. In no particular order: 168 | 169 | 0gb.us, ShadowNinja, Shaun/kizeren, RAPHAEL, DARGON, Calinou, Exio, 170 | vortexlabs/mrtux, marveidemanis, marktraceur, jmf/john\_minetest, 171 | sdzen/Muadtralk, VanessaE, PilzAdam, sfan5, celeron55, KikaRz, 172 | OldCoder, RealBadAngel, and all the people who commented in the 173 | forum topic. Thanks to you all! 174 | 175 | 176 | License 177 | ------- 178 | 179 | See `LICENSE.txt` for details. 180 | 181 | The files in the `irc` directory are part of the LuaIRC project. 182 | See `irc/LICENSE.txt` for details. 183 | -------------------------------------------------------------------------------- /botcmds.lua: -------------------------------------------------------------------------------- 1 | 2 | irc.bot_commands = {} 3 | 4 | -- From RFC1459: 5 | -- "Because of IRC’s scandanavian origin, the characters {}| are 6 | -- considered to be the lower case equivalents of the characters 7 | -- []\, respectively." 8 | local irctolower = { ["["]="{", ["\\"]="|", ["]"]="}" } 9 | 10 | local function irclower(s) 11 | return (s:lower():gsub("[%[%]\\]", irctolower)) 12 | end 13 | 14 | local function nickequals(nick1, nick2) 15 | return irclower(nick1) == irclower(nick2) 16 | end 17 | 18 | function irc.check_botcmd(msg) 19 | local prefix = irc.config.command_prefix 20 | local nick = irc.conn.nick 21 | local text = msg.args[2] 22 | local nickpart = text:sub(1, #nick) 23 | local suffix = text:sub(#nick+1, #nick+2) 24 | 25 | -- First check for a nick prefix 26 | if nickequals(nickpart, nick) 27 | and (suffix == ": " or suffix == ", ") then 28 | irc.bot_command(msg, text:sub(#nick + 3)) 29 | return true 30 | -- Then check for the configured prefix 31 | elseif prefix and text:sub(1, #prefix):lower() == prefix:lower() then 32 | irc.bot_command(msg, text:sub(#prefix + 1)) 33 | return true 34 | end 35 | return false 36 | end 37 | 38 | 39 | function irc.bot_command(msg, text) 40 | -- Remove leading whitespace 41 | text = text:match("^%s*(.*)") 42 | if text:sub(1, 1) == "@" then 43 | local _, _, player_to, message = text:find("^.([^%s]+)%s(.+)$") 44 | if not player_to then 45 | return 46 | elseif not minetest.get_player_by_name(player_to) then 47 | irc.reply("User '"..player_to.."' is not in the game.") 48 | return 49 | elseif not irc.joined_players[player_to] then 50 | irc.reply("User '"..player_to.."' is not using IRC.") 51 | return 52 | end 53 | minetest.chat_send_player(player_to, 54 | minetest.colorize(irc.config.pm_color, 55 | "PM from "..msg.user.nick.."@IRC: "..message, false)) 56 | irc.reply("Message sent!") 57 | return 58 | end 59 | local pos = text:find(" ", 1, true) 60 | local cmd, args 61 | if pos then 62 | cmd = text:sub(1, pos - 1) 63 | args = text:sub(pos + 1) 64 | else 65 | cmd = text 66 | args = "" 67 | end 68 | 69 | if not irc.bot_commands[cmd] then 70 | irc.reply("Unknown command '"..cmd.."'. Try 'help'." 71 | .." Or use @playername to send a private message") 72 | return 73 | end 74 | 75 | local _, message = irc.bot_commands[cmd].func(msg.user, args) 76 | if message then 77 | irc.reply(message) 78 | end 79 | end 80 | 81 | 82 | function irc.register_bot_command(name, def) 83 | if (not def.func) or (type(def.func) ~= "function") then 84 | error("Erroneous bot command definition. def.func missing.", 2) 85 | elseif name:sub(1, 1) == "@" then 86 | error("Erroneous bot command name. Command name begins with '@'.", 2) 87 | end 88 | irc.bot_commands[name] = def 89 | end 90 | 91 | 92 | irc.register_bot_command("help", { 93 | params = "", 94 | description = "Get help about a command", 95 | func = function(_, args) 96 | if args == "" then 97 | local cmdlist = { } 98 | for name in pairs(irc.bot_commands) do 99 | cmdlist[#cmdlist+1] = name 100 | end 101 | return true, "Available commands: "..table.concat(cmdlist, ", ") 102 | .." -- Use 'help ' to get" 103 | .." help about a specific command." 104 | end 105 | 106 | local cmd = irc.bot_commands[args] 107 | if not cmd then 108 | return false, "Unknown command '"..args.."'." 109 | end 110 | 111 | return true, ("Usage: %s%s %s -- %s"):format( 112 | irc.config.command_prefix or "", 113 | args, 114 | cmd.params or "", 115 | cmd.description or "") 116 | end 117 | }) 118 | 119 | 120 | irc.register_bot_command("list", { 121 | params = "", 122 | description = "List available commands.", 123 | func = function() 124 | return false, "The `list` command has been merged into `help`." 125 | .." Use `help` with no arguments to get a list." 126 | end 127 | }) 128 | 129 | 130 | irc.register_bot_command("whereis", { 131 | params = "", 132 | description = "Tell the location of ", 133 | func = function(_, args) 134 | if args == "" then 135 | return false, "Player name required." 136 | end 137 | local player = minetest.get_player_by_name(args) 138 | if not player then 139 | return false, "There is no player named '"..args.."'" 140 | end 141 | local fmt = "Player %s is at (%.2f,%.2f,%.2f)" 142 | local pos = player:get_pos() 143 | return true, fmt:format(args, pos.x, pos.y, pos.z) 144 | end 145 | }) 146 | 147 | 148 | local starttime = os.time() 149 | irc.register_bot_command("uptime", { 150 | description = "Tell how much time the server has been up", 151 | func = function() 152 | local cur_time = os.time() 153 | local diff = os.difftime(cur_time, starttime) 154 | local fmt = "Server has been running for %d:%02d:%02d" 155 | return true, fmt:format( 156 | math.floor(diff / 60 / 60), 157 | math.floor(diff / 60) % 60, 158 | math.floor(diff) % 60 159 | ) 160 | end 161 | }) 162 | 163 | 164 | irc.register_bot_command("players", { 165 | description = "List the players on the server", 166 | func = function() 167 | local players = minetest.get_connected_players() 168 | local names = {} 169 | for _, player in pairs(players) do 170 | table.insert(names, player:get_player_name()) 171 | end 172 | return true, string.format("%d connected player(s): %s", 173 | #players, 174 | table.concat(names, ", ") 175 | ) 176 | end 177 | }) 178 | 179 | -------------------------------------------------------------------------------- /callback.lua: -------------------------------------------------------------------------------- 1 | -- This file is licensed under the terms of the BSD 2-clause license. 2 | -- See LICENSE.txt for details. 3 | 4 | 5 | minetest.register_on_joinplayer(function(player) 6 | local name = player:get_player_name() 7 | if irc.connected and irc.config.send_join_part then 8 | irc.say("*** "..name.." joined the game") 9 | end 10 | end) 11 | 12 | 13 | minetest.register_on_leaveplayer(function(player, timed_out) 14 | local name = player:get_player_name() 15 | if irc.connected and irc.config.send_join_part then 16 | irc.say("*** "..name.." left the game".. 17 | (timed_out and " (Timed out)" or "")) 18 | end 19 | end) 20 | 21 | 22 | minetest.register_on_chat_message(function(name, message) 23 | if not irc.connected 24 | or message:sub(1, 1) == "/" 25 | or message:sub(1, 5) == "[off]" 26 | or not irc.joined_players[name] 27 | or (not minetest.check_player_privs(name, {shout=true})) then 28 | return 29 | end 30 | local nl = message:find("\n", 1, true) 31 | if nl then 32 | message = message:sub(1, nl - 1) 33 | end 34 | irc.say(irc.playerMessage(name, minetest.strip_colors(message))) 35 | end) 36 | 37 | 38 | minetest.register_on_shutdown(function() 39 | irc.disconnect("Game shutting down.") 40 | end) 41 | 42 | -------------------------------------------------------------------------------- /chatcmds.lua: -------------------------------------------------------------------------------- 1 | -- This file is licensed under the terms of the BSD 2-clause license. 2 | -- See LICENSE.txt for details. 3 | 4 | -- Note: This file does NOT conatin every chat command, only general ones. 5 | -- Feature-specific commands (like /join) are in their own files. 6 | 7 | 8 | minetest.register_chatcommand("irc_msg", { 9 | params = " ", 10 | description = "Send a private message to an IRC user", 11 | privs = {shout=true}, 12 | func = function(name, param) 13 | if not irc.connected then 14 | return false, "Not connected to IRC. Use /irc_connect to connect." 15 | end 16 | local found, _, toname, message = param:find("^([^%s]+)%s(.+)") 17 | if not found then 18 | return false, "Invalid usage, see /help irc_msg." 19 | end 20 | local toname_l = toname:lower() 21 | local validNick = false 22 | local hint = "They have to be in the channel" 23 | for nick in pairs(irc.conn.channels[irc.config.channel].users) do 24 | if nick:lower() == toname_l then 25 | validNick = true 26 | break 27 | end 28 | end 29 | if toname_l:find("serv$") or toname_l:find("bot$") then 30 | hint = "it looks like a bot or service" 31 | validNick = false 32 | end 33 | if not validNick then 34 | return false, "You can not message that user. ("..hint..")" 35 | end 36 | irc.say(toname, irc.playerMessage(name, message)) 37 | return true, "Message sent!" 38 | end 39 | }) 40 | 41 | 42 | minetest.register_chatcommand("irc_names", { 43 | params = "", 44 | description = "List the users in IRC.", 45 | func = function() 46 | if not irc.connected then 47 | return false, "Not connected to IRC. Use /irc_connect to connect." 48 | end 49 | local users = { } 50 | for nick in pairs(irc.conn.channels[irc.config.channel].users) do 51 | table.insert(users, nick) 52 | end 53 | return true, "Users in IRC: "..table.concat(users, ", ") 54 | end 55 | }) 56 | 57 | 58 | minetest.register_chatcommand("irc_connect", { 59 | description = "Connect to the IRC server.", 60 | privs = {irc_admin=true}, 61 | func = function(name) 62 | if irc.connected then 63 | return false, "You are already connected to IRC." 64 | end 65 | minetest.chat_send_player(name, "IRC: Connecting...") 66 | irc.connect() 67 | end 68 | }) 69 | 70 | 71 | minetest.register_chatcommand("irc_disconnect", { 72 | params = "[message]", 73 | description = "Disconnect from the IRC server.", 74 | privs = {irc_admin=true}, 75 | func = function(name, param) 76 | if not irc.connected then 77 | return false, "Not connected to IRC. Use /irc_connect to connect." 78 | end 79 | if param == "" then 80 | param = "Manual disconnect by "..name 81 | end 82 | irc.disconnect(param) 83 | end 84 | }) 85 | 86 | 87 | minetest.register_chatcommand("irc_reconnect", { 88 | description = "Reconnect to the IRC server.", 89 | privs = {irc_admin=true}, 90 | func = function(name) 91 | if not irc.connected then 92 | return false, "Not connected to IRC. Use /irc_connect to connect." 93 | end 94 | minetest.chat_send_player(name, "IRC: Reconnecting...") 95 | irc.disconnect("Reconnecting...") 96 | irc.connect() 97 | end 98 | }) 99 | 100 | 101 | minetest.register_chatcommand("irc_quote", { 102 | params = "", 103 | description = "Send a raw command to the IRC server.", 104 | privs = {irc_admin=true}, 105 | func = function(name, param) 106 | if not irc.connected then 107 | return false, "Not connected to IRC. Use /irc_connect to connect." 108 | end 109 | irc.queue(param) 110 | minetest.chat_send_player(name, "Command sent!") 111 | end 112 | }) 113 | 114 | 115 | local oldme = minetest.chatcommands["me"].func 116 | -- luacheck: ignore 117 | minetest.chatcommands["me"].func = function(name, param, ...) 118 | irc.say(("* %s %s"):format(name, param)) 119 | return oldme(name, param, ...) 120 | end 121 | 122 | if irc.config.send_kicks and minetest.chatcommands["kick"] then 123 | local oldkick = minetest.chatcommands["kick"].func 124 | -- luacheck: ignore 125 | minetest.chatcommands["kick"].func = function(name, param, ...) 126 | local plname, reason = param:match("^(%S+)%s*(.*)$") 127 | if not plname then 128 | return false, "Usage: /kick player [reason]" 129 | end 130 | irc.say(("*** Kicked %s.%s"):format(name, 131 | reason~="" and " Reason: "..reason or "")) 132 | return oldkick(name, param, ...) 133 | end 134 | end 135 | -------------------------------------------------------------------------------- /config.lua: -------------------------------------------------------------------------------- 1 | -- This file is licensed under the terms of the BSD 2-clause license. 2 | -- See LICENSE.txt for details. 3 | 4 | 5 | irc.config = {} 6 | 7 | local function setting(stype, name, default, required) 8 | local value 9 | if minetest.settings and minetest.settings.get and minetest.settings.get_bool then 10 | if stype == "bool" then 11 | value = minetest.settings:get_bool("irc."..name) 12 | elseif stype == "string" then 13 | value = minetest.settings:get("irc."..name) 14 | elseif stype == "number" then 15 | value = tonumber(minetest.settings:get("irc."..name)) 16 | end 17 | end 18 | if value == nil then 19 | if required then 20 | error("Required configuration option irc.".. 21 | name.." missing.") 22 | end 23 | value = default 24 | end 25 | irc.config[name] = value 26 | end 27 | 28 | ------------------------- 29 | -- BASIC USER SETTINGS -- 30 | ------------------------- 31 | 32 | setting("string", "nick", nil, true) -- Nickname 33 | setting("string", "server", nil, true) -- Server address to connect to 34 | setting("number", "port", 6667) -- Server port to connect to 35 | setting("string", "NSPass") -- NickServ password 36 | setting("string", "sasl.user", irc.config.nick) -- SASL username 37 | setting("string", "username", "Minetest") -- Username/ident 38 | setting("string", "realname", "Minetest") -- Real name/GECOS 39 | setting("string", "sasl.pass") -- SASL password 40 | setting("string", "channel", nil, true) -- Channel to join 41 | setting("string", "key") -- Key for the channel 42 | setting("bool", "send_join_part", true) -- Whether to send player join and part messages to the channel 43 | setting("bool", "send_kicks", false) -- Whether to send player kicked messages to the channel 44 | 45 | ----------------------- 46 | -- ADVANCED SETTINGS -- 47 | ----------------------- 48 | 49 | setting("string", "password") -- Server password 50 | setting("bool", "secure", false) -- Enable a TLS connection, requires LuaSEC 51 | setting("number", "timeout", 60) -- Underlying socket timeout in seconds. 52 | setting("number", "reconnect", 600) -- Time between reconnection attempts, in seconds. 53 | setting("string", "command_prefix") -- Prefix to use for bot commands 54 | setting("bool", "debug", false) -- Enable debug output 55 | setting("bool", "enable_player_part", true) -- Whether to enable players joining and parting the channel 56 | setting("bool", "auto_join", true) -- Whether to automatically show players in the channel when they join 57 | setting("bool", "auto_connect", true) -- Whether to automatically connect to the server on mod load 58 | setting("string", "chat_color", "#339933") -- Color of IRC chat in-game, green by default 59 | setting("string", "pm_color", "#8800AA") -- Color of IRC PMs in-game, purple by default 60 | -------------------------------------------------------------------------------- /hooks.lua: -------------------------------------------------------------------------------- 1 | -- This file is licensed under the terms of the BSD 2-clause license. 2 | -- See LICENSE.txt for details. 3 | 4 | local ie = ... 5 | 6 | -- MIME is part of LuaSocket 7 | local b64e = ie.require("mime").b64 8 | 9 | irc.hooks = {} 10 | irc.registered_hooks = {} 11 | 12 | 13 | local stripped_chars = "[\2\31]" 14 | 15 | local function normalize(text) 16 | -- Strip colors 17 | text = text:gsub("\3[0-9][0-9,]*", "") 18 | 19 | return text:gsub(stripped_chars, "") 20 | end 21 | 22 | 23 | function irc.doHook(conn) 24 | for name, hook in pairs(irc.registered_hooks) do 25 | for _, func in pairs(hook) do 26 | conn:hook(name, func) 27 | end 28 | end 29 | end 30 | 31 | 32 | function irc.register_hook(name, func) 33 | irc.registered_hooks[name] = irc.registered_hooks[name] or {} 34 | table.insert(irc.registered_hooks[name], func) 35 | end 36 | 37 | 38 | function irc.hooks.raw(line) 39 | if irc.config.debug then 40 | print("RECV: "..line) 41 | end 42 | end 43 | 44 | 45 | function irc.hooks.send(line) 46 | if irc.config.debug then 47 | print("SEND: "..line) 48 | end 49 | end 50 | 51 | 52 | function irc.hooks.chat(msg) 53 | local channel, text = msg.args[1], msg.args[2] 54 | if text:sub(1, 1) == string.char(1) then 55 | irc.conn:invoke("OnCTCP", msg) 56 | return 57 | end 58 | 59 | if channel == irc.conn.nick then 60 | irc.last_from = msg.user.nick 61 | irc.conn:invoke("PrivateMessage", msg) 62 | else 63 | irc.last_from = channel 64 | irc.conn:invoke("OnChannelChat", msg) 65 | end 66 | end 67 | 68 | 69 | local function get_core_version() 70 | local status = minetest.get_server_status() 71 | local start_pos = select(2, status:find("version=", 1, true)) 72 | local end_pos = status:find(",", start_pos, true) 73 | return status:sub(start_pos + 1, end_pos - 1) 74 | end 75 | 76 | 77 | function irc.hooks.ctcp(msg) 78 | local text = msg.args[2]:sub(2, -2) -- Remove ^C 79 | local args = text:split(' ') 80 | local command = args[1]:upper() 81 | 82 | local function reply(s) 83 | irc.queue(irc.msgs.notice(msg.user.nick, 84 | ("\1%s %s\1"):format(command, s))) 85 | end 86 | 87 | if command == "ACTION" and msg.args[1] == irc.config.channel then 88 | local action = text:sub(8, -1) 89 | irc.sendLocal(("* %s@IRC %s"):format(msg.user.nick, action)) 90 | elseif command == "VERSION" then 91 | reply(("Minetest version %s, IRC mod version %s.") 92 | :format(get_core_version(), irc.version)) 93 | elseif command == "PING" then 94 | reply(args[2]) 95 | elseif command == "TIME" then 96 | reply(os.date()) 97 | end 98 | end 99 | 100 | 101 | function irc.hooks.channelChat(msg) 102 | local text = normalize(msg.args[2]) 103 | 104 | irc.check_botcmd(msg) 105 | 106 | -- Don't let a user impersonate someone else by using the nick "IRC" 107 | local fake = msg.user.nick:lower():match("^[il|]rc$") 108 | if fake then 109 | irc.sendLocal("<"..msg.user.nick.."@IRC> "..text) 110 | return 111 | end 112 | 113 | -- Support multiple servers in a channel better by converting: 114 | -- " message" into " message" 115 | -- " *** player joined/left the game" into "*** player joined/left server" 116 | -- and " * player orders a pizza" into "* player@server orders a pizza" 117 | local foundchat, _, chatnick, chatmessage = 118 | text:find("^<([^>]+)> (.*)$") 119 | local foundjoin, _, joinnick = 120 | text:find("^%*%*%* ([^%s]+) joined the game$") 121 | local foundleave, _, leavenick = 122 | text:find("^%*%*%* ([^%s]+) left the game$") 123 | local foundtimedout, _, timedoutnick = 124 | text:find("^%*%*%* ([^%s]+) left the game %(Timed out%)$") 125 | local foundaction, _, actionnick, actionmessage = 126 | text:find("^%* ([^%s]+) (.*)$") 127 | 128 | if text:sub(1, 5) == "[off]" then 129 | return 130 | elseif foundchat then 131 | irc.sendLocal(("<%s@%s> %s") 132 | :format(chatnick, msg.user.nick, chatmessage)) 133 | elseif foundjoin then 134 | irc.sendLocal(("*** %s joined %s") 135 | :format(joinnick, msg.user.nick)) 136 | elseif foundleave then 137 | irc.sendLocal(("*** %s left %s") 138 | :format(leavenick, msg.user.nick)) 139 | elseif foundtimedout then 140 | irc.sendLocal(("*** %s left %s (Timed out)") 141 | :format(timedoutnick, msg.user.nick)) 142 | elseif foundaction then 143 | irc.sendLocal(("* %s@%s %s") 144 | :format(actionnick, msg.user.nick, actionmessage)) 145 | else 146 | irc.sendLocal(("<%s@IRC> %s"):format(msg.user.nick, text)) 147 | end 148 | end 149 | 150 | 151 | function irc.hooks.pm(msg) 152 | -- Trim prefix if it is found 153 | local text = msg.args[2] 154 | local prefix = irc.config.command_prefix 155 | if prefix and text:sub(1, #prefix) == prefix then 156 | text = text:sub(#prefix + 1) 157 | end 158 | irc.bot_command(msg, text) 159 | end 160 | 161 | 162 | function irc.hooks.kick(channel, target, prefix, reason) 163 | if target == irc.conn.nick then 164 | minetest.chat_send_all("IRC: kicked from "..channel.." by "..prefix.nick..".") 165 | irc.disconnect("Kicked") 166 | else 167 | irc.sendLocal(("-!- %s was kicked from %s by %s [%s]") 168 | :format(target, channel, prefix.nick, reason)) 169 | end 170 | end 171 | 172 | 173 | function irc.hooks.notice(user, target, message) 174 | if user and user.nick and target == irc.config.channel then 175 | irc.sendLocal("-"..user.nick.."@IRC- "..message) 176 | end 177 | end 178 | 179 | 180 | function irc.hooks.mode(user, target, modes, ...) 181 | local by = "" 182 | if user.nick then 183 | by = " by "..user.nick 184 | end 185 | local options = "" 186 | if select("#", ...) > 0 then 187 | options = " " 188 | end 189 | options = options .. table.concat({...}, " ") 190 | minetest.chat_send_all(("-!- mode/%s [%s%s]%s") 191 | :format(target, modes, options, by)) 192 | end 193 | 194 | 195 | function irc.hooks.nick(user, newNick) 196 | irc.sendLocal(("-!- %s is now known as %s") 197 | :format(user.nick, newNick)) 198 | end 199 | 200 | 201 | function irc.hooks.join(user, channel) 202 | irc.sendLocal(("-!- %s joined %s") 203 | :format(user.nick, channel)) 204 | end 205 | 206 | 207 | function irc.hooks.part(user, channel, reason) 208 | reason = reason or "" 209 | irc.sendLocal(("-!- %s has left %s [%s]") 210 | :format(user.nick, channel, reason)) 211 | end 212 | 213 | 214 | function irc.hooks.quit(user, reason) 215 | irc.sendLocal(("-!- %s has quit [%s]") 216 | :format(user.nick, reason)) 217 | end 218 | 219 | 220 | function irc.hooks.disconnect(_, isError) 221 | irc.connected = false 222 | if isError then 223 | minetest.log("error", "IRC: Error: Disconnected, reconnecting in one minute.") 224 | minetest.chat_send_all("IRC: Error: Disconnected, reconnecting in one minute.") 225 | minetest.after(60, irc.connect, irc) 226 | else 227 | minetest.log("action", "IRC: Disconnected.") 228 | minetest.chat_send_all("IRC: Disconnected.") 229 | end 230 | end 231 | 232 | 233 | function irc.hooks.preregister(conn) 234 | if not (irc.config["sasl.user"] and irc.config["sasl.pass"]) then return end 235 | local authString = b64e( 236 | ("%s\x00%s\x00%s"):format( 237 | irc.config["sasl.user"], 238 | irc.config["sasl.user"], 239 | irc.config["sasl.pass"]) 240 | ) 241 | conn:send("CAP REQ sasl") 242 | conn:send("AUTHENTICATE PLAIN") 243 | conn:send("AUTHENTICATE "..authString) 244 | conn:send("CAP END") 245 | end 246 | 247 | 248 | irc.register_hook("PreRegister", irc.hooks.preregister) 249 | irc.register_hook("OnRaw", irc.hooks.raw) 250 | irc.register_hook("OnSend", irc.hooks.send) 251 | irc.register_hook("DoPrivmsg", irc.hooks.chat) 252 | irc.register_hook("OnPart", irc.hooks.part) 253 | irc.register_hook("OnKick", irc.hooks.kick) 254 | irc.register_hook("OnJoin", irc.hooks.join) 255 | irc.register_hook("OnQuit", irc.hooks.quit) 256 | irc.register_hook("NickChange", irc.hooks.nick) 257 | irc.register_hook("OnCTCP", irc.hooks.ctcp) 258 | irc.register_hook("PrivateMessage", irc.hooks.pm) 259 | irc.register_hook("OnNotice", irc.hooks.notice) 260 | irc.register_hook("OnChannelChat", irc.hooks.channelChat) 261 | irc.register_hook("OnModeChange", irc.hooks.mode) 262 | irc.register_hook("OnDisconnect", irc.hooks.disconnect) 263 | 264 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | -- This file is licensed under the terms of the BSD 2-clause license. 2 | -- See LICENSE.txt for details. 3 | 4 | local modpath = minetest.get_modpath(minetest.get_current_modname()) 5 | 6 | -- Handle mod security if needed 7 | local ie, req_ie = _G, minetest.request_insecure_environment 8 | if req_ie then ie = req_ie() end 9 | if not ie then 10 | error("The IRC mod requires access to insecure functions in order ".. 11 | "to work. Please add the irc mod to your secure.trusted_mods ".. 12 | "setting or disable the irc mod.") 13 | end 14 | 15 | ie.package.path = 16 | -- To find LuaIRC's init.lua 17 | modpath.."/?/init.lua;" 18 | -- For LuaIRC to find its files 19 | ..modpath.."/?.lua;" 20 | ..ie.package.path 21 | 22 | -- The build of Lua that Minetest comes with only looks for libraries under 23 | -- /usr/local/share and /usr/local/lib but LuaSocket is often installed under 24 | -- /usr/share and /usr/lib. 25 | if not rawget(_G, "jit") and package.config:sub(1, 1) == "/" then 26 | 27 | ie.package.path = ie.package.path.. 28 | ";/usr/share/lua/5.1/?.lua".. 29 | ";/usr/share/lua/5.1/?/init.lua" 30 | 31 | ie.package.cpath = ie.package.cpath.. 32 | ";/usr/lib/lua/5.1/?.so".. 33 | ";/usr/lib64/lua/5.1/?.so" 34 | 35 | ie.package.cpath = "/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;"..ie.package.cpath 36 | 37 | 38 | end 39 | 40 | -- Temporarily set require so that LuaIRC can access it 41 | local old_require = require 42 | require = ie.require 43 | 44 | -- Silence warnings about `module` in `ltn12`. 45 | local old_module = rawget(_G, "module") 46 | rawset(_G, "module", ie.module) 47 | 48 | local lib = ie.require("irc") 49 | 50 | irc = { 51 | version = "0.2.0", 52 | connected = false, 53 | cur_time = 0, 54 | message_buffer = {}, 55 | recent_message_count = 0, 56 | joined_players = {}, 57 | modpath = modpath, 58 | lib = lib, 59 | } 60 | 61 | -- Compatibility 62 | rawset(_G, "mt_irc", irc) 63 | 64 | local getinfo = debug.getinfo 65 | local warned = { } 66 | 67 | local function warn_deprecated(k) 68 | local info = getinfo(3) 69 | local loc = info.source..":"..info.currentline 70 | if warned[loc] then return end 71 | warned[loc] = true 72 | print("COLON: "..tostring(k)) 73 | minetest.log("warning", "Deprecated use of colon notation when calling" 74 | .." method `"..tostring(k).."` at "..loc) 75 | end 76 | 77 | -- This is a hack. 78 | setmetatable(irc, { 79 | __newindex = function(t, k, v) 80 | if type(v) == "function" then 81 | local f = v 82 | v = function(me, ...) 83 | if rawequal(me, t) then 84 | warn_deprecated(k) 85 | return f(...) 86 | else 87 | return f(me, ...) 88 | end 89 | end 90 | end 91 | rawset(t, k, v) 92 | end, 93 | }) 94 | 95 | dofile(modpath.."/config.lua") 96 | dofile(modpath.."/messages.lua") 97 | loadfile(modpath.."/hooks.lua")(ie) 98 | dofile(modpath.."/callback.lua") 99 | dofile(modpath.."/chatcmds.lua") 100 | dofile(modpath.."/botcmds.lua") 101 | 102 | -- Restore old (safe) functions 103 | require = old_require 104 | rawset(_G, "module", old_module) 105 | 106 | if irc.config.enable_player_part then 107 | dofile(modpath.."/player_part.lua") 108 | else 109 | setmetatable(irc.joined_players, {__index = function() return true end}) 110 | end 111 | 112 | minetest.register_privilege("irc_admin", { 113 | description = "Allow IRC administrative tasks to be performed.", 114 | give_to_singleplayer = true, 115 | give_to_admin = true, 116 | }) 117 | 118 | local stepnum = 0 119 | 120 | minetest.register_globalstep(function(dtime) return irc.step(dtime) end) 121 | 122 | function irc.step() 123 | if stepnum == 3 then 124 | if irc.config.auto_connect then 125 | irc.connect() 126 | end 127 | end 128 | stepnum = stepnum + 1 129 | 130 | if not irc.connected then return end 131 | 132 | -- Hooks will manage incoming messages and errors 133 | local good, err = xpcall(function() irc.conn:think() end, debug.traceback) 134 | if not good then 135 | print(err) 136 | return 137 | end 138 | end 139 | 140 | 141 | function irc.connect() 142 | if irc.connected then 143 | minetest.log("error", "IRC: Ignoring attempt to connect when already connected.") 144 | return 145 | end 146 | irc.conn = irc.lib.new({ 147 | nick = irc.config.nick, 148 | username = irc.config.username, 149 | realname = irc.config.realname, 150 | }) 151 | irc.doHook(irc.conn) 152 | 153 | -- We need to swap the `require` function again since 154 | -- LuaIRC `require`s `ssl` if `irc.secure` is true. 155 | old_require = require 156 | require = ie.require 157 | 158 | local good, message = pcall(function() 159 | irc.conn:connect({ 160 | host = irc.config.server, 161 | port = irc.config.port, 162 | password = irc.config.password, 163 | timeout = irc.config.timeout, 164 | reconnect = irc.config.reconnect, 165 | secure = irc.config.secure 166 | }) 167 | end) 168 | 169 | require = old_require 170 | 171 | if not good then 172 | minetest.log("error", ("IRC: Connection error: %s: %s -- Reconnecting in %d seconds...") 173 | :format(irc.config.server, message, irc.config.reconnect)) 174 | minetest.after(irc.config.reconnect, function() irc.connect() end) 175 | return 176 | end 177 | 178 | if irc.config.NSPass then 179 | irc.conn:queue(irc.msgs.privmsg( 180 | "NickServ", "IDENTIFY "..irc.config.NSPass)) 181 | end 182 | 183 | irc.conn:join(irc.config.channel, irc.config.key) 184 | irc.connected = true 185 | minetest.log("action", "IRC: Connected!") 186 | minetest.chat_send_all("IRC: Connected!") 187 | end 188 | 189 | 190 | function irc.disconnect(message) 191 | if irc.connected then 192 | --The OnDisconnect hook will clear irc.connected and print a disconnect message 193 | irc.conn:disconnect(message) 194 | end 195 | end 196 | 197 | 198 | function irc.say(to, message) 199 | if not message then 200 | message = to 201 | to = irc.config.channel 202 | end 203 | to = to or irc.config.channel 204 | 205 | irc.queue(irc.msgs.privmsg(to, message)) 206 | end 207 | 208 | 209 | function irc.reply(message) 210 | if not irc.last_from then 211 | return 212 | end 213 | message = message:gsub("[\r\n%z]", " \\n ") 214 | irc.say(irc.last_from, message) 215 | end 216 | 217 | function irc.send(msg) 218 | if not irc.connected then return end 219 | irc.conn:send(msg) 220 | end 221 | 222 | function irc.queue(msg) 223 | if not irc.connected then return end 224 | irc.conn:queue(msg) 225 | end 226 | 227 | -------------------------------------------------------------------------------- /messages.lua: -------------------------------------------------------------------------------- 1 | -- This file is licensed under the terms of the BSD 2-clause license. 2 | -- See LICENSE.txt for details. 3 | 4 | irc.msgs = irc.lib.msgs 5 | 6 | function irc.logChat(message) 7 | minetest.log("action", "IRC CHAT: "..message) 8 | end 9 | 10 | function irc.sendLocal(message) 11 | minetest.chat_send_all(minetest.colorize(irc.config.chat_color, message)) 12 | irc.logChat(message) 13 | end 14 | 15 | function irc.playerMessage(name, message) 16 | return ("<%s> %s"):format(name, message) 17 | end 18 | -------------------------------------------------------------------------------- /mod.conf: -------------------------------------------------------------------------------- 1 | name = irc 2 | description = """ 3 | This mod is just a glue between IRC and Minetest. 4 | It provides two-way communication between the in-game chat, and an arbitrary IRC channel. 5 | """ 6 | -------------------------------------------------------------------------------- /player_part.lua: -------------------------------------------------------------------------------- 1 | -- This file is licensed under the terms of the BSD 2-clause license. 2 | -- See LICENSE.txt for details. 3 | 4 | 5 | function irc.player_part(name) 6 | if not irc.joined_players[name] then 7 | return false, "You are not in the channel" 8 | end 9 | irc.joined_players[name] = nil 10 | return true, "You left the channel" 11 | end 12 | 13 | function irc.player_join(name) 14 | if irc.joined_players[name] then 15 | return false, "You are already in the channel" 16 | elseif not minetest.get_player_by_name(name) then 17 | return false, "You need to be in-game to join the channel" 18 | end 19 | irc.joined_players[name] = true 20 | return true, "You joined the channel" 21 | end 22 | 23 | 24 | minetest.register_chatcommand("join", { 25 | description = "Join the IRC channel", 26 | privs = {shout=true}, 27 | func = function(name) 28 | return irc.player_join(name) 29 | end 30 | }) 31 | 32 | minetest.register_chatcommand("part", { 33 | description = "Part the IRC channel", 34 | privs = {shout=true}, 35 | func = function(name) 36 | return irc.player_part(name) 37 | end 38 | }) 39 | 40 | minetest.register_chatcommand("who", { 41 | description = "Tell who is currently on the channel", 42 | privs = {}, 43 | func = function() 44 | local out, n = { }, 0 45 | for plname in pairs(irc.joined_players) do 46 | n = n + 1 47 | out[n] = plname 48 | end 49 | table.sort(out) 50 | return true, n.." player(s) in channel: "..table.concat(out, ", ") 51 | end 52 | }) 53 | 54 | 55 | minetest.register_on_joinplayer(function(player) 56 | local name = player:get_player_name() 57 | irc.joined_players[name] = irc.config.auto_join 58 | end) 59 | 60 | 61 | minetest.register_on_leaveplayer(function(player) 62 | local name = player:get_player_name() 63 | irc.joined_players[name] = nil 64 | end) 65 | 66 | function irc.sendLocal(message) 67 | for name, _ in pairs(irc.joined_players) do 68 | minetest.chat_send_player(name, 69 | minetest.colorize(irc.config.chat_color, message)) 70 | end 71 | irc.logChat(message) 72 | end 73 | -------------------------------------------------------------------------------- /settingtypes.txt: -------------------------------------------------------------------------------- 1 | 2 | [Basic] 3 | 4 | # Whether to automatically connect to the server on mod load. 5 | # If false, you must use /irc_connect to connect. 6 | irc.auto_connect (Auto-connect on load) bool true 7 | 8 | # Nickname for the bot. May only contain characters A-Z, 0-9 9 | # '{', '}', '[', ']', '|', '^', '-', or '_'. 10 | irc.nick (Bot nickname) string Minetest 11 | 12 | # Server to connect to. 13 | irc.server (IRC server) string irc.freenode.net 14 | 15 | # Server port. 16 | # The standard IRC protocol port is 6667 for regular servers, 17 | # or 6697 for SSL-enabled servers. 18 | # If unsure, leave at 6667. 19 | irc.port (IRC server port) int 6667 1 65535 20 | 21 | # Channel the bot joins after connecting. 22 | irc.channel (Channel to join) string ##mt-irc-mod 23 | 24 | [Authentication] 25 | 26 | # Password for authenticating to NickServ. 27 | # Leave empty to not authenticate with NickServ. 28 | irc.NSPass (NickServ password) string 29 | 30 | # IRC server password. 31 | # Leave empty for no password. 32 | irc.password (Server password) string 33 | 34 | # Password for joining the channel. 35 | # Leave empty if your channel is not protected. 36 | irc.key (Channel key) string 37 | 38 | # Enable TLS connection. 39 | # Requires LuaSEC . 40 | irc.secure (Use TLS) bool false 41 | 42 | # Username for SASL authentication. 43 | # Leave empty to use the nickname. 44 | irc.sasl.user (SASL username) string 45 | 46 | # Password for SASL authentication. 47 | # Leave empty to not authenticate via SASL. 48 | irc.sasl.pass (SASL password) string 49 | 50 | [Advanced] 51 | 52 | # Enable this to make the bot send messages when players join 53 | # or leave the game server. 54 | irc.send_join_part (Send join and part messages) bool true 55 | 56 | # Enable this to make the bot send messages when players are kicked. 57 | irc.send_kicks (Send kick messages) bool false 58 | 59 | # Underlying socket timeout in seconds. 60 | irc.timeout (Timeout) int 60 1 61 | 62 | # Time between reconnection attempts, in seconds. 63 | irc.reconnect (Reconnect delay) int 600 1 64 | 65 | # Prefix to use for bot commands. 66 | irc.command_prefix (Command prefix) string 67 | 68 | # Enable debug output. 69 | irc.debug (Debug mode) bool false 70 | 71 | # Whether to enable players joining and parting the channel. 72 | irc.enable_player_part (Allow player join/part) bool true 73 | 74 | # Whether to automatically show players in the channel when they join. 75 | irc.auto_join (Auto join players) bool true 76 | --------------------------------------------------------------------------------