Skip to main content

Event Bus

XDiscordUltimate ships its own lightweight event bus: com.xreatlabs.xdiscordultimate.events.XDiscordEventBus. It is not the Bukkit event system — there are no @EventHandler annotations, no Listener interface, and events do not extend Event. Listeners are plain objects and events are plain POJOs.

How Dispatch Works

The bus keeps a CopyOnWriteArrayList of listeners. When you call publish(event), it reflects over each listener’s declared methods and invokes any method that takes a single argument isInstance(event):
java.lang.reflect.Method[] methods = listener.getClass().getDeclaredMethods();
for (Method method : methods) {
    if (method.getParameterCount() == 1
        && method.getParameterTypes()[0].isInstance(event)) {
        method.setAccessible(true);
        method.invoke(listener, event);
    }
}
Consequences worth knowing:
  • A listener is any object with one-argument methods named however you like.
  • Method name and annotations are ignored — only the parameter type matters.
  • Private methods are called (the bus calls setAccessible(true)).
  • Multiple methods accepting the same event type are all invoked.

API

public static void register(Object listener);
public static void unregister(Object listener);
public static void publish(Object event);
public static void clear();
public static int getListenerCount();

Listening for Verification

The built-in events are PlayerVerifiedEvent and PlayerUnlinkedEvent. Register your listener object in onEnable, unregister it in onDisable:
import com.xreatlabs.xdiscordultimate.XDiscordUltimate;
import com.xreatlabs.xdiscordultimate.events.XDiscordEventBus;
import com.xreatlabs.xdiscordultimate.events.PlayerVerifiedEvent;
import com.xreatlabs.xdiscordultimate.events.PlayerUnlinkedEvent;
import org.bukkit.plugin.java.JavaPlugin;

public class MyPlugin extends JavaPlugin {

    private final VerificationListener listener = new VerificationListener();

    @Override
    public void onEnable() {
        if (XDiscordUltimate.getInstance() != null) {
            XDiscordEventBus.register(listener);
        }
    }

    @Override
    public void onDisable() {
        XDiscordEventBus.unregister(listener);
    }

    public static class VerificationListener {

        public void onVerified(PlayerVerifiedEvent event) {
            getLogger().info(event.getPlayerName()
                + " verified as @" + event.getDiscordUsername());
        }

        public void onUnlinked(PlayerUnlinkedEvent event) {
            getLogger().info("Unlinked: " + event.getPlayerName());
        }
    }
}

PlayerVerifiedEvent Fields

public PlayerVerifiedEvent(UUID playerUuid,
                           String playerName,
                           String discordId,
                           String discordUsername);
GetterTypeDescription
getPlayerUuid()UUIDMinecraft UUID
getPlayerName()StringMinecraft username
getDiscordId()StringDiscord snowflake
getDiscordUsername()StringDiscord display name
getTimestamp()longEpoch ms when the event fired

Publishing Your Own Events

Any POJO works. Construct it, publish it, and every registered listener with a matching single-argument method receives it:
public class DonationReceivedEvent {
    private final UUID player;
    private final double amount;

    public DonationReceivedEvent(UUID player, double amount) {
        this.player = player;
        this.amount = amount;
    }

    public UUID getPlayer() { return player; }
    public double getAmount() { return amount; }
}

// elsewhere
XDiscordEventBus.publish(new DonationReceivedEvent(player.getUniqueId(), 5.00));
Dispatch is synchronous and runs on whatever thread called publish. Keep handlers fast — no database queries, no blocking I/O, no HTTP. If a handler needs to do slow work, hand it off to your own async task inside the handler and return immediately.

Next Steps

Database API

Look up linked accounts when an event fires.

Modules

Build a full module on top of the event bus and services.