目次
はじめに
Minecraft Forge Universalから新しいEventシステムが組み込まれた。ある処理にこちらの用意した処理を割り込ませる機能であり、介入しづらい処理にも介入できるようになりました。
BukkitPluginのEventシステムと考え方は同じです。
詳しく知りたい場合は、DI(依存性の注入)やAOP(アスペクト指向)などの概念、Struts2, SpringFrameworkなどの有名なフレームワークがキーワードとなるかもしれません。
基礎
説明を抽象化するため、SampleEventという架空のイベントを仮定して説明します。
メソッドにアノテーションと引数を指定すると、引数に指定したイベントの発火に合わせて呼び出されるようになります。
引数でイベントを指定するため、メソッド名は自由に設定できます。
@SubscribeEvent public void onSampleEvent(SampleEvent event) { }
このメソッドの場合はSampleEventがEventBusを介してpostされる箇所で呼び出されます。メソッドを持つクラスまたはそのインスタンスは適切な箇所でEventBusに登録する必要があります。
Minecraft Forgeの扱えるEventはMinecraft Forge API#イベントを参照すること。
解説
イベントハンドラ
処理を挟み込むには、イベントを待ち受けるメソッド(Event Handlerと呼ばれます)を作成します:
public void onSampleEvent(SampleEvent event) { // ここに処理を書きます... }
このままではただのメソッドなので、SubscribeEventアノテーションをつけてイベントハンドラであることを明示しなければなりません。
SubscribeEventアノテーション
SubscribeEventアノテーションをメソッドにつけることでメソッドがハンドラであることを明示し、引数に取ったイベントを購読できるようになります。
SubscribeEventアノテーションはメソッドを対象に取るアノテーションです。最も簡潔な記述は以下のとおりです:
@SubscribeEvent
この場合は、メソッドは優先度NORMALのイベントハンドラであるという指定になります。
以上をまとめると、次のようになります:
@SubscribeEvent public void onSampleEvent(SampleEvent event) { // ここに処理を書きます... }
イベントのキャンセル
イベントがCancelableな場合は、イベントをキャンセルできます。
スキップできる処理はイベントによって異なりますが、バニラの処理と後述するreceiveCanceledがtrueのハンドラの処理が対象になります。
詳しくはそれぞれのEventのドキュメントを参照しています。
イベントの結果
イベントがHasResultな場合は、イベントに結果を持たせられます。
ResultはDENY,DEFAULT,ALLOWの三値をとります。
各イベントで若干意味は異なりますが、基本的には
それぞれ、
- DENY
- 否定。不成功。イベントをキャンセルするのによく似る。
- DEFAULT
- 判定をバニラと同様にする。結果への不介入。処理は挟むが、その後の処理については別に干渉したくない場合に用いる。
- ALLOW
- 強制。成功。バニラがどんな判定をしようが、構いなくこちら側で動作を強制する。
イベントハンドラの設定
SubscribeEventアノテーションでは、ハンドラについて設定できます。
現時点では次のような指定が行えます:
型 | 項目名 | デフォルト値 | 概要 | 指定できる値 |
EventPriority | priority | EventPriority.NORMAL | ハンドラの優先度。 |
|
boolean | receiveCanceled | false | この値にtrueを指定した場合は、イベントがキャンセルされた際にイベントを購読しない。 |
|
イベントの優先度
上記の表にあるように、イベントの優先度は5種類ありますが、イベントが呼び出される順序は下記のようになっています。
- EventPriority.HIGHEST
- EventPriority.HIGH
- EventPriority.NORMAL
- EventPriority.LOW
- EventPriority.LOWEST
優先度が高いものから順繰りに実行されていきます。
HIGHESTなど高い優先度のハンドラでイベントがキャンセルされると、それ以下の優先度かつreceiveCanceledがtrueの場合ハンドラの処理がスキップされるということです。
イベントハンドラの登録
以上のようにメソッドを記述した上で、EventBusにそのメソッドを記述したクラスやそのインスタンスを登録しなければなりません。
記述しているメソッドが購読するイベントに応じて、登録するEventBusは変わります。
例えば、ForgeEventHookというクラスにMinecraftForge.EVENT_BUSで発火されるイベントのハンドラを記述した場合は
MinecraftForge.EVENT_BUS.register(new ForgeEventHook())
または
MinecraftForge.EVENT_BUS.register(ForgeEventHook.class)
というように登録します。
インスタンスで登録した場合は、インスタンスメソッドでハンドラを記述します。
クラスで登録した場合は、クラスメソッドでハンドラを記述します。
MinecraftForge.EVENT_BUSに限っては、@EventBusSubscriberでクラスを注釈すれば自動的に登録されます。
この場合は、クラスメソッドでハンドラを記述します。
MinecraftForgeが提供するEventBusには三種類あります。
- MinecraftForge.EVENT_BUS
- 基本的なイベント群はここから発火される。以下のBusで発火されないイベントはここと覚えれば良い。
- MinecraftForge.TERRAIN_GEN_BUS
- 地形生成に関するイベントはここから発火される。
- MinecraftForge.ORE_GEN_BUS
- 鉱石生成に関するイベントはここから発火される。
以前はFMLCommonHandler.instance().bus()という物もありましたが、MinecraftForge.EVENT_BUSに統合されました。
イベントの自作
Minecraft Forgeの利用しているイベントの仕組みと全く同一の仕組みを利用して、イベントを自作できます。
自作と言っても、Eventクラスを継承していればイベントとして機能しますので、好きに設計することができます。
クラスを作成すれば、あとは任意のタイミングで任意のEventBusからpostを呼び出せば発火できます。
CancelableやHasResultの指定も同様に行えますが、その場合スキップ判定等は自分で行わなければならないことに注意してください。