Skip to content

Repository files navigation

Chatty

Chatty (Bukkit plugin)

GitHub release (latest by date)GitHub All ReleasesGitHub code size in bytesJitPackCodacy Badge

Chatty v3 is a ground-up rewrite built on Kyori's Adventure library. It is approaching its first stable release (3.0.0); this branch holds its code.

  • Stable builds — the Releases page (once 3.0.0 is tagged).
  • Development builds — the latest artifact from the "Actions" tab (see the "Artifacts" section).

Chatty v2.* is deprecated and no longer maintained. Upgrading from v2? See MIGRATION.md — v3 migrates your old config automatically.

Chatty is the modern chat management system for Bukkit-compatible servers. It's based on-top of Kyori's Adventure library, that makes it so powerful and stable.

Key features:

  • Chat channels ("local" and "global" by default)
  • Private messaging
  • Moderation (CAPS, advertisements, swears)
  • Notifications (chat, action bar, title and advancement toasts)
  • "Vanilla" messages configuring (join/quit/death)
  • MiniMessage both legacy (&) styling format

Two kinds of per-player appearance

chats.yml has two features that both change how a message looks, and they answer different questions:

Chosen byChanges
stylesthe reader's permission chatty.style.<id>how the chat looks to that reader
sender-formatsthe sender's permission chatty.sender-format.<id> or chatty.chat.<chat>.sender-format.<id>how that player's messages look to everybody

So sender-formats is what gives a rank its own prefix in chat, and styles is what lets one reader see the chat in a different colour. They compose: the sender's rank is resolved first, and the reader's style is then taken from that rank's own styles.

chats:
global:
format: '{prefix}{player}: {message}'sender-formats:
vip:
priority: 10format: '&6[VIP] &r{player}&8: &f{message}'styles:
red: { format: '&6[VIP] &r&c{player}&8: &c{message}' }

Highest priority wins when a sender qualifies for several. A rank that defines no styles is shown the same way to every reader.

Moderation

Caps, advertisement and swear filters, plus mute:

/mute <player> [10m|2h|3d|1w] [reason] # no duration means permanent
/unmute <player>

Mutes are stored with the player, so they survive a restart and apply on every server sharing the database. A muted player cannot use public chats or private messages. chatty.command.mute grants the commands, chatty.bypass.mute exempts a player — operators hold both by default.

Placeholders

With PlaceholderAPI installed, Chatty exposes its own data so TAB, scoreboards, Discord bridges and anything else can read it:

PlaceholderValue
%chatty_chat%id of the chat the player currently writes to
%chatty_chat_displayname%its display name
%chatty_chat_range%its range in blocks (-3 cross-server, -2 server, -1 world)
%chatty_chat_range_<id>%the range of a named chat, e.g. %chatty_chat_range_local%
%chatty_chat_displayname_<id>%the display name of a named chat
%chatty_prefix% / %chatty_suffix%the prefix and suffix Chatty resolves for the player
%chatty_spy%whether spy mode is on
%chatty_player_message%the last message the player sent through Chatty
%chatty_targetname%who that message named, or the player themselves
%rel_chatty_ignore%whether the first player ignores the second

%chatty_prefix% is empty unless Vault or LuckPerms is installed, because that is where the prefix comes from.

The last two describe the message a player just sent, so a command run afterwards can quote it — a Discord bridge, or a punishment naming what was said:

/discordsrv broadcast <channel> %chatty_targetname% » %chatty_player_message%
/cmi jail %player_name% said: %chatty_player_message% 2h

%chatty_targetname% is the first player mentioned in that message; with no mention it is the sender, so it is never empty for an online player.

Using the API

Add the API as a compileOnly dependency and declare Chatty as a plugin dependency — the classes come from the running plugin at runtime:

repositories { maven { url ='https://jitpack.io' } }
dependencies { compileOnly 'ru.brikster:chatty-api:3.0.0' }
depend: [ Chatty ]

The published artifact carries Chatty's relocated Adventure, because the plugin bundles its own copy to keep working on servers that have none. That is why it must be compileOnly: a second copy on your own classpath would be a different class to the JVM. Sources and javadoc jars are published alongside it.

Events

EventWhenCancellable
ChattyInitEventChatty is starting, before it reads its configurationno
ChattyPreMessageEventa chat message is formatted, before it is sentno
ChattyMessageEventa chat message has been sentno
ChattyMuteEventa player is about to be mutedyes
ChattyUnmuteEventa player's mute is about to be liftedyes

All of them are fired off the main thread, so a listener must be marked accordingly and must not touch the Bukkit API directly.

ChattyMuteEvent also lets a listener change the mute before it is stored — setUntil and setReason — so a punishment system can escalate a repeat offender:

@EventHandlerpublicvoidonMute(ChattyMuteEventevent) {
if (offences(event.getTargetUniqueId()) > 3) {
event.setUntil(ChattyMuteEvent.PERMANENT);
event.setReason("repeated offences");
}
}

Cancelling either event leaves the player as they were and tells the sender nothing, so a plugin that vetoes a mute should say why itself.

Platforms

Paper, Spigot and Purpur from 1.8.8 up to 26.x, and Folia. Folia support is verified by booting a real Folia server: the plugin schedules its own work and never touches the Bukkit scheduler, and the bundled bStats, which does, is skipped there.

Text formatting

Every spelling below is covered by ColourSpellingMatrixTest, so this table is what the code does rather than what it intends to do. All of them work in chat formats, in message-format, in lang/ files and in a prefix or suffix coming from LuckPerms or Vault.

SpellingExampleSupported
Legacy colour&cyes
Legacy decoration&l&n&o&m&k&ryes
Section sign§cyes
MiniMessage colour<red>yes
MiniMessage hex<#757575>yes
Ampersand hex&#757575yes
Spigot spread hex&x&7&5&7&5&7&5yes
Gradient<gradient:#ff0000:#00ff00>yes
Rainbow<rainbow>yes
Bare hash#757575no, prints as text

Writing colour codes in your own messages is a separate question — that needs chatty.decoration.*, see the permissions section of the migration guide.

Building

Chatty uses Gradle to handle dependencies & building. Building needs JDK 21; the jar it produces targets Java 11, so it runs on Java 11 and newer.

Compiling from source

git clone https://github.com/Brikster/Chatty.git
cd Chatty/
./gradlew build

Output jar will be placed into /build/libs directory.

Testing

Run the unit tests:

./gradlew test

Run the end-to-end smoke test — it boots real Minecraft servers with the built plugin and verifies that it enables cleanly on a fresh install, processes live in-game chat, correctly migrates a legacy v2 configuration, still runs on a legacy server (1.8.8), and coexists with DiscordSRV:

./gradlew build
JAVA_HOME=/path/to/jdk-21 bash scripts/smoke-test.sh

JAVA_HOME must point at a JDK the target server accepts: 21 for 1.21.x, 11 for 1.16.5, 25 for 26.x. Pick the server version with MC_VERSION, and switch off the parts a lane cannot run:

MC_VERSION=26.2 CHAT_TEST=0 JAVA_HOME=/path/to/jdk-25 bash scripts/smoke-test.sh

CHAT_TEST=0 skips the in-game bot, which cannot join a server newer than protocol 1.21.9, and LEGACY_SCENARIO=0 skips the 1.8.8 lane. The legacy scenario needs a Java 11 runtime; it is downloaded automatically, or point LEGACY_JAVA_HOME at an existing one.

Both run automatically on every push via GitHub Actions, with the smoke test as a matrix over 1.21.11, 1.16.5 and 26.2.

About

Bukkit-compatible chat management system

Topics

Resources

Stars

122 stars

Watchers

11 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - Brikster/Chatty: Bukkit-compatible chat management system · GitHub
Skip to content

