Skip to content

Events Guide

Events let your plugin react when something happens on the proxy — a player logs in, sends a chat message, gets transferred, or pings the server. WaterdogPE calls every interested handler when an event fires, and some events let you cancel or modify what happens next.

All event classes live in dev.waterdog.waterdogpe.event (the framework) and dev.waterdog.waterdogpe.event.defaults (the built-in events).

Subscribing to an event

You subscribe through the EventManager, which you reach with proxy.getEventManager(). Do this in your plugin's onEnable():

java
import dev.waterdog.waterdogpe.event.defaults.PlayerChatEvent;
import dev.waterdog.waterdogpe.player.ProxiedPlayer;

@Override
public void onEnable() {
    this.getProxy().getEventManager()
        .subscribe(PlayerChatEvent.class, this::onChat);
}

private void onChat(PlayerChatEvent event) {
    ProxiedPlayer player = event.getPlayer();

    if (event.getMessage().contains("badword")) {
        event.setCancelled(true);              // block the message
        player.sendMessage("§cWatch your language!");
    }
}

The two arguments are the event class and a handler — any method that takes the event as its single parameter (this::onChat is a method reference; a lambda works too).

Event priority

When several handlers listen to the same event, you can control their order with an EventPriority. Lower priorities run first, so higher-priority handlers see (and can override) the result:

java
import dev.waterdog.waterdogpe.event.EventPriority;

this.getProxy().getEventManager()
    .subscribe(PlayerChatEvent.class, this::onChat, EventPriority.HIGHEST);

Priorities, from first to last: LOWEST, LOW, NORMAL (the default), HIGH, HIGHEST.

Cancelling events

Events that implement CancellableEvent can be cancelled to stop the action they represent:

java
event.setCancelled(true);     // or simply event.setCancelled();
boolean cancelled = event.isCancelled();

Calling setCancelled on an event that is not cancellable throws an exception, so only cancel the events marked cancellable in the reference table below.

Async events

Some events are annotated @AsyncEvent. Their handlers run on a background thread pool instead of the main thread, which is ideal for work that doesn't need to block the connection (and for handlers that don't change anything).

For async (and other "completable") events, callEvent returns a CompletableFuture you can chain on:

java
this.getProxy().getEventManager().callEvent(event)
    .whenComplete((completedEvent, error) -> {
        // runs once every handler has finished
    });

For ordinary (synchronous) events, callEvent returns null.

Calling your own events

You can define and fire your own events, too. Create a class extending dev.waterdog.waterdogpe.event.Event (implement CancellableEvent if it should be cancellable, add @AsyncEvent if handlers should run off-thread), then:

java
MyCustomEvent event = new MyCustomEvent(...);
this.getProxy().getEventManager().callEvent(event);
if (event.isCancelled()) {
    // a handler cancelled it
}

Event reference

Every event below is in dev.waterdog.waterdogpe.event.defaults. Player events extend PlayerEvent, so they all expose getPlayer().

Connection & lifecycle

EventCancellableAsyncFires when…Key methods
ProxyStartEventThe proxy has started and bound its listener.getProxy()
PreClientDataSetEventA player's login data is decoded, before the player object exists.getClientData(), getXuid(), getUuid(), getDisplayName()
PlayerAuthenticatedEventThe ProxiedPlayer is created from the login packet.getLoginData(), getAddress(), setCancelReason()
PlayerLoginEventRight before the player connects to their initial server. Cancel to deny login.getPlayer(), setCancelReason(String)
InitialServerDeterminedEventThe player's first server has been decided.getInitialServer()
InitialServerConnectedEventThe player has logged into their first server.getConnection(), getServerInfo()
PlayerDisconnectedEventA player disconnects or is kicked.getReason()

Servers & transfers

EventCancellableAsyncFires when…Key methods
ServerTransferRequestEventA transfer to another server is requested (e.g. via player.connect). Cancel to block, or change the target.getTargetServer(), setTargetServer(ServerInfo)
ServerConnectedEventA player has connected to a (non-initial) server.getConnection(), getTargetServer()
ServerTransferEventThe transfer is starting.getSourceServer(), getTargetServer(), setTransferScreenAllowed(boolean)
TransferCompleteEventThe player is now on the new server and the old connection is dropped.getSourceServer(), getTargetServer(), getConnection()
PostTransferCompleteEventThe player has fully spawned on the new server.getConnection()
FastTransferRequestEventA "fast transfer" is requested by a downstream server.getServerInfo(), getAddress(), getPort()

Chat, commands & permissions

EventCancellableAsyncFires when…Key methods
PlayerChatEventA player sends a chat message. Cancel to block, or edit it.getMessage(), setMessage(String)
DispatchCommandEventA player runs a proxy command. Cancel to block it.getSender(), getCommand(), getArgs()
PlayerPermissionCheckEventplayer.hasPermission(...) is called. Override the result here.getPermission(), hasPermission(), setHasPermission(boolean)

Pings, queries & resource packs

EventCancellableAsyncFires when…Key methods
ProxyPingEventA client pings the proxy (server-list). Customise the MOTD and counts.getMotd()/setMotd(), getPlayerCount()/setPlayerCount(), getMaximumPlayerCount(), setVersion()
ProxyQueryEventA query request is received (extends ProxyPingEvent).getMap(), setHasWhitelist(boolean)
PlayerResourcePackInfoSendEventBefore the resource-pack info packet is sent to a player.getPacket(), setPacket(...)
PlayerResourcePackApplyEventThe resource pack stack is applied.getStackPacket(), setStackPacket(...)
ResourcePacksRebuildEventResource packs are rebuilt.getPacksInfoPacket(), getStackPacket()
IncompatibleProtocolEventA client with an unsupported protocol version connects.getProtocolVersion(), setDisconnectMessage(...)

Common recipes

Welcome a player when they join their first server:

java
events.subscribe(InitialServerConnectedEvent.class, event ->
    event.getPlayer().sendMessage("§aWelcome to the network!"));

Customise the server-list MOTD and player count:

java
events.subscribe(ProxyPingEvent.class, event -> {
    event.setMotd("§bMy Network");
    event.setPlayerCount(event.getPlayers().size());
    event.setMaximumPlayerCount(1000);
});

Deny login for banned players:

java
events.subscribe(PlayerLoginEvent.class, event -> {
    if (isBanned(event.getPlayer().getXuid())) {
        event.setCancelReason("§cYou are banned.");
        event.setCancelled(true);
    }
});

Keep handlers fast, especially for synchronous events on the connection path (login, transfers, pings). Don't run slow database or network calls directly inside them — do that work in the background (see Scheduling Tasks) and cache the results, or use an @AsyncEvent handler where appropriate.

Released under the GPL-3.0 License.