Skip to content

Working with the Kelp event utils

PXAV edited this page Feb 4, 2021 · 3 revisions

This tutorial teaches how event handling is changed when using Kelp.

Using @EventHandler

Of course, you can still use the standard way of handling events:

@EventHandler
public void handlePlayerInteraction(PlayerInteractEvent event) {
  // handle your event
}

But your class does not have to implement the Listener interface anymore. You can use this annotation wherever you want without registering it. You only have to register all listeners in a package once on plugin startup (in your onEnable() method):

injector.getInstance(EventHandlerRegistration.class).initialize("de.pxav.artifactId");

Using @Subscribes

Methods annotated with @Subscribes(eventClass) are executed every time one of the given events is triggered. This allows you to reuse them in your code if you only have simple operations in it. Example:

@Subscribes({PlayerJoinEvent.class, PlayerQuitEvent.class})
public void updateOnlineCount() {
  kelpServer.getOnlinePlayers().forEach(current -> {
    current.sendBossBar("Online players: " + kelpServer.getOnlinePlayers().size());
  });
}

This method updates the player count in the boss bar of all players on the server.

Similar to the normal event handlers, subscriptions have to be registered once for a package:

injector.getInstance(KelpEventRepository.class).detectSubscriptions("de.pxav.artifactId"); // (your package names)

But be careful with parameters used by your annotated method. Currently, it is supported to have a Player or KelpPlayer parameter if you use any PlayerEvent or KelpPlayerEvent. If you use another event type or have multiple parameters, don't use the annotation.

Dynamic event registration

You can also create new event handlers (and unregister them) during the server runtime using KelpListener:

KelpListener.listen(PlayerInteractEvent.class)
  .handle(interaction -> {
    interaction.getPlayer().sendMessage("Tracked interaction!");
    interaction.getPlayer().sendMessage("Another example message");
   });

Those listeners can be created and removed dynamically during server runtime and don't have to be registered.

The handle method returns a UUID, which can be used to unregister the listener:

KelpEventRepository#removeListener(listenerId);

Using critera

You can define unlimited criteria, which have to be fulfilled so that the event handler is called. This is useful to increase readability because you don't clutter all checks into your handler.

KelpListener.listen(PlayerInteractEvent.class)
  .criterion(interaction -> interaction.getAction() == Action.RIGHT_CLICK_BLOCK)
  .handle(interaction 
    -> interaction.getPlayer().sendMessage("Tracked right click block interaction!"));

The class EventCriteria provides some default criteria that can be used so that you don't always have to create your criteria predicates yourself. An example would be:

KelpListener.listen(KelpPlayerUpdateSettingsEvent.class)
  .criterion(KelpPlayerUpdateSettingsEvent::hasLanguageChanged)
  .criterion(EventCriteria.playerHasPermission("system.admin"))
  .handle(change -> {
    KelpPlayer player = change.getPlayer();
    player.sendMessage("It seems like you have changed your client language.");
    player.sendMessage("Dou you want to change the language of the Admin Tools as well?");
  });

This example checks if the language has changed and the player is an admin. You can assign as many criteria as you want.

Letting a listener expire

You can define certain conditions/criteria, which will cause the listener to unregister itself. Some examples are:

KelpListener.listen(KelpPlayerLoginEvent.class)
  .expireAfterExecutions(5)
  .handle(login -> {
    KelpPlayer player = login.getPlayer();
    // do something with the player
  });

This example handles 5 logins and will then unregister itself.

KelpListener.listen(KelpPlayerLoginEvent.class)
  .expireAfter(2, TimeUnit.MINUTES)
  .handle(login -> {
    KelpPlayer player = login.getPlayer();
    // do something with the player
  });

The listener will be active for two minutes and after that, the event won't be handled anymore.

KelpListener.listen(KelpPlayerLoginEvent.class)
  .expireIf(login -> login.getMessage().equalsIgnoreCase("..."))
  .handle(login -> {
    KelpPlayer player = login.getPlayer();
    // do something with the player
  });

This will check if the login message is equal to another string and then unregister the listener. If you do not specify when Kelp should check for the changes (like in this example), it will always check before the handler is executed. By appending a ConditionalExpiryTestStage you can say whether it should be checked after the handler or always (before and after the handler). You can also use EventCriteria here.

Minimal executions

KelpListener.listen(KelpPlayerLoginEvent.class)
  .expireIf(login -> login.getMessage().equalsIgnoreCase("..."))
  .minimalExecutions(5)
  .handle(login -> {
    KelpPlayer player = login.getPlayer();
    // do something with the player
  });

This listener will be called 5 times and only after that, the conditional expiry will be checked. The only expiry that has a higher priority is the scheduled expiry.

Clone this wiki locally