Skip to content

Latest commit

 

History

History
250 lines (197 loc) · 8.76 KB

1-3_如何编写监听器.md

File metadata and controls

250 lines (197 loc) · 8.76 KB

上一节 下一节

第一章 第三节 如何编写监听器

参与编写者: MagicLu550,innc11

建议学习时间: 30分钟

学习要点: 学习如何构建一个简单的监听器,和自己构造事件

其实看一看这章,没有啥可讲的。监听器的内容很简单,很多人认识它的困难主要是概念上, 而不是使用上。

注册监听器有两个步骤: 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,我将会添加这方面的内容

上一节 下一节