Skip to content

自定义事件 ​

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。