Repository files navigation

Chatty

Chatty (Bukkit plugin)

GitHub release (latest by date)GitHub All ReleasesGitHub code size in bytesJitPackCodacy Badge

Chatty v3 is a ground-up rewrite built on Kyori's Adventure library. It is approaching its first stable release (3.0.0); this branch holds its code.

  • Stable builds — the Releases page (once 3.0.0 is tagged).
  • Development builds — the latest artifact from the "Actions" tab (see the "Artifacts" section).

Chatty v2.* is deprecated and no longer maintained. Upgrading from v2? See MIGRATION.md — v3 migrates your old config automatically.

Chatty is the modern chat management system for Bukkit-compatible servers. It's based on-top of Kyori's Adventure library, that makes it so powerful and stable.

Key features:

  • Chat channels ("local" and "global" by default)
  • Private messaging
  • Moderation (CAPS, advertisements, swears)
  • Notifications (chat, action bar, title and advancement toasts)
  • "Vanilla" messages configuring (join/quit/death)
  • MiniMessage both legacy (&) styling format

Two kinds of per-player appearance

chats.yml has two features that both change how a message looks, and they answer different questions:

Chosen byChanges
stylesthe reader's permission chatty.style.<id>how the chat looks to that reader
sender-formatsthe sender's permission chatty.sender-format.<id> or chatty.chat.<chat>.sender-format.<id>how that player's messages look to everybody

So sender-formats is what gives a rank its own prefix in chat, and styles is what lets one reader see the chat in a different colour. They compose: the sender's rank is resolved first, and the reader's style is then taken from that rank's own styles.

chats:
global:
format: '{prefix}{player}: {message}'sender-formats:
vip:
priority: 10format: '&6[VIP] &r{player}&8: &f{message}'styles:
red: { format: '&6[VIP] &r&c{player}&8: &c{message}' }

Highest priority wins when a sender qualifies for several. A rank that defines no styles is shown the same way to every reader.

Moderation

Caps, advertisement and swear filters, plus mute:

/mute <player> [10m|2h|3d|1w] [reason] # no duration means permanent
/unmute <player>

Mutes are stored with the player, so they survive a restart and apply on every server sharing the database. A muted player cannot use public chats or private messages. chatty.command.mute grants the commands, chatty.bypass.mute exempts a player — operators hold both by default.

Placeholders

With PlaceholderAPI installed, Chatty exposes its own data so TAB, scoreboards, Discord bridges and anything else can read it:

PlaceholderValue
%chatty_chat%id of the chat the player currently writes to
%chatty_chat_displayname%its display name
%chatty_chat_range%its range in blocks (-3 cross-server, -2 server, -1 world)
%chatty_chat_range_<id>%the range of a named chat, e.g. %chatty_chat_range_local%
%chatty_chat_displayname_<id>%the display name of a named chat
%chatty_prefix% / %chatty_suffix%the prefix and suffix Chatty resolves for the player
%chatty_spy%whether spy mode is on
%chatty_player_message%the last message the player sent through Chatty
%chatty_targetname%who that message named, or the player themselves
%rel_chatty_ignore%whether the first player ignores the second

%chatty_prefix% is empty unless Vault or LuckPerms is installed, because that is where the prefix comes from.

The last two describe the message a player just sent, so a command run afterwards can quote it — a Discord bridge, or a punishment naming what was said:

/discordsrv broadcast <channel> %chatty_targetname% » %chatty_player_message%
/cmi jail %player_name% said: %chatty_player_message% 2h

%chatty_targetname% is the first player mentioned in that message; with no mention it is the sender, so it is never empty for an online player.

Using the API

Add the API as a compileOnly dependency and declare Chatty as a plugin dependency — the classes come from the running plugin at runtime:

repositories { maven { url ='https://jitpack.io' } }
dependencies { compileOnly 'ru.brikster:chatty-api:3.0.0' }
depend: [ Chatty ]

The published artifact carries Chatty's relocated Adventure, because the plugin bundles its own copy to keep working on servers that have none. That is why it must be compileOnly: a second copy on your own classpath would be a different class to the JVM. Sources and javadoc jars are published alongside it.

Events

EventWhenCancellable
ChattyInitEventChatty is starting, before it reads its configurationno
ChattyPreMessageEventa chat message is formatted, before it is sentno
ChattyMessageEventa chat message has been sentno
ChattyMuteEventa player is about to be mutedyes
ChattyUnmuteEventa player's mute is about to be liftedyes

All of them are fired off the main thread, so a listener must be marked accordingly and must not touch the Bukkit API directly.

ChattyMuteEvent also lets a listener change the mute before it is stored — setUntil and setReason — so a punishment system can escalate a repeat offender:

@EventHandlerpublicvoidonMute(ChattyMuteEventevent) {
if (offences(event.getTargetUniqueId()) > 3) {
event.setUntil(ChattyMuteEvent.PERMANENT);
event.setReason("repeated offences");
}
}

Cancelling either event leaves the player as they were and tells the sender nothing, so a plugin that vetoes a mute should say why itself.

Platforms

Paper, Spigot and Purpur from 1.8.8 up to 26.x, and Folia. Folia support is verified by booting a real Folia server: the plugin schedules its own work and never touches the Bukkit scheduler, and the bundled bStats, which does, is skipped there.

Text formatting

Every spelling below is covered by ColourSpellingMatrixTest, so this table is what the code does rather than what it intends to do. All of them work in chat formats, in message-format, in lang/ files and in a prefix or suffix coming from LuckPerms or Vault.

SpellingExampleSupported
Legacy colour&cyes
Legacy decoration&l&n&o&m&k&ryes
Section sign§cyes
MiniMessage colour<red>yes
MiniMessage hex<#757575>yes
Ampersand hex&#757575yes
Spigot spread hex&x&7&5&7&5&7&5yes
Gradient<gradient:#ff0000:#00ff00>yes
Rainbow<rainbow>yes
Bare hash#757575no, prints as text

Writing colour codes in your own messages is a separate question — that needs chatty.decoration.*, see the permissions section of the migration guide.

Building

Chatty uses Gradle to handle dependencies & building. Building needs JDK 21; the jar it produces targets Java 11, so it runs on Java 11 and newer.

Compiling from source

git clone https://github.com/Brikster/Chatty.git
cd Chatty/
./gradlew build

Output jar will be placed into /build/libs directory.

Testing

Run the unit tests:

./gradlew test

Run the end-to-end smoke test — it boots real Minecraft servers with the built plugin and verifies that it enables cleanly on a fresh install, processes live in-game chat, correctly migrates a legacy v2 configuration, still runs on a legacy server (1.8.8), and coexists with DiscordSRV:

./gradlew build
JAVA_HOME=/path/to/jdk-21 bash scripts/smoke-test.sh

JAVA_HOME must point at a JDK the target server accepts: 21 for 1.21.x, 11 for 1.16.5, 25 for 26.x. Pick the server version with MC_VERSION, and switch off the parts a lane cannot run:

MC_VERSION=26.2 CHAT_TEST=0 JAVA_HOME=/path/to/jdk-25 bash scripts/smoke-test.sh

CHAT_TEST=0 skips the in-game bot, which cannot join a server newer than protocol 1.21.9, and LEGACY_SCENARIO=0 skips the 1.8.8 lane. The legacy scenario needs a Java 11 runtime; it is downloaded automatically, or point LEGACY_JAVA_HOME at an existing one.

Both run automatically on every push via GitHub Actions, with the smoke test as a matrix over 1.21.11, 1.16.5 and 26.2.

About

Bukkit-compatible chat management system

Topics

Resources

Stars

122 stars

Watchers

11 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Brikster/Chatty: Bukkit-compatible chat management system · GitHub
Skip to content

