Channel-based chat system for Hytale servers. Multiple channels, quick-chat routing, private messaging, nicknames, and moderation — all in one plugin.
Channel System — Multiple channels with custom colors, nicknames, distance-based and world-restricted delivery.
Quick Chat — Prefix symbols to route messages to any channel without switching. ! for Global, ~ for Trade.
Private Messaging — /msg and /r with reply tracking, ignore lists, and offline detection.
Player Nicknames — Custom display names up to 20 characters with hex colors and two-color gradients.
Mention System — @player highlighting with configurable color and bold formatting.
Clickable URLs — Chat and private messages automatically turn URLs into clickable links (configurable).
Moderation Tools — Per-channel ban, mute, moderators, word filter (censor/block modes), and chat cooldown.
In-Game Settings UI — /ch, /ch settings, /ch list, and /ch help open a unified UI for profile, channels, and moderator tools.
Permission Integration — HyperPerms and LuckPerms prefix/suffix support with hex color codes.
PlaceholderAPI Integration — Supports external %...% placeholders in channel format text and includes a built-in %werchat_*% expansion.
Plugin API — Exposes a lightweight WerchatAPI for other plugins to query channels, manage membership/focus, and submit chat through Werchat's pipeline.
Message Colors — Independent message text colors and gradients, separate from nickname colors.
Persistent Storage — JSON-based data with dirty + debounced saves (20s) and a final flush on shutdown.
- Drop
Werchat-1.11.3.jarin yourmods/folder - Start your server — four default channels are created automatically
- Use
/chto open the settings UI (/ch listopens directly to Channels) - Type
!helloto quick-chat in Global or~hellofor Trade
/ch # Open Werchat settings UI
/ch list # Open Channels tab
/ch global # Switch to Global channel
/ch join trade # Join the Trade channel
/msg Steve Hey! # Send a private message
/ch playernick CoolName # Set your nickname
| Channel | Nick | Color | Range | Auto-Join | Quick-Chat Symbol |
|---|---|---|---|---|---|
| Global | Global | White (#ffffff) |
Unlimited | Yes | ! |
| Local | Local | Gray (#808080) |
100 blocks | Yes | — |
| Trade | Trade | Gold (#ffd700) |
Unlimited | Yes | ~ |
| Support | Support | Green (#00ff00) |
Unlimited | Yes | — |
/chor/ch settingsopens the Werchat settings UI.- Main tab includes focused-channel controls, nickname/color tools, and permission-filtered command help.
- Channels tab includes join/leave/focus actions plus owner, description, and MOTD visibility.
- Moderator channel management uses a dropdown selector so large channel counts stay usable.
| Command | Aliases | Description |
|---|---|---|
/ch |
— | Open Werchat settings UI |
/ch settings |
— | Open Werchat settings UI |
/ch list |
/ch l |
Open Channels tab in the settings UI |
/ch join <channel> [password] |
/ch j |
Join a channel |
/ch leave <channel> |
— | Leave a channel |
/ch <channel> |
— | Switch active channel |
/ch who <channel> |
/ch w |
View channel members |
/ch info <channel> |
— | View channel details |
/ch create <name> [nick] |
— | Create a new channel |
/ch playernick <name> [#color] [#gradient] |
/ch pnick, /ch nickname |
Set your nickname |
/ch msgcolor <#color> [#gradient] |
/ch chatcolor |
Set your message color |
/ch help |
/ch ? |
Open Main tab help (permission-filtered) |
| Command | Aliases | Description |
|---|---|---|
/msg <player> <message> |
/whisper, /w, /tell, /pm |
Send a private message |
/r <message> |
/reply |
Reply to last PM |
/ignore <player> |
— | Toggle ignore on a player |
/ignorelist |
— | List ignored players |
| Command | Aliases | Description |
|---|---|---|
/ch color <channel> <#hex> [#hex] |
— | Set channel tag color (and optional message color) |
/ch nick <channel> <nick> |
— | Set channel shortcut name |
/ch rename <channel> <newname> |
— | Rename a channel |
/ch password <channel> [password] |
/ch pass |
Set or clear channel password |
/ch distance <channel> <blocks> |
/ch range |
Set range (0 = unlimited) |
/ch world <channel> add|remove <world> |
— | Restrict channel to worlds |
/ch mod <channel> <player> |
/ch moderator |
Add a channel moderator |
/ch unmod <channel> <player> |
— | Remove a channel moderator |
/ch ban <channel> <player> |
— | Ban a player from a channel |
/ch unban <channel> <player> |
— | Unban a player |
/ch mute <channel> <player> |
— | Mute a player in a channel |
/ch unmute <channel> <player> |
— | Unmute a player |
/ch remove <channel> |
/ch delete, /ch del |
Delete a channel |
/ch reload |
— | Reload Werchat config and channel data from disk |
Channel moderators can use admin commands on their own channels without needing global permission nodes.
If /ch create <name> is used without a nick, Werchat auto-generates a short nick from the first character and disambiguates collisions:
- Example:
12312345 -> 1,1234903425 -> 1-2,1 -> 1-3.
All Permissions
| Permission | Description |
|---|---|
werchat.* |
All Werchat permissions (wildcard) |
werchat.list |
List channels |
werchat.join |
Join channels |
werchat.leave |
Leave channels |
werchat.create |
Create channels |
werchat.who |
View channel members |
werchat.info |
View channel info |
werchat.switch |
Switch active channel |
werchat.color |
Set channel colors |
werchat.nick |
Set channel nick |
werchat.password |
Set channel password |
werchat.rename |
Rename channels |
werchat.remove |
Delete channels |
werchat.mod |
Manage channel moderators |
werchat.distance |
Set channel range |
werchat.ban |
Ban/unban from channels |
werchat.mute |
Mute/unmute in channels |
werchat.world |
Set world restrictions |
werchat.reload |
Reload Werchat config/channel data |
werchat.msg |
Send private messages |
werchat.ignore |
Ignore players |
werchat.quickchat |
Use quick-chat symbols |
werchat.playernick |
Set own nickname |
werchat.playernick.others |
Set other players' nicknames |
werchat.nickcolor |
Set nickname color/gradient |
werchat.msgcolor |
Set own message color |
werchat.msgcolor.others |
Set other players' message color |
werchat.cooldown.bypass |
Bypass chat cooldown |
Players with werchat.* or * also bypass cooldowns and the word filter.
Per-channel permission nodes:
werchat.channel.<channel>.joinwerchat.channel.<channel>.speakwerchat.channel.<channel>.read(primary receive/read node)
These nodes are enforced in normal /ch + chat flow only when channelPermissions.enforce is enabled.
Config file: mods/com.werchat_Werchat/config.json
View full config
{
"defaultChannelName": "Global",
"autoJoinDefault": true,
"showJoinLeaveMessages": true,
"allowPrivateMessages": true,
"channelPermissions": {
"enforce": false
},
"banMessage": "You have been banned from {channel}",
"muteMessage": "You have been muted in {channel}",
"wordFilter": {
"enabled": false,
"mode": "censor",
"replacement": "***",
"notifyPlayer": true,
"warningMessage": "Your message contained inappropriate language.",
"words": ["..."]
},
"cooldown": {
"enabled": false,
"seconds": 3,
"message": "Please wait {seconds}s before sending another message.",
"bypassPermission": "werchat.cooldown.bypass"
},
"mentions": {
"enabled": true,
"color": "#FFFF55"
},
"clickableUrls": {
"enabled": true
},
"ignoreChatCancellations": false
}| Key | Default | Description |
|---|---|---|
defaultChannelName |
"Global" |
Default channel players are placed in |
autoJoinDefault |
true |
Auto-join default channel on connect |
showJoinLeaveMessages |
true |
Broadcast join/leave messages to channels |
allowPrivateMessages |
true |
Whether /msg is enabled |
channelPermissions.enforce |
false |
Enforce per-channel join/speak/read nodes in normal /ch + chat flow |
banMessage |
"You have been banned from {channel}" |
Message shown to banned players |
muteMessage |
"You have been muted in {channel}" |
Message shown to muted players |
wordFilter.enabled |
false |
Enable the word filter |
wordFilter.mode |
"censor" |
censor replaces bad words, block rejects the message |
wordFilter.replacement |
"***" |
Replacement string in censor mode |
wordFilter.notifyPlayer |
true |
Warn the player when filtered |
wordFilter.warningMessage |
"Your message contained..." |
Warning message text |
wordFilter.words |
[] |
Words to filter (case-insensitive); empty by default |
cooldown.enabled |
false |
Enable chat cooldown |
cooldown.seconds |
3 |
Seconds between messages |
cooldown.message |
"Please wait {seconds}s..." |
Cooldown message |
cooldown.bypassPermission |
"werchat.cooldown.bypass" |
Permission to bypass cooldown |
mentions.enabled |
true |
Enable @mention highlighting |
mentions.color |
"#FFFF55" |
Hex color for mention highlights |
clickableUrls.enabled |
true |
Convert detected URLs in chat/PM text into clickable links |
ignoreChatCancellations |
false |
Process chat even if cancelled by other plugins |
When channelPermissions.enforce is enabled:
joinchecks run in/ch joinand/ch <channel>auto-join.speakchecks run before sending messages.readchecks run for sender selection and per-recipient delivery.- Password checks still apply; permission nodes never bypass channel passwords.
Channel Format Placeholders
Custom channel message formats support these placeholders:
| Placeholder | Description |
|---|---|
{name} |
Full channel name |
{nick} |
Channel nick/abbreviation |
{color} |
Channel color code |
{sender} |
Player display name |
{msg} |
Message content |
{prefix} |
Player's permission prefix (HyperPerms/LuckPerms) |
{suffix} |
Player's permission suffix (HyperPerms/LuckPerms) |
Default format: {nick} {sender}: {msg}
Format literals also support PlaceholderAPI placeholders when PlaceholderAPI is installed.
{prefix} / {suffix} resolve directly from HyperPerms/LuckPerms when those plugins are present, even without PlaceholderAPI placeholders.
Werchat also registers a built-in PlaceholderAPI expansion with identifier werchat.
Top-level Werchat placeholders:
| Placeholder | Description |
|---|---|
%werchat_channels_total% |
Total number of channels |
%werchat_channels% |
Comma-separated channel names |
%werchat_default_channel% |
Default channel name |
%werchat_selected_channel% |
Focused channel name for the player (recommended) |
%werchat_selected_channel_<key>% |
Focused channel field/value by key (preferred keyed form) |
%werchat_channel% |
Focused channel name for the player (legacy alias) |
%werchat_channel_<selector>% |
Specific channel by selector (returns channel name) |
%werchat_channel_<selector>_<key>% |
Specific channel field/value by selector + key (primary keyed form) |
%werchat_channel_<selector>__<key>% |
Edge-case keyed syntax for selectors with underscore ambiguity |
%werchat_ignored_players_total% |
Number of ignored players |
%werchat_ignored_players% |
Comma-separated ignored player names |
%werchat_known_name% |
Real account username |
%werchat_display_colour% |
Player display color |
%werchat_display_color% |
Player display color (US spelling alias) |
%werchat_msg_color% |
Player message color |
%werchat_msg_gradient% |
Player message gradient as #START,#END (blank when no gradient) |
%werchat_msg_gradient_end% |
Player message gradient end color |
%werchat_nick_color% |
Player nickname color |
%werchat_nick_gradient_end% |
Player nickname gradient end color |
%werchat_nick% |
Custom nickname only (blank if none set) |
%werchat_display_name% |
Final chat name (nickname if set, else username) |
Name placeholder semantics:
known_name: always the real account name.nick: only the custom nickname value, can be blank.display_name: what Werchat renders in chat.
Channel-scoped Werchat placeholder syntax:
Preferred keyed forms:
%werchat_selected_channel_<key>%
%werchat_channel_<selector>_<key>%
Braced selector forms (recommended for underscore channel names):
%werchat_channel_{<selector>}%
%werchat_channel_{<selector>}_<key>%
Direct channel selector alias:
%werchat_channel_<selector>% (returns that channel's name)
Edge-case keyed form (use only when selector/key underscore ambiguity appears):
%werchat_channel_<selector>__<key>%
<selector> values:
- Exact channel name or nick.
- Optional
{}wrapper is supported for explicit selectors (example:{trade_german}). - Channel names with underscores are supported (example:
trade_name). - Legacy active alias (
activeby default) is still supported for compatibility.
Key separator note:
_(single underscore) is the primary keyed separator.__(double underscore) is the backup separator for ambiguous channel names (example:trade_name).- Example explicit form:
%werchat_channel_{trade_german}_member_count%.
<key> values:
| Key | Description |
|---|---|
name |
Channel's canonical name (what admins create/rename) |
nick |
Channel's short label/alias |
colorhex |
Channel tag color as hex (#RRGGBB) |
format |
Raw channel format template string |
color |
Channel tag color as hex (#RRGGBB) |
effective_msg_colorhex |
Final message text color hex (message color override or tag color fallback) |
join_permission |
Permission node string associated with joining this channel (werchat.channel.<name>.join) |
read_permission |
Permission node string associated with reading/receiving this channel (werchat.channel.<name>.read) |
msg_color_hex |
Explicit message text color hex override (#RRGGBB), blank when unset |
msg_color |
Explicit message text color hex (#RRGGBB), blank when unset |
quickchatsymbol |
Quick-chat trigger symbol (for example !), blank when unset |
speak_permission |
Permission node string associated with speaking in this channel (werchat.channel.<name>.speak) |
worlds_count |
Number of configured world restrictions |
worlds |
Worlds shown as text (All worlds or a comma-separated list) |
distance |
Channel chat range in blocks (0 means global/unlimited) |
member_count |
Current number of channel members |
member_names |
Comma-separated member names (online username, fallback known name, then short UUID) |
moderator_count |
Current number of channel moderators |
moderator_names |
Comma-separated moderator names (online username, fallback known name, then short UUID) |
muted_count |
Current number of muted members |
muted_names |
Comma-separated muted member names (online username, fallback known name, then short UUID) |
owner |
Channel owner UUID |
owner_name |
Best-known owner name (online username fallback to stored known name) |
is_autojoin |
true if this channel auto-joins players on connect |
is_muted |
true if the requesting player context is muted in this channel |
is_banned |
true if the requesting player context is banned from this channel |
is_member |
true if the requesting player context is a member of this channel |
is_moderator |
true if the requesting player context is a moderator of this channel |
is_verbose |
true if channel verbose mode is enabled |
is_default |
true if this is the server default channel |
is_focusable |
true if players are allowed to focus/select this channel |
is_global |
true if channel range is global (distance <= 0) |
is_local |
true if channel range is local (distance > 0) |
has_password |
true if a password is set on this channel |
has_msg_color |
true if explicit message color override is set |
has_worlds |
true if world restrictions are configured |
has_quickchatsymbol |
true if a quick-chat symbol is configured |
Plugin API
Access Werchat's integration API:
WerchatAPI api = WerchatPlugin.api();
if (api != null) {
WerchatOperationOptions opts = WerchatOperationOptions.enforcePermissions();
WerchatActionResult join = api.joinChannel(playerId, "trade", null, opts);
if (join.isSuccess()) {
api.setFocusedChannel(playerId, "trade", opts);
api.submitPlayerChat(playerId, "Selling iron!", opts);
}
}API notes:
submitPlayerChat(...)is the primary API method for submitting player chat.WerchatActionResultandWerchatMembershipResultexpose explicit status enums instead of booleans.- Channel lookups can now be explicit: use
getChannelExact(...),joinChannelExact(...),setFocusedChannelExact(...), etc. for deterministic integrations, or default/fuzzy methods for command-like behavior. api.getApiVersion(),api.getCapabilities(), andapi.hasCapability(...)let integrations gate behavior safely.- Hooks are available through
registerHook(...)/unregisterHook(...)for pre/post API action handling.
Building from Source
Requirements: Java 21+, Gradle 8.12+ (wrapper included)
./gradlew buildRelease
# Output: build/libs/Werchat-1.11.3.jar (built for latest release channel)Build variants:
./gradlew buildRelease # latest release channel
./gradlew buildPreRelease # latest pre-release channel
./gradlew build # defaults to release channelThe plugin manifest.json ServerVersion is injected automatically at build time from Hytale Maven metadata.
If you need a manual override for testing, set an explicit version:
./gradlew build -Phytale_server_version=2026.02.18-f3b8fff95Part of the HyperSystems suite: HyperPerms | HyperEssentials | HyperFactions | Werchat

