Event Registration
Register event listeners in your plugin's start() method using the EventRegistry:
1@Override2protected void start() {3 // Method reference style4 getEventRegistry().register(5 PlayerConnectEvent.class, 6 this::onPlayerConnect7 );8 9 // Lambda style10 getEventRegistry().register(11 PlayerDisconnectEvent.class, 12 event -> {13 getLogger().info(event.getPlayer().getName() + " left");14 }15 );16}Player Events
| event | trigger | keyed? | key data |
|---|---|---|---|
| PlayerConnectEvent | Player joins server | No | player, playerRef, world |
| PlayerReadyEvent | Player fully loaded | Yes (world) | player, ref |
| PlayerDisconnectEvent | Player leaves server | No | player, reason |
| PlayerChatEvent | Player sends chat | Yes (world) | sender, content (async!) |
| PlayerInteractEvent | Player interacts | Yes (world) | actionType, itemInHand |
| PlayerMouseButtonEvent | Mouse click | ? | player, button |
| PlayerCraftEvent | Player crafts item | ? | player, recipe |
keyed events
Events marked "Keyed" require a key (usually world name) during registration, or use
registerGlobal() to listen across all worlds.Block & World Events
| event | trigger | key methods |
|---|---|---|
| BreakBlockEvent | Block fully broken | getBlockType(), getTargetBlock(), getItemInHand() |
| DamageBlockEvent | Block being mined | getBlockType(), getDamage(), setDamage() |
| PlaceBlockEvent | Block placed | getBlockType(), getTargetBlock() |
| UseBlockEvent | Block interacted | Pre and Post variants |
| DropItemEvent | Item dropped | PlayerRequest, Drop variants |
Block Break Example
1import com.hypixel.hytale.server.core.event.events.ecs.BreakBlockEvent;23getEventRegistry().register(BreakBlockEvent.class, event -> {4 BlockType type = event.getBlockType();5 Vector3i pos = event.getTargetBlock();6 ItemStack tool = event.getItemInHand();7 8 // Check for specific block (e.g. ore)9 if (type.getName().contains("ore")) {10 // Handle ore mining11 }12 13 // Cancel to prevent breaking14 event.setCancelled(true);15});Entity Events
| event | trigger | notes |
|---|---|---|
| EntityRemoveEvent | Entity removed from world | Use for death detection |
| LivingEntityInventoryChangeEvent | Inventory changed | |
| LivingEntityUseBlockEvent | Entity uses block |
no direct death event
There's no simple
EntityDeathEvent. For mob kills, use EntityRemoveEventor look into KillFeedEvent (internal ECS, more complex).Other Events
| event | trigger |
|---|---|
| ChangeGameModeEvent | Gamemode changed |
| CraftRecipeEvent | Item crafted (Pre/Post) |
| DiscoverZoneEvent | Zone discovered |
| SwitchActiveSlotEvent | Hotbar slot changed |
| BootEvent / ShutdownEvent | Server start/stop |
discover more events
Run
jar tf HytaleServer.jar | grep -i event to list all available events.Event Handler Patterns
Player Connect Handler
1private void onPlayerConnect(PlayerConnectEvent event) {2 Player player = event.getPlayer();3 String name = player.getName();4 UUID uuid = player.getUuid();5 6 getLogger().info("Player connected: " + name);7 8 // Send welcome message (thread-safe)9 sendWelcome(player);10 11 // Modify player (needs world.execute)12 player.getWorld().execute(() -> {13 setupNewPlayer(player);14 });15}1617private void sendWelcome(Player player) {18 FormattedMessage msg = createMessage("Welcome to the server!");19 player.getPlayerConnection().write(20 new ShowEventTitle(0.5f, 0.5f, 2.0f, null, true, msg, null)21 );22}Chat Handler with Cancellation
async event
PlayerChatEvent is async. Use thread-safe collections and be careful with world access.
1// Note: PlayerChatEvent uses getSender() and getContent(), not getPlayer()/getMessage()2private void onPlayerChat(PlayerChatEvent event) {3 PlayerRef sender = event.getSender();4 String content = event.getContent();5 6 // Filter bad words7 if (containsBadWords(content)) {8 event.setCancelled(true);9 return;10 }11 12 // Log chat13 getLogger().at(Level.INFO).log("[CHAT] %s: %s", sender.getUuid(), content);14}Event Priority
Control event handling order with priority:
1// First priority - runs first2getEventRegistry().register(3 PlayerConnectEvent.class,4 EventPriority.FIRST,5 this::onConnectFirst6);78// Normal priority (default)9getEventRegistry().register(10 PlayerConnectEvent.class,11 this::onConnectNormal12);1314// Last priority - runs last15getEventRegistry().register(16 PlayerConnectEvent.class,17 EventPriority.LAST,18 this::onConnectLast19);| priority | order | use case |
|---|---|---|
| FIRST | First | Logging, metrics |
| EARLY | Second | Security checks, filters |
| NORMAL | Middle | Standard handling |
| LATE | Fourth | Post-processing |
| LAST | Last | Final cleanup |
not bukkit!
Hytale uses FIRST/EARLY/NORMAL/LATE/LAST, not HIGHEST/HIGH/NORMAL/LOW/LOWEST.
Cancellable Events
Some events can be cancelled to prevent the action:
1private void onBlockBreak(BlockBreakEvent event) {2 Player player = event.getPlayer();3 Block block = event.getBlock();4 5 // Protect spawn area6 if (isInSpawnArea(event.getPosition())) {7 event.setCancelled(true);8 player.sendMessage("&cYou cannot break blocks here!");9 return;10 }11 12 // Log legitimate breaks13 getLogger().info(player.getName() + " broke " + block.getType());14}check cancellation
Always check
event.isCancelled() if your handler runs after others that might have cancelled the event.Unregistering Events
Clean up event listeners when no longer needed:
1private EventRegistration connectHandler; 23@Override4protected void start() {5 // Store registration for later removal6 connectHandler = getEventRegistry().register(7 PlayerConnectEvent.class,8 this::onConnect9 );10}1112@Override13protected void shutdown() {14 // Unregister when plugin stops15 if (connectHandler != null) {16 connectHandler.unregister();17 }18}