Repository files navigation

Chatty

Chatty (Bukkit plugin)

GitHub release (latest by date)GitHub All ReleasesGitHub code size in bytesJitPackCodacy Badge

Chatty v3 is a ground-up rewrite built on Kyori's Adventure library. It is approaching its first stable release (3.0.0); this branch holds its code.

  • Stable builds — the Releases page (once 3.0.0 is tagged).
  • Development builds — the latest artifact from the "Actions" tab (see the "Artifacts" section).

Chatty v2.* is deprecated and no longer maintained. Upgrading from v2? See MIGRATION.md — v3 migrates your old config automatically.

Chatty is the modern chat management system for Bukkit-compatible servers. It's based on-top of Kyori's Adventure library, that makes it so powerful and stable.

Key features:

  • Chat channels ("local" and "global" by default)
  • Private messaging
  • Moderation (CAPS, advertisements, swears)
  • Notifications (chat, action bar, title and advancement toasts)
  • "Vanilla" messages configuring (join/quit/death)
  • MiniMessage both legacy (&) styling format

Two kinds of per-player appearance

chats.yml has two features that both change how a message looks, and they answer different questions:

Chosen byChanges
stylesthe reader's permission chatty.style.<id>how the chat looks to that reader
sender-formatsthe sender's permission chatty.sender-format.<id> or chatty.chat.<chat>.sender-format.<id>how that player's messages look to everybody

So sender-formats is what gives a rank its own prefix in chat, and styles is what lets one reader see the chat in a different colour. They compose: the sender's rank is resolved first, and the reader's style is then taken from that rank's own styles.

chats:
global:
format: '{prefix}{player}: {message}'sender-formats:
vip:
priority: 10format: '&6[VIP] &r{player}&8: &f{message}'styles:
red: { format: '&6[VIP] &r&c{player}&8: &c{message}' }

Highest priority wins when a sender qualifies for several. A rank that defines no styles is shown the same way to every reader.

Moderation

Caps, advertisement and swear filters, plus mute:

/mute <player> [10m|2h|3d|1w] [reason] # no duration means permanent
/unmute <player>

Mutes are stored with the player, so they survive a restart and apply on every server sharing the database. A muted player cannot use public chats or private messages. chatty.command.mute grants the commands, chatty.bypass.mute exempts a player — operators hold both by default.

Placeholders

With PlaceholderAPI installed, Chatty exposes its own data so TAB, scoreboards, Discord bridges and anything else can read it:

PlaceholderValue
%chatty_chat%id of the chat the player currently writes to
%chatty_chat_displayname%its display name
%chatty_chat_range%its range in blocks (-3 cross-server, -2 server, -1 world)
%chatty_chat_range_<id>%the range of a named chat, e.g. %chatty_chat_range_local%
%chatty_chat_displayname_<id>%the display name of a named chat
%chatty_prefix% / %chatty_suffix%the prefix and suffix Chatty resolves for the player
%chatty_spy%whether spy mode is on
%chatty_player_message%the last message the player sent through Chatty
%chatty_targetname%who that message named, or the player themselves
%rel_chatty_ignore%whether the first player ignores the second

%chatty_prefix% is empty unless Vault or LuckPerms is installed, because that is where the prefix comes from.

The last two describe the message a player just sent, so a command run afterwards can quote it — a Discord bridge, or a punishment naming what was said:

/discordsrv broadcast <channel> %chatty_targetname% » %chatty_player_message%
/cmi jail %player_name% said: %chatty_player_message% 2h

%chatty_targetname% is the first player mentioned in that message; with no mention it is the sender, so it is never empty for an online player.

Using the API

Add the API as a compileOnly dependency and declare Chatty as a plugin dependency — the classes come from the running plugin at runtime:

repositories { maven { url ='https://jitpack.io' } }
dependencies { compileOnly 'ru.brikster:chatty-api:3.0.0' }
depend: [ Chatty ]

The published artifact carries Chatty's relocated Adventure, because the plugin bundles its own copy to keep working on servers that have none. That is why it must be compileOnly: a second copy on your own classpath would be a different class to the JVM. Sources and javadoc jars are published alongside it.

Events

EventWhenCancellable
ChattyInitEventChatty is starting, before it reads its configurationno
ChattyPreMessageEventa chat message is formatted, before it is sentno
ChattyMessageEventa chat message has been sentno
ChattyMuteEventa player is about to be mutedyes
ChattyUnmuteEventa player's mute is about to be liftedyes

All of them are fired off the main thread, so a listener must be marked accordingly and must not touch the Bukkit API directly.

ChattyMuteEvent also lets a listener change the mute before it is stored — setUntil and setReason — so a punishment system can escalate a repeat offender:

@EventHandlerpublicvoidonMute(ChattyMuteEventevent) {
if (offences(event.getTargetUniqueId()) > 3) {
event.setUntil(ChattyMuteEvent.PERMANENT);
event.setReason("repeated offences");
}
}

Cancelling either event leaves the player as they were and tells the sender nothing, so a plugin that vetoes a mute should say why itself.

Platforms

Paper, Spigot and Purpur from 1.8.8 up to 26.x, and Folia. Folia support is verified by booting a real Folia server: the plugin schedules its own work and never touches the Bukkit scheduler, and the bundled bStats, which does, is skipped there.

Text formatting

Every spelling below is covered by ColourSpellingMatrixTest, so this table is what the code does rather than what it intends to do. All of them work in chat formats, in message-format, in lang/ files and in a prefix or suffix coming from LuckPerms or Vault.

SpellingExampleSupported
Legacy colour&cyes
Legacy decoration&l&n&o&m&k&ryes
Section sign§cyes
MiniMessage colour<red>yes
MiniMessage hex<#757575>yes
Ampersand hex&#757575yes
Spigot spread hex&x&7&5&7&5&7&5yes
Gradient<gradient:#ff0000:#00ff00>yes
Rainbow<rainbow>yes
Bare hash#757575no, prints as text

Writing colour codes in your own messages is a separate question — that needs chatty.decoration.*, see the permissions section of the migration guide.

Building

Chatty uses Gradle to handle dependencies & building. Building needs JDK 21; the jar it produces targets Java 11, so it runs on Java 11 and newer.

Compiling from source

git clone https://github.com/Brikster/Chatty.git
cd Chatty/
./gradlew build

Output jar will be placed into /build/libs directory.

Testing

Run the unit tests:

./gradlew test

Run the end-to-end smoke test — it boots real Minecraft servers with the built plugin and verifies that it enables cleanly on a fresh install, processes live in-game chat, correctly migrates a legacy v2 configuration, still runs on a legacy server (1.8.8), and coexists with DiscordSRV:

./gradlew build
JAVA_HOME=/path/to/jdk-21 bash scripts/smoke-test.sh

JAVA_HOME must point at a JDK the target server accepts: 21 for 1.21.x, 11 for 1.16.5, 25 for 26.x. Pick the server version with MC_VERSION, and switch off the parts a lane cannot run:

MC_VERSION=26.2 CHAT_TEST=0 JAVA_HOME=/path/to/jdk-25 bash scripts/smoke-test.sh

CHAT_TEST=0 skips the in-game bot, which cannot join a server newer than protocol 1.21.9, and LEGACY_SCENARIO=0 skips the 1.8.8 lane. The legacy scenario needs a Java 11 runtime; it is downloaded automatically, or point LEGACY_JAVA_HOME at an existing one.

Both run automatically on every push via GitHub Actions, with the smoke test as a matrix over 1.21.11, 1.16.5 and 26.2.

About

Bukkit-compatible chat management system

Topics

Resources

Stars

122 stars

Watchers

11 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Brikster/Chatty: Bukkit-compatible chat management system · GitHub
Skip to content

