251 lines
6.5 KiB
Markdown
251 lines
6.5 KiB
Markdown
---
|
|
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<UUID> 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<String> 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<Vector3i> 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;
|
|
}
|
|
}
|
|
```
|