API
If you are a developer, ChatControl offers a comprehensive API to implement your own functionality into this plugin. The API source code is now available on GitHub, providing direct access to all events, parties, and other integration points.
API Source Code Access
The complete API source code is accessible at: GitHub - ChatControl API
Key API Classes
ChatControl's API is organized into several categories of classes that serve different purposes:
Chat Events
ChannelPreChatEvent- Called before a message is processed in a channelChannelPostChatEvent- Called after a message is processed in a channelPlayerMessageEvent- Called when a player sends a chat messagePlayerPreMentionEvent- Called before a player mention is processedPlayerMentionEvent- Called when a player mentions another playerPrePrivateMessageEvent- Called before a private message is sent
Channel Events
ChannelJoinEvent- Called when a player joins a channelChannelLeaveEvent- Called when a player leaves a channelChatChannelProxyEvent- Called when handling proxy chat channels
Moderation Events
MuteEvent- Called when a player is mutedSpyEvent- Called when chat spying is activatedPreRuleMatchEvent- Called before a rule is matchedRuleReplaceEvent- Called when a rule replaces text
Utility Classes
ChatControlAPI- Main API entry point with useful methodsParty- Utility for creating custom chat channelsSampleCustomPlaceholders- Examples of custom placeholder creation
Creating a Custom Party Channel
A party channel in ChatControl allows only players in the same group (such as a faction, town, clan or plot) to see each others' messages. Many plugins are supported out of the box (see the Party comment in the Channels section of your settings.yml), including SimpleClans via simpleclans-clan and simpleclans-ally — check that list before writing your own integration. Here's how to create one:
Warning
Custom parties registered through the two-argument Party.register() are evaluated on the sender's server only, so in proxy networks, messages in such channels do not reach players on other servers. If your plugin shares its group data across servers (i.e. over a database), use the three-argument overload Party.register(name, isInParty, isInRemoteParty) where the last function resolves membership from the receiver and the remote sender's UUID, and your channel will work network-wide.
Step 1: Configure Dependencies
Add ChatControl as a dependency in your plugin's plugin.yml:
name: YourPlugin
version: 1.0
main: com.yourplugin.Main
softdepend: [ChatControl]This ensures your plugin loads after ChatControl, allowing you to access its API.
Step 2: Register Your Party
Register your party name in your plugin's onLoad() method. ChatControl loads its channels while it enables, and softdepend makes your plugin enable after it, so a party registered in onEnable() arrives too late and ChatControl fails to load the channel using it with "No such channel party". Bukkit runs every plugin's onLoad() before any plugin is enabled, so registering there always works. If you must register later, run /chc reload afterwards to re-read the channels.
import org.mineacademy.chatcontrol.api.Party;
public class YourPlugin extends JavaPlugin {
@Override
public void onLoad() {
// Only register if ChatControl is present
if (Bukkit.getPluginManager().getPlugin("ChatControl") != null) {
registerCustomParty();
}
}
private void registerCustomParty() {
Party.register("myplugin-claim", (receiver, sender) -> {
// Replace with your own logic to determine if players are in the same group
Claim claim = findClaimLocation(receiver.getLocation());
List<UUID> claimPlayers = claim.getOnlinePlayers();
// Return true if both players are in the same group
return claimPlayers.contains(sender.getUniqueId()) &&
claimPlayers.contains(receiver.getUniqueId());
});
}
private Claim findClaimLocation(Location location) {
// Your custom logic to find a claim at a location
return new Claim(); // Example
}
}Step 3: Configure in settings.yml
After registering your party, you can use it in the Party key in Channels.List in ChatControl's settings.yml:
Channels:
List:
claims:
Format: claims-chat
Party: myplugin-claimWorking with Events
You can listen to ChatControl events in your plugin. Here's an example of monitoring when players are muted:
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.mineacademy.chatcontrol.api.MuteEvent;
import org.mineacademy.fo.model.SimpleTime;
import java.util.UUID;
import org.mineacademy.chatcontrol.api.Channel;
public class ChatEventListener implements Listener {
@EventHandler
public void onPlayerMuted(MuteEvent event) {
// Check what type of mute event occurred
if (event.isPlayerMute()) {
// Handle player mute event
String playerName = event.getTargetPlayerName();
UUID playerUUID = event.getTargetPlayerUniqueId();
if (event.isMute()) {
// This is a mute action (not unmute)
SimpleTime duration = event.getDuration();
String durationText = duration != null ? duration.toString() : "permanently";
getLogger().info("Player " + playerName + " was muted for " + durationText);
// You can also cancel the mute if needed
// event.setCancelled(true);
} else {
// This is an unmute action
getLogger().info("Player " + playerName + " was unmuted");
}
} else if (event.isChannelMute()) {
// Handle channel mute event
Channel channel = event.getTargetChannel();
if (event.isMute()) {
SimpleTime duration = event.getDuration();
getLogger().info("Channel " + channel.getName() + " was muted for " + duration);
} else {
getLogger().info("Channel " + channel.getName() + " was unmuted");
}
} else if (event.isServerMute()) {
// Handle server-wide mute
if (event.isMute()) {
SimpleTime duration = event.getDuration();
getLogger().info("Server chat was muted for " + duration);
} else {
getLogger().info("Server chat was unmuted");
}
}
}
}Using ChatControlAPI
The ChatControlAPI class provides several utility methods for interacting with the plugin:
Warning
Player data is loaded from the database asynchronously around the time a player joins, and unloaded when he quits. Any method that works with a player's data, such as getCache, checkMessage, checkRules or sendMessage, throws an exception when his data is not loaded yet. Call ChatControlAPI.isPlayerCached(player) first and skip your logic when it returns false. This matters most when you call us from a join listener or from a task you schedule on join, because the data is often not ready at that point.
import org.bukkit.entity.Player;
import org.bukkit.command.CommandSender;
import org.mineacademy.chatcontrol.api.ChatControlAPI;
import org.mineacademy.chatcontrol.model.Checker;
import org.mineacademy.chatcontrol.model.RuleType;
import org.mineacademy.chatcontrol.model.Channel;
import org.mineacademy.chatcontrol.model.db.PlayerCache;
import org.mineacademy.chatcontrol.operator.Rule.RuleCheck;
// Check if server chat is globally muted
boolean isChatMuted = ChatControlAPI.isChatMuted();
// Always check that a player's data is loaded before using any method that needs it
if (!ChatControlAPI.isPlayerCached(player))
return;
// Get a player's cache data
PlayerCache playerCache = ChatControlAPI.getCache(player);
// Check if a message would trigger any filters (antispam, anticaps, etc.)
Checker messageCheck = ChatControlAPI.checkMessage(player, "Hello world!");
if (messageCheck.isCancelled()) {
getLogger().info("Message would be blocked: " + messageCheck.getCancelReason());
}
// Apply specific rules to a message (CHAT, COMMAND, JOIN, etc.)
RuleCheck ruleCheck = ChatControlAPI.checkRules(RuleType.CHAT, player, "Hello world!");
if (ruleCheck.isMatched()) {
getLogger().info("Message matched rule: " + ruleCheck.getMatchedRule().getName());
}
// Check if a player is considered a newcomer
boolean isNewcomer = ChatControlAPI.isNewcomer(player);
// Check if a specific channel exists
boolean channelExists = ChatControlAPI.isChannelInstalled("global");
// Send a message to a channel through a player
if (channelExists) {
ChatControlAPI.sendMessage(player, "global", "Hello everyone!");
}This example demonstrates the core API functionality for:
- Checking global chat mute status
- Verifying a player's data is loaded before using it
- Accessing player data
- Filtering messages through various checks
- Testing messages against specific rule types
- Determining newcomer status
- Working with channels
Advanced Integration
For more advanced integrations, refer to the API source code on GitHub. The code is well-documented and provides comprehensive examples of how to use each component.