ajdnikov Dashboard

Chatting Documentation

State UnreleasedVersion 1.0.0Platform Velocity 3.4+Java 21Needs Redis

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 /msg and /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

ComponentRuns onRequired
Chatting (chatting-1.0.0.jar)Every Velocity 3.4+ proxy, Java 21Yes
Redis serverAnywhere every proxy can reachYes
LuckPermsThe proxyOptional — for prefixes and suffixes
ChattingBackend (chatting-backend-1.0.0.jar)Paper 26.2 backends, Java 25Optional — see Signed chat

Installation

  1. Put chatting-1.0.0.jar in the plugins/ folder of every Velocity proxy, and start each one once. This creates plugins/chatting/config.properties.
  2. Point every proxy at the same Redis:
    redis.host=10.0.0.6
    redis.port=6379
    redis.password=change-me
    redis.channel=chatting\:chat
  3. Restart the proxies. The console logs Connected to Redis at 10.0.0.6:6379, channel chatting:chat and, with LuckPerms installed, Hooked into LuckPerms.
  4. 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 sees msg.format.receiver; the sender gets msg.format.sender as 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 /msg can 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.

KeyDefaultDescription
redis.host127.0.0.1Redis host.
redis.port6379Redis port.
redis.password(empty)Redis password. Empty means none.
redis.channelchatting:chatThe 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-servertrueSkip 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

CommandAliasesDescription
/msg <player> <message>/m, /w, /tell, /whisperPrivate message to a player on any proxy
/reply <message>/rAnswer 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.