Repository files navigation

Chatty

Chatty (Bukkit plugin)

GitHub release (latest by date)GitHub All ReleasesGitHub code size in bytesJitPackCodacy Badge

Chatty v3 is a ground-up rewrite built on Kyori's Adventure library. It is approaching its first stable release (3.0.0); this branch holds its code.

  • Stable builds — the Releases page (once 3.0.0 is tagged).
  • Development builds — the latest artifact from the "Actions" tab (see the "Artifacts" section).

Chatty v2.* is deprecated and no longer maintained. Upgrading from v2? See MIGRATION.md — v3 migrates your old config automatically.

Chatty is the modern chat management system for Bukkit-compatible servers. It's based on-top of Kyori's Adventure library, that makes it so powerful and stable.

Key features:

  • Chat channels ("local" and "global" by default)
  • Private messaging
  • Moderation (CAPS, advertisements, swears)
  • Notifications (chat, action bar, title and advancement toasts)
  • "Vanilla" messages configuring (join/quit/death)
  • MiniMessage both legacy (&) styling format

Two kinds of per-player appearance

chats.yml has two features that both change how a message looks, and they answer different questions:

Chosen byChanges
stylesthe reader's permission chatty.style.<id>how the chat looks to that reader
sender-formatsthe sender's permission chatty.sender-format.<id> or chatty.chat.<chat>.sender-format.<id>how that player's messages look to everybody

So sender-formats is what gives a rank its own prefix in chat, and styles is what lets one reader see the chat in a different colour. They compose: the sender's rank is resolved first, and the reader's style is then taken from that rank's own styles.

chats:
global:
format: '{prefix}{player}: {message}'sender-formats:
vip:
priority: 10format: '&6[VIP] &r{player}&8: &f{message}'styles:
red: { format: '&6[VIP] &r&c{player}&8: &c{message}' }

Highest priority wins when a sender qualifies for several. A rank that defines no styles is shown the same way to every reader.

Moderation

Caps, advertisement and swear filters, plus mute:

/mute <player> [10m|2h|3d|1w] [reason] # no duration means permanent
/unmute <player>

Mutes are stored with the player, so they survive a restart and apply on every server sharing the database. A muted player cannot use public chats or private messages. chatty.command.mute grants the commands, chatty.bypass.mute exempts a player — operators hold both by default.

Placeholders

With PlaceholderAPI installed, Chatty exposes its own data so TAB, scoreboards, Discord bridges and anything else can read it:

PlaceholderValue
%chatty_chat%id of the chat the player currently writes to
%chatty_chat_displayname%its display name
%chatty_chat_range%its range in blocks (-3 cross-server, -2 server, -1 world)
%chatty_chat_range_<id>%the range of a named chat, e.g. %chatty_chat_range_local%
%chatty_chat_displayname_<id>%the display name of a named chat
%chatty_prefix% / %chatty_suffix%the prefix and suffix Chatty resolves for the player
%chatty_spy%whether spy mode is on
%chatty_player_message%the last message the player sent through Chatty
%chatty_targetname%who that message named, or the player themselves
%rel_chatty_ignore%whether the first player ignores the second

%chatty_prefix% is empty unless Vault or LuckPerms is installed, because that is where the prefix comes from.

The last two describe the message a player just sent, so a command run afterwards can quote it — a Discord bridge, or a punishment naming what was said:

/discordsrv broadcast <channel> %chatty_targetname% » %chatty_player_message%
/cmi jail %player_name% said: %chatty_player_message% 2h

%chatty_targetname% is the first player mentioned in that message; with no mention it is the sender, so it is never empty for an online player.

Using the API

Add the API as a compileOnly dependency and declare Chatty as a plugin dependency — the classes come from the running plugin at runtime:

repositories { maven { url ='https://jitpack.io' } }
dependencies { compileOnly 'ru.brikster:chatty-api:3.0.0' }
depend: [ Chatty ]

The published artifact carries Chatty's relocated Adventure, because the plugin bundles its own copy to keep working on servers that have none. That is why it must be compileOnly: a second copy on your own classpath would be a different class to the JVM. Sources and javadoc jars are published alongside it.

Events

EventWhenCancellable
ChattyInitEventChatty is starting, before it reads its configurationno
ChattyPreMessageEventa chat message is formatted, before it is sentno
ChattyMessageEventa chat message has been sentno
ChattyMuteEventa player is about to be mutedyes
ChattyUnmuteEventa player's mute is about to be liftedyes

All of them are fired off the main thread, so a listener must be marked accordingly and must not touch the Bukkit API directly.

ChattyMuteEvent also lets a listener change the mute before it is stored — setUntil and setReason — so a punishment system can escalate a repeat offender:

@EventHandlerpublicvoidonMute(ChattyMuteEventevent) {
if (offences(event.getTargetUniqueId()) > 3) {
event.setUntil(ChattyMuteEvent.PERMANENT);
event.setReason("repeated offences");
}
}

Cancelling either event leaves the player as they were and tells the sender nothing, so a plugin that vetoes a mute should say why itself.

Platforms

Paper, Spigot and Purpur from 1.8.8 up to 26.x, and Folia. Folia support is verified by booting a real Folia server: the plugin schedules its own work and never touches the Bukkit scheduler, and the bundled bStats, which does, is skipped there.

Text formatting

Every spelling below is covered by ColourSpellingMatrixTest, so this table is what the code does rather than what it intends to do. All of them work in chat formats, in message-format, in lang/ files and in a prefix or suffix coming from LuckPerms or Vault.

SpellingExampleSupported
Legacy colour&cyes
Legacy decoration&l&n&o&m&k&ryes
Section sign§cyes
MiniMessage colour<red>yes
MiniMessage hex<#757575>yes
Ampersand hex&#757575yes
Spigot spread hex&x&7&5&7&5&7&5yes
Gradient<gradient:#ff0000:#00ff00>yes
Rainbow<rainbow>yes
Bare hash#757575no, prints as text

Writing colour codes in your own messages is a separate question — that needs chatty.decoration.*, see the permissions section of the migration guide.

Building

Chatty uses Gradle to handle dependencies & building. Building needs JDK 21; the jar it produces targets Java 11, so it runs on Java 11 and newer.

Compiling from source

git clone https://github.com/Brikster/Chatty.git
cd Chatty/
./gradlew build

Output jar will be placed into /build/libs directory.

Testing

Run the unit tests:

./gradlew test

Run the end-to-end smoke test — it boots real Minecraft servers with the built plugin and verifies that it enables cleanly on a fresh install, processes live in-game chat, correctly migrates a legacy v2 configuration, still runs on a legacy server (1.8.8), and coexists with DiscordSRV:

./gradlew build
JAVA_HOME=/path/to/jdk-21 bash scripts/smoke-test.sh

JAVA_HOME must point at a JDK the target server accepts: 21 for 1.21.x, 11 for 1.16.5, 25 for 26.x. Pick the server version with MC_VERSION, and switch off the parts a lane cannot run:

MC_VERSION=26.2 CHAT_TEST=0 JAVA_HOME=/path/to/jdk-25 bash scripts/smoke-test.sh

CHAT_TEST=0 skips the in-game bot, which cannot join a server newer than protocol 1.21.9, and LEGACY_SCENARIO=0 skips the 1.8.8 lane. The legacy scenario needs a Java 11 runtime; it is downloaded automatically, or point LEGACY_JAVA_HOME at an existing one.

Both run automatically on every push via GitHub Actions, with the smoke test as a matrix over 1.21.11, 1.16.5 and 26.2.

About

Bukkit-compatible chat management system

Topics

Resources

Stars

122 stars

Watchers

11 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - Brikster/Chatty: Bukkit-compatible chat management system · GitHub
Skip to content

