Bukkit插件教程篇之事件处理器

开始

插件不仅只能根据命令来作出一些处理,它还能根据服务器内发生的一些事作出对应的处理,这就是我们本章需要学到的知识!

**↑不来一首BGM吗?**

本章要求

  • 了解事件
  • 了解监听器
  • 认识事件处理器
  • 学会使用监听器
  • 学会使用事件处理器
  • 学会注册监听器
  • 学会注销监听器

事件

Bukkit中存在众多事件(可以去doc里搜索一下关键字“Event”),比如“玩家出生事件”或者“方块被烧毁事件”,这些事件发生时都会被Bukkit实例化并传递给事件处理器处理这个事件。
例如:[方块被放置事件] –> [Bukkit实例化该事件] –> [Bukkit传递该事件给监听器的事件处理器] –> [监听器处理该事件] –> [监听器要求取消该事件] –> [事件未发生]

创建监听器

Bukkit为插件开发者写了一个很实用的接口——监听器!我们在创建监听器的时候,只需要实现这个接口就行了!
在这里我要说一下的是,我建议同学们为监听器单独创建一个包:Listener包。这样将有助于我们管理插件代码!
然后我们在监听器包下新建一个类,并使该类实现Listener接口,代码如下:

1
2
3
4
5
6
7
package cn.viosin.minecraft.Listener;

import org.bukkit.event.Listener;

public class BlockPlaceListener implements Listener{

}

现在,我们的事件监听器类已经写好了,但是它还没有任何事件处理器!
它像一个调皮的小孩一样听着老师讲的所有知识但却不作出任何反应。

监听器

正如上面所言,Bukkit中存在众多事件,但如果没有一个监听器去监听它,那么它的发生将只有Bukkit知道,我们的插件对此一无所知!因此我们必须为插件创建一个监听器,好让我们的插件得知服务器内发生了那些事件,以便于我们处理它!如果你的插件拥有了一个监听器,而且你能保证这个监听器能够正常工作,那么你的插件将会监听服务器内发生的某一类事件,不管它何时发生,不管它在哪里发生,也不管它究竟是被谁触发的。也就是说,你的插件将了解有关该事件的全部!

事件处理器

你现在有了一个监听器,它可以让你的插件知道服务器里什么时候发生了什么事情。但是,你的插件仅仅是知道了并没有什么卵用,因为它并不对此做出任何反应!
就像你上课仅仅是看着老师在黑板上讲课但是却从来都没有听进去过一样!没!有!卵!用!
因此,我们需要给这些监听器增加一些事件处理器,以便于我们在监听到了事件发生时,对该事件作一定的处理。

创建事件处理器

事件处理器其实就是监听器类下包含的一个方法,但是它必须带有@EventHandler注解,这样Bukkit才知道这是一个事件处理器,而不是一个你自己写给自己或写给其他人用的方法。
你可以使用这行代码来创建事件处理器public void 方法名称 (监听的事件类 e) { /*do someting*/ },这样服务器内发生了某时间时他将会传递一个监听的事件类的实例给这个方法,然后我们可以在这个方法里写一些代码来处理这个事件。
例子:

1
2
3
4
5
6
7
@EventHandler
public void BlockPlaceHandler(BlockPlaceEvent e) {
Player p = e.getPlayer(); //获取触发该事件的玩家
double health = p.getHealth(); //获取该玩家的生命值
p.setHealth(++health); //让该玩家的生命值+1
e.setCancelled(true); //取消这个事件
}

这时候整个文件的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package cn.viosin.minecraft.Listener;

import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;

public class BlockPlaceListener implements Listener{
@EventHandler
public void BlockPlaceHandler(BlockPlaceEvent e) {
Player p = e.getPlayer(); //获取触发该事件的玩家
double health = p.getHealth(); //获取该玩家的生命值
p.setHealth(++health); //让该玩家的生命值+1
e.setCancelled(true); //取消这个事件
}
}
**现在,你的事件监听器有了处理器,他能在老师教授一些知识的时候作出一些对应的反应了!**

注册监听器

但是……我们的监听器很不幸,他根本听不到老师讲的内容。
要注册一个监听器很简单,但是你必须先拥有一个该监听器实例。注册监听器的方法写在PluginManager类(插件管理器)里,它的声明如下:registerEvents(Listener listener, Plugin plugin),我们需要传递一个Listener类和一个Plugin类过去。
Plugin类是注册这个监听器的插件,我们的插件主类可以强制转换成Plugin类型,所以如果我们在主类中注册这个监听器的话,第二项直接填this即可。而前面的Listener则更容易解释了,我们上面写的BlockPlaceListener类实现了Listener类接口,所以我们可以直接把它传递过去。(因为它会自动强制转换成LIstener类嘛)
注册方法:Bukkit.getPluginManager().registerEvents(new BlockPlaceListener, this);先使用Bukkit类下的静态方法getPluginManager()获取到PluginManager的实例,再调用PluginManager类的方法registerEvents,并创建一个BlockPlaceListener的实例同this一起传递过去,完成监听器的注册。
(PluginManager类中还有其他的注册监听器的方法,详情请查看spigotdoc)
我们只需要把这段代码加在onEnable方法中,这样插件被启用时我们的监听器器也会被注册,开始生效。
这样,你的监听器现在可以听到老师的讲话了!而且他还能在老师教授一些知识的时候作出一些对应的反应!为他欢呼吧~

注销监听器

注册的监听器会消耗服务器性能,因为他需要Bukkit在发生该事件时传递数据给监听器。因此当监听器不再被需要使用时,我们应该立即将它注销掉。注销监听器有多种方法,这里分点介绍:

注销对应事件的监听器

举例BlockPlaceEvent.getHandlerList().unregister(Listener listener);
这里需要传递一个需要注销的监听器实例过去,由于我们上面没有保存这个监听器的实例在插件类体里,所以这个方法对我们来说行不通。

举例BlockPlaceEvent.getHandlerList().unregister(Plugin plugin);
这句话的意思应该很好理解,就是注销该插件中所有有关该事件的监听器。但是由于我们不是使用registerEvent(Class<? extends Event> event, Listener listener, EventPriority priority, EventExecutor executor, Plugin plugin)方法来注册监听器的,所以这个方法也行不通。

注销对应类的监听器

这几个方法写在HandlerList下,且属于静态方法,所以不需要HandlerList实例也能直接调用。
HandlerList.unregisterAll(Listener listener);
注销该监听器类的所有监听器实例,我们可以使用这个方法,不过调用这个的时候仍然需要new一个监听器传递过去。
HandlerList.unregisterAll(Plugin plugin);
注销该插件所有已被注册的监听器,我们可以使用这个方法。
‘HandlerList.unregisterAll();’
打死也不要用这个方法!直接注销服务器的所有监听器!其他插件的监听器也会被你注销掉!

综上所述,对于上面我举的例子,推荐使用HandlerList.unregisterAll(Plugin plugin);,因为我们是需要在关闭该插件的时候注销掉该监听器,所以直接注销该插件注册的所有监听器就行了。
在onDisable方法里加上这段代码HandlerList.unregisterAll(this);

自定义事件

自定义事件暂时不讲,本章内容中心为“事件处理器”,有兴趣的同学请去阅读这篇文章

本章完

点我返回目录

感谢各位的阅读!

人生不易,仓鼠断气