Developer API
AstralChat exposes its services through the main plugin instance and fires a cancellable Bukkit event for every channel message. Other plugins can integrate by depending on com.astralrealms:chat.
Maven coordinates
Repository: https://maven.astralrealms.fr/repository/maven-public/.
Plugin handle
Services
Every service is exposed via a Lombok-generated getter on the plugin instance.
Getter | Type | Use |
|---|---|---|
|
| Broadcast into a channel, pause/resume, network packet helpers. |
|
| Render and broadcast components to channel subscribers. Implements the shared |
|
| Programmatically send a PM. |
|
| Read and mutate ignore relationships. Shared via the AstralCore service repository. |
|
| Run filters; register custom filters. |
|
| Dispatch a mention notification programmatically. |
|
| Look up a tag by id; iterate all tags. |
|
| Subscription state, cached |
|
| The recent-message cache (similarity filter, cooldowns) and the HTTP call to the moderation classifier — |
|
| Threshold evaluation, staff notification, and the |
|
|
|
|
| AstralChat's own menus (the ignored-list menu). |
|
| Loaded |
|
| Loaded |
|
| Loaded |
|
| Loaded |
| AstralCore services | The plugin's own MariaDB, Redis and RabbitMQ handles. |
The chat service and ignore service are also registered with AstralCore's service repository so any other plugin can resolve them without a hard dependency on AstralChat:
The shared ChatService interface is deliberately narrow — sendMessage(uuid, component), broadcastMessage(component[, channel]), actionBar(uuid, component) and isIgnoring(viewer, target). All four are network-aware: a target on another server is reached over RabbitMQ. Rendering a player's chat message (broadcastChatMessage) is not part of it and needs the concrete PaperChatService.
IgnoreService.isIgnoring is the raw relationship check. The AstralChat-specific IgnoreServiceImpl.isIgnored(viewer, sender) is the one to use before delivering something, because it also honours the staff bypass.
Broadcasting
For a full player chat message — subscription check, ChannelChatEvent, filters, rendering, cross-server fan-out, caching and storage — use the concrete chat service. It takes the unrendered body and returns the filtered body, or null when the message must not be shown:
Pause and cooldown are enforced by ChannelListener on the vanilla chat event, not by this call.
Sending a private message
The call is network-aware and returns asynchronously via the RabbitMQ pipeline. Failure reasons surface as status codes which are mapped to message keys (see Private Messages).
Listening to chat events
ChannelChatEvent is a cancellable Bukkit event fired by PaperChatService.broadcastChatMessage, after the subscription check and before the line is rendered. It carries the unrendered message body, so a listener rewriting component rewrites the player's words only — the channel format, prefix and display name are applied afterwards and cannot be touched here. It is marked async whenever it is constructed off the main thread, which is the normal path for player chat.
FiltersListener is itself just a listener on this event, so custom listeners compete with the filters on equal terms — order them with the usual EventPriority.
Method | Notes |
|---|---|
| Sender. |
| Raw string the player typed (pre-filter). |
| The message body about to be rendered and broadcast. |
| The |
| Inherited from |
Always check Bukkit.isPrimaryThread() before touching Bukkit APIs from inside the handler — the event fires async when AstralChat handles the message off the main thread.
Filters
Filters are configuration-driven, not runtime-registrable: FilterService walks filtersConfiguration().filters() and there is no register hook. The three available implementations are fixed by the ChatFilterType enum (REGEX, CAPS, SIMILARITY), each pairing a type name with the configuration record it deserializes into. Adding a fourth means adding an enum constant, a ChatFilter<T> subclass and a rebuild.
The T is the filter's own @ConfigSerializable configuration record, and enabled plus the shared Actions block (log, notification-channel, cancel, replacement, custom-message, actions) come from the base class.
To run the configured filters against arbitrary text without going through chat:
FilterResult factories, for an implementation:
Factory | Meaning |
|---|---|
| Pass through. |
| Match without a reason. |
| Match with a reason string (used by |
| Match with a replacement component for the broadcast. |
Reading per-player state
PlayerChatData is persisted by AstralSync — pull it through SyncAPI:
Mutating these flags directly bypasses the user-facing confirmation messages — use the action types from Actions for normal flows; only touch the snapshot directly for admin tooling.
Member | Meaning |
|---|---|
| Subscribed channel names (an immutable copy; mutate with |
|
|
| The equipped tag's id, or |
| The |
| The |
| The |
| Per-channel timestamp of the player's last message, backing the cooldowns. |
Moderation
analyze returns null when the classifier is disabled or the content is blank, and answers identical content from a 60-second in-memory cache. To record a decision of your own, build a FlaggedMessage through its builder and insert it via plugin.autoModeration().repository(); to apply a human verdict, call plugin.autoModeration().review(id, ReviewLabel.TOXIC, reviewerId). See Auto Moderation.