Repository files navigation

Chatty

Chatty (Bukkit plugin)

GitHub release (latest by date)GitHub All ReleasesGitHub code size in bytesJitPackCodacy Badge

Chatty v3 is a ground-up rewrite built on Kyori's Adventure library. It is approaching its first stable release (3.0.0); this branch holds its code.

  • Stable builds — the Releases page (once 3.0.0 is tagged).
  • Development builds — the latest artifact from the "Actions" tab (see the "Artifacts" section).

Chatty v2.* is deprecated and no longer maintained. Upgrading from v2? See MIGRATION.md — v3 migrates your old config automatically.

Chatty is the modern chat management system for Bukkit-compatible servers. It's based on-top of Kyori's Adventure library, that makes it so powerful and stable.

Key features:

  • Chat channels ("local" and "global" by default)
  • Private messaging
  • Moderation (CAPS, advertisements, swears)
  • Notifications (chat, action bar, title and advancement toasts)
  • "Vanilla" messages configuring (join/quit/death)
  • MiniMessage both legacy (&) styling format

Two kinds of per-player appearance

chats.yml has two features that both change how a message looks, and they answer different questions:

Chosen byChanges
stylesthe reader's permission chatty.style.<id>how the chat looks to that reader
sender-formatsthe sender's permission chatty.sender-format.<id> or chatty.chat.<chat>.sender-format.<id>how that player's messages look to everybody

So sender-formats is what gives a rank its own prefix in chat, and styles is what lets one reader see the chat in a different colour. They compose: the sender's rank is resolved first, and the reader's style is then taken from that rank's own styles.

chats:
global:
format: '{prefix}{player}: {message}'sender-formats:
vip:
priority: 10format: '&6[VIP] &r{player}&8: &f{message}'styles:
red: { format: '&6[VIP] &r&c{player}&8: &c{message}' }

Highest priority wins when a sender qualifies for several. A rank that defines no styles is shown the same way to every reader.

Moderation

Caps, advertisement and swear filters, plus mute:

/mute <player> [10m|2h|3d|1w] [reason] # no duration means permanent
/unmute <player>

Mutes are stored with the player, so they survive a restart and apply on every server sharing the database. A muted player cannot use public chats or private messages. chatty.command.mute grants the commands, chatty.bypass.mute exempts a player — operators hold both by default.

Placeholders

With PlaceholderAPI installed, Chatty exposes its own data so TAB, scoreboards, Discord bridges and anything else can read it:

PlaceholderValue
%chatty_chat%id of the chat the player currently writes to
%chatty_chat_displayname%its display name
%chatty_chat_range%its range in blocks (-3 cross-server, -2 server, -1 world)
%chatty_chat_range_<id>%the range of a named chat, e.g. %chatty_chat_range_local%
%chatty_chat_displayname_<id>%the display name of a named chat
%chatty_prefix% / %chatty_suffix%the prefix and suffix Chatty resolves for the player
%chatty_spy%whether spy mode is on
%chatty_player_message%the last message the player sent through Chatty
%chatty_targetname%who that message named, or the player themselves
%rel_chatty_ignore%whether the first player ignores the second

%chatty_prefix% is empty unless Vault or LuckPerms is installed, because that is where the prefix comes from.

The last two describe the message a player just sent, so a command run afterwards can quote it — a Discord bridge, or a punishment naming what was said:

/discordsrv broadcast <channel> %chatty_targetname% » %chatty_player_message%
/cmi jail %player_name% said: %chatty_player_message% 2h

%chatty_targetname% is the first player mentioned in that message; with no mention it is the sender, so it is never empty for an online player.

Using the API

Add the API as a compileOnly dependency and declare Chatty as a plugin dependency — the classes come from the running plugin at runtime:

repositories { maven { url ='https://jitpack.io' } }
dependencies { compileOnly 'ru.brikster:chatty-api:3.0.0' }
depend: [ Chatty ]

The published artifact carries Chatty's relocated Adventure, because the plugin bundles its own copy to keep working on servers that have none. That is why it must be compileOnly: a second copy on your own classpath would be a different class to the JVM. Sources and javadoc jars are published alongside it.

Events

EventWhenCancellable
ChattyInitEventChatty is starting, before it reads its configurationno
ChattyPreMessageEventa chat message is formatted, before it is sentno
ChattyMessageEventa chat message has been sentno
ChattyMuteEventa player is about to be mutedyes
ChattyUnmuteEventa player's mute is about to be liftedyes

All of them are fired off the main thread, so a listener must be marked accordingly and must not touch the Bukkit API directly.

ChattyMuteEvent also lets a listener change the mute before it is stored — setUntil and setReason — so a punishment system can escalate a repeat offender:

@EventHandlerpublicvoidonMute(ChattyMuteEventevent) {
if (offences(event.getTargetUniqueId()) > 3) {
event.setUntil(ChattyMuteEvent.PERMANENT);
event.setReason("repeated offences");
}
}

Cancelling either event leaves the player as they were and tells the sender nothing, so a plugin that vetoes a mute should say why itself.

Platforms

Paper, Spigot and Purpur from 1.8.8 up to 26.x, and Folia. Folia support is verified by booting a real Folia server: the plugin schedules its own work and never touches the Bukkit scheduler, and the bundled bStats, which does, is skipped there.

Text formatting

Every spelling below is covered by ColourSpellingMatrixTest, so this table is what the code does rather than what it intends to do. All of them work in chat formats, in message-format, in lang/ files and in a prefix or suffix coming from LuckPerms or Vault.

SpellingExampleSupported
Legacy colour&cyes
Legacy decoration&l&n&o&m&k&ryes
Section sign§cyes
MiniMessage colour<red>yes
MiniMessage hex<#757575>yes
Ampersand hex&#757575yes
Spigot spread hex&x&7&5&7&5&7&5yes
Gradient<gradient:#ff0000:#00ff00>yes
Rainbow<rainbow>yes
Bare hash#757575no, prints as text

Writing colour codes in your own messages is a separate question — that needs chatty.decoration.*, see the permissions section of the migration guide.

Building

Chatty uses Gradle to handle dependencies & building. Building needs JDK 21; the jar it produces targets Java 11, so it runs on Java 11 and newer.

Compiling from source

git clone https://github.com/Brikster/Chatty.git
cd Chatty/
./gradlew build

Output jar will be placed into /build/libs directory.

Testing

Run the unit tests:

./gradlew test

Run the end-to-end smoke test — it boots real Minecraft servers with the built plugin and verifies that it enables cleanly on a fresh install, processes live in-game chat, correctly migrates a legacy v2 configuration, still runs on a legacy server (1.8.8), and coexists with DiscordSRV:

./gradlew build
JAVA_HOME=/path/to/jdk-21 bash scripts/smoke-test.sh

JAVA_HOME must point at a JDK the target server accepts: 21 for 1.21.x, 11 for 1.16.5, 25 for 26.x. Pick the server version with MC_VERSION, and switch off the parts a lane cannot run:

MC_VERSION=26.2 CHAT_TEST=0 JAVA_HOME=/path/to/jdk-25 bash scripts/smoke-test.sh

CHAT_TEST=0 skips the in-game bot, which cannot join a server newer than protocol 1.21.9, and LEGACY_SCENARIO=0 skips the 1.8.8 lane. The legacy scenario needs a Java 11 runtime; it is downloaded automatically, or point LEGACY_JAVA_HOME at an existing one.

Both run automatically on every push via GitHub Actions, with the smoke test as a matrix over 1.21.11, 1.16.5 and 26.2.

About

Bukkit-compatible chat management system

Topics

Resources

Stars

122 stars

Watchers

11 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Brikster/Chatty: Bukkit-compatible chat management system · GitHub
Skip to content

