Dispatching Events
This guide covers how to fire events from your code.
Getting the EventBus
Section titled “Getting the EventBus”Access the event bus through the server instance:
IEventBus eventBus = HytaleServer.get().getEventBus();Basic Dispatch Patterns
Section titled “Basic Dispatch Patterns”Simple Dispatch (No-Arg Event)
Section titled “Simple Dispatch (No-Arg Event)”For events with a no-argument constructor:
eventBus.dispatch(BootEvent.class);Dispatch with Event Instance
Section titled “Dispatch with Event Instance”For events that require constructor arguments:
MyEvent event = new MyEvent(data);eventBus.dispatchFor(MyEvent.class).dispatch(event);Keyed Event Dispatch
Section titled “Keyed Event Dispatch”For events with a KeyType other than Void, provide the key:
// dispatch to listeners registered for "adventure" world// global listeners also receive thiseventBus.dispatchFor(ZoneEnterEvent.class, world.getName()) .dispatch(new ZoneEnterEvent(world, player, zoneName));Async Event Dispatch
Section titled “Async Event Dispatch”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()); } });Handling Cancellable Events
Section titled “Handling Cancellable Events”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 handlersactuallyTeleport(player, event.getDestination());Reading Modified Values
Section titled “Reading Modified Values”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());}Performance Optimization: hasListener()
Section titled “Performance Optimization: hasListener()”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.
Complete Examples
Section titled “Complete Examples”Example: Custom Teleport System
Section titled “Example: Custom Teleport System”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; }}Example: Async Chat Processing
Section titled “Example: Async Chat Processing”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()); } }); }}Example: Keyed Minigame Events
Section titled “Example: Keyed Minigame Events”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)); }}Dispatch Patterns Summary
Section titled “Dispatch Patterns Summary”| Pattern | Use 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 |