Event Listener
The event listener of UltiTools module is basically the same as Bukkit's event listener.
Please refer to Bukkit Event Listener.
Create a Listener
Create a class that implements Listener and add @EventHandler annotation to the method that handles the event.
@EventListener
public class BackListener implements Listener {
@EventHandler
public void onPlayerDeath(PlayerDeathEvent event) {
...
}
}The @EventListener annotation has an optional manualRegister parameter (default false). For listeners loaded through the standard module JAR path (as with @UltiToolsModule), setting manualRegister to true means component scanning skips automatic registration for that listener: you must register it manually via getListenerManager().register(this, YourListener.class).
Register Event Listener
Register the listener in registerSelf of the class that inherits UltiToolsPlugin.
The six-parameter connector constructor is marked for removal
The example below calls the six-parameter UltiToolsPlugin constructor, which carries @Deprecated(since = "6.0.8", forRemoval = true) and hardcodes the resource folder path, so javac reports a removal warning on every build. Move the integration to the External Plugin API and call UltiToolsAPI.connect from your own JavaPlugin, or keep the connector and call the seven-parameter constructor passing resourceFolderPath yourself: both are supported on v6.2.5. The replacement signature for connectors is still being decided in issue #217, and the removal itself is tracked in issue #213.
package com.ultikits.docs.listener;
import com.ultikits.ultitools.abstracts.UltiToolsPlugin;
import com.ultikits.ultitools.abstracts.data.AuditableDataEntity;
import com.ultikits.ultitools.abstracts.data.BaseDataEntity;
import com.ultikits.ultitools.annotations.*;
import com.ultikits.ultitools.interfaces.DataOperator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.bukkit.entity.Player;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class UltiToolsConnector extends UltiToolsPlugin {
public UltiToolsConnector(String pluginName, String version, List<String> authors, List<String> loadAfter, int minUltiToolsVersion, String mainClass) {
super(pluginName, version, authors, loadAfter, minUltiToolsVersion, mainClass);
}
@Override
public boolean registerSelf() throws IOException {
// register listener
getListenerManager().register(this, SomeListener.class);
return true;
}
@Override
public void unregisterSelf() {
}
@Override
public void reloadSelf() {
super.reloadSelf();
}
}Sure, you can also use the automatic registration function provided by UltiTools. For details, please refer to this article.
Temporary Listener
Many times we just need to listen to events temporarily. In traditional plugin development, we often maintain a list to record the players who need to listen temporarily, which is very troublesome.
UltiTools encapsulates Bukkit's event listener, so you can listen to events anywhere, which is very convenient and automatic.
Temporary Listener Builder
Starting with v6.1.0, use the modern TempListener builder API for cleaner, more flexible temporary listeners:
// Simple usage - listen to all block interactions
TempListener.common(PlayerInteractEvent.class)
.listen(event -> {
player.sendMessage("You clicked a block!");
return true; // return true to auto-unregister
});Builder Methods:
eventHandler(TempEventHandler<E> handler)— Sets the event handler. Returnstrueto auto-unregister,falseto continue listening.filter(Function<E, Boolean> filter)— Add a pre-handler filter. Returnstrueto handle the event,falseto ignore it.priority(EventPriority priority)— Set handler priority (default:NORMAL).build()— Build and return theTempListener(manualregister()required).listen(TempEventHandler<E> handler)— Build and immediately register in one call.
build() passes your filter through
As of v6.3.0, .filter(x).build() is the single recommended way to get a listener that both filters and can be unregistered: build() calls the same four-argument SimpleTempListener constructor listen(...) already used, so the filter you set is applied, and calling register() on the returned TempListener gives you the handle to call unregister() on — one construction call, both capabilities, no second listener needed. Before v6.3.0, build() called a three-argument constructor that had no filter parameter, so a filter set through .filter(...) was silently discarded; listen(...) did pass the filter through, but returned void, with no handle to unregister. Both gaps are closed by the same fix.
Example: Wait for player to interact with a specific block type
// Listen for left-clicks on wooden blocks only
TempListener.common(PlayerInteractEvent.class)
.priority(EventPriority.HIGH)
.filter(event -> {
Block block = event.getClickedBlock();
return block != null && block.getType().name().contains("WOOD");
})
.listen(event -> {
event.getPlayer().sendMessage("You clicked a wooden block!");
return true; // auto-unregister after first match
});Example: Wait for chat response with timeout
// Listen for player chat
TempListener.common(AsyncPlayerChatEvent.class)
.filter(event -> event.getPlayer().equals(targetPlayer))
.listen(event -> {
String message = event.getMessage();
if (message.equalsIgnoreCase("yes")) {
processConfirmation(targetPlayer);
}
return true; // auto-unregister
});INFO
The TempEventHandler<E> is a functional interface that receives the event and returns a boolean:
- Return
trueto automatically unregister the listener after handling. - Return
falseto keep the listener active for subsequent events.
Legacy Temporary Listener (SimpleTempListener)
Four constructors deprecated for removal in Phase 7
As of v6.3.0, SimpleTempListener's no-argument constructor and its two- and three-argument overloads — including the no-filter (Class, TempEventHandler) shape used below — carry @Deprecated(since = "6.3.0", forRemoval = true) and are scheduled for removal in a future Phase 7 milestone. They confusably overlap: two three-argument overloads differ only in whether the last parameter is EventPriority or a filter Function, with no compile-time signal for picking the wrong one. Prefer the builder API above, or the four-argument all-args constructor new SimpleTempListener<>(eventClass, priority, handler, filter) directly, which is not deprecated.
The legacy direct instantiation approach using SimpleTempListener still works for the example below, but the constructor it calls is now on a removal track; the builder API is the recommended approach for new code:
// Legacy approach - still works, but its constructor is deprecated for removal in Phase 7
TempListener listener = new SimpleTempListener(PlayerInteractEvent.class, event -> {
// do something...
return true; // return true to unregister this listener
});
listener.register(); // start listeningFor player-specific events, the legacy PlayerTempListener is also deprecated. Use the builder with a filter instead:
// OLD (deprecated):
// TempListener listener = new PlayerTempListener<>(
// PlayerInteractEvent.class,
// event -> { /* ... */ return true; },
// targetPlayer
// );
// NEW (recommended):
TempListener.common(PlayerInteractEvent.class)
.filter(event -> event.getPlayer().equals(targetPlayer))
.listen(event -> { /* ... */ return true; });As of v6.3.0, .filter(x).build() (shown at the top of this section) is the recommended way to get a listener that both filters and can be unregistered by hand — you no longer need to construct SimpleTempListener directly for that combination.