Chatting Documentation
Chatting makes chat network-wide. A message typed on any backend reaches every player on every server, across one Velocity proxy or several, through Redis pub/sub. It adds /msg and /reply that work across proxies, shows LuckPerms prefixes and suffixes, and is built around 1.19.1+ signed chat so nobody gets kicked and nobody sees a message twice.
Overview
- Global chat across every backend and every proxy connected to the same Redis.
- Private messages with
/msgand/reply, to a player on any proxy, with tab completion of everyone online network-wide. - LuckPerms prefixes and suffixes when LuckPerms runs on the proxy. Without it the plugin still works; prefixes are just empty.
- Server names are never shown in chat: the network reads as one server.
- No colour injection: the player's message is always inserted as plain text.
- Survives Redis outages: if Redis is unreachable, chat is still delivered on the local proxy, and the subscription reconnects on its own every 3 seconds.
Requirements
| Component | Runs on | Required |
|---|---|---|
Chatting (chatting-1.0.0.jar) | Every Velocity 3.4+ proxy, Java 21 | Yes |
| Redis server | Anywhere every proxy can reach | Yes |
| LuckPerms | The proxy | Optional — for prefixes and suffixes |
ChattingBackend (chatting-backend-1.0.0.jar) | Paper 26.2 backends, Java 25 | Optional — see Signed chat |
Installation
- Put
chatting-1.0.0.jarin theplugins/folder of every Velocity proxy, and start each one once. This createsplugins/chatting/config.properties. - Point every proxy at the same Redis:
redis.host=10.0.0.6 redis.port=6379 redis.password=change-me redis.channel=chatting\:chat - Restart the proxies. The console logs
Connected to Redis at 10.0.0.6:6379, channel chatting:chatand, with LuckPerms installed,Hooked into LuckPerms. - Optional: install ChattingBackend on the backends and set
exclude-source-server=false(see below).
Every proxy must use the same redis.channel. In a .properties file a colon in a value may be written as \:; both forms work.
Signed Chat & Doubles
Since Minecraft 1.19.1, chat messages are signed. A proxy can no longer cancel a signed message — trying it kicks the player — so Chatting never cancels chat. That leaves one question: who shows the message to the players on the sender's own server? There are two setups.
Default: let the backend show it (no backend plugin)
The backend shows the message to players on its own server, as it normally would. Chatting delivers it to everyone else, and skips the sender's server so nobody sees it twice. This is exclude-source-server=true, the default.
Trade-off: players on the sender's server see the backend's own chat format, everyone else sees Chatting's format.
With ChattingBackend: one format everywhere
Install ChattingBackend on every backend. It cancels chat on the backend — which is still allowed there — so the only copy anybody sees is Chatting's broadcast. Then set:
exclude-source-server=false
Now everyone, including players on the sender's server, sees the same format. ChattingBackend has no config, commands or permissions.
With ChattingBackend installed and exclude-source-server=true, players on the sender's server see nothing. Without ChattingBackend and with exclude-source-server=false, they see the message twice.
Private Messages
/msg <player> <message>reaches the player wherever they are on the network. The receiver seesmsg.format.receiver; the sender getsmsg.format.senderas an echo./reply <message>answers the last player you exchanged a private message with. That memory is cleared when you leave.- Who is online network-wide is kept in a Redis hash, so
/msgcan find and tab-complete players on other proxies.
The player registry needs to write to Redis. If the proxy is pointed at a read-only replica, global chat still works but /msg can only see players on the same proxy — and the console says so at start-up.
Configuration
plugins/chatting/config.properties, created on first start and read as UTF-8, so characters like » in a format are safe. Restart the proxy after editing.
| Key | Default | Description |
|---|---|---|
redis.host | 127.0.0.1 | Redis host. |
redis.port | 6379 | Redis port. |
redis.password | (empty) | Redis password. Empty means none. |
redis.channel | chatting:chat | The pub/sub channel. Must match on every proxy. |
format | {prefix}{player}{suffix}&8: &f{message} | Global chat format. Placeholders: {prefix}, {player}, {suffix}, {message}. |
exclude-source-server | true | Skip players on the sender's server. Set false only with ChattingBackend installed. |
msg.format.receiver | &8[&e{sender} &8-> &eYou&8] &f{message} | What the receiver of a private message sees. Placeholders: {sender}, {target}, {message}. |
msg.format.sender | &8[&eYou &8-> &e{target}&8] &f{message} | The echo shown to the sender. |
msg.not-found | &cThat player is not online. | Shown when the /msg target is not online on any proxy. |
reply.none | &cYou have no one to reply to. | Shown when /reply has no previous conversation. |
Formats use & colour codes; § codes (as some LuckPerms prefixes use) are converted, so both styles work.
Commands
| Command | Aliases | Description |
|---|---|---|
/msg <player> <message> | /m, /w, /tell, /whisper | Private message to a player on any proxy |
/reply <message> | /r | Answer your last private conversation |
Both are player-only and have no permission node — every player can use them. Because they are registered on the proxy, they replace the backend's own /msg and /tell.
Redis Details
- Nothing is stored long-term. Messages go over pub/sub; the only key is the online-player hash
chatting:players, which each proxy cleans up for its own players on quit and shutdown. Redis needs no persistence. - Each proxy ignores its own echo, using a random instance id generated at start-up, so a message is never delivered twice by the proxy that sent it.
- If Redis is down, global chat is delivered on the local proxy only and a warning is logged; private messages fail with Messaging is unavailable right now. The subscriber retries every 3 seconds.
Troubleshooting
Q: Players get kicked with "illegal protocol state" or a chat error
A: Another proxy plugin is cancelling or rewriting signed chat. Chatting itself never cancels chat and delivers messages after the chat event, which is what avoids this kick.
Q: Players on the sender's server see the message twice — or not at all
A: exclude-source-server does not match your backend setup. See Signed chat & doubles.
Q: Chat works but /msg cannot find players on the other proxy
A: Check the start-up log for Redis rejected a test write: you are connected to a read-only replica. Point redis.host at the primary.
Q: No prefixes
A: LuckPerms must be installed on the proxy. The log line LuckPerms not found - prefixes and suffixes will be empty means it was not found at start-up.
Q: Need a build?
A: Chatting is not released. Ask for it in the Discord server.