Repository files navigation

Chatty

Chatty (Bukkit plugin)

GitHub release (latest by date)GitHub All ReleasesGitHub code size in bytesJitPackCodacy Badge

Chatty v3 is a ground-up rewrite built on Kyori's Adventure library. It is approaching its first stable release (3.0.0); this branch holds its code.

  • Stable builds — the Releases page (once 3.0.0 is tagged).
  • Development builds — the latest artifact from the "Actions" tab (see the "Artifacts" section).

Chatty v2.* is deprecated and no longer maintained. Upgrading from v2? See MIGRATION.md — v3 migrates your old config automatically.

Chatty is the modern chat management system for Bukkit-compatible servers. It's based on-top of Kyori's Adventure library, that makes it so powerful and stable.

Key features:

  • Chat channels ("local" and "global" by default)
  • Private messaging
  • Moderation (CAPS, advertisements, swears)
  • Notifications (chat, action bar, title and advancement toasts)
  • "Vanilla" messages configuring (join/quit/death)
  • MiniMessage both legacy (&) styling format

Two kinds of per-player appearance

chats.yml has two features that both change how a message looks, and they answer different questions:

Chosen byChanges
stylesthe reader's permission chatty.style.<id>how the chat looks to that reader
sender-formatsthe sender's permission chatty.sender-format.<id> or chatty.chat.<chat>.sender-format.<id>how that player's messages look to everybody

So sender-formats is what gives a rank its own prefix in chat, and styles is what lets one reader see the chat in a different colour. They compose: the sender's rank is resolved first, and the reader's style is then taken from that rank's own styles.

chats:
global:
format: '{prefix}{player}: {message}'sender-formats:
vip:
priority: 10format: '&6[VIP] &r{player}&8: &f{message}'styles:
red: { format: '&6[VIP] &r&c{player}&8: &c{message}' }

Highest priority wins when a sender qualifies for several. A rank that defines no styles is shown the same way to every reader.

Moderation

Caps, advertisement and swear filters, plus mute:

/mute <player> [10m|2h|3d|1w] [reason] # no duration means permanent
/unmute <player>

Mutes are stored with the player, so they survive a restart and apply on every server sharing the database. A muted player cannot use public chats or private messages. chatty.command.mute grants the commands, chatty.bypass.mute exempts a player — operators hold both by default.

Placeholders

With PlaceholderAPI installed, Chatty exposes its own data so TAB, scoreboards, Discord bridges and anything else can read it:

PlaceholderValue
%chatty_chat%id of the chat the player currently writes to
%chatty_chat_displayname%its display name
%chatty_chat_range%its range in blocks (-3 cross-server, -2 server, -1 world)
%chatty_chat_range_<id>%the range of a named chat, e.g. %chatty_chat_range_local%
%chatty_chat_displayname_<id>%the display name of a named chat
%chatty_prefix% / %chatty_suffix%the prefix and suffix Chatty resolves for the player
%chatty_spy%whether spy mode is on
%chatty_player_message%the last message the player sent through Chatty
%chatty_targetname%who that message named, or the player themselves
%rel_chatty_ignore%whether the first player ignores the second

%chatty_prefix% is empty unless Vault or LuckPerms is installed, because that is where the prefix comes from.

The last two describe the message a player just sent, so a command run afterwards can quote it — a Discord bridge, or a punishment naming what was said:

/discordsrv broadcast <channel> %chatty_targetname% » %chatty_player_message%
/cmi jail %player_name% said: %chatty_player_message% 2h

%chatty_targetname% is the first player mentioned in that message; with no mention it is the sender, so it is never empty for an online player.

Using the API

Add the API as a compileOnly dependency and declare Chatty as a plugin dependency — the classes come from the running plugin at runtime:

repositories { maven { url ='https://jitpack.io' } }
dependencies { compileOnly 'ru.brikster:chatty-api:3.0.0' }
depend: [ Chatty ]

The published artifact carries Chatty's relocated Adventure, because the plugin bundles its own copy to keep working on servers that have none. That is why it must be compileOnly: a second copy on your own classpath would be a different class to the JVM. Sources and javadoc jars are published alongside it.

Events

EventWhenCancellable
ChattyInitEventChatty is starting, before it reads its configurationno
ChattyPreMessageEventa chat message is formatted, before it is sentno
ChattyMessageEventa chat message has been sentno
ChattyMuteEventa player is about to be mutedyes
ChattyUnmuteEventa player's mute is about to be liftedyes

All of them are fired off the main thread, so a listener must be marked accordingly and must not touch the Bukkit API directly.

ChattyMuteEvent also lets a listener change the mute before it is stored — setUntil and setReason — so a punishment system can escalate a repeat offender:

@EventHandlerpublicvoidonMute(ChattyMuteEventevent) {
if (offences(event.getTargetUniqueId()) > 3) {
event.setUntil(ChattyMuteEvent.PERMANENT);
event.setReason("repeated offences");
}
}

Cancelling either event leaves the player as they were and tells the sender nothing, so a plugin that vetoes a mute should say why itself.

Platforms

Paper, Spigot and Purpur from 1.8.8 up to 26.x, and Folia. Folia support is verified by booting a real Folia server: the plugin schedules its own work and never touches the Bukkit scheduler, and the bundled bStats, which does, is skipped there.

Text formatting

Every spelling below is covered by ColourSpellingMatrixTest, so this table is what the code does rather than what it intends to do. All of them work in chat formats, in message-format, in lang/ files and in a prefix or suffix coming from LuckPerms or Vault.

SpellingExampleSupported
Legacy colour&cyes
Legacy decoration&l&n&o&m&k&ryes
Section sign§cyes
MiniMessage colour<red>yes
MiniMessage hex<#757575>yes
Ampersand hex&#757575yes
Spigot spread hex&x&7&5&7&5&7&5yes
Gradient<gradient:#ff0000:#00ff00>yes
Rainbow<rainbow>yes
Bare hash#757575no, prints as text

Writing colour codes in your own messages is a separate question — that needs chatty.decoration.*, see the permissions section of the migration guide.

Building

Chatty uses Gradle to handle dependencies & building. Building needs JDK 21; the jar it produces targets Java 11, so it runs on Java 11 and newer.

Compiling from source

git clone https://github.com/Brikster/Chatty.git
cd Chatty/
./gradlew build

Output jar will be placed into /build/libs directory.

Testing

Run the unit tests:

./gradlew test

Run the end-to-end smoke test — it boots real Minecraft servers with the built plugin and verifies that it enables cleanly on a fresh install, processes live in-game chat, correctly migrates a legacy v2 configuration, still runs on a legacy server (1.8.8), and coexists with DiscordSRV:

./gradlew build
JAVA_HOME=/path/to/jdk-21 bash scripts/smoke-test.sh

JAVA_HOME must point at a JDK the target server accepts: 21 for 1.21.x, 11 for 1.16.5, 25 for 26.x. Pick the server version with MC_VERSION, and switch off the parts a lane cannot run:

MC_VERSION=26.2 CHAT_TEST=0 JAVA_HOME=/path/to/jdk-25 bash scripts/smoke-test.sh

CHAT_TEST=0 skips the in-game bot, which cannot join a server newer than protocol 1.21.9, and LEGACY_SCENARIO=0 skips the 1.8.8 lane. The legacy scenario needs a Java 11 runtime; it is downloaded automatically, or point LEGACY_JAVA_HOME at an existing one.

Both run automatically on every push via GitHub Actions, with the smoke test as a matrix over 1.21.11, 1.16.5 and 26.2.

About

Bukkit-compatible chat management system

Topics

Resources

Stars

122 stars

Watchers

11 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Brikster/Chatty: Bukkit-compatible chat management system · GitHub
Skip to content

