事件监听器

要监听一个事件,必须要注册一个事件监听器。方法是创建一个方法,方法名任意,将方法的第一个参数定义为目标事件类型,然后给该方法附上 Listener 注解,如下所示。

import org.spongepowered.api.event.Listener;

@Listener
public void onSomeEvent(SomeEvent event) {
    // Do something with the event
}

此外,包含这些方法的类必须在事件管理器注册:

小技巧

如果你的主类(即附有 Plugin 注解的类)有事件监听器,则你不需要注册事件对象,因为 Sponge 会自动执行此操作。

注解

事件总线 支持父类型 。例如, ChangeBlockEvent.Break 继承自 ChangeBlockEvent 。因此,一个监听了 ChangeBlockEvent 事件的插件可以收到来自 ChangeBlockEvent.Break 事件的通知。但是,一个监听了 ChangeBlockEvent.Break 事件的插件却不会收到来自 ChangeBlockEvent 事件的任何其他子类型事件的通知。

注册或取消事件监听器

在插件主类之外,添加注解``@Listener``来对事件监听器进行注册,你可以通过使用 EventManager#registerListeners(Object, Object) 方法来注册这个事件监听器,该方法需要一个插件主类的引用以及事件监听类的实例。

示例:在其他类中注册事件监听器

import org.spongepowered.api.Sponge;

public class ExampleListener {

    @Listener
    public void onSomeEvent(SomeEvent event) {
        // Do something with the event
    }
}

Sponge.getEventManager().registerListeners(this, new ExampleListener());

动态注册事件监听器

一些像脚本插件的插件或许会希望有动态注册事件监听器的功能。这是指事件监听器不是单纯通过 @Listener 来注册的,而是让保有监听器的类实现 EventListener 接口。这个事件监听器可以通过调用 EventManager#registerListener 来注册,该方法需要插件主类的引用,被监听的事件类和这个实现了 EventListener 类的实例作为参数。同时,你可以将 Order 参数放在监听器参数之前,来指定该事件监听器的执行 Order 。或者在监听器类参数之前传入一个额外的布尔值参数,来决定这个监听器是否在服务器启动之前被调用。

示例:实现 EventListener

import org.spongepowered.api.event.EventListener;
import org.spongepowered.api.event.block.ChangeBlockEvent;

public class ExampleListener implements EventListener<ChangeBlockEvent.Break> {

    @Override
    public void handle(ChangeBlockEvent.Break event) throws Exception {
        [...]
    }
}

示例:动态注册事件监听器

EventListener<ChangeBlockEvent.Break> listener = new ExampleListener();
Sponge.getEventManager().registerListener(this, ChangeBlockEvent.Break.class, listener);

小技巧

通过 @Listener 注解注册的监听器可自行决定其执行顺序(参见 关于 @Listener 部分的内容)。对于动态注册的事件监听器,可通过向 EventManager#registerListener 传入第三个参数 Order 来实现一样的效果。

取消注册事件监听器

你可以通过使用 EventManager#unregisterListeners(Object) 方法来去取消一个事件监听器的注册,该方法接受一个事件监听器类的实例作为参数。

EventListener listener = ...;
Sponge.getEventManager().unregisterListeners(listener);

或者,你可以通过传入一个插件的引用,调用 EventManager#unregisterPluginListeners(Object) 方法来取消掉所有该插件注册的事件监听器。请务必注意这个方法会移除 所有 此插件的事件监听器,包括那些用 @Listener 注册的监听器。

PluginContainer plugin = ...;
Sponge.getEventManager().unregisterPluginListeners(plugin);

关于 @Listener

注解 @Listener 有若干个可配置的字段:

  • order 用于设置事件监听器的执行优先级。参见 SpongeAPI 中 Order 这一枚举以获取可能的 order 选项。

  • beforeModifications 指定事件监听器是否在服务端 Mod ,如 Forge Mod 之前执行,默认为 false 。

默认情况下, @Listener 将会被配置成当事件是可取消而且已被(例如另一个插件)取消时,你的事件监听器 会被执行。

GameReloadEvent

为了防止所有的插件提供其自己的重新加载(Reload)命令。Sponge 提供了一个内置的回调方法用于插件监听,并在执行时,执行任何重新加载的操作。重新加载的操作到底是什么样子的完全由插件自己去决定。当诸如 /sponge plugins reload 这样的命令被执行时,事件 GameReloadEvent 将会被触发。重新加载这一操作并不一定局限于重新加载配置。

import org.spongepowered.api.event.game.GameReloadEvent;

@Listener
public void reload(GameReloadEvent event) {
    // Do reload stuff
}

注意这和一般理解上的“重新加载”不同,这个事件仅仅是用于插件的回调,实际上其他的什么事情都没有做。

发布事件

为了调度一个事件,你需要一个实现了 Event 接口的对象。

你可以通过事件总线( EventManager )触发事件:

boolean cancelled = Sponge.getEventManager().post(theEventObject);

如果该事件被取消,则返回 true ,否则为 false

发布 Sponge 事件

内建的事件实例可以通过 SpongeEventFactory 静态生成。这个类的代码是自动生成的,因此并没有相关的 JavaDocs。你可以通过你的 IDE 的自动补全,列出已有的方法。一个事件实例通过 SpongeEventFactory 生成后,将会被作为 EventManager#post(Event) 方法的参数传入。

示例:发布 LightningEvent(闪电事件)

import org.spongepowered.api.event.action.LightningEvent;
import org.spongepowered.api.event.cause.Cause;
import org.spongepowered.api.event.cause.EventContext;
import org.spongepowered.api.event.cause.EventContextKeys;
import org.spongepowered.api.event.SpongeEventFactory;

PluginContainer plugin = ...;
EventContext eventContext = EventContext.builder().add(EventContextKeys.PLUGIN, plugin).build();

LightningEvent lightningEvent = SpongeEventFactory.createLightningEventPre(Cause.of(eventContext, plugin));
Sponge.getEventManager().post(lightningEvent);

警告

Cause 不能为空,它至少应该包含你的插件主类。