2.6
This commit is contained in:
145
docs/mcguide/28-电脑网络游戏/课程3:编写Bukkit插件/3-进阶内容/2-自定义事件.md
Normal file
145
docs/mcguide/28-电脑网络游戏/课程3:编写Bukkit插件/3-进阶内容/2-自定义事件.md
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
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.*
|
||||
Reference in New Issue
Block a user