Repository files navigation

Chatty

Chatty (Bukkit plugin)

GitHub release (latest by date)GitHub All ReleasesGitHub code size in bytesJitPackCodacy Badge

Chatty v3 is a ground-up rewrite built on Kyori's Adventure library. It is approaching its first stable release (3.0.0); this branch holds its code.

  • Stable builds — the Releases page (once 3.0.0 is tagged).
  • Development builds — the latest artifact from the "Actions" tab (see the "Artifacts" section).

Chatty v2.* is deprecated and no longer maintained. Upgrading from v2? See MIGRATION.md — v3 migrates your old config automatically.

Chatty is the modern chat management system for Bukkit-compatible servers. It's based on-top of Kyori's Adventure library, that makes it so powerful and stable.

Key features:

  • Chat channels ("local" and "global" by default)
  • Private messaging
  • Moderation (CAPS, advertisements, swears)
  • Notifications (chat, action bar, title and advancement toasts)
  • "Vanilla" messages configuring (join/quit/death)
  • MiniMessage both legacy (&) styling format

Two kinds of per-player appearance

chats.yml has two features that both change how a message looks, and they answer different questions:

Chosen byChanges
stylesthe reader's permission chatty.style.<id>how the chat looks to that reader
sender-formatsthe sender's permission chatty.sender-format.<id> or chatty.chat.<chat>.sender-format.<id>how that player's messages look to everybody

So sender-formats is what gives a rank its own prefix in chat, and styles is what lets one reader see the chat in a different colour. They compose: the sender's rank is resolved first, and the reader's style is then taken from that rank's own styles.

chats:
global:
format: '{prefix}{player}: {message}'sender-formats:
vip:
priority: 10format: '&6[VIP] &r{player}&8: &f{message}'styles:
red: { format: '&6[VIP] &r&c{player}&8: &c{message}' }

Highest priority wins when a sender qualifies for several. A rank that defines no styles is shown the same way to every reader.

Moderation

Caps, advertisement and swear filters, plus mute:

/mute <player> [10m|2h|3d|1w] [reason] # no duration means permanent
/unmute <player>

Mutes are stored with the player, so they survive a restart and apply on every server sharing the database. A muted player cannot use public chats or private messages. chatty.command.mute grants the commands, chatty.bypass.mute exempts a player — operators hold both by default.

Placeholders

With PlaceholderAPI installed, Chatty exposes its own data so TAB, scoreboards, Discord bridges and anything else can read it:

PlaceholderValue
%chatty_chat%id of the chat the player currently writes to
%chatty_chat_displayname%its display name
%chatty_chat_range%its range in blocks (-3 cross-server, -2 server, -1 world)
%chatty_chat_range_<id>%the range of a named chat, e.g. %chatty_chat_range_local%
%chatty_chat_displayname_<id>%the display name of a named chat
%chatty_prefix% / %chatty_suffix%the prefix and suffix Chatty resolves for the player
%chatty_spy%whether spy mode is on
%chatty_player_message%the last message the player sent through Chatty
%chatty_targetname%who that message named, or the player themselves
%rel_chatty_ignore%whether the first player ignores the second

%chatty_prefix% is empty unless Vault or LuckPerms is installed, because that is where the prefix comes from.

The last two describe the message a player just sent, so a command run afterwards can quote it — a Discord bridge, or a punishment naming what was said:

/discordsrv broadcast <channel> %chatty_targetname% » %chatty_player_message%
/cmi jail %player_name% said: %chatty_player_message% 2h

%chatty_targetname% is the first player mentioned in that message; with no mention it is the sender, so it is never empty for an online player.

Using the API

Add the API as a compileOnly dependency and declare Chatty as a plugin dependency — the classes come from the running plugin at runtime:

repositories { maven { url ='https://jitpack.io' } }
dependencies { compileOnly 'ru.brikster:chatty-api:3.0.0' }
depend: [ Chatty ]

The published artifact carries Chatty's relocated Adventure, because the plugin bundles its own copy to keep working on servers that have none. That is why it must be compileOnly: a second copy on your own classpath would be a different class to the JVM. Sources and javadoc jars are published alongside it.

Events

EventWhenCancellable
ChattyInitEventChatty is starting, before it reads its configurationno
ChattyPreMessageEventa chat message is formatted, before it is sentno
ChattyMessageEventa chat message has been sentno
ChattyMuteEventa player is about to be mutedyes
ChattyUnmuteEventa player's mute is about to be liftedyes

All of them are fired off the main thread, so a listener must be marked accordingly and must not touch the Bukkit API directly.

ChattyMuteEvent also lets a listener change the mute before it is stored — setUntil and setReason — so a punishment system can escalate a repeat offender:

@EventHandlerpublicvoidonMute(ChattyMuteEventevent) {
if (offences(event.getTargetUniqueId()) > 3) {
event.setUntil(ChattyMuteEvent.PERMANENT);
event.setReason("repeated offences");
}
}

Cancelling either event leaves the player as they were and tells the sender nothing, so a plugin that vetoes a mute should say why itself.

Platforms

Paper, Spigot and Purpur from 1.8.8 up to 26.x, and Folia. Folia support is verified by booting a real Folia server: the plugin schedules its own work and never touches the Bukkit scheduler, and the bundled bStats, which does, is skipped there.

Text formatting

Every spelling below is covered by ColourSpellingMatrixTest, so this table is what the code does rather than what it intends to do. All of them work in chat formats, in message-format, in lang/ files and in a prefix or suffix coming from LuckPerms or Vault.

SpellingExampleSupported
Legacy colour&cyes
Legacy decoration&l&n&o&m&k&ryes
Section sign§cyes
MiniMessage colour<red>yes
MiniMessage hex<#757575>yes
Ampersand hex&#757575yes
Spigot spread hex&x&7&5&7&5&7&5yes
Gradient<gradient:#ff0000:#00ff00>yes
Rainbow<rainbow>yes
Bare hash#757575no, prints as text

Writing colour codes in your own messages is a separate question — that needs chatty.decoration.*, see the permissions section of the migration guide.

Building

Chatty uses Gradle to handle dependencies & building. Building needs JDK 21; the jar it produces targets Java 11, so it runs on Java 11 and newer.

Compiling from source

git clone https://github.com/Brikster/Chatty.git
cd Chatty/
./gradlew build

Output jar will be placed into /build/libs directory.

Testing

Run the unit tests:

./gradlew test

Run the end-to-end smoke test — it boots real Minecraft servers with the built plugin and verifies that it enables cleanly on a fresh install, processes live in-game chat, correctly migrates a legacy v2 configuration, still runs on a legacy server (1.8.8), and coexists with DiscordSRV:

./gradlew build
JAVA_HOME=/path/to/jdk-21 bash scripts/smoke-test.sh

JAVA_HOME must point at a JDK the target server accepts: 21 for 1.21.x, 11 for 1.16.5, 25 for 26.x. Pick the server version with MC_VERSION, and switch off the parts a lane cannot run:

MC_VERSION=26.2 CHAT_TEST=0 JAVA_HOME=/path/to/jdk-25 bash scripts/smoke-test.sh

CHAT_TEST=0 skips the in-game bot, which cannot join a server newer than protocol 1.21.9, and LEGACY_SCENARIO=0 skips the 1.8.8 lane. The legacy scenario needs a Java 11 runtime; it is downloaded automatically, or point LEGACY_JAVA_HOME at an existing one.

Both run automatically on every push via GitHub Actions, with the smoke test as a matrix over 1.21.11, 1.16.5 and 26.2.

About

Bukkit-compatible chat management system

Topics

Resources

Stars

122 stars

Watchers

11 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - Brikster/Chatty: Bukkit-compatible chat management system · GitHub
Skip to content

