参与编写者: MagicLu550,innc11,smartcmd
nukkit插件最主要的运行方式就是:
事件被触发 -> 执行动作
所以说监听器是插件中非常重要的部分
其实看一看这章,没有啥可讲的。监听器的内容很简单,很多人认识它的困难主要是概念上, 而不是使用上。
注册监听器有两个步骤: 1.定义监听器 2.注册监听器
nukkit监听器的构成: 事件监听和优先级
nukkit的监听器是通过 反射(reflect) 实现的,因此基于它,开发者容易上手,且上手 更简便。nukkit的监听器设计形同bukkit,也易于bukkit上手
nukkit声明一个事件的监听管理器是通过注解实现的,即@EventHandler
@EventHandler的源码如图
package cn.nukkit.event;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 定义一个事件的处理器的注解。<br>
* Annotation that defines a handler.
*
* <p>一个处理器的重要程度被称作处理器的<b>优先级</b>,优先级高的处理器有更多的决定权。参见:{@link #priority()}<br>
* The importance of a handler is called its <b>priority</b>, handlers with higher priority speaks louder then
* lower ones. See: {@link #priority()}</p>
*
* <p>处理器可以选择忽略或不忽略被取消的事件,这种特性可以在{@link #ignoreCancelled()}中定义。<br>
* A handler can choose to ignore a cancelled event or not, that can be defined in {@link #ignoreCancelled()}.</p>
*
* @author MagicDroidX(code) @ Nukkit Project
* @author 粉鞋大妈(javadoc) @ Nukkit Project
* @see cn.nukkit.event.Listener
* @see cn.nukkit.event.Event
* @since Nukkit 1.0 | Nukkit API 1.0.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventHandler {
/**
* 定义这个处理器的优先级。<br>
* Define the priority of the handler.
*
* <p>Nukkit调用处理器时会按照优先级从低到高的顺序调用,这样保证了高优先级的监听器能覆盖低优先级监听器做出的处理。
* 调用的先后顺序如下:<br> </p>
* When Nukkit calls all handlers, ones with lower priority is called earlier,
* that make handlers with higher priority can replace the decisions made by lower ones.
* The order that Nukkit call handlers is from the first to the last as:
* <ol>
* <li>EventPriority.LOWEST
* <li>EventPriority.LOW
* <li>EventPriority.NORMAL
* <li>EventPriority.HIGH
* <li>EventPriority.HIGHEST
* <li>EventPriority.MONITOR
* </ol>
*
* @return 这个处理器的优先级。<br>The priority of this handler.
* @see cn.nukkit.event.EventHandler
*/
EventPriority priority() default EventPriority.NORMAL;
/**
* 定义这个处理器是否忽略被取消的事件。<br>
* Define if the handler ignores a cancelled event.
*
* <p>如果为{@code true}而且事件发生,这个处理器不会被调用,反之相反。<br>
* If ignoreCancelled is {@code true} and the event is cancelled, the method is
* not called. Otherwise, the method is always called.</p>
*
* @return 这个处理器是否忽略被取消的事件。<br>Whether cancelled events should be ignored.
* @see cn.nukkit.event.EventHandler
*/
boolean ignoreCancelled() default false;
}
第一个是优先级,第二个是是否忽略事件被取消
默认的优先级是normal,从注释可以知道,这是他们的先后顺序,LOWEST会最先被调用,其次是LOW,最后是MONITOR,如果在LOWEST监听器中调用了Event.setCancelled(true),Nukkit则会忽略掉后面的 ignoreCancelled 被设置为true或者保持默认的优先级更高的监听器
-
EventPriority.LOWEST
-
EventPriority.LOW
-
EventPriority.NORMAL
-
EventPriority.HIGH
-
EventPriority.HIGHEST
-
EventPriority.MONITOR
而实现监听器的优先级标记是通过 枚举(Enum) 实现的
优先级的目的是为了保证监听器按照顺序执行,以使得一个监听器操作完会 进入下一个监听器继续执行,以确保执行的有序性。下一个监听器的相同操作 会覆盖之前监听器的相同操作。
同时,事件可以被我手动取消的,但是有时候事件虽然取消,但依然需要操作, 那么ignoreCancelled可以发挥作用了,当然默认是忽略掉取消的事件,也就是 说取消的事件默认不会被监听(这里可能有所错误,我这个不太常用)
一个EventHandler基本都是监听一个事件的(我只尝试过一个事件的),代码中 这样使用
package net.noyark.www;
import cn.nukkit.event.EventHandler;
import cn.nukkit.event.Listener;
import cn.nukkit.event.player.PlayerJoinEvent;
public class OtherListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e){
//执行代码
}
}
这里的意思就是当玩家进入服务器时,就会触发PlayerJoinEvent事件,服务器会 形成一个PlayerJoinEvent对象,并且调用先前注册的有关PlayerJoinEvent的 EventHandler,将对象传入,这样就实现了一个 事件的调用 获取对象的内容,则通过e调用即可,我们不需要很明白它的具体细节,只需要知道, 使用EventHandler注解的方法(且有一个Event的子类类型参数,并且它所在的监听器被注册), 就会在事件发生时,相应的被调用,如上文所讲,这里的代码案例就是当发生玩家加入时, 这个onPlayerJoin方法会被服务端调用。
package net.noyark.www;
import cn.nukkit.event.EventHandler;
import cn.nukkit.event.Listener;
import cn.nukkit.event.player.PlayerJoinEvent;
public class OtherListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e){
e.getPlayer().sendMessage("你好 "+e.getPlayer());
}
}
例如这个代码,在玩家加入时,将会向玩家发送一个"你好 玩家的名字",这就是 我们监听器的作用
package net.noyark.www;
import cn.nukkit.event.EventHandler;
import cn.nukkit.event.EventPriority;
import cn.nukkit.event.Listener;
import cn.nukkit.event.player.PlayerJoinEvent;
public class OtherListener implements Listener {
@EventHandler(priority = EventPriority.HIGH,ignoreCancelled = true)
public void onPlayerJoin(PlayerJoinEvent e){
e.getPlayer().sendMessage("你好 "+e.getPlayer());
}
}
如果要使用我们之前所说的参数,则这样使用。
事实上,监听器的基本使用方式也就这些,nukkit也提供了很多事件给予我们使用,也允许我们 自己制作事件自己使用,在第二部分中,我们将会讲解提供了哪些事件
如何自己定义一个事件
事实上,nukkit的事件是通过callEvent调用的,所以,我们同样可以通过callEvent实现我们自己 的事件。
this.getServer().getPluginManager().callEvent(Event e);
首先我们先定义一个事件类
package net.noyark.www;
import cn.nukkit.event.Event;
public class MyEvent extends Event {
}
之后,我们在监听器使用我们的事件
package net.noyark.www;
import cn.nukkit.event.EventHandler;
import cn.nukkit.event.Listener;
public class OtherListener implements Listener {
@EventHandler
public void onMy(MyEvent e){
}
}
之后,我们就可以使用我们的事件了。
this.getServer().getPluginManager().registerEvents(new OtherListener(),this);
如何触发我们的事件? 事件的触发则通过callEvent触发,假如,我们写一个玩家假如时,如果他的 名字叫abc,就触发MyEvent事件
package net.noyark.www;
import cn.nukkit.event.EventHandler;
import cn.nukkit.event.Listener;
import cn.nukkit.event.player.PlayerJoinEvent;
public class OtherListener implements Listener {
@EventHandler
public void onMy(MyEvent e){
}
@EventHandler
public void onPLayerJoin(PlayerJoinEvent e){
if("abc".equals(e.getPlayer().getName())){
Example.getPlugin().getServer()
.getPluginManager()
.callEvent(new MyEvent());
}
}
}
这里,我们完成了我们的自定义事件
假如我们要注册一个EventHandler,不去注册其他的该如何。 事实上,可以实现这个,nukkit提供了registerEvent方法, 可以注册单个EventHandler,但不太常用,我这里也不会再过多 阐述了,如果想了解,可以发issue,我将会添加这方面的内容