自定义事件
Bukkit 提供的事件(玩家移动、聊天等)是固定的。如果你想在"玩家强化物品"这种自定义时机,触发一个事件给自己和其他插件监听——就要自己造事件。
为什么需要自定义事件
比如你想做强化插件,玩家强化装备时希望别的插件能感知到(比如经济插件扣钱、成就插件记一笔)。最干净的做法是:强化时触发一个 ItemUpgradeEvent,别的插件监听它即可,解耦。
创建自定义事件
自定义事件继承 org.bukkit.event.Event,并写固定样板代码:
java
public class RuaEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private Player p;
public RuaEvent(Player p) {
this.p = p;
}
public Player getPlayer() {
return p;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
// 这个静态方法必须有
public static HandlerList getHandlerList() {
return handlers;
}
}两个 getHandlerList 都不能少
- 实例方法
getHandlers():Bukkit 用它找监听器 - 静态方法
getHandlerList():Bukkit 注册时用,少了它事件无法工作
HandlerList 储存监听本事件的监听器。Bukkit 触发事件的本质就是遍历这个列表调用对应方法。
触发自定义事件
在合适的时机调用 Bukkit.getPluginManager().callEvent(...):
java
// 玩家聊天说 "rua" 时触发 RuaEvent
@EventHandler
public void onChat(AsyncPlayerChatEvent e) {
if (e.getMessage().equalsIgnoreCase("rua")) {
RuaEvent event = new RuaEvent(e.getPlayer());
Bukkit.getPluginManager().callEvent(event); // 触发!
if (event.getPlayer() != null) {
event.getPlayer().sendMessage("rua~");
}
}
}监听自定义事件
和监听普通事件完全一样:
java
@EventHandler
public void onRua(RuaEvent e) {
e.getPlayer().sendMessage("你 rua 了!");
}别的插件也能监听你的 RuaEvent——只要它们能引用到这个类(打包进 jar 或作为 API 提供)。
可取消的自定义事件
想让事件能被监听器取消,让它实现 Cancellable:
java
public class ItemUpgradeEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled = false;
// ... 其他字段和方法
@Override
public boolean isCancelled() { return cancelled; }
@Override
public void setCancelled(boolean cancel) { this.cancelled = cancel; }
@Override
public HandlerList getHandlers() { return handlers; }
public static HandlerList getHandlerList() { return handlers; }
}触发后检查是否被取消:
java
ItemUpgradeEvent event = new ItemUpgradeEvent(player, item);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return; // 被别的插件取消了,不继续强化
}
// 继续强化逻辑能否监听 PlayerEvent 父类?
所有 Player*Event 都继承 PlayerEvent,但你不能监听 PlayerEvent 本身——因为它没有 getHandlerList()。要监听所有玩家事件,只能逐个监听具体的 PlayerXxxEvent。
自定义事件让插件之间能通信、解耦。下一篇深入 plugin.yml。
