Files
netease-bedrock-wiki/mcguide/28-电脑网络游戏/课程3:编写Bukkit插件/3-进阶内容/2-自定义事件.md
2025-07-31 17:53:14 +08:00

146 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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.*