Skip to content

Dispatching Events

This guide covers how to fire events from your code.

Access the event bus through the server instance:

IEventBus eventBus = HytaleServer.get().getEventBus();

For events with a no-argument constructor:

eventBus.dispatch(BootEvent.class);

For events that require constructor arguments:

MyEvent event = new MyEvent(data);
eventBus.dispatchFor(MyEvent.class).dispatch(event);

For events with a KeyType other than Void, provide the key:

// dispatch to listeners registered for "adventure" world
// global listeners also receive this
eventBus.dispatchFor(ZoneEnterEvent.class, world.getName())
.dispatch(new ZoneEnterEvent(world, player, zoneName));

For IAsyncEvent types, use dispatchForAsync():

eventBus.dispatchForAsync(PlayerChatEvent.class)
.dispatch(new PlayerChatEvent(sender, targets, message))
.whenComplete((event, error) -> {
if (error != null) {
getLogger().error("Chat event error", error);
return;
}
if (!event.isCancelled()) {
broadcastMessage(event.getTargets(), event.getContent());
}
});

For events implementing ICancellable, check the cancelled state after dispatch:

PlayerTeleportEvent event = new PlayerTeleportEvent(player, destination);
eventBus.dispatchFor(PlayerTeleportEvent.class).dispatch(event);
if (event.isCancelled()) {
sendMessage(player, "Teleport was blocked!");
return;
}
// proceed with the action - destination may have been modified by handlers
actuallyTeleport(player, event.getDestination());

Handlers may modify mutable fields on events. Always read values from the event after dispatch:

PlayerTeleportEvent event = new PlayerTeleportEvent(player, originalDestination);
eventBus.dispatchFor(PlayerTeleportEvent.class).dispatch(event);
if (!event.isCancelled()) {
// use the potentially-modified destination, not originalDestination
performTeleport(player, event.getDestination());
}

Dispatching to no listeners is safe - the event bus returns a no-op dispatcher internally. However, if event construction is expensive, you can check first:

IEventDispatcher<ExpensiveEvent, ExpensiveEvent> dispatcher =
eventBus.dispatchFor(ExpensiveEvent.class);
if (dispatcher.hasListener()) {
// only compute expensive data if someone will handle it
ExpensiveEvent event = new ExpensiveEvent(computeExpensiveData());
dispatcher.dispatch(event);
}

This is optional - only useful when:

  • Event construction involves expensive computation
  • The event fires very frequently (every tick, every inventory change)

For simple events, just dispatch directly.

public class TeleportManager {
public boolean teleportPlayer(PlayerRef player, Vector3d destination) {
IEventBus eventBus = HytaleServer.get().getEventBus();
PlayerTeleportEvent event = new PlayerTeleportEvent(player, destination);
eventBus.dispatchFor(PlayerTeleportEvent.class).dispatch(event);
if (event.isCancelled()) {
return false;
}
performTeleport(player, event.getDestination());
return true;
}
}
public class ChatManager {
public void handleChat(PlayerRef sender, String message) {
IEventBus eventBus = HytaleServer.get().getEventBus();
PlayerChatEvent event = new PlayerChatEvent(sender, getAllOnlinePlayers(), message);
eventBus.dispatchForAsync(PlayerChatEvent.class)
.dispatch(event)
.whenComplete((processedEvent, error) -> {
if (error != null) {
getLogger().error("Chat processing error", error);
return;
}
if (processedEvent.isCancelled()) {
sendToPlayer(sender, "Your message was blocked.");
return;
}
for (PlayerRef target : processedEvent.getTargets()) {
sendToPlayer(target, processedEvent.getContent());
}
});
}
}
public class MinigameManager {
public void startMinigame(String minigameId, List<PlayerRef> players) {
IEventBus eventBus = HytaleServer.get().getEventBus();
// keyed by minigame ID - only listeners for this minigame receive it
eventBus.dispatchFor(MinigameStartEvent.class, minigameId)
.dispatch(new MinigameStartEvent(minigameId, players));
}
public void endMinigame(String minigameId, PlayerRef winner, int durationSeconds) {
IEventBus eventBus = HytaleServer.get().getEventBus();
eventBus.dispatchFor(MinigameEndEvent.class, minigameId)
.dispatch(new MinigameEndEvent(minigameId, winner, durationSeconds));
}
}
PatternUse Case
dispatch(Event.class)Simple no-arg events
dispatchFor(Event.class).dispatch(event)Events with arguments
dispatchFor(Event.class, key).dispatch(event)Keyed events
dispatchForAsync(Event.class).dispatch(event)Async events
dispatcher.hasListener()Optional optimization for expensive events