Repository files navigation

Chatty

Chatty (Bukkit plugin)

GitHub release (latest by date)GitHub All ReleasesGitHub code size in bytesJitPackCodacy Badge

Chatty v3 is a ground-up rewrite built on Kyori's Adventure library. It is approaching its first stable release (3.0.0); this branch holds its code.

  • Stable builds — the Releases page (once 3.0.0 is tagged).
  • Development builds — the latest artifact from the "Actions" tab (see the "Artifacts" section).

Chatty v2.* is deprecated and no longer maintained. Upgrading from v2? See MIGRATION.md — v3 migrates your old config automatically.

Chatty is the modern chat management system for Bukkit-compatible servers. It's based on-top of Kyori's Adventure library, that makes it so powerful and stable.

Key features:

  • Chat channels ("local" and "global" by default)
  • Private messaging
  • Moderation (CAPS, advertisements, swears)
  • Notifications (chat, action bar, title and advancement toasts)
  • "Vanilla" messages configuring (join/quit/death)
  • MiniMessage both legacy (&) styling format

Two kinds of per-player appearance

chats.yml has two features that both change how a message looks, and they answer different questions:

Chosen byChanges
stylesthe reader's permission chatty.style.<id>how the chat looks to that reader
sender-formatsthe sender's permission chatty.sender-format.<id> or chatty.chat.<chat>.sender-format.<id>how that player's messages look to everybody

So sender-formats is what gives a rank its own prefix in chat, and styles is what lets one reader see the chat in a different colour. They compose: the sender's rank is resolved first, and the reader's style is then taken from that rank's own styles.

chats:
global:
format: '{prefix}{player}: {message}'sender-formats:
vip:
priority: 10format: '&6[VIP] &r{player}&8: &f{message}'styles:
red: { format: '&6[VIP] &r&c{player}&8: &c{message}' }

Highest priority wins when a sender qualifies for several. A rank that defines no styles is shown the same way to every reader.

Moderation

Caps, advertisement and swear filters, plus mute:

/mute <player> [10m|2h|3d|1w] [reason] # no duration means permanent
/unmute <player>

Mutes are stored with the player, so they survive a restart and apply on every server sharing the database. A muted player cannot use public chats or private messages. chatty.command.mute grants the commands, chatty.bypass.mute exempts a player — operators hold both by default.

Placeholders

With PlaceholderAPI installed, Chatty exposes its own data so TAB, scoreboards, Discord bridges and anything else can read it:

PlaceholderValue
%chatty_chat%id of the chat the player currently writes to
%chatty_chat_displayname%its display name
%chatty_chat_range%its range in blocks (-3 cross-server, -2 server, -1 world)
%chatty_chat_range_<id>%the range of a named chat, e.g. %chatty_chat_range_local%
%chatty_chat_displayname_<id>%the display name of a named chat
%chatty_prefix% / %chatty_suffix%the prefix and suffix Chatty resolves for the player
%chatty_spy%whether spy mode is on
%chatty_player_message%the last message the player sent through Chatty
%chatty_targetname%who that message named, or the player themselves
%rel_chatty_ignore%whether the first player ignores the second

%chatty_prefix% is empty unless Vault or LuckPerms is installed, because that is where the prefix comes from.

The last two describe the message a player just sent, so a command run afterwards can quote it — a Discord bridge, or a punishment naming what was said:

/discordsrv broadcast <channel> %chatty_targetname% » %chatty_player_message%
/cmi jail %player_name% said: %chatty_player_message% 2h

%chatty_targetname% is the first player mentioned in that message; with no mention it is the sender, so it is never empty for an online player.

Using the API

Add the API as a compileOnly dependency and declare Chatty as a plugin dependency — the classes come from the running plugin at runtime:

repositories { maven { url ='https://jitpack.io' } }
dependencies { compileOnly 'ru.brikster:chatty-api:3.0.0' }
depend: [ Chatty ]

The published artifact carries Chatty's relocated Adventure, because the plugin bundles its own copy to keep working on servers that have none. That is why it must be compileOnly: a second copy on your own classpath would be a different class to the JVM. Sources and javadoc jars are published alongside it.

Events

EventWhenCancellable
ChattyInitEventChatty is starting, before it reads its configurationno
ChattyPreMessageEventa chat message is formatted, before it is sentno
ChattyMessageEventa chat message has been sentno
ChattyMuteEventa player is about to be mutedyes
ChattyUnmuteEventa player's mute is about to be liftedyes

All of them are fired off the main thread, so a listener must be marked accordingly and must not touch the Bukkit API directly.

ChattyMuteEvent also lets a listener change the mute before it is stored — setUntil and setReason — so a punishment system can escalate a repeat offender:

@EventHandlerpublicvoidonMute(ChattyMuteEventevent) {
if (offences(event.getTargetUniqueId()) > 3) {
event.setUntil(ChattyMuteEvent.PERMANENT);
event.setReason("repeated offences");
}
}

Cancelling either event leaves the player as they were and tells the sender nothing, so a plugin that vetoes a mute should say why itself.

Platforms

Paper, Spigot and Purpur from 1.8.8 up to 26.x, and Folia. Folia support is verified by booting a real Folia server: the plugin schedules its own work and never touches the Bukkit scheduler, and the bundled bStats, which does, is skipped there.

Text formatting

Every spelling below is covered by ColourSpellingMatrixTest, so this table is what the code does rather than what it intends to do. All of them work in chat formats, in message-format, in lang/ files and in a prefix or suffix coming from LuckPerms or Vault.

SpellingExampleSupported
Legacy colour&cyes
Legacy decoration&l&n&o&m&k&ryes
Section sign§cyes
MiniMessage colour<red>yes
MiniMessage hex<#757575>yes
Ampersand hex&#757575yes
Spigot spread hex&x&7&5&7&5&7&5yes
Gradient<gradient:#ff0000:#00ff00>yes
Rainbow<rainbow>yes
Bare hash#757575no, prints as text

Writing colour codes in your own messages is a separate question — that needs chatty.decoration.*, see the permissions section of the migration guide.

Building

Chatty uses Gradle to handle dependencies & building. Building needs JDK 21; the jar it produces targets Java 11, so it runs on Java 11 and newer.

Compiling from source

git clone https://github.com/Brikster/Chatty.git
cd Chatty/
./gradlew build

Output jar will be placed into /build/libs directory.

Testing

Run the unit tests:

./gradlew test

Run the end-to-end smoke test — it boots real Minecraft servers with the built plugin and verifies that it enables cleanly on a fresh install, processes live in-game chat, correctly migrates a legacy v2 configuration, still runs on a legacy server (1.8.8), and coexists with DiscordSRV:

./gradlew build
JAVA_HOME=/path/to/jdk-21 bash scripts/smoke-test.sh

JAVA_HOME must point at a JDK the target server accepts: 21 for 1.21.x, 11 for 1.16.5, 25 for 26.x. Pick the server version with MC_VERSION, and switch off the parts a lane cannot run:

MC_VERSION=26.2 CHAT_TEST=0 JAVA_HOME=/path/to/jdk-25 bash scripts/smoke-test.sh

CHAT_TEST=0 skips the in-game bot, which cannot join a server newer than protocol 1.21.9, and LEGACY_SCENARIO=0 skips the 1.8.8 lane. The legacy scenario needs a Java 11 runtime; it is downloaded automatically, or point LEGACY_JAVA_HOME at an existing one.

Both run automatically on every push via GitHub Actions, with the smoke test as a matrix over 1.21.11, 1.16.5 and 26.2.

About

Bukkit-compatible chat management system

Topics

Resources

Stars

122 stars

Watchers

11 watching

Forks

Releases

Used by

Contributors

Languages