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

2017年4月2日 (日) 23:42時点における版

はじめに

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 ハンドラの優先度。
  • EventPriority.HIGHEST
  • EventPriority.HIGH
  • EventPriority.NORMAL
  • EventPriority.LOW
  • EventPriority.LOWEST
boolean receiveCanceled false この値にtrueを指定した場合は、イベントがキャンセルされた際にイベントを購読しない。
  • true
  • false
イベントの優先度

上記の表にあるように、イベントの優先度は5種類ありますが、イベントが呼び出される順序は下記のようになっています。

  1. EventPriority.HIGHEST
  2. EventPriority.HIGH
  3. EventPriority.NORMAL
  4. EventPriority.LOW
  5. 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の指定も同様に行えますが、その場合スキップ判定等は自分で行わなければならないことに注意してください。