# 自定义事件
我们现在所了解的事件都是Bukkit提供的. 例如, 玩家移动等.
那如果我们想自己去做一个事件呢?
# 按需创建类
比如, 我想自己做出来一个RuaEvent, 实现在玩家聊天说rua的时候触发.
很明显, Bukkit只会提供玩家发送聊天信息的事件, 肯定不会单独为了实现在玩家聊天发送rua的时候单独做个事件. 那应该怎么做?
首先想到的应该是监听玩家聊天事件, 然后判断玩家聊天发送的内容是什么, 如果是rua做我想做的事情. 这是常规的解决方法.
但是如果我想做一个强化插件, 我想在玩家强化物品的时候触发一个事件给自己和其他插件, 那我应该怎么做? 不如自定义一个属于自己的事件!
这里我们以创建上文的RuaEvent事件举例, 我们的大致思路是这样的:
- 创建一个
RuaEvent类. - 监听玩家聊天, 判断玩家聊天内容, 如果是
rua, 让Bukkit触发我们新建的RuaEvent对象. - 向玩家发送消息
rua.
我们就先新建一个类RuaEvent, 让其继承org.bukkit.event.Event类. 在该类中写下这些固定代码:
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代码最终如下:
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接口:
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已经自定义成功, 现在我们只需要做第二步即可:
- 如果RuaEvent是个不可取消事件
@EventHandler
public void onPlayerChat_DEMO1 (PlayerChatEvent e){ //如果RuaEvent是个不可取消事件
if(e.getMessage().equals("rua")) Bukkit.getServer().getPluginManager().callEvent(new RuaEvent(e.getPlayer())); //触发事件
e.sendMessage("Rua!");
}
- 如果RuaEvent是个可取消事件
@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.
进阶
30分钟