--- title: Cancellable Events type: docs weight: 3 --- Some events implement the `ICancellable` interface, allowing you to prevent the default game behavior. ## The ICancellable Interface ```java public interface ICancellable { boolean isCancelled(); void setCancelled(boolean cancelled); } ``` ## ECS Cancellable Events ECS events use a similar interface `ICancellableEcsEvent`: ```java public interface ICancellableEcsEvent { boolean isCancelled(); void setCancelled(boolean cancelled); } ``` ## Cancelling Events ```java getEventRegistry().register(BreakBlockEvent.class, event -> { Vector3i position = event.getTargetBlock(); if (isProtectedArea(position)) { event.setCancelled(true); // Note: BreakBlockEvent doesn't have direct player access // Use ECS components if you need to message the player } }); ``` ## Checking Cancellation Status ```java getEventRegistry().register(EventPriority.LATE, BreakBlockEvent.class, event -> { if (event.isCancelled()) { // Another handler cancelled this event return; } // Process the event recordBlockBreak(event.getTargetBlock(), event.getBlockType()); }); ``` ## Common Cancellable Events ### Player Events | Event | Cancel Effect | |-------|---------------| | `PlayerSetupConnectEvent` | Prevents player from connecting | | `PlayerChatEvent` | Prevents message from being sent | | `PlayerMouseButtonEvent` | Prevents mouse button action | | `PlayerInteractEvent` | Prevents interaction (deprecated) | ### ECS Block Events | Event | Cancel Effect | |-------|---------------| | `BreakBlockEvent` | Prevents block from being broken | | `PlaceBlockEvent` | Prevents block from being placed | | `DamageBlockEvent` | Prevents damage to block | | `UseBlockEvent.Pre` | Prevents block use action | ### Other ECS Events | Event | Cancel Effect | |-------|---------------| | `DropItemEvent` | Prevents item from being dropped | | `CraftRecipeEvent` | Prevents crafting | ## Best Practices ### Check Before Acting Always check `isCancelled()` before performing actions: ```java getEventRegistry().register(BreakBlockEvent.class, event -> { // Check if already cancelled if (event.isCancelled()) { return; } // Your logic here if (shouldPrevent(event.getTargetBlock())) { event.setCancelled(true); } }); ``` ### Use Appropriate Priority ```java // Protection plugins should use EARLY getEventRegistry().register(EventPriority.EARLY, BreakBlockEvent.class, event -> { if (isProtected(event.getTargetBlock())) { event.setCancelled(true); } }); // Feature plugins should respect cancellation getEventRegistry().register(EventPriority.NORMAL, BreakBlockEvent.class, event -> { if (!event.isCancelled()) { giveBlockReward(event.getTargetBlock()); } }); // Logging should use LATE getEventRegistry().register(EventPriority.LATE, BreakBlockEvent.class, event -> { logBlockBreakAttempt(event.getTargetBlock(), event.isCancelled()); }); ``` ### Provide Feedback with Chat Events When cancelling chat events, you can notify the player: ```java // Note: PlayerChatEvent has String key, use registerAsyncGlobal() getEventRegistry().registerAsyncGlobal(PlayerChatEvent.class, future -> { return future.thenApply(event -> { if (containsBadWord(event.getContent())) { event.setCancelled(true); // Send message via PlayerRef (PlayerRef.sendMessage() works) event.getSender().sendMessage(Message.raw("Please don't use that word!")); } return event; }); }); ``` ## Uncancelling Events You can also uncancel an event that was previously cancelled: ```java getEventRegistry().register(EventPriority.LATE, BreakBlockEvent.class, event -> { // Override cancellation for certain block types if (event.isCancelled() && event.getBlockType().getId().equals("temporary_block")) { event.setCancelled(false); } }); ``` {{< callout type="warning" >}} Uncancelling events can cause conflicts with other plugins. Use sparingly and document this behavior. {{< /callout >}} ## Example: Connection Whitelist ```java public class WhitelistPlugin extends JavaPlugin { private final Set whitelist = new HashSet<>(); @Override public void start() { // Cancel connection for non-whitelisted players getEventRegistry().register(PlayerSetupConnectEvent.class, event -> { if (!whitelist.contains(event.getUuid())) { event.setCancelled(true); event.setReason("You are not whitelisted on this server!"); } }); } public void addToWhitelist(UUID uuid) { whitelist.add(uuid); } public void removeFromWhitelist(UUID uuid) { whitelist.remove(uuid); } } ``` ## Example: Chat Filter ```java public class ChatFilterPlugin extends JavaPlugin { private final Set bannedWords = new HashSet<>(); @Override public void start() { loadBannedWords(); // Note: PlayerChatEvent has String key, use registerAsyncGlobal() getEventRegistry().registerAsyncGlobal(PlayerChatEvent.class, future -> { return future.thenApply(event -> { String message = event.getContent().toLowerCase(); for (String banned : bannedWords) { if (message.contains(banned)) { event.setCancelled(true); // Send message via PlayerRef event.getSender().sendMessage(Message.raw("Your message was blocked!")); break; } } return event; }); }); } } ``` ## Example: Block Protection ```java public class ProtectionPlugin extends JavaPlugin { private final Set protectedBlocks = new HashSet<>(); @Override public void start() { // Register at EARLY to cancel before other plugins process getEventRegistry().register(EventPriority.EARLY, BreakBlockEvent.class, event -> { if (protectedBlocks.contains(event.getTargetBlock())) { event.setCancelled(true); } }); getEventRegistry().register(EventPriority.EARLY, PlaceBlockEvent.class, event -> { if (isProtectedArea(event.getTargetBlock())) { event.setCancelled(true); } }); } private boolean isProtectedArea(Vector3i pos) { // Check if position is in a protected region return false; } } ```