Understanding Minestom Events

Concept explanation of Minestom's event-driven architecture for handling server actions

java (17+) 2025-11-03 minestom events listeners concepts

Description

Minestom uses an event-driven architecture where various server actions trigger events that can be listened to and handled by your code. This system allows you to intercept, modify, or cancel default behaviors.

Key Concepts

Event-Driven Architecture

Events are fired when specific actions occur in the server:

  • Player actions: Join, quit, chat, move, interact
  • Block actions: Place, break, interact
  • Entity actions: Spawn, damage, death
  • Server actions: Tick, startup, shutdown
  • Packet actions: Incoming/outgoing network packets

Event Listeners

Event listeners are functions that respond to events:

  • Registration: Register listeners with GlobalEventHandler
  • Execution: Listeners are called when events fire
  • Priority: Multiple listeners can handle the same event
  • Cancellation: Events can be cancelled to prevent default behavior
  • Modification: Event data can be modified before processing

Event Lifecycle

  1. Event creation: Event is created with relevant data
  2. Listener invocation: All registered listeners are called
  3. Event processing: Default behavior executes (if not cancelled)
  4. Event completion: Event is finished

Event Types

  • PlayerSpawnEvent: When player joins/spawns
  • PlayerDisconnectEvent: When player leaves
  • PlayerChatEvent: When player sends message
  • PlayerMoveEvent: When player moves
  • PlayerBlockBreakEvent: When player breaks block
  • PlayerBlockPlaceEvent: When player places block
  • EntityDamageEvent: When entity takes damage
  • EntityDeathEvent: When entity dies
  • ServerTickMonitorEvent: Every server tick

Event Cancellation

Events can be cancelled:

  • setCancelled(true): Prevents default behavior
  • isCancelled(): Check if event is cancelled
  • Cancelled events: Default behavior is skipped

Event Priority

Listeners can have priorities:

  • HIGHEST: Executes first
  • HIGH: Executes early
  • NORMAL: Default priority
  • LOW: Executes late
  • LOWEST: Executes last

Event Modification

Events contain mutable data:

  • Modify event properties: Change event data
  • Access event context: Get players, blocks, entities
  • Chain events: Trigger other events

Use Cases

  • Permission systems: Check permissions before actions
  • Chat filtering: Filter or modify chat messages
  • Custom mechanics: Implement game-specific rules
  • Logging: Log important events
  • Integration: Connect with external systems
  • Modification: Change default game behavior

Benefits

  • Modularity: Separate concerns into listeners
  • Flexibility: Easy to add/remove functionality
  • Extensibility: Plugins can add their own events
  • Control: Fine-grained control over server behavior

Best Practices

  • Register listeners at startup
  • Unregister listeners when no longer needed
  • Use appropriate priorities
  • Check event cancellation before processing
  • Don’t block the event thread with long operations
  • Handle exceptions gracefully
  • Document event behavior
  • Use event filters to reduce unnecessary processing

Code

RAW
// Get global event handlerGlobalEventHandler eventHandler = MinecraftServer.getGlobalEventHandler();// Register player join event listenereventHandler.addListener(PlayerSpawnEvent.class, event -> {    // This code runs when a player joins    if (event.getEntity() instanceof Player player) {        player.sendMessage("Welcome to the server!");    }});// Register chat event with modificationeventHandler.addListener(PlayerChatEvent.class, event -> {    // Modify chat format    String message = event.getMessage();    Player player = event.getPlayer();        // Cancel if message contains certain words    if (message.contains("spam")) {        event.setCancelled(true);        player.sendMessage("Your message was filtered");        return;    }        // Modify chat format    event.setChatFormat((sender, text) ->         Component.text("<" + sender.getUsername() + "> " + text)    );});// Register block break event with cancellationeventHandler.addListener(PlayerBlockBreakEvent.class, event -> {    Block block = event.getBlock();        // Prevent breaking certain blocks    if (block.compare(Block.BEDROCK)) {        event.setCancelled(true);        event.getPlayer().sendMessage("You cannot break bedrock!");    }});// Register event with priorityeventHandler.addListener(PlayerMoveEvent.class, EventPriority.HIGH, event -> {    // This listener runs early (HIGH priority)    Player player = event.getPlayer();        // Check boundaries    if (event.getNewPosition().y() < 0) {        event.setCancelled(true);        player.teleport(event.getPlayerPosition());    }});// Multiple listeners for same eventeventHandler.addListener(EntityDamageEvent.class, event -> {    // First listener: Log damage    System.out.println("Entity damaged: " + event.getDamage());});eventHandler.addListener(EntityDamageEvent.class, event -> {    // Second listener: Modify damage    if (event.getEntity() instanceof Player) {        event.setDamage(event.getDamage() * 0.5f); // Reduce damage by 50%    }});// Unregister listener (if you keep reference)EventListener<PlayerSpawnEvent> listener = event -> {    // Listener code};eventHandler.addListener(PlayerSpawnEvent.class, listener);// Later...eventHandler.removeListener(PlayerSpawnEvent.class, listener);

Comments

No comments yet. Be the first to comment!