mirror of
https://github.com/minetest-mods/irc.git
synced 2025-06-29 22:50:32 +02:00
Compare commits
69 Commits
remove-lua
...
nalc-1.2.0
Author | SHA1 | Date | |
---|---|---|---|
0f46251d00 | |||
ceb40e2bb3 | |||
612a94bbf1 | |||
5e3659761b | |||
ac0387786c | |||
05ab5e9fbd | |||
2a88c47de4 | |||
0f00fa8c7e | |||
351a86cbf2 | |||
1b71c304c5 | |||
47f889c178 | |||
1c23f8987b | |||
66bb7fc47d | |||
6a7053582d | |||
5e877956a5 | |||
60bf32e157 | |||
b4fbccd64a | |||
c9c57a6f93 | |||
f57bdba5e9 | |||
070eb51236 | |||
e80bbe3a62 | |||
1d4fd5a162 | |||
6bf4e111c2 | |||
5f8850bc15 | |||
2f55e0f9a0 | |||
78fbe26a2c | |||
33542b07fe | |||
6bbb26f9f9 | |||
ae0cb08e3e | |||
bb5f549193 | |||
4c334e9967 | |||
a18820356a | |||
0c8538bfb8 | |||
9f8b4fd4af | |||
73cdb58c99 | |||
3e2d98f9ef | |||
12248cc847 | |||
160088c232 | |||
03070e41c4 | |||
b5786979ab | |||
d5ad8ffca4 | |||
0f6e1dacc4 | |||
ecc1d450ba | |||
18f286f4b5 | |||
0c47e10a90 | |||
43493eb2ea | |||
f98282818d | |||
03edbd29ed | |||
464f2febee | |||
0c900dbac2 | |||
38832b3c55 | |||
fd1a570794 | |||
18b80bd127 | |||
43cb77fab8 | |||
df229cabe6 | |||
30fa81a3ab | |||
32294995be | |||
d0ebde3884 | |||
9e15a886b4 | |||
12b1b07afe | |||
e92eec3987 | |||
8aa442e87f | |||
5655f75946 | |||
8e6a9a287f | |||
26ca287b09 | |||
3b35bb1871 | |||
56a5de4a91 | |||
706a6fbe27 | |||
e87d2e5bf2 |
11
.github/workflows/check-release.yml
vendored
Normal file
11
.github/workflows/check-release.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
on: [push, pull_request]
|
||||||
|
name: Check & Release
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@master
|
||||||
|
- name: lint
|
||||||
|
uses: Roang-zero1/factorio-mod-luacheck@master
|
||||||
|
with:
|
||||||
|
luacheckrc_url: https://raw.githubusercontent.com/minetest-mods/irc/master/.luacheckrc
|
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -1,3 +1,3 @@
|
|||||||
[submodule "src/LuaIRC"]
|
[submodule "irc"]
|
||||||
path = irc
|
path = irc
|
||||||
url = https://github.com/ShadowNinja/LuaIRC.git
|
url = https://sys4.fr/gitea/mtcontrib/LuaIRC.git
|
||||||
|
14
.luacheckrc
Normal file
14
.luacheckrc
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
allow_defined_top = true
|
||||||
|
|
||||||
|
read_globals = {
|
||||||
|
"minetest"
|
||||||
|
}
|
||||||
|
|
||||||
|
exclude_files = {
|
||||||
|
"irc/*",
|
||||||
|
}
|
||||||
|
|
||||||
|
globals = {
|
||||||
|
"irc",
|
||||||
|
}
|
@ -1,24 +1,26 @@
|
|||||||
IRC Mod API
|
IRC Mod API
|
||||||
-----------
|
===========
|
||||||
|
|
||||||
This file documents the Minetest IRC mod API.
|
This file documents the Minetest IRC mod API.
|
||||||
|
|
||||||
BASICS
|
Basics
|
||||||
------
|
------
|
||||||
In order to allow your mod to interface with this mod, you must add 'irc'
|
|
||||||
(without the quotes) to your mod's 'depends.txt' file.
|
In order to allow your mod to interface with this mod, you must add `irc`
|
||||||
|
to your mod's `depends.txt` file.
|
||||||
|
|
||||||
|
|
||||||
REFERENCE
|
Reference
|
||||||
---------
|
---------
|
||||||
|
|
||||||
mt_irc:say([name, ]message)
|
irc.say([name,] message)
|
||||||
Sends <message> to either the channel (if <name> is nil or not specified),
|
Sends <message> to either the channel (if <name> is nil or not specified),
|
||||||
or to the given user (if <name> is specified).
|
or to the given user (if <name> is specified).
|
||||||
Example:
|
Example:
|
||||||
mt_irc:say("Hello, Channel!")
|
irc.say("Hello, Channel!")
|
||||||
mt_irc:say("john1234", "How are you?")
|
irc.say("john1234", "How are you?")
|
||||||
|
|
||||||
mt_irc:register_bot_command(name, cmdDef)
|
irc.register_bot_command(name, cmdDef)
|
||||||
Registers a new bot command named <name>.
|
Registers a new bot command named <name>.
|
||||||
When an user sends a private message to the bot with the command name, the
|
When an user sends a private message to the bot with the command name, the
|
||||||
command's function is called.
|
command's function is called.
|
||||||
@ -26,38 +28,39 @@ mt_irc:register_bot_command(name, cmdDef)
|
|||||||
cmdDef = {
|
cmdDef = {
|
||||||
params = "<param1> ...", -- A description of the command's parameters
|
params = "<param1> ...", -- A description of the command's parameters
|
||||||
description = "My command", -- A description of what the command does. (one-liner)
|
description = "My command", -- A description of what the command does. (one-liner)
|
||||||
func = function(user, param)
|
func = function(user, args)
|
||||||
-- This function gets called when the command is invoked.
|
-- This function gets called when the command is invoked.
|
||||||
-- <user> is a user table for the user that ran the command.
|
-- <user> is a user table for the user that ran the command.
|
||||||
-- (See the LuaIRC documentation for details.)
|
-- (See the LuaIRC documentation for details.)
|
||||||
-- It contains fields such as 'nick' and 'ident'
|
-- It contains fields such as 'nick' and 'ident'
|
||||||
-- <param> is a string of parameters to the command (may be "")
|
-- <args> is a string of arguments to the command (may be "")
|
||||||
|
-- This function should return boolean success and a message.
|
||||||
end,
|
end,
|
||||||
};
|
};
|
||||||
Example:
|
Example:
|
||||||
mt_irc:register_bot_command("hello", {
|
irc.register_bot_command("hello", {
|
||||||
params = "",
|
params = "",
|
||||||
description = "Greet user",
|
description = "Greet user",
|
||||||
func = function(user, param)
|
func = function(user, param)
|
||||||
mt_irc:say(user.nick, "Hello!")
|
return true, "Hello!"
|
||||||
end,
|
end,
|
||||||
});
|
});
|
||||||
|
|
||||||
mt_irc.joined_players[name]
|
irc.joined_players[name]
|
||||||
This table holds the players who are currently on the channel (may be less
|
This table holds the players who are currently on the channel (may be less
|
||||||
than the players in the game). It is modified by the /part and /join chat
|
than the players in the game). It is modified by the /part and /join chat
|
||||||
commands.
|
commands.
|
||||||
Example:
|
Example:
|
||||||
if mt_irc.joined_players["joe"] then
|
if irc.joined_players["joe"] then
|
||||||
-- Joe is talking on IRC
|
-- Joe is talking on IRC
|
||||||
end
|
end
|
||||||
|
|
||||||
mt_irc:register_hook(name, func)
|
irc.register_hook(name, func)
|
||||||
Registers a function to be called when an event happens. <name> is the name
|
Registers a function to be called when an event happens. <name> is the name
|
||||||
of the event, and <func> is the function to be called. See HOOKS below
|
of the event, and <func> is the function to be called. See HOOKS below
|
||||||
for more information
|
for more information
|
||||||
Example:
|
Example:
|
||||||
mt_irc:register_hook("OnSend", function(line)
|
irc.register_hook("OnSend", function(line)
|
||||||
print("SEND: "..line)
|
print("SEND: "..line)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -72,15 +75,15 @@ string.expandvars(string, vars)
|
|||||||
local s = tpl:expandvars({foo=1, bar="Hello"})
|
local s = tpl:expandvars({foo=1, bar="Hello"})
|
||||||
assert(s == "1 Hello $(baz)")
|
assert(s == "1 Hello $(baz)")
|
||||||
|
|
||||||
In addition, all the configuration options decribed in `README.txt' are
|
In addition, all the configuration options decribed in `README.txt` are
|
||||||
available to other mods, though they should be considered "read only". Do
|
available to other mods, though they should be considered read-only. Do
|
||||||
not modify these settings at runtime or you will most likely crash the
|
not modify these settings at runtime or you might crash the server!
|
||||||
server!
|
|
||||||
|
|
||||||
|
|
||||||
HOOKS
|
Hooks
|
||||||
---------
|
-----
|
||||||
The 'mt_irc:register_hook' function can register functions to be called
|
|
||||||
|
The `irc.register_hook` function can register functions to be called
|
||||||
when some events happen. The events supported are the same as the LuaIRC
|
when some events happen. The events supported are the same as the LuaIRC
|
||||||
ones with a few added (mostly for internal use).
|
ones with a few added (mostly for internal use).
|
||||||
See src/LuaIRC/doc/irc.luadoc for more information.
|
See src/LuaIRC/doc/irc.luadoc for more information.
|
144
README.md
144
README.md
@ -1,122 +1,139 @@
|
|||||||
|
[](https://github.com/minetest-mods/irc/actions)
|
||||||
|
|
||||||
IRC Mod for Minetest
|
IRC Mod for Minetest
|
||||||
====================
|
====================
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
This mod is just a glue between IRC and Minetest. It provides two-way
|
This mod is just a glue between IRC and Minetest. It provides two-way
|
||||||
communication between the in-game chat, and an arbitrary IRC channel.
|
communication between the in-game chat, and an arbitrary IRC channel.
|
||||||
|
|
||||||
The forum topic is at http://minetest.net/forum/viewtopic.php?id=3905
|
The forum topic is [here][forum].
|
||||||
|
|
||||||
|
[forum]: https://forum.minetest.net/viewtopic.php?f=11&t=3905
|
||||||
|
|
||||||
|
|
||||||
Installing
|
Installing
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Quick one line install for linux:
|
Quick one line install for Linux:
|
||||||
|
|
||||||
cd <Mod directory> && git clone https://github.com/kaeza/minetest-irc.git irc && cd irc && git submodule update --init
|
cd <Mods directory> && git clone --recursive https://github.com/minetest-mods/irc.git
|
||||||
|
|
||||||
Please change `<Mod directory>` to fit your installation of minetest.
|
Please change `<Mods directory>` to fit your installation of Minetest.
|
||||||
For more information, see [the wiki](http://wiki.minetest.net/Installing_mods).
|
For more information, see [the wiki][wiki].
|
||||||
|
|
||||||
The Minetest IRC mod uses submodules, therefore you will have to run
|
The IRC mod's git repository uses submodules, therefore you will have to run
|
||||||
`git submodule init` when first installing the mod, and `git submodule update`
|
`git submodule init` when first installing the mod (unless you used
|
||||||
every time that a submodule is updated. These steps can be combined as
|
`--recursive` as above), and `git submodule update` every time that a submodule
|
||||||
`git submodule update --init`.
|
is updated. These steps can be combined into `git submodule update --init`.
|
||||||
|
|
||||||
The Minetest IRC mod also requires LuaSocket. This can be installed using your
|
You'll need to install LuaSocket. You can do so with your package manager on
|
||||||
package manager on many distributions, for example on Arch Linux:
|
many distributions, for example:
|
||||||
|
|
||||||
|
# # On Arch Linux:
|
||||||
# pacman -S lua51-socket
|
# pacman -S lua51-socket
|
||||||
|
# # On Debian/Ubuntu:
|
||||||
|
# # Debian/Ubuntu's LuaSocket packages are broken, so use LuaRocks.
|
||||||
|
# apt-get install luarocks
|
||||||
|
# luarocks install luasocket
|
||||||
|
|
||||||
|
You will also need to add IRC to your trusted mods if you haven't disabled mod
|
||||||
|
security. Here's an example configuration line:
|
||||||
|
|
||||||
|
secure.trusted_mods = irc
|
||||||
|
|
||||||
|
[wiki]: https://wiki.minetest.net/Installing_mods
|
||||||
|
|
||||||
|
|
||||||
Settings
|
Settings
|
||||||
--------
|
--------
|
||||||
|
|
||||||
All settings are changed in `minetest.conf`. If any of these settings
|
All settings are changed in `minetest.conf`. If any of these settings
|
||||||
are not set, the default value is used.
|
are not set, the default value is used.
|
||||||
|
|
||||||
* `irc.server` (string, default "irc.freenode.net")
|
* `irc.server` (string):
|
||||||
This is the IRC server the mod connects to.
|
The address of the IRC server to connect to.
|
||||||
|
|
||||||
* `irc.channel` (string, default "##mt-irc-mod")
|
* `irc.channel` (string):
|
||||||
The IRC channel to join.
|
The IRC channel to join.
|
||||||
|
|
||||||
* `irc.interval` (number, default 2.0)
|
* `irc.interval` (number, default 2.0):
|
||||||
This prevents the server from flooding. It should be at
|
This prevents the server from flooding. It should be at
|
||||||
least 2.0 but can be higher. After four messages this much
|
least 2.0 but can be higher. After four messages this much
|
||||||
time must pass between folowing messages.
|
time must pass between folowing messages.
|
||||||
|
|
||||||
* `irc.nick` (string, default "MT-FFFFFF")
|
* `irc.nick` (string):
|
||||||
Nickname used as "proxy" for the in-game chat.
|
Nickname the server uses when it connects to IRC.
|
||||||
'F' stands for a random base-16 number.
|
|
||||||
|
|
||||||
* `irc.password` (string, default "")
|
* `irc.password` (string, default nil):
|
||||||
Password to use when connecting to the server.
|
Password to use when connecting to the server.
|
||||||
|
|
||||||
* `irc.NSPass` (string, default nil)
|
* `irc.NSPass` (string, default nil):
|
||||||
NickServ password. Don't use this if you use SASL authentication.
|
NickServ password. Don't set this if you use SASL authentication.
|
||||||
|
|
||||||
* `irc.SASLPass` (string, default nil)
|
* `irc.sasl.pass` (string, default nil):
|
||||||
SASL password, same as nickserv password.
|
SASL password, same as nickserv password.
|
||||||
You should use this instead of NickServ authentication
|
You should use this instead of NickServ authentication
|
||||||
if the server supports it.
|
if the server supports it.
|
||||||
|
|
||||||
* `irc.SASLUser` (string, default irc.nick)
|
* `irc.sasl.user` (string, default `irc.nick`):
|
||||||
The SASL username. This should normaly be set to your main NickServ account name.
|
The SASL username. This should normaly be set to your
|
||||||
|
NickServ account name.
|
||||||
|
|
||||||
* `irc.debug` (boolean, default false)
|
* `irc.debug` (boolean, default false):
|
||||||
Whether to output debug information.
|
Whether to output debug information.
|
||||||
|
|
||||||
* `irc.disable_auto_connect` (boolean, default false)
|
* `irc.disable_auto_connect` (boolean, default false):
|
||||||
If false, the bot is connected by default. If true, a player with
|
If false, the bot is connected by default. If true, a player with
|
||||||
the 'irc_admin' privilege has to use the /irc_connect command to
|
the 'irc_admin' privilege has to use the `/irc_connect` command to
|
||||||
connect to the server.
|
connect to the server.
|
||||||
|
|
||||||
* `irc.disable_auto_join` (boolean, default false)
|
* `irc.disable_auto_join` (boolean, default false):
|
||||||
If false, players join the channel automatically upon entering the
|
If false, players join the channel automatically upon entering the
|
||||||
game. If true, each user must manually use the /join command to
|
game. If true, each user must manually use the `/join` command to
|
||||||
join the channel. In any case, the players may use the /part
|
join the channel. In any case, the players may use the `/part`
|
||||||
command to opt-out of being in the channel.
|
command to opt-out of being in the channel.
|
||||||
|
|
||||||
* `irc.send_join_part` (boolean, default true)
|
* `irc.send_join_part` (boolean, default true):
|
||||||
Determines whether to send player join and part messages to the channel.
|
Determines whether to send player join and part messages to the channel.
|
||||||
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
|
||||||
Once the game is connected to the IRC channel, chatting using the 'T' or
|
Once the game is connected to the IRC channel, chatting in-game will send
|
||||||
F10 hotkeys will send the messages to the channel, and will be visible
|
messages to the channel, and will be visible by anyone. Also, messages sent
|
||||||
by anyone. Also, when someone sends a message to the channel, that text
|
to the channel will be visible in-game.
|
||||||
will be visible in-game.
|
|
||||||
|
|
||||||
Messages that begin with `[off]` from in-game or IRC are not sent to the
|
Messages that begin with `[off]` from in-game or IRC are not sent to the
|
||||||
other side.
|
other side.
|
||||||
|
|
||||||
This mod also adds a few chat commands:
|
This mod also adds a few chat commands:
|
||||||
|
|
||||||
* `/irc_msg <nick> <message>`
|
* `/irc_msg <nick> <message>`:
|
||||||
Sends a private message to a IRC user.
|
Send a private message to a IRC user.
|
||||||
|
|
||||||
* `/join`
|
* `/join`:
|
||||||
Join the IRC chat.
|
Join the IRC chat.
|
||||||
|
|
||||||
* `/part`
|
* `/part`:
|
||||||
Part the IRC chat.
|
Part the IRC chat.
|
||||||
|
|
||||||
* `/irc_connect`
|
* `/irc_connect`:
|
||||||
Connect the bot manually to the IRC network.
|
Connect the bot manually to the IRC network.
|
||||||
|
|
||||||
* `/irc_disconnect`
|
* `/irc_disconnect`:
|
||||||
Disconnect the bot manually from the IRC network (this does not
|
Disconnect the bot manually from the IRC network (this does not
|
||||||
shutdown the game).
|
shutdown the game).
|
||||||
|
|
||||||
* `/irc_reconnect`
|
* `/irc_reconnect`:
|
||||||
Equivilant to `/irc_disconnect` followed by `/irc_connect`.
|
Equivalent to `/irc_disconnect` followed by `/irc_connect`.
|
||||||
|
|
||||||
You can also send private messages from IRC to in-game players.
|
You can also send private messages from IRC to in-game players
|
||||||
|
by sending a private message to the bot (set with the `irc.nick`
|
||||||
To do it, you must send a private message to the bot (set with
|
option above), in the following format:
|
||||||
the `irc.nick` option above), in the following format:
|
|
||||||
|
|
||||||
@playername message
|
@playername message
|
||||||
|
|
||||||
@ -125,21 +142,29 @@ a private message from IRC with:
|
|||||||
|
|
||||||
/msg server_nick @mtuser Hello!
|
/msg server_nick @mtuser Hello!
|
||||||
|
|
||||||
To avoid possible misunderstandings (since all in-game players use the
|
The bot also supports some basic commands, which are invoked by saying
|
||||||
same IRC user to converse with you), the "proxy" user will reject any
|
the bot name followed by either a colon or a comma and the command, or
|
||||||
private messages that are not in that format, and will send back a
|
sending a private message to it. For example: `ServerBot: help whereis`.
|
||||||
nice reminder as a private message.
|
|
||||||
|
|
||||||
The bot also supports some basic commands, which are invoked by sending
|
* `help [<command>]`:
|
||||||
a private message to it. Use `!list` to get a list of commands, and
|
Prints help about a command, or a list of supported commands if no
|
||||||
`!help <command>` to get help about a specific command.
|
command is given.
|
||||||
|
|
||||||
|
* `uptime`:
|
||||||
|
Prints the server's running time.
|
||||||
|
|
||||||
|
* `whereis <player>`:
|
||||||
|
Prints the coordinates of the given player.
|
||||||
|
|
||||||
|
* `players`:
|
||||||
|
Lists players currently in the server.
|
||||||
|
|
||||||
|
|
||||||
Thanks
|
Thanks
|
||||||
------
|
------
|
||||||
|
|
||||||
I'd like to thank the users who supported this mod both on the Minetest
|
I'd like to thank the users who supported this mod both on the Minetest
|
||||||
Forums and on the #minetest channel. In no particular order:
|
Forums and on the `#minetest` channel. In no particular order:
|
||||||
|
|
||||||
0gb.us, ShadowNinja, Shaun/kizeren, RAPHAEL, DARGON, Calinou, Exio,
|
0gb.us, ShadowNinja, Shaun/kizeren, RAPHAEL, DARGON, Calinou, Exio,
|
||||||
vortexlabs/mrtux, marveidemanis, marktraceur, jmf/john\_minetest,
|
vortexlabs/mrtux, marveidemanis, marktraceur, jmf/john\_minetest,
|
||||||
@ -151,10 +176,7 @@ forum topic. Thanks to you all!
|
|||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
(C) 2012-2013 Diego Martínez <kaeza@users.sf.net>
|
See `LICENSE.txt` for details.
|
||||||
|
|
||||||
See LICENSE.txt for licensing information.
|
|
||||||
|
|
||||||
The files in the irc directory are part of the LuaIRC project.
|
|
||||||
See irc/LICENSE.txt for licensing information.
|
|
||||||
|
|
||||||
|
The files in the `irc` directory are part of the LuaIRC project.
|
||||||
|
See `irc/LICENSE.txt` for details.
|
||||||
|
143
botcmds.lua
143
botcmds.lua
@ -1,39 +1,59 @@
|
|||||||
|
|
||||||
mt_irc.bot_commands = {}
|
irc.bot_commands = {}
|
||||||
|
|
||||||
function mt_irc:check_botcmd(msg)
|
-- From RFC1459:
|
||||||
local prefix = mt_irc.config.command_prefix
|
-- "Because of IRC’s scandanavian origin, the characters {}| are
|
||||||
local nick = mt_irc.conn.nick:lower()
|
-- considered to be the lower case equivalents of the characters
|
||||||
|
-- []\, respectively."
|
||||||
|
local irctolower = { ["["]="{", ["\\"]="|", ["]"]="}" }
|
||||||
|
|
||||||
|
local function irclower(s)
|
||||||
|
return (s:lower():gsub("[%[%]\\]", irctolower))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function nickequals(nick1, nick2)
|
||||||
|
return irclower(nick1) == irclower(nick2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function irc.check_botcmd(msg)
|
||||||
|
local prefix = irc.config.command_prefix
|
||||||
|
local nick = irc.conn.nick
|
||||||
local text = msg.args[2]
|
local text = msg.args[2]
|
||||||
local nickpart = text:sub(1, #nick + 2):lower()
|
local nickpart = text:sub(1, #nick)
|
||||||
|
local suffix = text:sub(#nick+1, #nick+2)
|
||||||
|
|
||||||
-- First check for a nick prefix
|
-- First check for a nick prefix
|
||||||
if nickpart == nick..": " or
|
if nickequals(nickpart, nick)
|
||||||
nickpart == nick..", " then
|
and (suffix == ": " or suffix == ", ") then
|
||||||
self:bot_command(msg, text:sub(#nick + 3))
|
irc.bot_command(msg, text:sub(#nick + 3))
|
||||||
return true
|
return true
|
||||||
-- Then check for the configured prefix
|
-- Then check for the configured prefix
|
||||||
elseif prefix and text:sub(1, #prefix):lower() == prefix:lower() then
|
elseif prefix and text:sub(1, #prefix):lower() == prefix:lower() then
|
||||||
self:bot_command(msg, text:sub(#prefix + 1))
|
irc.bot_command(msg, text:sub(#prefix + 1))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:bot_command(msg, text)
|
function irc.bot_command(msg, text)
|
||||||
|
-- Remove leading whitespace
|
||||||
|
text = text:match("^%s*(.*)")
|
||||||
if text:sub(1, 1) == "@" then
|
if text:sub(1, 1) == "@" then
|
||||||
local found, _, player_to, message = text:find("^.([^%s]+)%s(.+)$")
|
local _, _, player_to, message = text:find("^.([^%s]+)%s(.+)$")
|
||||||
if not minetest.get_player_by_name(player_to) then
|
if not player_to then
|
||||||
mt_irc:reply("User '"..player_to.."' is not in the game.")
|
|
||||||
return
|
return
|
||||||
elseif not mt_irc.joined_players[player_to] then
|
elseif not minetest.get_player_by_name(player_to) then
|
||||||
mt_irc:reply("User '"..player_to.."' is not using IRC.")
|
irc.reply("User '"..player_to.."' is not in the game.")
|
||||||
|
return
|
||||||
|
elseif not irc.joined_players[player_to] then
|
||||||
|
irc.reply("User '"..player_to.."' is not using IRC.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
minetest.chat_send_player(player_to,
|
minetest.chat_send_player(player_to,
|
||||||
"PM from "..msg.user.nick.."@IRC: "..message, false)
|
minetest.colorize(irc.config.pm_color,
|
||||||
mt_irc:reply("Message sent!")
|
"PM from "..msg.user.nick.."@IRC: "..message, false))
|
||||||
|
irc.reply("Message sent!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local pos = text:find(" ", 1, true)
|
local pos = text:find(" ", 1, true)
|
||||||
@ -46,110 +66,111 @@ function mt_irc:bot_command(msg, text)
|
|||||||
args = ""
|
args = ""
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.bot_commands[cmd] then
|
if not irc.bot_commands[cmd] then
|
||||||
self:reply("Unknown command '"..cmd.."'. Try 'list'."
|
irc.reply("Unknown command '"..cmd.."'. Try 'help'."
|
||||||
.." Or use @playername <message> to send a private message")
|
.." Or use @playername <message> to send a private message")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
self.bot_commands[cmd].func(msg.user, args)
|
local _, message = irc.bot_commands[cmd].func(msg.user, args)
|
||||||
|
if message then
|
||||||
|
irc.reply(message)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:register_bot_command(name, def)
|
function irc.register_bot_command(name, def)
|
||||||
if (not def.func) or (type(def.func) ~= "function") then
|
if (not def.func) or (type(def.func) ~= "function") then
|
||||||
error("Erroneous bot command definition. def.func missing.", 2)
|
error("Erroneous bot command definition. def.func missing.", 2)
|
||||||
elseif name:sub(1, 1) == "@" then
|
elseif name:sub(1, 1) == "@" then
|
||||||
error("Erroneous bot command name. Command name begins with '@'.", 2)
|
error("Erroneous bot command name. Command name begins with '@'.", 2)
|
||||||
end
|
end
|
||||||
self.bot_commands[name] = def
|
irc.bot_commands[name] = def
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
mt_irc:register_bot_command("help", {
|
irc.register_bot_command("help", {
|
||||||
params = "<command>",
|
params = "<command>",
|
||||||
description = "Get help about a command",
|
description = "Get help about a command",
|
||||||
func = function(user, args)
|
func = function(_, args)
|
||||||
if args == "" then
|
if args == "" then
|
||||||
mt_irc:reply("No command name specified. Use 'list' for a list of commands")
|
local cmdlist = { }
|
||||||
return
|
for name in pairs(irc.bot_commands) do
|
||||||
|
cmdlist[#cmdlist+1] = name
|
||||||
|
end
|
||||||
|
return true, "Available commands: "..table.concat(cmdlist, ", ")
|
||||||
|
.." -- Use 'help <command name>' to get"
|
||||||
|
.." help about a specific command."
|
||||||
end
|
end
|
||||||
|
|
||||||
local cmd = mt_irc.bot_commands[args]
|
local cmd = irc.bot_commands[args]
|
||||||
if not cmd then
|
if not cmd then
|
||||||
mt_irc:reply("Unknown command '"..cmdname.."'.")
|
return false, "Unknown command '"..args.."'."
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
mt_irc:reply(("Usage: %c%s %s -- %s"):format(
|
return true, ("Usage: %s%s %s -- %s"):format(
|
||||||
mt_irc.config.command_prefix,
|
irc.config.command_prefix or "",
|
||||||
args,
|
args,
|
||||||
cmd.params or "<no parameters>",
|
cmd.params or "<no parameters>",
|
||||||
cmd.description or "<no description>"))
|
cmd.description or "<no description>")
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
mt_irc:register_bot_command("list", {
|
irc.register_bot_command("list", {
|
||||||
params = "",
|
params = "",
|
||||||
description = "List available commands.",
|
description = "List available commands.",
|
||||||
func = function(user, args)
|
func = function()
|
||||||
local cmdlist = "Available commands: "
|
return false, "The `list` command has been merged into `help`."
|
||||||
for name, cmd in pairs(mt_irc.bot_commands) do
|
.." Use `help` with no arguments to get a list."
|
||||||
cmdlist = cmdlist..name..", "
|
|
||||||
end
|
|
||||||
mt_irc:reply(cmdlist.." -- Use 'help <command name>' to get"
|
|
||||||
.." help about a specific command.")
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
mt_irc:register_bot_command("whereis", {
|
irc.register_bot_command("whereis", {
|
||||||
params = "<player>",
|
params = "<player>",
|
||||||
description = "Tell the location of <player>",
|
description = "Tell the location of <player>",
|
||||||
func = function(user, args)
|
func = function(_, args)
|
||||||
if args == "" then
|
if args == "" then
|
||||||
mt_irc:bot_help(user, "whereis")
|
return false, "Player name required."
|
||||||
return
|
end
|
||||||
|
local player = minetest.get_player_by_name(args)
|
||||||
|
if not player then
|
||||||
|
return false, "There is no player named '"..args.."'"
|
||||||
end
|
end
|
||||||
local player = minetest.env:get_player_by_name(args)
|
|
||||||
if player then
|
|
||||||
local fmt = "Player %s is at (%.2f,%.2f,%.2f)"
|
local fmt = "Player %s is at (%.2f,%.2f,%.2f)"
|
||||||
local pos = player:getpos()
|
local pos = player:get_pos()
|
||||||
mt_irc:reply(fmt:format(args, pos.x, pos.y, pos.z))
|
return true, fmt:format(args, pos.x, pos.y, pos.z)
|
||||||
return
|
|
||||||
end
|
|
||||||
mt_irc:reply("There is no player named '"..args.."'")
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
local starttime = os.time()
|
local starttime = os.time()
|
||||||
mt_irc:register_bot_command("uptime", {
|
irc.register_bot_command("uptime", {
|
||||||
description = "Tell how much time the server has been up",
|
description = "Tell how much time the server has been up",
|
||||||
func = function(user, args)
|
func = function()
|
||||||
local cur_time = os.time()
|
local cur_time = os.time()
|
||||||
local diff = os.difftime(cur_time, starttime)
|
local diff = os.difftime(cur_time, starttime)
|
||||||
local fmt = "Server has been running for %d:%02d:%02d"
|
local fmt = "Server has been running for %d:%02d:%02d"
|
||||||
mt_irc:reply(fmt:format(
|
return true, fmt:format(
|
||||||
math.floor(diff / 60 / 60),
|
math.floor(diff / 60 / 60),
|
||||||
math.mod(math.floor(diff / 60), 60),
|
math.floor(diff / 60) % 60,
|
||||||
math.mod(math.floor(diff), 60)
|
math.floor(diff) % 60
|
||||||
))
|
)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
mt_irc:register_bot_command("players", {
|
irc.register_bot_command("players", {
|
||||||
description = "List the players on the server",
|
description = "List the players on the server",
|
||||||
func = function(user, args)
|
func = function()
|
||||||
local players = minetest.get_connected_players()
|
local players = minetest.get_connected_players()
|
||||||
local names = {}
|
local names = {}
|
||||||
for _, player in pairs(players) do
|
for _, player in pairs(players) do
|
||||||
table.insert(names, player:get_player_name())
|
table.insert(names, player:get_player_name())
|
||||||
end
|
end
|
||||||
mt_irc:reply("Connected players: "
|
return true, "Connected players: "
|
||||||
..table.concat(names, ", "))
|
..table.concat(names, ", ")
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
19
callback.lua
19
callback.lua
@ -4,25 +4,26 @@
|
|||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
if mt_irc.connected and mt_irc.config.send_join_part then
|
if irc.connected and irc.config.send_join_part then
|
||||||
mt_irc:say("*** "..name.." joined the game")
|
irc.say("*** "..name.." joined the game")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player, timed_out)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
if mt_irc.connected and mt_irc.config.send_join_part then
|
if irc.connected and irc.config.send_join_part then
|
||||||
mt_irc:say("*** "..name.." left the game")
|
irc.say("*** "..name.." left the game"..
|
||||||
|
(timed_out and " (Timed out)" or ""))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_chat_message(function(name, message)
|
minetest.register_on_chat_message(function(name, message)
|
||||||
if not mt_irc.connected
|
if not irc.connected
|
||||||
or message:sub(1, 1) == "/"
|
or message:sub(1, 1) == "/"
|
||||||
or message:sub(1, 5) == "[off]"
|
or message:sub(1, 5) == "[off]"
|
||||||
or not mt_irc.joined_players[name]
|
or not irc.joined_players[name]
|
||||||
or (not minetest.check_player_privs(name, {shout=true})) then
|
or (not minetest.check_player_privs(name, {shout=true})) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -30,11 +31,11 @@ minetest.register_on_chat_message(function(name, message)
|
|||||||
if nl then
|
if nl then
|
||||||
message = message:sub(1, nl - 1)
|
message = message:sub(1, nl - 1)
|
||||||
end
|
end
|
||||||
mt_irc:say(mt_irc:playerMessage(name, message))
|
irc.say(irc.playerMessage(name, core.strip_colors(message)))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_shutdown(function()
|
minetest.register_on_shutdown(function()
|
||||||
mt_irc:disconnect("Game shutting down.")
|
irc.disconnect("Game shutting down.")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
90
chatcmds.lua
90
chatcmds.lua
@ -10,33 +10,31 @@ minetest.register_chatcommand("irc_msg", {
|
|||||||
description = "Send a private message to an IRC user",
|
description = "Send a private message to an IRC user",
|
||||||
privs = {shout=true},
|
privs = {shout=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if not mt_irc.connected then
|
if not irc.connected then
|
||||||
minetest.chat_send_player(name, "Not connected to IRC. Use /irc_connect to connect.")
|
return false, "Not connected to IRC. Use /irc_connect to connect."
|
||||||
return
|
|
||||||
end
|
end
|
||||||
local found, _, toname, message = param:find("^([^%s]+)%s(.+)")
|
local found, _, toname, message = param:find("^([^%s]+)%s(.+)")
|
||||||
if not found then
|
if not found then
|
||||||
minetest.chat_send_player(name, "Invalid usage, see /help irc_msg.")
|
return false, "Invalid usage, see /help irc_msg."
|
||||||
return
|
|
||||||
end
|
end
|
||||||
local toname_l = toname:lower()
|
local toname_l = toname:lower()
|
||||||
local validNick = false
|
local validNick = false
|
||||||
for nick, user in pairs(mt_irc.conn.channels[mt_irc.config.channel].users) do
|
local hint = "They have to be in the channel"
|
||||||
|
for nick in pairs(irc.conn.channels[irc.config.channel].users) do
|
||||||
if nick:lower() == toname_l then
|
if nick:lower() == toname_l then
|
||||||
validNick = true
|
validNick = true
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if toname_l:find("serv$") or toname_l:find("bot$") then
|
if toname_l:find("serv$") or toname_l:find("bot$") then
|
||||||
|
hint = "it looks like a bot or service"
|
||||||
validNick = false
|
validNick = false
|
||||||
end
|
end
|
||||||
if not validNick then
|
if not validNick then
|
||||||
minetest.chat_send_player(name,
|
return false, "You can not message that user. ("..hint..")"
|
||||||
"You can not message that user. (Hint: They have to be in the channel)")
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
mt_irc:say(toname, mt_irc:playerMessage(name, message))
|
irc.say(toname, irc.playerMessage(name, message))
|
||||||
minetest.chat_send_player(name, "Message sent!")
|
return true, "Message sent!"
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -44,12 +42,15 @@ minetest.register_chatcommand("irc_msg", {
|
|||||||
minetest.register_chatcommand("irc_names", {
|
minetest.register_chatcommand("irc_names", {
|
||||||
params = "",
|
params = "",
|
||||||
description = "List the users in IRC.",
|
description = "List the users in IRC.",
|
||||||
func = function(name, params)
|
func = function()
|
||||||
local users = { }
|
if not irc.connected then
|
||||||
for k, v in pairs(mt_irc.conn.channels[mt_irc.config.channel].users) do
|
return false, "Not connected to IRC. Use /irc_connect to connect."
|
||||||
table.insert(users, k)
|
|
||||||
end
|
end
|
||||||
minetest.chat_send_player(name, "Users in IRC: "..table.concat(users, ", "))
|
local users = { }
|
||||||
|
for nick in pairs(irc.conn.channels[irc.config.channel].users) do
|
||||||
|
table.insert(users, nick)
|
||||||
|
end
|
||||||
|
return true, "Users in IRC: "..table.concat(users, ", ")
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -57,13 +58,12 @@ minetest.register_chatcommand("irc_names", {
|
|||||||
minetest.register_chatcommand("irc_connect", {
|
minetest.register_chatcommand("irc_connect", {
|
||||||
description = "Connect to the IRC server.",
|
description = "Connect to the IRC server.",
|
||||||
privs = {irc_admin=true},
|
privs = {irc_admin=true},
|
||||||
func = function(name, param)
|
func = function(name)
|
||||||
if mt_irc.connected then
|
if irc.connected then
|
||||||
minetest.chat_send_player(name, "You are already connected to IRC.")
|
return false, "You are already connected to IRC."
|
||||||
return
|
|
||||||
end
|
end
|
||||||
minetest.chat_send_player(name, "IRC: Connecting...")
|
minetest.chat_send_player(name, "IRC: Connecting...")
|
||||||
mt_irc:connect()
|
irc.connect()
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -73,14 +73,13 @@ minetest.register_chatcommand("irc_disconnect", {
|
|||||||
description = "Disconnect from the IRC server.",
|
description = "Disconnect from the IRC server.",
|
||||||
privs = {irc_admin=true},
|
privs = {irc_admin=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if not mt_irc.connected then
|
if not irc.connected then
|
||||||
minetest.chat_send_player(name, "You are not connected to IRC.")
|
return false, "Not connected to IRC. Use /irc_connect to connect."
|
||||||
return
|
|
||||||
end
|
end
|
||||||
if params == "" then
|
if param == "" then
|
||||||
params = "Manual disconnect by "..name
|
param = "Manual disconnect by "..name
|
||||||
end
|
end
|
||||||
mt_irc:disconnect(param)
|
irc.disconnect(param)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -88,13 +87,13 @@ minetest.register_chatcommand("irc_disconnect", {
|
|||||||
minetest.register_chatcommand("irc_reconnect", {
|
minetest.register_chatcommand("irc_reconnect", {
|
||||||
description = "Reconnect to the IRC server.",
|
description = "Reconnect to the IRC server.",
|
||||||
privs = {irc_admin=true},
|
privs = {irc_admin=true},
|
||||||
func = function(name, param)
|
func = function(name)
|
||||||
if not mt_irc.connected then
|
if not irc.connected then
|
||||||
minetest.chat_send_player(name, "You are not connected to IRC.")
|
return false, "Not connected to IRC. Use /irc_connect to connect."
|
||||||
return
|
|
||||||
end
|
end
|
||||||
mt_irc:disconnect("Reconnecting...")
|
minetest.chat_send_player(name, "IRC: Reconnecting...")
|
||||||
mt_irc:connect()
|
irc.disconnect("Reconnecting...")
|
||||||
|
irc.connect()
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -104,19 +103,32 @@ minetest.register_chatcommand("irc_quote", {
|
|||||||
description = "Send a raw command to the IRC server.",
|
description = "Send a raw command to the IRC server.",
|
||||||
privs = {irc_admin=true},
|
privs = {irc_admin=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if not mt_irc.connected then
|
if not irc.connected then
|
||||||
minetest.chat_send_player(name, "You are not connected to IRC.")
|
return false, "Not connected to IRC. Use /irc_connect to connect."
|
||||||
return
|
|
||||||
end
|
end
|
||||||
mt_irc:queue(param)
|
irc.queue(param)
|
||||||
minetest.chat_send_player(name, "Command sent!")
|
minetest.chat_send_player(name, "Command sent!")
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
local oldme = minetest.chatcommands["me"].func
|
local oldme = minetest.chatcommands["me"].func
|
||||||
|
-- luacheck: ignore
|
||||||
minetest.chatcommands["me"].func = function(name, param, ...)
|
minetest.chatcommands["me"].func = function(name, param, ...)
|
||||||
oldme(name, param, ...)
|
irc.say(("* %s %s"):format(name, param))
|
||||||
mt_irc:say(("* %s %s"):format(name, param))
|
return oldme(name, param, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if irc.config.send_kicks and minetest.chatcommands["kick"] then
|
||||||
|
local oldkick = minetest.chatcommands["kick"].func
|
||||||
|
-- luacheck: ignore
|
||||||
|
minetest.chatcommands["kick"].func = function(name, param, ...)
|
||||||
|
local plname, reason = param:match("^(%S+)%s*(.*)$")
|
||||||
|
if not plname then
|
||||||
|
return false, "Usage: /kick player [reason]"
|
||||||
|
end
|
||||||
|
irc.say(("*** Kicked %s.%s"):format(name,
|
||||||
|
reason~="" and " Reason: "..reason or ""))
|
||||||
|
return oldkick(name, param, ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
48
config.lua
48
config.lua
@ -2,36 +2,45 @@
|
|||||||
-- See LICENSE.txt for details.
|
-- See LICENSE.txt for details.
|
||||||
|
|
||||||
|
|
||||||
mt_irc.config = {}
|
irc.config = {}
|
||||||
|
|
||||||
local function setting(stype, name, default)
|
local function setting(stype, name, default, required)
|
||||||
local value
|
local value
|
||||||
|
if minetest.settings and minetest.settings.get and minetest.settings.get_bool then
|
||||||
if stype == "bool" then
|
if stype == "bool" then
|
||||||
value = minetest.setting_getbool("irc."..name)
|
value = minetest.settings:get_bool("irc."..name)
|
||||||
elseif stype == "string" then
|
elseif stype == "string" then
|
||||||
value = minetest.setting_get("irc."..name)
|
value = minetest.settings:get("irc."..name)
|
||||||
elseif stype == "number" then
|
elseif stype == "number" then
|
||||||
value = tonumber(minetest.setting_get("irc."..name))
|
value = tonumber(minetest.settings:get("irc."..name))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if value == nil then
|
if value == nil then
|
||||||
|
if required then
|
||||||
|
error("Required configuration option irc."..
|
||||||
|
name.." missing.")
|
||||||
|
end
|
||||||
value = default
|
value = default
|
||||||
end
|
end
|
||||||
mt_irc.config[name] = value
|
irc.config[name] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
-- BASIC USER SETTINGS --
|
-- BASIC USER SETTINGS --
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
setting("string", "nick") -- Nickname (default "MT-<hash>", <hash> 6 random hexidecimal characters)
|
setting("string", "nick", nil, true) -- Nickname
|
||||||
setting("string", "server", "irc.freenode.net") -- Server to connect on joinplayer
|
setting("string", "server", nil, true) -- Server address to connect to
|
||||||
setting("number", "port", 6667) -- Port to connect on joinplayer
|
setting("number", "port", 6667) -- Server port to connect to
|
||||||
setting("string", "NSPass") -- NickServ password
|
setting("string", "NSPass") -- NickServ password
|
||||||
setting("string", "SASLUser", mt_irc.config.nick) -- SASL username
|
setting("string", "sasl.user", irc.config.nick) -- SASL username
|
||||||
setting("string", "SASLPass") -- SASL password
|
setting("string", "username", "Minetest") -- Username/ident
|
||||||
setting("string", "channel", "##mt-irc-mod") -- Channel to join
|
setting("string", "realname", "Minetest") -- Real name/GECOS
|
||||||
|
setting("string", "sasl.pass") -- SASL password
|
||||||
|
setting("string", "channel", nil, true) -- Channel to join
|
||||||
setting("string", "key") -- Key for the channel
|
setting("string", "key") -- Key for the channel
|
||||||
setting("bool", "send_join_part", true) -- Whether to send player join and part messages to the channel
|
setting("bool", "send_join_part", true) -- Whether to send player join and part messages to the channel
|
||||||
|
setting("bool", "send_kicks", false) -- Whether to send player kicked messages to the channel
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
-- ADVANCED SETTINGS --
|
-- ADVANCED SETTINGS --
|
||||||
@ -40,20 +49,11 @@ setting("bool", "send_join_part", true) -- Whether to send player join and par
|
|||||||
setting("string", "password") -- Server password
|
setting("string", "password") -- Server password
|
||||||
setting("bool", "secure", false) -- Enable a TLS connection, requires LuaSEC
|
setting("bool", "secure", false) -- Enable a TLS connection, requires LuaSEC
|
||||||
setting("number", "timeout", 60) -- Underlying socket timeout in seconds.
|
setting("number", "timeout", 60) -- Underlying socket timeout in seconds.
|
||||||
|
setting("number", "reconnect", 600) -- Time between reconnection attempts, in seconds.
|
||||||
setting("string", "command_prefix") -- Prefix to use for bot commands
|
setting("string", "command_prefix") -- Prefix to use for bot commands
|
||||||
setting("bool", "debug", false) -- Enable debug output
|
setting("bool", "debug", false) -- Enable debug output
|
||||||
setting("bool", "enable_player_part", true) -- Whether to enable players joining and parting the channel
|
setting("bool", "enable_player_part", true) -- Whether to enable players joining and parting the channel
|
||||||
setting("bool", "auto_join", true) -- Whether to automatically show players in the channel when they join
|
setting("bool", "auto_join", true) -- Whether to automatically show players in the channel when they join
|
||||||
setting("bool", "auto_connect", true) -- Whether to automatically connect to the server on mod load
|
setting("bool", "auto_connect", true) -- Whether to automatically connect to the server on mod load
|
||||||
|
setting("string", "chat_color", "#339933") -- Color of IRC chat in-game, green by default
|
||||||
-- Generate a random nickname if one isn't specified.
|
setting("string", "pm_color", "#8800AA") -- Color of IRC PMs in-game, purple by default
|
||||||
if not mt_irc.config.nick then
|
|
||||||
local pr = PseudoRandom(os.time())
|
|
||||||
-- Workaround for bad distribution in minetest PRNG implementation.
|
|
||||||
mt_irc.config.nick = ("MT-%02X%02X%02X"):format(
|
|
||||||
pr:next(0, 255),
|
|
||||||
pr:next(0, 255),
|
|
||||||
pr:next(0, 255)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
183
hooks.lua
183
hooks.lua
@ -1,17 +1,16 @@
|
|||||||
-- This file is licensed under the terms of the BSD 2-clause license.
|
-- This file is licensed under the terms of the BSD 2-clause license.
|
||||||
-- See LICENSE.txt for details.
|
-- See LICENSE.txt for details.
|
||||||
|
|
||||||
|
local ie = ...
|
||||||
|
|
||||||
mt_irc.hooks = {}
|
-- MIME is part of LuaSocket
|
||||||
mt_irc.registered_hooks = {}
|
local b64e = ie.require("mime").b64
|
||||||
|
|
||||||
|
irc.hooks = {}
|
||||||
|
irc.registered_hooks = {}
|
||||||
|
|
||||||
|
|
||||||
-- TODO: Add proper conversion from CP1252 to UTF-8.
|
local stripped_chars = "[\2\31]"
|
||||||
local stripped_chars = {"\2", "\31"}
|
|
||||||
for c = 127, 255 do
|
|
||||||
table.insert(stripped_chars, string.char(c))
|
|
||||||
end
|
|
||||||
stripped_chars = "["..table.concat(stripped_chars, "").."]"
|
|
||||||
|
|
||||||
local function normalize(text)
|
local function normalize(text)
|
||||||
-- Strip colors
|
-- Strip colors
|
||||||
@ -21,8 +20,8 @@ local function normalize(text)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:doHook(conn)
|
function irc.doHook(conn)
|
||||||
for name, hook in pairs(self.registered_hooks) do
|
for name, hook in pairs(irc.registered_hooks) do
|
||||||
for _, func in pairs(hook) do
|
for _, func in pairs(hook) do
|
||||||
conn:hook(name, func)
|
conn:hook(name, func)
|
||||||
end
|
end
|
||||||
@ -30,59 +29,67 @@ function mt_irc:doHook(conn)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:register_hook(name, func)
|
function irc.register_hook(name, func)
|
||||||
self.registered_hooks[name] = self.registered_hooks[name] or {}
|
irc.registered_hooks[name] = irc.registered_hooks[name] or {}
|
||||||
table.insert(self.registered_hooks[name], func)
|
table.insert(irc.registered_hooks[name], func)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.raw(line)
|
function irc.hooks.raw(line)
|
||||||
if mt_irc.config.debug then
|
if irc.config.debug then
|
||||||
print("RECV: "..line)
|
print("RECV: "..line)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.send(line)
|
function irc.hooks.send(line)
|
||||||
if mt_irc.config.debug then
|
if irc.config.debug then
|
||||||
print("SEND: "..line)
|
print("SEND: "..line)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.chat(msg)
|
function irc.hooks.chat(msg)
|
||||||
local channel, text = msg.args[1], msg.args[2]
|
local channel, text = msg.args[1], msg.args[2]
|
||||||
if text:sub(1, 1) == string.char(1) then
|
if text:sub(1, 1) == string.char(1) then
|
||||||
mt_irc.conn:invoke("OnCTCP", msg)
|
irc.conn:invoke("OnCTCP", msg)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if channel == mt_irc.conn.nick then
|
if channel == irc.conn.nick then
|
||||||
mt_irc.last_from = msg.user.nick
|
irc.last_from = msg.user.nick
|
||||||
mt_irc.conn:invoke("PrivateMessage", msg)
|
irc.conn:invoke("PrivateMessage", msg)
|
||||||
else
|
else
|
||||||
mt_irc.last_from = channel
|
irc.last_from = channel
|
||||||
mt_irc.conn:invoke("OnChannelChat", msg)
|
irc.conn:invoke("OnChannelChat", msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.ctcp(msg)
|
local function get_core_version()
|
||||||
|
local status = minetest.get_server_status()
|
||||||
|
local start_pos = select(2, status:find("version=", 1, true))
|
||||||
|
local end_pos = status:find(",", start_pos, true)
|
||||||
|
return status:sub(start_pos + 1, end_pos - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function irc.hooks.ctcp(msg)
|
||||||
local text = msg.args[2]:sub(2, -2) -- Remove ^C
|
local text = msg.args[2]:sub(2, -2) -- Remove ^C
|
||||||
local args = text:split(' ')
|
local args = text:split(' ')
|
||||||
local command = args[1]:upper()
|
local command = args[1]:upper()
|
||||||
|
|
||||||
local function reply(s)
|
local function reply(s)
|
||||||
mt_irc:queue(irc.msgs.notice(msg.user.nick,
|
irc.queue(irc.msgs.notice(msg.user.nick,
|
||||||
("\1%s %s\1"):format(command, s)))
|
("\1%s %s\1"):format(command, s)))
|
||||||
end
|
end
|
||||||
|
|
||||||
if command == "ACTION" and msg.args[1] == mt_irc.config.channel then
|
if command == "ACTION" and msg.args[1] == irc.config.channel then
|
||||||
local action = text:sub(8, -1)
|
local action = text:sub(8, -1)
|
||||||
mt_irc:sendLocal(("* %s@IRC %s"):format(msg.user.nick, action))
|
irc.sendLocal(("* %s@IRC %s"):format(msg.user.nick, action))
|
||||||
elseif command == "VERSION" then
|
elseif command == "VERSION" then
|
||||||
reply(("Minetest IRC mod version %s.")
|
reply(("Minetest version %s, IRC mod version %s.")
|
||||||
:format(mt_irc.version))
|
:format(get_core_version(), irc.version))
|
||||||
elseif command == "PING" then
|
elseif command == "PING" then
|
||||||
reply(args[2])
|
reply(args[2])
|
||||||
elseif command == "TIME" then
|
elseif command == "TIME" then
|
||||||
@ -91,9 +98,18 @@ function mt_irc.hooks.ctcp(msg)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.channelChat(msg)
|
function irc.hooks.channelChat(msg)
|
||||||
local text = normalize(msg.args[2])
|
local text = normalize(msg.args[2])
|
||||||
|
|
||||||
|
irc.check_botcmd(msg)
|
||||||
|
|
||||||
|
-- Don't let a user impersonate someone else by using the nick "IRC"
|
||||||
|
local fake = msg.user.nick:lower():match("^[il|]rc$")
|
||||||
|
if fake then
|
||||||
|
irc.sendLocal("<"..msg.user.nick.."@IRC> "..text)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Support multiple servers in a channel better by converting:
|
-- Support multiple servers in a channel better by converting:
|
||||||
-- "<server@IRC> <player> message" into "<player@server> message"
|
-- "<server@IRC> <player> message" into "<player@server> message"
|
||||||
-- "<server@IRC> *** player joined/left the game" into "*** player joined/left server"
|
-- "<server@IRC> *** player joined/left the game" into "*** player joined/left server"
|
||||||
@ -104,61 +120,64 @@ function mt_irc.hooks.channelChat(msg)
|
|||||||
text:find("^%*%*%* ([^%s]+) joined the game$")
|
text:find("^%*%*%* ([^%s]+) joined the game$")
|
||||||
local foundleave, _, leavenick =
|
local foundleave, _, leavenick =
|
||||||
text:find("^%*%*%* ([^%s]+) left the game$")
|
text:find("^%*%*%* ([^%s]+) left the game$")
|
||||||
|
local foundtimedout, _, timedoutnick =
|
||||||
|
text:find("^%*%*%* ([^%s]+) left the game %(Timed out%)$")
|
||||||
local foundaction, _, actionnick, actionmessage =
|
local foundaction, _, actionnick, actionmessage =
|
||||||
text:find("^%* ([^%s]+) (.*)$")
|
text:find("^%* ([^%s]+) (.*)$")
|
||||||
|
|
||||||
mt_irc:check_botcmd(msg)
|
|
||||||
|
|
||||||
if text:sub(1, 5) == "[off]" then
|
if text:sub(1, 5) == "[off]" then
|
||||||
return
|
return
|
||||||
elseif foundchat then
|
elseif foundchat then
|
||||||
mt_irc:sendLocal(("<%s@%s> %s")
|
irc.sendLocal(("<%s@%s> %s")
|
||||||
:format(chatnick, msg.user.nick, chatmessage))
|
:format(chatnick, msg.user.nick, chatmessage))
|
||||||
elseif foundjoin then
|
elseif foundjoin then
|
||||||
mt_irc:sendLocal(("*** %s joined %s")
|
irc.sendLocal(("*** %s joined %s")
|
||||||
:format(joinnick, msg.user.nick))
|
:format(joinnick, msg.user.nick))
|
||||||
elseif foundleave then
|
elseif foundleave then
|
||||||
mt_irc:sendLocal(("*** %s left %s")
|
irc.sendLocal(("*** %s left %s")
|
||||||
:format(leavenick, msg.user.nick))
|
:format(leavenick, msg.user.nick))
|
||||||
|
elseif foundtimedout then
|
||||||
|
irc.sendLocal(("*** %s left %s (Timed out)")
|
||||||
|
:format(timedoutnick, msg.user.nick))
|
||||||
elseif foundaction then
|
elseif foundaction then
|
||||||
mt_irc:sendLocal(("* %s@%s %s")
|
irc.sendLocal(("* %s@%s %s")
|
||||||
:format(actionnick, msg.user.nick, actionmessage))
|
:format(actionnick, msg.user.nick, actionmessage))
|
||||||
else
|
else
|
||||||
mt_irc:sendLocal(("<%s@IRC> %s"):format(msg.user.nick, text))
|
irc.sendLocal(("<%s@IRC> %s"):format(msg.user.nick, text))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.pm(msg)
|
function irc.hooks.pm(msg)
|
||||||
-- Trim prefix if it is found
|
-- Trim prefix if it is found
|
||||||
local text = msg.args[2]
|
local text = msg.args[2]
|
||||||
local prefix = mt_irc.config.command_prefix
|
local prefix = irc.config.command_prefix
|
||||||
if prefix and text:sub(1, #prefix) == prefix then
|
if prefix and text:sub(1, #prefix) == prefix then
|
||||||
text = text:sub(#prefix + 1)
|
text = text:sub(#prefix + 1)
|
||||||
end
|
end
|
||||||
mt_irc:bot_command(msg, text)
|
irc.bot_command(msg, text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.kick(channel, target, prefix, reason)
|
function irc.hooks.kick(channel, target, prefix, reason)
|
||||||
if target == mt_irc.conn.nick then
|
if target == irc.conn.nick then
|
||||||
minetest.chat_send_all("IRC: kicked from "..channel.." by "..prefix.nick..".")
|
minetest.chat_send_all("IRC: kicked from "..channel.." by "..prefix.nick..".")
|
||||||
mt_irc:disconnect("Kicked")
|
irc.disconnect("Kicked")
|
||||||
else
|
else
|
||||||
mt_irc:sendLocal(("-!- %s was kicked from %s by %s [%s]")
|
irc.sendLocal(("-!- %s was kicked from %s by %s [%s]")
|
||||||
:format(target, channel, prefix.nick, reason))
|
:format(target, channel, prefix.nick, reason))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.notice(user, target, message)
|
function irc.hooks.notice(user, target, message)
|
||||||
if user.nick and target == mt_irc.config.channel then
|
if user.nick and target == irc.config.channel then
|
||||||
mt_irc:sendLocal("-"..user.nick.."@IRC- "..message)
|
irc.sendLocal("-"..user.nick.."@IRC- "..message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.mode(user, target, modes, ...)
|
function irc.hooks.mode(user, target, modes, ...)
|
||||||
local by = ""
|
local by = ""
|
||||||
if user.nick then
|
if user.nick then
|
||||||
by = " by "..user.nick
|
by = " by "..user.nick
|
||||||
@ -173,37 +192,37 @@ function mt_irc.hooks.mode(user, target, modes, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.nick(user, newNick)
|
function irc.hooks.nick(user, newNick)
|
||||||
mt_irc:sendLocal(("-!- %s is now known as %s")
|
irc.sendLocal(("-!- %s is now known as %s")
|
||||||
:format(user.nick, newNick))
|
:format(user.nick, newNick))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.join(user, channel)
|
function irc.hooks.join(user, channel)
|
||||||
mt_irc:sendLocal(("-!- %s joined %s")
|
irc.sendLocal(("-!- %s joined %s")
|
||||||
:format(user.nick, channel))
|
:format(user.nick, channel))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.part(user, channel, reason)
|
function irc.hooks.part(user, channel, reason)
|
||||||
reason = reason or ""
|
reason = reason or ""
|
||||||
mt_irc:sendLocal(("-!- %s has left %s [%s]")
|
irc.sendLocal(("-!- %s has left %s [%s]")
|
||||||
:format(user.nick, channel, reason))
|
:format(user.nick, channel, reason))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.quit(user, reason)
|
function irc.hooks.quit(user, reason)
|
||||||
mt_irc:sendLocal(("-!- %s has quit [%s]")
|
irc.sendLocal(("-!- %s has quit [%s]")
|
||||||
:format(user.nick, reason))
|
:format(user.nick, reason))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.disconnect(message, isError)
|
function irc.hooks.disconnect(_, isError)
|
||||||
mt_irc.connected = false
|
irc.connected = false
|
||||||
if isError then
|
if isError then
|
||||||
minetest.log("error", "IRC: Error: Disconnected, reconnecting in one minute.")
|
minetest.log("error", "IRC: Error: Disconnected, reconnecting in one minute.")
|
||||||
minetest.chat_send_all("IRC: Error: Disconnected, reconnecting in one minute.")
|
minetest.chat_send_all("IRC: Error: Disconnected, reconnecting in one minute.")
|
||||||
minetest.after(60, mt_irc.connect, mt_irc)
|
minetest.after(60, irc.connect, irc)
|
||||||
else
|
else
|
||||||
minetest.log("action", "IRC: Disconnected.")
|
minetest.log("action", "IRC: Disconnected.")
|
||||||
minetest.chat_send_all("IRC: Disconnected.")
|
minetest.chat_send_all("IRC: Disconnected.")
|
||||||
@ -211,34 +230,34 @@ function mt_irc.hooks.disconnect(message, isError)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc.hooks.preregister(conn)
|
function irc.hooks.preregister(conn)
|
||||||
if not (mt_irc.config.SASLUser and mt_irc.config.SASLPass) then return end
|
if not (irc.config["sasl.user"] and irc.config["sasl.pass"]) then return end
|
||||||
local authString = mt_irc.b64e(
|
local authString = b64e(
|
||||||
("%s\x00%s\x00%s"):format(
|
("%s\x00%s\x00%s"):format(
|
||||||
mt_irc.config.SASLUser,
|
irc.config["sasl.user"],
|
||||||
mt_irc.config.SASLUser,
|
irc.config["sasl.user"],
|
||||||
mt_irc.config.SASLPass)
|
irc.config["sasl.pass"])
|
||||||
)
|
)
|
||||||
conn:send("CAP REQ sasl")
|
conn:send("CAP REQ sasl")
|
||||||
conn:send("AUTHENTICATE PLAIN")
|
conn:send("AUTHENTICATE PLAIN")
|
||||||
conn:send("AUTHENTICATE "..authString)
|
conn:send("AUTHENTICATE "..authString)
|
||||||
--LuaIRC will send CAP END
|
conn:send("CAP END")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
mt_irc:register_hook("PreRegister", mt_irc.hooks.preregister)
|
irc.register_hook("PreRegister", irc.hooks.preregister)
|
||||||
mt_irc:register_hook("OnRaw", mt_irc.hooks.raw)
|
irc.register_hook("OnRaw", irc.hooks.raw)
|
||||||
mt_irc:register_hook("OnSend", mt_irc.hooks.send)
|
irc.register_hook("OnSend", irc.hooks.send)
|
||||||
mt_irc:register_hook("DoPrivmsg", mt_irc.hooks.chat)
|
irc.register_hook("DoPrivmsg", irc.hooks.chat)
|
||||||
mt_irc:register_hook("OnPart", mt_irc.hooks.part)
|
irc.register_hook("OnPart", irc.hooks.part)
|
||||||
mt_irc:register_hook("OnKick", mt_irc.hooks.kick)
|
irc.register_hook("OnKick", irc.hooks.kick)
|
||||||
mt_irc:register_hook("OnJoin", mt_irc.hooks.join)
|
irc.register_hook("OnJoin", irc.hooks.join)
|
||||||
mt_irc:register_hook("OnQuit", mt_irc.hooks.quit)
|
irc.register_hook("OnQuit", irc.hooks.quit)
|
||||||
mt_irc:register_hook("NickChange", mt_irc.hooks.nick)
|
irc.register_hook("NickChange", irc.hooks.nick)
|
||||||
mt_irc:register_hook("OnCTCP", mt_irc.hooks.ctcp)
|
irc.register_hook("OnCTCP", irc.hooks.ctcp)
|
||||||
mt_irc:register_hook("PrivateMessage", mt_irc.hooks.pm)
|
irc.register_hook("PrivateMessage", irc.hooks.pm)
|
||||||
mt_irc:register_hook("OnNotice", mt_irc.hooks.notice)
|
irc.register_hook("OnNotice", irc.hooks.notice)
|
||||||
mt_irc:register_hook("OnChannelChat", mt_irc.hooks.channelChat)
|
irc.register_hook("OnChannelChat", irc.hooks.channelChat)
|
||||||
mt_irc:register_hook("OnModeChange", mt_irc.hooks.mode)
|
irc.register_hook("OnModeChange", irc.hooks.mode)
|
||||||
mt_irc:register_hook("OnDisconnect", mt_irc.hooks.disconnect)
|
irc.register_hook("OnDisconnect", irc.hooks.disconnect)
|
||||||
|
|
||||||
|
201
init.lua
201
init.lua
@ -3,14 +3,51 @@
|
|||||||
|
|
||||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
|
||||||
package.path =
|
-- Handle mod security if needed
|
||||||
package.path..";"
|
local ie, req_ie = _G, minetest.request_insecure_environment
|
||||||
-- To find LuaIRC's init.lua
|
if req_ie then ie = req_ie() end
|
||||||
..modpath.."/?/init.lua;"
|
if not ie then
|
||||||
-- For LuaIRC to find its files
|
error("The IRC mod requires access to insecure functions in order "..
|
||||||
..modpath.."/?.lua"
|
"to work. Please add the irc mod to your secure.trusted_mods "..
|
||||||
|
"setting or disable the irc mod.")
|
||||||
|
end
|
||||||
|
|
||||||
mt_irc = {
|
ie.package.path =
|
||||||
|
-- To find LuaIRC's init.lua
|
||||||
|
modpath.."/?/init.lua;"
|
||||||
|
-- For LuaIRC to find its files
|
||||||
|
..modpath.."/?.lua;"
|
||||||
|
..ie.package.path
|
||||||
|
|
||||||
|
-- The build of Lua that Minetest comes with only looks for libraries under
|
||||||
|
-- /usr/local/share and /usr/local/lib but LuaSocket is often installed under
|
||||||
|
-- /usr/share and /usr/lib.
|
||||||
|
if not rawget(_G, "jit") and package.config:sub(1, 1) == "/" then
|
||||||
|
|
||||||
|
ie.package.path = ie.package.path..
|
||||||
|
";/usr/share/lua/5.1/?.lua"..
|
||||||
|
";/usr/share/lua/5.1/?/init.lua"
|
||||||
|
|
||||||
|
ie.package.cpath = ie.package.cpath..
|
||||||
|
";/usr/lib/lua/5.1/?.so"..
|
||||||
|
";/usr/lib64/lua/5.1/?.so"
|
||||||
|
|
||||||
|
ie.package.cpath = "/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;"..ie.package.cpath
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Temporarily set require so that LuaIRC can access it
|
||||||
|
local old_require = require
|
||||||
|
require = ie.require
|
||||||
|
|
||||||
|
-- Silence warnings about `module` in `ltn12`.
|
||||||
|
local old_module = rawget(_G, "module")
|
||||||
|
rawset(_G, "module", ie.module)
|
||||||
|
|
||||||
|
local lib = ie.require("irc")
|
||||||
|
|
||||||
|
irc = {
|
||||||
version = "0.2.0",
|
version = "0.2.0",
|
||||||
connected = false,
|
connected = false,
|
||||||
cur_time = 0,
|
cur_time = 0,
|
||||||
@ -18,44 +55,82 @@ mt_irc = {
|
|||||||
recent_message_count = 0,
|
recent_message_count = 0,
|
||||||
joined_players = {},
|
joined_players = {},
|
||||||
modpath = modpath,
|
modpath = modpath,
|
||||||
lib = require("irc"),
|
lib = lib,
|
||||||
}
|
}
|
||||||
local irc = mt_irc.lib
|
|
||||||
|
-- Compatibility
|
||||||
|
rawset(_G, "mt_irc", irc)
|
||||||
|
|
||||||
|
local getinfo = debug.getinfo
|
||||||
|
local warned = { }
|
||||||
|
|
||||||
|
local function warn_deprecated(k)
|
||||||
|
local info = getinfo(3)
|
||||||
|
local loc = info.source..":"..info.currentline
|
||||||
|
if warned[loc] then return end
|
||||||
|
warned[loc] = true
|
||||||
|
print("COLON: "..tostring(k))
|
||||||
|
minetest.log("warning", "Deprecated use of colon notation when calling"
|
||||||
|
.." method `"..tostring(k).."` at "..loc)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This is a hack.
|
||||||
|
setmetatable(irc, {
|
||||||
|
__newindex = function(t, k, v)
|
||||||
|
if type(v) == "function" then
|
||||||
|
local f = v
|
||||||
|
v = function(me, ...)
|
||||||
|
if rawequal(me, t) then
|
||||||
|
warn_deprecated(k)
|
||||||
|
return f(...)
|
||||||
|
else
|
||||||
|
return f(me, ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rawset(t, k, v)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
dofile(modpath.."/config.lua")
|
dofile(modpath.."/config.lua")
|
||||||
dofile(modpath.."/messages.lua")
|
dofile(modpath.."/messages.lua")
|
||||||
dofile(modpath.."/hooks.lua")
|
loadfile(modpath.."/hooks.lua")(ie)
|
||||||
dofile(modpath.."/callback.lua")
|
dofile(modpath.."/callback.lua")
|
||||||
dofile(modpath.."/chatcmds.lua")
|
dofile(modpath.."/chatcmds.lua")
|
||||||
dofile(modpath.."/botcmds.lua")
|
dofile(modpath.."/botcmds.lua")
|
||||||
dofile(modpath.."/util.lua")
|
|
||||||
if mt_irc.config.enable_player_part then
|
-- Restore old (safe) functions
|
||||||
|
require = old_require
|
||||||
|
rawset(_G, "module", old_module)
|
||||||
|
|
||||||
|
if irc.config.enable_player_part then
|
||||||
dofile(modpath.."/player_part.lua")
|
dofile(modpath.."/player_part.lua")
|
||||||
else
|
else
|
||||||
setmetatable(mt_irc.joined_players, {__index = function(index) return true end})
|
setmetatable(irc.joined_players, {__index = function() return true end})
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_privilege("irc_admin", {
|
minetest.register_privilege("irc_admin", {
|
||||||
description = "Allow IRC administrative tasks to be performed.",
|
description = "Allow IRC administrative tasks to be performed.",
|
||||||
give_to_singleplayer = true
|
give_to_singleplayer = true,
|
||||||
|
give_to_admin = true,
|
||||||
})
|
})
|
||||||
|
|
||||||
local stepnum = 0
|
local stepnum = 0
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime) return mt_irc:step(dtime) end)
|
minetest.register_globalstep(function(dtime) return irc.step(dtime) end)
|
||||||
|
|
||||||
function mt_irc:step(dtime)
|
function irc.step()
|
||||||
if stepnum == 3 then
|
if stepnum == 3 then
|
||||||
if self.config.auto_connect then
|
if irc.config.auto_connect then
|
||||||
self:connect()
|
irc.connect()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
stepnum = stepnum + 1
|
stepnum = stepnum + 1
|
||||||
|
|
||||||
if not self.connected then return end
|
if not irc.connected then return end
|
||||||
|
|
||||||
-- Hooks will manage incoming messages and errors
|
-- Hooks will manage incoming messages and errors
|
||||||
local good, err = xpcall(function() self.conn:think() end, debug.traceback)
|
local good, err = xpcall(function() irc.conn:think() end, debug.traceback)
|
||||||
if not good then
|
if not good then
|
||||||
print(err)
|
print(err)
|
||||||
return
|
return
|
||||||
@ -63,76 +138,90 @@ function mt_irc:step(dtime)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:connect()
|
function irc.connect()
|
||||||
if self.connected then
|
if irc.connected then
|
||||||
minetest.log("error", "IRC: Ignoring attempt to connect when already connected.")
|
minetest.log("error", "IRC: Ignoring attempt to connect when already connected.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self.conn = irc.new({
|
irc.conn = irc.lib.new({
|
||||||
nick = self.config.nick,
|
nick = irc.config.nick,
|
||||||
username = "Minetest",
|
username = irc.config.username,
|
||||||
realname = "Minetest",
|
realname = irc.config.realname,
|
||||||
})
|
})
|
||||||
self:doHook(self.conn)
|
irc.doHook(irc.conn)
|
||||||
good, message = pcall(function()
|
|
||||||
self.conn:connect({
|
-- We need to swap the `require` function again since
|
||||||
host = self.config.server,
|
-- LuaIRC `require`s `ssl` if `irc.secure` is true.
|
||||||
port = self.config.port,
|
old_require = require
|
||||||
pass = self.config.password,
|
require = ie.require
|
||||||
timeout = self.config.timeout,
|
|
||||||
secure = self.config.secure
|
local good, message = pcall(function()
|
||||||
|
irc.conn:connect({
|
||||||
|
host = irc.config.server,
|
||||||
|
port = irc.config.port,
|
||||||
|
password = irc.config.password,
|
||||||
|
timeout = irc.config.timeout,
|
||||||
|
reconnect = irc.config.reconnect,
|
||||||
|
secure = irc.config.secure
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
require = old_require
|
||||||
|
|
||||||
if not good then
|
if not good then
|
||||||
minetest.log("error", ("IRC: Connection error: %s: %s -- Reconnecting in ten minutes...")
|
minetest.log("error", ("IRC: Connection error: %s: %s -- Reconnecting in %d seconds...")
|
||||||
:format(self.config.server, message))
|
:format(irc.config.server, message, irc.config.reconnect))
|
||||||
minetest.after(600, function() self:connect() end)
|
minetest.after(irc.config.reconnect, function() irc.connect() end)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.config.NSPass then
|
if irc.config.NSPass then
|
||||||
self:say("NickServ", "IDENTIFY "..self.config.NSPass)
|
irc.conn:queue(irc.msgs.privmsg(
|
||||||
|
"NickServ", "IDENTIFY "..irc.config.NSPass))
|
||||||
end
|
end
|
||||||
|
|
||||||
self.conn:join(self.config.channel, self.config.key)
|
irc.conn:join(irc.config.channel, irc.config.key)
|
||||||
self.connected = true
|
irc.connected = true
|
||||||
minetest.log("action", "IRC: Connected!")
|
minetest.log("action", "IRC: Connected!")
|
||||||
minetest.chat_send_all("IRC: Connected!")
|
minetest.chat_send_all("IRC: Connected!")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:disconnect(message)
|
function irc.disconnect(message)
|
||||||
if self.connected then
|
if irc.connected then
|
||||||
--The OnDisconnect hook will clear self.connected and print a disconnect message
|
--The OnDisconnect hook will clear irc.connected and print a disconnect message
|
||||||
self.conn:disconnect(message)
|
irc.conn:disconnect(message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:say(to, message)
|
function irc.say(to, message)
|
||||||
if not message then
|
if not message then
|
||||||
message = to
|
message = to
|
||||||
to = self.config.channel
|
to = irc.config.channel
|
||||||
end
|
end
|
||||||
to = to or self.config.channel
|
to = to or irc.config.channel
|
||||||
|
|
||||||
self:queue(irc.msgs.privmsg(to, message))
|
irc.queue(irc.msgs.privmsg(to, message))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:reply(message)
|
function irc.reply(message)
|
||||||
if not self.last_from then
|
if not irc.last_from then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self:say(self.last_from, message)
|
message = message:gsub("[\r\n%z]", " \\n ")
|
||||||
|
irc.say(irc.last_from, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mt_irc:send(msg)
|
function irc.send(msg)
|
||||||
self.conn:send(msg)
|
if not irc.connected then return end
|
||||||
|
irc.conn:send(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mt_irc:queue(msg)
|
function irc.queue(msg)
|
||||||
self.conn:queue(msg)
|
if not irc.connected then return end
|
||||||
|
irc.conn:queue(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
minetest.log("action", "[irc] loaded.")
|
||||||
|
2
irc
2
irc
Submodule irc updated: bc9805a33c...b8d594e651
14
messages.lua
14
messages.lua
@ -1,13 +1,17 @@
|
|||||||
-- This file is licensed under the terms of the BSD 2-clause license.
|
-- This file is licensed under the terms of the BSD 2-clause license.
|
||||||
-- See LICENSE.txt for details.
|
-- See LICENSE.txt for details.
|
||||||
|
|
||||||
mt_irc.msgs = mt_irc.lib.msgs
|
irc.msgs = irc.lib.msgs
|
||||||
|
|
||||||
function mt_irc:sendLocal(message)
|
function irc.logChat(message)
|
||||||
minetest.chat_send_all(message)
|
minetest.log("action", "IRC CHAT: "..message)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mt_irc:playerMessage(name, message)
|
function irc.sendLocal(message)
|
||||||
|
minetest.chat_send_all(minetest.colorize(irc.config.chat_color, message))
|
||||||
|
irc.logChat(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
function irc.playerMessage(name, message)
|
||||||
return ("<%s> %s"):format(name, message)
|
return ("<%s> %s"):format(name, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
5
mod.conf
Normal file
5
mod.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
name = irc
|
||||||
|
description = """
|
||||||
|
This mod is just a glue between IRC and Minetest.
|
||||||
|
It provides two-way communication between the in-game chat, and an arbitrary IRC channel.
|
||||||
|
"""
|
@ -2,68 +2,71 @@
|
|||||||
-- See LICENSE.txt for details.
|
-- See LICENSE.txt for details.
|
||||||
|
|
||||||
|
|
||||||
function mt_irc:player_part(name)
|
function irc.player_part(name)
|
||||||
if not self.joined_players[name] then
|
if not irc.joined_players[name] then
|
||||||
minetest.chat_send_player(name, "IRC: You are not in the channel.")
|
return false, "You are not in the channel"
|
||||||
return
|
|
||||||
end
|
end
|
||||||
self.joined_players[name] = nil
|
irc.joined_players[name] = nil
|
||||||
minetest.chat_send_player(name, "IRC: You are now out of the channel.")
|
return true, "You left the channel"
|
||||||
end
|
end
|
||||||
|
|
||||||
function mt_irc:player_join(name)
|
function irc.player_join(name)
|
||||||
if self.joined_players[name] then
|
if irc.joined_players[name] then
|
||||||
minetest.chat_send_player(name, "IRC: You are already in the channel.")
|
return false, "You are already in the channel"
|
||||||
return
|
elseif not minetest.get_player_by_name(name) then
|
||||||
|
return false, "You need to be in-game to join the channel"
|
||||||
end
|
end
|
||||||
self.joined_players[name] = true
|
irc.joined_players[name] = true
|
||||||
minetest.chat_send_player(name, "IRC: You are now in the channel.")
|
return true, "You joined the channel"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
minetest.register_chatcommand("join", {
|
minetest.register_chatcommand("join", {
|
||||||
description = "Join the IRC channel",
|
description = "Join the IRC channel",
|
||||||
privs = {shout=true},
|
privs = {shout=true},
|
||||||
func = function(name, param)
|
func = function(name)
|
||||||
mt_irc:player_join(name)
|
return irc.player_join(name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand("part", {
|
minetest.register_chatcommand("part", {
|
||||||
description = "Part the IRC channel",
|
description = "Part the IRC channel",
|
||||||
privs = {shout=true},
|
privs = {shout=true},
|
||||||
func = function(name, param)
|
func = function(name)
|
||||||
mt_irc:player_part(name)
|
return irc.player_part(name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand("who", {
|
minetest.register_chatcommand("who", {
|
||||||
description = "Tell who is currently on the channel",
|
description = "Tell who is currently on the channel",
|
||||||
privs = {},
|
privs = {},
|
||||||
func = function(name, param)
|
func = function()
|
||||||
local s = ""
|
local out, n = { }, 0
|
||||||
for name, _ in pairs(mt_irc.joined_players) do
|
for plname in pairs(irc.joined_players) do
|
||||||
s = s..", "..name
|
n = n + 1
|
||||||
|
out[n] = plname
|
||||||
end
|
end
|
||||||
minetest.chat_send_player(name, "Players On Channel:"..s)
|
table.sort(out)
|
||||||
|
return true, "Players in channel: "..table.concat(out, ", ")
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
mt_irc.joined_players[name] = mt_irc.config.auto_join
|
irc.joined_players[name] = irc.config.auto_join
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
mt_irc.joined_players[name] = nil
|
irc.joined_players[name] = nil
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function mt_irc:sendLocal(message)
|
function irc.sendLocal(message)
|
||||||
for name, _ in pairs(self.joined_players) do
|
for name, _ in pairs(irc.joined_players) do
|
||||||
minetest.chat_send_player(name, message)
|
minetest.chat_send_player(name,
|
||||||
|
minetest.colorize(irc.config.chat_color, message))
|
||||||
end
|
end
|
||||||
|
irc.logChat(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
75
settingtypes.txt
Normal file
75
settingtypes.txt
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
[Basic]
|
||||||
|
|
||||||
|
# Whether to automatically connect to the server on mod load.
|
||||||
|
# If false, you must use /irc_connect to connect.
|
||||||
|
irc.auto_connect (Auto-connect on load) bool true
|
||||||
|
|
||||||
|
# Nickname for the bot. May only contain characters A-Z, 0-9
|
||||||
|
# '{', '}', '[', ']', '|', '^', '-', or '_'.
|
||||||
|
irc.nick (Bot nickname) string Minetest
|
||||||
|
|
||||||
|
# Server to connect to.
|
||||||
|
irc.server (IRC server) string irc.freenode.net
|
||||||
|
|
||||||
|
# Server port.
|
||||||
|
# The standard IRC protocol port is 6667 for regular servers,
|
||||||
|
# or 6697 for SSL-enabled servers.
|
||||||
|
# If unsure, leave at 6667.
|
||||||
|
irc.port (IRC server port) int 6667 1 65535
|
||||||
|
|
||||||
|
# Channel the bot joins after connecting.
|
||||||
|
irc.channel (Channel to join) string ##mt-irc-mod
|
||||||
|
|
||||||
|
[Authentication]
|
||||||
|
|
||||||
|
# Password for authenticating to NickServ.
|
||||||
|
# Leave empty to not authenticate with NickServ.
|
||||||
|
irc.NSPass (NickServ password) string
|
||||||
|
|
||||||
|
# IRC server password.
|
||||||
|
# Leave empty for no password.
|
||||||
|
irc.password (Server password) string
|
||||||
|
|
||||||
|
# Password for joining the channel.
|
||||||
|
# Leave empty if your channel is not protected.
|
||||||
|
irc.key (Channel key) string
|
||||||
|
|
||||||
|
# Enable TLS connection.
|
||||||
|
# Requires LuaSEC <https://github.com/brunoos/luasec>.
|
||||||
|
irc.secure (Use TLS) bool false
|
||||||
|
|
||||||
|
# Username for SASL authentication.
|
||||||
|
# Leave empty to use the nickname.
|
||||||
|
irc.sasl.user (SASL username) string
|
||||||
|
|
||||||
|
# Password for SASL authentication.
|
||||||
|
# Leave empty to not authenticate via SASL.
|
||||||
|
irc.sasl.pass (SASL password) string
|
||||||
|
|
||||||
|
[Advanced]
|
||||||
|
|
||||||
|
# Enable this to make the bot send messages when players join
|
||||||
|
# or leave the game server.
|
||||||
|
irc.send_join_part (Send join and part messages) bool true
|
||||||
|
|
||||||
|
# Enable this to make the bot send messages when players are kicked.
|
||||||
|
irc.send_kicks (Send kick messages) bool false
|
||||||
|
|
||||||
|
# Underlying socket timeout in seconds.
|
||||||
|
irc.timeout (Timeout) int 60 1
|
||||||
|
|
||||||
|
# Time between reconnection attempts, in seconds.
|
||||||
|
irc.reconnect (Reconnect delay) int 600 1
|
||||||
|
|
||||||
|
# Prefix to use for bot commands.
|
||||||
|
irc.command_prefix (Command prefix) string
|
||||||
|
|
||||||
|
# Enable debug output.
|
||||||
|
irc.debug (Debug mode) bool false
|
||||||
|
|
||||||
|
# Whether to enable players joining and parting the channel.
|
||||||
|
irc.enable_player_part (Allow player join/part) bool true
|
||||||
|
|
||||||
|
# Whether to automatically show players in the channel when they join.
|
||||||
|
irc.auto_join (Auto join players) bool true
|
20
util.lua
20
util.lua
@ -1,20 +0,0 @@
|
|||||||
--Base 64 encode -- for SASL authentication
|
|
||||||
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
|
||||||
function mt_irc.b64e(data)
|
|
||||||
return ((data:gsub('.', function(x)
|
|
||||||
local r,b='',x:byte()
|
|
||||||
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
|
|
||||||
return r;
|
|
||||||
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
|
|
||||||
if (#x < 6) then return '' end
|
|
||||||
local c=0
|
|
||||||
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
|
|
||||||
return b:sub(c+1,c+1)
|
|
||||||
end)..({ '', '==', '=' })[#data%3+1])
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Requested by Exio
|
|
||||||
string.expandvars = function(s, vars)
|
|
||||||
return s:gsub("%$%(([^)]+)%)", vars)
|
|
||||||
end
|
|
Reference in New Issue
Block a user