5 min

Events

React to game events like player connections, chat messages, and world changes.

Event Registration

Register event listeners in your plugin's start() method using the EventRegistry:

1@Override
2protected void start() {
3 // Method reference style
4 getEventRegistry().register(
5 PlayerConnectEvent.class,
6 this::onPlayerConnect
7 );
8
9 // Lambda style
10 getEventRegistry().register(
11 PlayerDisconnectEvent.class,
12 event -> {
13 getLogger().info(event.getPlayer().getName() + " left");
14 }
15 );
16}

Player Events

eventtriggerkeyed?key data
PlayerConnectEventPlayer joins serverNoplayer, playerRef, world
PlayerReadyEventPlayer fully loadedYes (world)player, ref
PlayerDisconnectEventPlayer leaves serverNoplayer, reason
PlayerChatEventPlayer sends chatYes (world)sender, content (async!)
PlayerInteractEventPlayer interactsYes (world)actionType, itemInHand
PlayerMouseButtonEventMouse click?player, button
PlayerCraftEventPlayer 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

eventtriggerkey methods
BreakBlockEventBlock fully brokengetBlockType(), getTargetBlock(), getItemInHand()
DamageBlockEventBlock being minedgetBlockType(), getDamage(), setDamage()
PlaceBlockEventBlock placedgetBlockType(), getTargetBlock()
UseBlockEventBlock interactedPre and Post variants
DropItemEventItem droppedPlayerRequest, Drop variants

Block Break Example

1import com.hypixel.hytale.server.core.event.events.ecs.BreakBlockEvent;
2
3getEventRegistry().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 mining
11 }
12
13 // Cancel to prevent breaking
14 event.setCancelled(true);
15});

Entity Events

eventtriggernotes
EntityRemoveEventEntity removed from worldUse for death detection
LivingEntityInventoryChangeEventInventory changed
LivingEntityUseBlockEventEntity 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

eventtrigger
ChangeGameModeEventGamemode changed
CraftRecipeEventItem crafted (Pre/Post)
DiscoverZoneEventZone discovered
SwitchActiveSlotEventHotbar slot changed
BootEvent / ShutdownEventServer 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}
16
17private 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 words
7 if (containsBadWords(content)) {
8 event.setCancelled(true);
9 return;
10 }
11
12 // Log chat
13 getLogger().at(Level.INFO).log("[CHAT] %s: %s", sender.getUuid(), content);
14}

Event Priority

Control event handling order with priority:

1// First priority - runs first
2getEventRegistry().register(
3 PlayerConnectEvent.class,
4 EventPriority.FIRST,
5 this::onConnectFirst
6);
7
8// Normal priority (default)
9getEventRegistry().register(
10 PlayerConnectEvent.class,
11 this::onConnectNormal
12);
13
14// Last priority - runs last
15getEventRegistry().register(
16 PlayerConnectEvent.class,
17 EventPriority.LAST,
18 this::onConnectLast
19);
priorityorderuse case
FIRSTFirstLogging, metrics
EARLYSecondSecurity checks, filters
NORMALMiddleStandard handling
LATEFourthPost-processing
LASTLastFinal 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 area
6 if (isInSpawnArea(event.getPosition())) {
7 event.setCancelled(true);
8 player.sendMessage("&cYou cannot break blocks here!");
9 return;
10 }
11
12 // Log legitimate breaks
13 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;
2
3@Override
4protected void start() {
5 // Store registration for later removal
6 connectHandler = getEventRegistry().register(
7 PlayerConnectEvent.class,
8 this::onConnect
9 );
10}
11
12@Override
13protected void shutdown() {
14 // Unregister when plugin stops
15 if (connectHandler != null) {
16 connectHandler.unregister();
17 }
18}