minetest_modding_book/_en/players/chat.md
2024-10-23 00:39:22 +01:00

198 lines
6.1 KiB
Markdown

---
title: Chat and Commands
layout: default
root: ../..
idx: 4.2
description: Registering a chatcommand and handling chat messages with register_on_chat_message
redirect_from: /en/chapters/chat.html
cmd_online:
level: warning
title: Offline players can run commands
message: |
A player name is passed instead of a player object because mods
can run commands on behalf of offline players. For example, the IRC
bridge allows players to run commands without joining the game.
So make sure that you don't assume that the player is online.
You can check by seeing if `core.get_player_by_name` returns a player.
cb_cmdsprivs:
level: warning
title: Privileges and Chat Commands
message: |
The shout privilege isn't needed for a player to trigger this callback.
This is because chat commands are implemented in Lua, and are just
chat messages that begin with a /.
---
## Introduction <!-- omit in toc -->
Mods can interact with player chat, including
sending messages, intercepting messages, and registering chat commands.
- [Sending Messages](#sending-messages)
- [To All Players](#to-all-players)
- [To Specific Players](#to-specific-players)
- [Chat Commands](#chat-commands)
- [Accepting Multiple Arguments](#accepting-multiple-arguments)
- [Using string.split](#using-stringsplit)
- [Using Lua patterns](#using-lua-patterns)
- [Intercepting Messages](#intercepting-messages)
## Sending Messages
### To All Players
To send a message to every player in the game, call the `chat_send_all` function.
```lua
core.chat_send_all("This is a chat message to all players")
```
Here is an example of how this appears in-game:
<player1> Look at this entrance
This is a chat message to all players
<player2> What about it?
The message appears on a separate line to distinguish it from in-game player chat.
### To Specific Players
To send a message to a specific player, call the `chat_send_player` function:
```lua
core.chat_send_player("player1", "This is a chat message for player1")
```
This message displays in the same manner as messages to all players, but is
only visible to the named player, in this case, player1.
## Chat Commands
To register a chat command, for example `/foo`, use `register_chatcommand`:
```lua
core.register_chatcommand("foo", {
privs = {
interact = true,
},
func = function(name, param)
return true, "You said " .. param .. "!"
end,
})
```
In the above snippet, `interact` is listed as a required
[privilege](privileges.html) meaning that only players with the `interact` privilege can run the command.
`param` is a string containing everything a player writes after the chatcommand
name. For example, if a user types `/grantme one,two,three` then `param` will be
`one,two,three`.
Chat commands can return up to two values,
the first being a Boolean indicating success, and the second being a
message to send to the user.
{% include notice.html notice=page.cmd_online %}
### Accepting Multiple Arguments
<a name="complex-subcommands"></a>
`param` gives you all the arguments to a chat command in a single string. It's
common for chat commands to need to extract multiple arguments. There are two
ways of doing this, either using Minetest's string split or Lua patterns.
#### Using string.split
A string can be split up into words using `string.split(" ")`:
```lua
local parts = param:split(" ")
local cmd = parts[1]
if cmd == "join" then
local team_name = parts[2]
team.join(name, team_name)
return true, "Joined team!"
elseif cmd == "max_users" then
local team_name = parts[2]
local max_users = tonumber(parts[3])
if team_name and max_users then
return true, "Set max users of team " .. team_name .. " to " .. max_users
else
return false, "Usage: /team max_users <team_name> <number>"
end
else
return false, "Command needed"
end
```
#### Using Lua patterns
[Lua patterns](https://www.lua.org/pil/20.2.html) are a way of extracting stuff
from text using rules. They're best suited for when there are arguments that can
contain spaces or more control is needed on how parameters are captured.
```lua
local to, msg = param:match("^([%a%d_-]+) (.+)$")
```
The above code implements `/msg <to> <message>`. Let's go through left to right:
* `^` means match the start of the string.
* `()` is a matching group - anything that matches stuff in here will be
returned from string.match.
* `[]` means accept characters in this list.
* `%a` means accept any letter and `%d` means accept any digit.
* `[%a%d_-]` means accept any letter or digit or `_` or `-`.
* `+` means match the thing before one or more times.
* `.` means match any character in this context.
* `$` means match the end of the string.
Put simply, the pattern matches the name (a word with only letters/numbers/-/_),
then a space, then the message (one or more of any character). The name and
message are returned, because they're surrounded by parentheses.
That's how most mods implement complex chat commands. A better guide to Lua
Patterns would probably be the
[lua-users.org tutorial](http://lua-users.org/wiki/PatternsTutorial)
or the [PIL documentation](https://www.lua.org/pil/20.2.html).
## Intercepting Messages
To intercept a message, use register_on_chat_message:
```lua
core.register_on_chat_message(function(name, message)
print(name .. " said " .. message)
return false
end)
```
By returning false, you allow the chat message to be sent by the default
handler. You can actually remove the line `return false` and it would still
work the same, because `nil` is returned implicitly and is treated like false.
{% include notice.html notice=page.cb_cmdsprivs %}
You should make sure you take into account that it may be a chat command,
or the user may not have `shout`.
```lua
core.register_on_chat_message(function(name, message)
if message:sub(1, 1) == "/" then
print(name .. " ran chat command")
elseif core.check_player_privs(name, { shout = true }) then
print(name .. " said " .. message)
else
print(name .. " tried to say " .. message ..
" but doesn't have shout")
end
return false
end)
```