Init
This commit is contained in:
250
content/core-concepts/events/cancellable-events.en.md
Normal file
250
content/core-concepts/events/cancellable-events.en.md
Normal file
@@ -0,0 +1,250 @@
|
||||
---
|
||||
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;
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user