Astral Realms Documentation Help

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

<dependency> <groupId>com.astralrealms</groupId> <artifactId>chat</artifactId> <version>1.0-SNAPSHOT</version> <scope>provided</scope> </dependency>

Repository: https://maven.astralrealms.fr/repository/maven-public/.

Plugin handle

import com.astralrealms.chat.AstralChat; AstralChat plugin = AstralChat.getPlugin(AstralChat.class);

Services

Every service is exposed via a Lombok-generated getter on the plugin instance.

Getter

Type

Use

plugin.channels()

ChannelService

Broadcast into a channel, pause/resume, network packet helpers.

plugin.chat()

PaperChatService

Render and broadcast components to channel subscribers. Implements the shared ChatService interface.

plugin.privateMessages()

PrivateMessageService

Programmatically send a PM.

plugin.ignores()

IgnoreService (impl: IgnoreServiceImpl)

Read and mutate ignore relationships. Shared via the AstralCore service repository.

plugin.filters()

FilterService

Run filters; register custom filters.

plugin.mentions()

MentionService

Dispatch a mention notification programmatically.

plugin.tags()

TagService

Look up a tag by id; iterate all tags.

plugin.players()

PlayerService

Subscription state, cached PlayerChatData.

plugin.moderation()

ModerationService

Per-channel cooldown bookkeeping.

plugin.configuration()

MainConfiguration

Loaded config.yml. Call findChannel, defaultChannel, isEnabled.

plugin.groupsConfiguration()

GroupsConfiguration

Loaded groups.yml.

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:

AstralPaperAPI.getService(ChatService.class) .ifPresent(chat -> chat.broadcastChatMessage(player, "global", component, raw)); AstralPaperAPI.getService(IgnoreService.class) .ifPresent(ignores -> ignores.isIgnoring(viewer, candidate));

Broadcasting

ChatChannel channel = plugin.configuration().findChannel("global").orElseThrow(); Component message = Component.text("Server restart in 5 minutes", NamedTextColor.RED); plugin.channels().broadcast(channel, message);

For a fully-rendered chat message that respects pause and cooldown, use the chat service:

plugin.chat().broadcastChatMessage(sender, "global", component, rawString);

Sending a private message

plugin.privateMessages() .sendPrivateMessage(sender, recipient, "Hello!");

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 an async cancellable Bukkit event fired by DefaultChannelChatListener after rendering and before viewer fan-out.

import com.astralrealms.chat.event.ChannelChatEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import net.kyori.adventure.text.Component; public class ExampleListener implements Listener { @EventHandler public void onChannelChat(ChannelChatEvent event) { Player sender = event.getPlayer(); String raw = event.getMessage(); Component component = event.getComponent(); ChatChannel channel = event.getChannel(); // Rewrite — replace the broadcast component event.setComponent(component.append(Component.text(" *edited*"))); // Or cancel — sender's message never reaches subscribers if (raw.contains("forbidden")) { event.setCancelled(true); } } }

Method

Notes

getPlayer()

Sender.

getMessage()

Raw string the player typed (pre-filter).

getComponent()/setComponent(Component)

The rendered component about to be broadcast.

getChannel()

The ChatChannel.

isCancelled()/setCancelled(boolean)

Inherited.

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.

Registering a custom filter

import com.astralrealms.chat.filters.ChatFilter; import com.astralrealms.chat.filters.FilterResult; import org.bukkit.entity.Player; public class CustomFilter extends ChatFilter { public CustomFilter() { super("custom", List.of()); } @Override public FilterResult filter(String message, Player player) { if (message.contains("blocked")) return FilterResult.match("custom filter matched"); return FilterResult.noMatch(); } } // During onEnable, after AstralChat is loaded plugin.filters().registerFilter(new CustomFilter());

FilterResult factories:

Factory

Meaning

FilterResult.noMatch()

Pass through.

FilterResult.match()

Match without a reason.

FilterResult.match(String)

Match with a reason string (used by notification-channel templates).

FilterResult.match(String, Component)

Match with a replacement component for the broadcast.

Reading per-player state

PlayerChatData is persisted by AstralSync — pull it through SyncAPI:

import com.astralrealms.chat.snapshot.PlayerChatData; import com.astralrealms.sync.SyncAPI; SyncAPI.findData(player.getUniqueId(), PlayerChatData.class) .ifPresent(data -> { boolean pmOn = data.privateMessagesEnabled(); String tag = data.chatTag(); Set<String> subs = data.subscribedChannels(); });

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.

Last modified: 25 July 2026