--- front: hard: 进阶 time: 30分钟 --- # 自定义事件 我们现在所了解的事件都是Bukkit提供的. 例如, 玩家移动等. 那如果我们想自己去做一个事件呢? ## 按需创建类 比如, 我想自己做出来一个`RuaEvent`, 实现在玩家聊天说`rua`的时候触发. 很明显, Bukkit只会提供玩家发送聊天信息的事件, 肯定不会单独为了实现在玩家聊天发送`rua`的时候单独做个事件. 那应该怎么做? 首先想到的应该是监听玩家聊天事件, 然后判断玩家聊天发送的内容是什么, 如果是`rua`做我想做的事情. 这是常规的解决方法. 但是如果我想做一个强化插件, 我想在玩家强化物品的时候触发一个事件给自己和其他插件, 那我应该怎么做? 不如自定义一个属于自己的事件! 这里我们以创建上文的`RuaEvent`事件举例, 我们的大致思路是这样的: 1. 创建一个`RuaEvent`类. 2. 监听玩家聊天, 判断玩家聊天内容, 如果是`rua`, 让Bukkit触发我们新建的`RuaEvent`对象. 3. 向玩家发送消息`rua`. 我们就先新建一个类`RuaEvent`, 让其继承`org.bukkit.event.Event`类. 在该类中写下这些固定代码: ```java public class RuaEvent extends Event{ private static final HandlerList handlers = new HandlerList(); @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ``` HandlerList储存与监听本事件的监听器相关的对象. 这意味着Bukkit中注册监听器的本质就是在每个对应的事件HandlerList中加入该监听器的有关对象. 这也意味着Bukkit中事件的触发本质是遍历被触发事件的HandlerList, 调用监听器对应方法. > 假如我想让服务器里的玩家触发的所有事件, 已知所有的诸如PlayerJoinEvent等玩家事件都继承了PlayerEvent, 那我可以监听PlayerEvent事件吗? > 答案是不可以, 因为`PlayerEvent`没有`getHandlerList()`方法, 结合上面的内容, 你应该可以意识到PlayerEvent是无法正常工作的吧. > 所以你只能把所有Player开头的Event监听一个遍才可以达到目的! 现在我们的自定义事件雏形已经完成. 你可以根据自己的需要添加相关代码! 这里我们示例的`RuaEvent`代码最终如下: ```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; } } ``` ## 可取消事件的实现 等一等, 这样做出来的事件没有`setCancelled`方法和`isCancelled`方法, 这是不可取消的事件. 如果想做成可取消事件, 需要实现`Cancellable`接口: ```java public class RuaEvent extends Event implements Cancellable{ private static final HandlerList handlers = new HandlerList(); private Player p; private boolean cancelledFlag = false; public RuaEvent(Player p){ this.p = p; } public Player getPlayer(){ return p; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } @Override public boolean isCancelled() { return cancelledFlag; } @Override public void setCancelled(boolean cancelledFlag) { this.cancelledFlag = cancelledFlag; } } ``` 如果是不可取消的事件, 无需实现`Cancelled`. 截止到现在, `RuaEvent`已经自定义成功, 现在我们只需要做第二步即可: 1. 如果RuaEvent是个不可取消事件 ```java @EventHandler public void onPlayerChat_DEMO1 (PlayerChatEvent e){ //如果RuaEvent是个不可取消事件 if(e.getMessage().equals("rua")) Bukkit.getServer().getPluginManager().callEvent(new RuaEvent(e.getPlayer())); //触发事件 e.sendMessage("Rua!"); } ``` 2. 如果RuaEvent是个可取消事件 ```java @EventHandler public void onPlayerChat_DEMO1 (PlayerChatEvent e){ //如果RuaEvent是个可取消事件 if(e.getMessage().equals("rua")){ RuaEvent event = new RuaEvent(e.getPlayer()); Bukkit.getServer().getPluginManager().callEvent(event); if(event.isCancelled()) { return; //事件被取消, 终止事件的处理 } // 事件未取消对应的逻辑 e.sendMessage("Rua!"); } } ``` *在这里监听了**PlayerChatEvent**,但是此事件已被标记@Deprecated,实际的开发过程中不推荐监听此事件.* *实际开发中建议监听的是**AsyncPlayerChatEvent**事件. 注意这是异步监听,用法基本类同于上述事件的监听,具体请参见JavaDoc.*