
NetworkChat
Network-wide chat plugin for Velocity + Paper server: intercepts chat on backends and forwards it to the proxy, which sends it to all network-connected players with configurable formatting.
For any issue contact me on Telegram https://t.me/IceWolf23_X
This may be the only Plugin I will maintain up-to-date
NetworkChat
NetworkChat is a network-wide chat plugin for Velocity + Paper. It turns multiple backend servers into one shared chat experience: global chat (everyone online on the proxy sees it), cross-server private messages, mentions/pings, a word filter, clickable inventory previews, and an optional Discord bridge.
Current version: 1.0.1
How it works
NetworkChat ships as a single universal jar that runs on both platforms:
- Velocity (proxy) is the "hub": it receives chat packets from Paper servers, applies formats/cooldown/filter, highlights mentions, logs to console, optionally bridges to/from Discord, and broadcasts messages to everyone connected to the proxy.
- Paper (backend) is the "executor": it captures local chat, provides
/msgand/reply, reads LuckPerms group data (primary group + group prefix), plays mention/PM sounds, and builds the view-only GUI previews for[i],[inv], etc.
The two sides communicate via Minecraft plugin messaging, so the plugin must be installed on the proxy and on every backend.
Features
- Global chat across the whole network (all Paper servers behind the proxy)
- Formatting by LuckPerms group (e.g. owner/admin/helper) +
{prefix}placeholder (group prefix) - Cross-server private messages:
/msgand/reply - Tab completion for
/msgtargets and@mentionsinside/msg//replyuses the proxy-wide online list (excluding yourself) - Discord bridge (optional): Minecraft -> Discord (global chat + PMs) and Discord -> Minecraft (global channel)
- Discord -> Minecraft messages are sanitized (no Minecraft color/format codes from Discord)
- Mentions/pings: just type a player's name in chat (typing
@Namealso works) - Special pings:
@alland@help - Personal ping toggle:
/ping toggle - Configurable anti-spam cooldown (with a bypass permission)
- Configurable word censoring (optional hover to reveal the original word)
- Full chat log in the proxy console (global chat + PMs)
- Proxy join/quit messages (network connect/disconnect)
- First-join broadcast message (network-wide) with a lifetime unique counter
- Proxy broadcast command:
/broadcast(alias:/bc) - Staff PM spy:
/spy - Clickable ChatItems (view-only GUIs):
[i]item in hand (if it's a shulker box, the token becomes[shulker]and shows its contents)[armor]armor + offhand[hotbar]hotbar[inv]full inventory (5 rows)[ender]ender chest
- Colors:
&codes + HEX&#RRGGBB(for config formats/messages/tokens)
Colors and formatting
- You can use legacy
&codes (example:&aHello) and hex colors like𛙩in both configs. - These codes are meant for configured strings (formats/messages/tokens). Player chat content is kept as-is.
- Discord -> Minecraft messages are sanitized, so Discord users cannot inject Minecraft color/format codes.
Requirements
- Velocity (proxy) with NetworkChat installed
- Paper (installed on each backend server)
- Java 17+
- LuckPerms (optional but recommended)
- Paper: required for group-based formats (
chat.formats.global.<group>) and{prefix}(group prefix). Without LuckPerms, the plugin will just usechat.formats.global.defaultand{prefix}will be empty. - Velocity: recommended to manage proxy-side permissions (e.g.
@all,@help,/spy,/ping,/broadcast).
- Paper: required for group-based formats (
Installation
- Download the universal jar (one file for Velocity + Paper). Example filename:
networkchat-1.0.1.jar. - Put the same jar in your Velocity plugins folder.
- Put the same jar in the plugins folder of each Paper backend.
- Start the proxy and backends once to generate the config files:
- Proxy (Velocity):
plugins/networkchat/config.yml - Backends (Paper):
plugins/NetworkChat/config.yml(generated per server)
- Proxy (Velocity):
- Edit both configs. Tip: keep the Paper config the same on every backend if you want consistent GUI titles/sounds/tokens.
- Reload:
- Proxy config:
/nchat reloadon Velocity (also asks all backends to reload) - Backend config (single server):
/nchat reloadon Paper (or restart the backend)
- Proxy config:
Quick start
Global chat
Chat normally: your message is forwarded to the proxy and broadcast to everyone on the network.
LuckPerms group formats ({prefix})
Global chat formatting is controlled on the proxy in chat.formats.global.<group>.
<group>is the player's LuckPerms primary group (read on Paper), lowercased.{prefix}is the LuckPerms group prefix (not the user prefix). If it's empty, make sure your groups have a prefix set in LuckPerms.
Mentions / pings
Mentions are automatic: if your message contains a player's exact username as a word (e.g. Hi Steve), the plugin treats it as a ping.
- The name is highlighted in chat (proxy-side, configurable).
- The mentioned player can receive an actionbar + sound (played on the backend where they are connected), if enabled and if they didn't disable pings.
- You can customize the highlight under
render.mention.*in the Velocity config (default adds a blue@visually). - Players can opt out of being notified using
/ping toggle(give themnetworkchat.ping.toggle).
You can enable/disable sound and actionbar separately in the proxy config:
mentions.ping_sound_enabledmentions.actionbar_enabled
The actual sound/actionbar content is configured on Paper backends (plugins/NetworkChat/config.yml):
- Mention sound:
mentions.sound,mentions.volume,mentions.pitch - Actionbar text:
messages.mention_actionbar
Special pings
@allnotifies all online players (permissionnetworkchat.ping.allrequired).@helpnotifies only online players with the help-role permissionnetworkchat.role.help(permissionnetworkchat.ping.helprequired).
ChatItems
Type one of the tokens (e.g. [inv]): it becomes clickable and opens a view-only GUI preview.
ChatItems work across servers: the backend where the message is sent uploads a snapshot to the proxy, and when someone clicks the token the backend they are currently on requests the snapshot from the proxy and opens the GUI. If the sender doesn't have permission for a token, the text will stay as normal text (not clickable).
Private messages
Use /msg <player> <message> to message any player online on the proxy (even if they are on a different backend), and /reply (or /r) to reply to your last conversation.
Staff can use /spy on the proxy to see a log of private messages (useful for moderation).
Cooldown and word filter
The proxy can enforce a cooldown between messages and censor blacklisted words (both affect global chat and private messages).
Discord bridge (optional)
If enabled, the global chat is mirrored between Minecraft and a Discord channel (two-way).
Private messages can be mirrored to a second Discord channel as a read-only log.
Commands
"Where" means where the command is executed:
- Paper commands are executed on the backend server you are currently on.
- Velocity commands are executed on the proxy.
| Command | Where | Description |
|---|---|---|
/msg <player> <message> | Paper | Cross-server private message |
/reply <message> (alias: /r) | Paper | Reply to the last conversation |
/chatitem <id> | Paper | Opens a GUI (used by clicks) |
/ping toggle | Velocity | Enable/disable receiving pings |
/spy | Velocity | Toggle PM spying |
/broadcast <message> (alias: /bc) | Velocity | Broadcast a message to the whole network |
/nchat / /networkchat | Velocity | Plugin info |
/nchat reload | Velocity | Reload proxy config and request backend reload |
/nchat reload | Paper | Reload backend config (single server) |
Permissions
Note: some permissions are checked on Paper (e.g. /msg, ChatItems), while others are checked on Velocity (e.g. @all, /spy, /broadcast, /ping toggle).
If you use LuckPerms, make sure you grant permissions in the correct context (Paper vs Velocity).
Admin / staff
networkchat.command- use/nchat(info)networkchat.admin-/nchat reloadnetworkchat.broadcast-/broadcastnetworkchat.spy-/spy
Private messages
networkchat.msg-/msgnetworkchat.reply-/reply
Pings
networkchat.ping.toggle-/ping togglenetworkchat.ping.all- use@allnetworkchat.ping.help- use@helpnetworkchat.role.help- receives@helpnotifications
Cooldown
networkchat.cooldown.bypass- bypass cooldown
ChatItems (token + open GUI)
networkchat.chatitem.item-[i]networkchat.chatitem.shulker-[shulker](generated when using[i]on a shulker box)networkchat.chatitem.armor-[armor]networkchat.chatitem.hotbar-[hotbar]networkchat.chatitem.inv-[inv]networkchat.chatitem.ender-[ender]
Placeholders
Velocity (proxy)
Chat formats (chat.formats.*)
{nc_prefix}: NetworkChat prefix from the proxy config (prefix:){prefix}: sender LuckPerms group prefix (provided by the backend; can be empty)- Global chat:
{player},{message} - Private messages:
{from},{to},{from_prefix},{to_prefix},{message}(prefixes can be empty;{to_prefix}is best-effort across servers) - Spy format:
{from},{to},{message}(also supports{from_prefix}/{to_prefix})
Console logging (logging.*)
- Global log:
{server},{prefix},{player},{message} - PM log:
{server},{prefix},{from},{to},{message} - Note:
{prefix}here is the sender LuckPerms group prefix (same meaning as in chat formats).
Proxy messages (messages.*)
{nc_prefix}: NetworkChat prefix from the proxy config (prefix:)- Join/Quit:
{player} - First join (
messages.first_join):{player},{counter}(lifetime unique players on the proxy) - Cooldown (
messages.cooldown):{seconds} - Plugin info (
messages.plugin_info):{plugin},{version} - Note:
{prefix}is intentionally not provided here (keep{prefix}reserved for LuckPerms group prefixes in chat formats).
Mention rendering (render.mention.format)
{mention_prefix}: configured mention prefix (e.g.&b@){name}: the mentioned player name
Paper (backend)
{prefix}: NetworkChat prefix from the backend config (prefix:)- Mention actionbar (
messages.mention_actionbar):{player}(the sender name) +{prefix} {prefix}is also available in GUI titles and ChatItems token/hover strings.
Example configuration
Velocity (proxy) plugins/networkchat/config.yml
This file controls formats, join/quit/first-join messages, cooldown, word filter, console logging, pings and the Discord bridge.
prefix: "&7[NC]&r "
chat:
formats:
# Per-group formats (LuckPerms primary group from Paper). Always keep "default".
global:
default: "{nc_prefix}&7[G] {prefix}&f{player}&8: &r{message}"
owner: "{nc_prefix}&7[G] {prefix}&#ff5555{player}&8: &r{message}"
helper: "{nc_prefix}&7[G] {prefix}&a{player}&8: &r{message}"
# Private messages (cross-server)
pm_to_target: "{nc_prefix}&5[PM] {from_prefix}&f{from}&7 -> &fyou&7: &r{message}"
pm_to_sender: "{nc_prefix}&5[PM] &fyou&7 -> {to_prefix}&f{to}&7: &r{message}"
spy: "{nc_prefix}&8[SPY] &7{from} &8-> &7{to}&8: &r{message}"
messages:
join: "{nc_prefix}&a+ &f{player}"
quit: "{nc_prefix}&c- &f{player}"
first_join: "{nc_prefix}&e{player} &7joined for the first time! &7(# {counter})"
cooldown: "{nc_prefix}&cWait &f{seconds}&c seconds before chatting again."
player_not_online: "{nc_prefix}&cPlayer not online: &f{player}"
no_permission: "{nc_prefix}&cYou don't have permission."
# ...you can customize all the other messages too
mentions:
# These only enable/disable backend notifications (sound/actionbar).
ping_sound_enabled: true
actionbar_enabled: true
render:
mention:
# Visual highlight in chat for mentions (independent from sound/actionbar).
enabled: true
prefix: "&b@"
format: "{mention_prefix}{name}&r"
filter:
blacklist:
- "badword"
- "anotherword"
# If true, hovering the censored mask shows the original word.
reveal_on_hover: true
censor:
# Symbol/pattern used to mask the banned word (repeated/truncated to match the original word length).
symbol: "*"
# Color applied to the masked word. Supports '&' legacy codes and hex like '𛙩'.
color: "&c"
rate_limit:
# Seconds between messages (permission to bypass: networkchat.cooldown.bypass)
cooldown_seconds: 2
logging:
enabled: true
global: "[G] [{server}] {prefix}{player}: {message}"
pm: "[PM] [{server}] {from} -> {to}: {message}"
discord:
enabled: false
token: ""
guild_id: ""
channels:
global:
id: ""
format:
to_discord: "[{type}] [{server}] {author}: {message}"
from_discord: "{nc_prefix}&9[Discord] &b{author}&8: &r{message}"
private_messages:
id: ""
to_discord: "[{type}] [{server}] {author}: {message}"
What you usually edit here:
prefixandchat.formats.global.*(colors, per-group formats, etc.)messages.join/messages.quit/messages.first_joinrate_limit.cooldown_seconds(anti-spam)filter.blacklist+filter.reveal_on_hover+filter.censor.*(censor filter)discord.*(only if you want Discord bridge)
Key notes:
chat.formats.global.<group>: the key is the LuckPerms primary group name from Paper (lowercased); keepdefaultas fallback.{prefix}in chat formats is the sender group prefix from Paper (can be empty).{nc_prefix}is the plugin prefix from this file.mentions.*: only enables/disables backend notifications. The actual sound/actionbar is configured on Paper.render.mention.*: controls only the visual highlight for mentions.filter.blacklist: replaces the banned word with a configurable mask (same length). Customize viafilter.censor.symbolandfilter.censor.color. Withreveal_on_hover: true, hover shows the original word.rate_limit.cooldown_seconds: applies to global chat and private messages; bypass permission:networkchat.cooldown.bypass.logging.*: logs to the proxy console; you can customize the log line format.
Paper (backend) plugins/NetworkChat/config.yml
This file controls ChatItems tokens + GUI titles, mention/PM sounds, and backend messages.
You should copy the same config to every backend if you want consistent behavior.
prefix: "&7[NC]&r "
messages:
no_permission: "{prefix}&cYou don't have permission."
chatitem_invalid: "{prefix}&cInvalid data."
mention_actionbar: "&e{player} mentioned you in chat"
render:
# Optional: used only for tab completion when typing @Name (normal pings don't require '@')
mention:
trigger: "@"
chatitem:
token: "&b[i]&r"
hover: "&7Click to view the item"
gui_title: "{prefix}&8Item"
empty: "&c[x]&r"
shulker:
token: "&b[shulker]&r"
hover: "&7Click to view the shulker"
gui_title: "{prefix}&8Shulker"
armor:
token: "&b[armor]&r"
hover: "&7Click to view armor"
gui_title: "{prefix}&8Armor"
empty: "&c[x]&r"
hotbar:
token: "&b[hotbar]&r"
hover: "&7Click to view the hotbar"
gui_title: "{prefix}&8Hotbar"
empty: "&c[x]&r"
inv:
token: "&b[inv]&r"
hover: "&7Click to view inventory"
gui_title: "{prefix}&8Inventory"
empty: "&c[x]&r"
ender:
token: "&b[ender]&r"
hover: "&7Click to view ender chest"
gui_title: "{prefix}&8EnderChest"
empty: "&c[x]&r"
mentions:
# Mention ping sound (played by the backend server where the mentioned player is connected)
sound: "minecraft:block.note_block.bell"
volume: 1.0
pitch: 0.5
private_messages:
# Private message notification sound
sound: "minecraft:entity.chicken.egg"
volume: 1.0
pitch: 1.0
What you usually edit here:
prefixrender.*(ChatItem tokens/hover text/GUI titles)mentions.*andmessages.mention_actionbar(mention sound + actionbar)private_messages.*(PM notification sound)
Key notes:
- ChatItems are view-only inventories (players cannot move items).
[i]shows the item in your main hand. If the item is a shulker box and you have permission, it becomes[shulker]and shows the shulker contents.- If there is nothing to preview, the placeholder becomes the configured
emptytext and is not clickable. - Mention and PM sounds are played by the backend where the receiver is connected (this avoids proxy limitations).
Example: LuckPerms group formats (proxy)
chat:
formats:
global:
default: "{nc_prefix}&7[G] {prefix}&f{player}&8: &r{message}"
owner: "{nc_prefix}&7[G] {prefix}&c{player}&8: &r{message}"
helper: "{nc_prefix}&7[G] {prefix}&a{player}&8: &r{message}"
Example: word filter (proxy)
filter:
blacklist:
- word1
- word2
reveal_on_hover: true
censor:
symbol: "*"
color: "&c"
Discord setup (optional, proxy)
Configure it in plugins/networkchat/config.yml:
discord:
enabled: true
token: "YOUR_BOT_TOKEN"
guild_id: "YOUR_GUILD_ID"
channels:
global:
id: "GLOBAL_CHANNEL_ID"
format:
to_discord: "[{type}] [{server}] {author}: {message}"
from_discord: "{nc_prefix}&9[Discord] &b{author}&8: &r{message}"
private_messages:
id: "PM_CHANNEL_ID"
to_discord: "[{type}] [{server}] {author}: {message}"
Notes:
- Keep
discord.tokenprivate (don't share it). discord.guild_idis optional, but recommended if you want an extra safety check (only accept messages from that guild).channels.global.idis used for both Minecraft -> Discord and Discord -> Minecraft.channels.private_messages.idis Minecraft -> Discord only (read-only from Discord).- Messages sent by the bot itself (and other bots) are ignored.
- After editing the config, run
/nchat reloadon the proxy. - For Discord -> Minecraft you must enable the bot Message Content Intent in the Discord Developer Portal and give the bot permissions to read that channel.
- Discord -> Minecraft message content is always treated as plain text (Discord users cannot use Minecraft color/format codes).
Discord placeholders
Minecraft -> Discord (to_discord formats):
channels.global.format.to_discordandchannels.private_messages.to_discord:{type}:G(global) orPM(private message log){server}: backend server name (e.g.survival){author}:- global: player name including LuckPerms group prefix (colors stripped)
- PM:
from -> to
{player}: sender Minecraft username (no prefix){from}/{to}: PM endpoints (for global chat,{to}is empty and{from}matches{player}){message}: message content (plain text)
Discord -> Minecraft (from_discord format):
channels.global.format.from_discord:{type}:DISCORD{server}:discord{nc_prefix}: plugin prefix from the proxy config (prefix:){author}: Discord display name{message}: message content (sanitized, no Minecraft formatting injection)
Troubleshooting
- Global chat doesn't reach other servers: make sure the jar is installed on Velocity and every Paper backend, then restart once and check the proxy console for errors.
{prefix}is empty in chat formats: install LuckPerms on Paper and set a group prefix for the player's primary group.- Mentions highlight but no sound/actionbar: check
mentions.ping_sound_enabled/mentions.actionbar_enabled(proxy), and the sound/actionbar settings on Paper; also the target may have disabled pings. - ChatItems are not clickable: check ChatItem permissions (
networkchat.chatitem.*) and that the sender is using the correct token (and holding an item for[i]/[shulker]). - Discord bridge doesn't work: verify token/channel IDs, bot permissions, Message Content Intent, then run
/nchat reloadon the proxy.
Notes
- v1.0.0 only: make sure the proxy + backends run the same NetworkChat version.
- v1.0.1 and later: NetworkChat is already unified as a single universal jar, so you just place the same file on Velocity + every Paper backend.
- Proxy-side permissions (e.g.
@all,@help,/spy,/ping) require a permissions system on the proxy (e.g. LuckPerms on Velocity). - The first-join counter is stored on the proxy in
plugins/networkchat/first-joins.yml(delete it to reset the counter).
