最新版 |
編集中の文章 |
1行目: |
1行目: |
| ==はじめに== | | ==はじめに== |
− | Minecraft Forge Universalから新しいEventシステムが組み込まれた。ある処理にこちらの用意した処理を割り込ませる機能であり、介入しづらい処理にも介入できるようになりました。<br>
| + | <p> |
− | BukkitPluginのEventシステムと考え方は同じです。<br>
| + | Minecraft Forge Universalから新しいEventシステムが組み込まれた. アノテーションと引数により実行されるメソッドを動的に割り込ませる機能であり, 割り込みタイミングによってはItemやEntity側でやるよりもよりスマートに(より保守しやすい)コードで実装できるのが特徴である. |
− | 詳しく知りたい場合は、DI(依存性の注入)やAOP(アスペクト指向)などの概念、Struts2, SpringFrameworkなどの有名なフレームワークがキーワードとなるかもしれません。
| + | </p> |
| + | <p> |
| + | BukkitPluginのEventシステムやFMLの@ModなどもこのEventシステムと同じ概念である. より詳しく知りたい場合のキーワードとして, DI(依存性の注入)やAOP(アスペクト指向)などの概念, Struts2, SpringFrameworkなどが有名なフレームワークとしてある. |
| + | </p> |
| | | |
− | == 基礎 == | + | ==基本== |
− | 説明を抽象化するため、SampleEventという架空のイベントを仮定して説明します。<br>
| + | <p> |
− | | + | 基本はFMLの基本と同じである. すなわちイベント時に呼び出されるメソッドにアノテーションと引数を指定する. |
− | メソッドにアノテーションと引数を指定すると、引数に指定したイベントの発火に合わせて呼び出されるようになります。<br>
| + | </p> |
− | 引数でイベントを指定するため、メソッド名は自由に設定できます。
| |
| <source lang = "java"> | | <source lang = "java"> |
− | @SubscribeEvent | + | @ForgeSubScribe |
− | public void onSampleEvent(SampleEvent event) { | + | public void sampleEvent(Event event) |
| + | { |
| } | | } |
| </source> | | </source> |
− | このメソッドの場合はSampleEventがEventBusを介してpostされる箇所で呼び出されます。メソッドを持つクラスまたはそのインスタンスは適切な箇所でEventBusに登録する必要があります。
| + | <p> |
− | | + | このメソッドはEventクラスが生成される箇所で呼び出される. なお, メソッドを持つクラスは適切な箇所でMinecraftForgeのAPIを使って登録する必要がある. |
− | Minecraft Forgeの扱えるEventは[[Minecraft Forge API#イベント]]を参照すること。
| + | </p> |
− | | |
− | == 解説 ==
| |
− | | |
− | === イベントハンドラ ===
| |
− | 処理を挟み込むには、イベントを待ち受けるメソッド(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>
| |
− | | |
− | ==== イベントハンドラの設定 ====
| |
− | 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">
| |
− | MinecraftForge.EVENT_BUS.register(new ForgeEventHook())
| |
− | </source> | |
− | または
| |
| <source lang = "java"> | | <source lang = "java"> |
− | MinecraftForge.EVENT_BUS.register(ForgeEventHook.class) | + | MinecraftForge.EVENT_BUS.register(new ForgeEventClass()) |
| </source> | | </source> |
− | というように登録します。
| + | <p> |
− | | + | もちろんここでは具体的なサンプルは扱わない. Eventクラスは実際にはどこかで呼ばれることはないし, クラス名も適当である. しかし, Forgeのイベントは概ねこの呼び出し方ということを把握しておく必要がある. |
− | インスタンスで登録した場合は、インスタンスメソッドでハンドラを記述します。<br>
| + | </p> |
− | クラスで登録した場合は、クラスメソッドでハンドラを記述します。<br>
| |
− | MinecraftForge.EVENT_BUSに限っては、@EventBusSubscriberでクラスを注釈すれば自動的に登録されます。<br>
| |
− | この場合は、クラスメソッドでハンドラを記述します。
| |
− | | |
− | MinecraftForgeが提供するEventBusには三種類あります。
| |
− | ; MinecraftForge.EVENT_BUS
| |
− | : 基本的なイベント群はここから発火される。以下のBusで発火されないイベントはここと覚えれば良い。
| |
− | ; MinecraftForge.TERRAIN_GEN_BUS
| |
− | : 地形生成に関するイベントはここから発火される。
| |
− | ; MinecraftForge.ORE_GEN_BUS
| |
− | : 鉱石生成に関するイベントはここから発火される。
| |
− | | |
− | 以前はFMLCommonHandler.instance().bus()という物もありましたが、MinecraftForge.EVENT_BUSに統合されました。
| |
− | | |
− | === 利用可能なメソッド解説 ===
| |
− | イベントによって様々あるが、ここではベースクラス[[Event]]について解説する。
| |
− | | |
− | ==== イベントのキャンセル ====
| |
− | イベントがCancelableな場合は、イベントをキャンセルできます。<br>
| |
− | 具体的にはsetCanceledでtrueを渡すとキャンセルすることになります。<br>
| |
− | イベントがCancelableかどうかは、そのイベントにCancelableアノテーションがついているかによって判断できます。<br>
| |
− | スキップできる処理はイベントによって異なりますが、バニラの処理と後述するreceiveCanceledがtrueのハンドラの処理が対象になります。<br>
| |
− | 詳しくはそれぞれのEventのドキュメントを参照しています。
| |
− | | |
− | ==== イベントの結果 ====
| |
− | イベントがHasResultな場合は、イベントに結果を持たせられます。<br>
| |
− | 具体的にはsetResultを呼び出すことで結果を決定できます。<br>
| |
− | イベントがHasResultかどうかは、そのイベントにHasResultアノテーションがついているかによって判断できます。<br>
| |
− | ResultはDENY,DEFAULT,ALLOWの三値をとります。<br>
| |
− | 各イベントで若干意味は異なりますが、基本的には
| |
− | それぞれ、
| |
− | ; DENY
| |
− | : 強制不成功。イベントをキャンセルするのによく似る。
| |
− | ; DEFAULT
| |
− | : 判定をバニラと同様にする。結果への不介入。処理は挟むが、その後の処理については別に干渉したくない場合に用いる。
| |
− | ; ALLOW
| |
− | : 強制成功。DENYの全く逆。
| |
| | | |
− | == イベントの自作 == | + | ==Forgeが扱えるイベント一覧== |
− | Minecraft Forgeの利用しているイベントの仕組みと全く同一の仕組みを利用して、イベントを自作できます。<br>
| + | <p> |
− | 自作と言っても、Eventクラスを継承していればイベントとして機能しますので、好きに設計することができます。<br>
| + | MinecraftForge 6.3.0.363時点, なおこれはイベントに関わるクラスを列挙したものである. |
− | クラスを作成すれば、あとは任意のタイミングで任意のEventBusからpostを呼び出せば発火できます。
| + | </p> |
| | | |
− | CancelableやHasResultの指定も同様に行えますが、その場合スキップ判定等は自分で行わなければならないことに注意してください。
| + | *net.minecraftforge.event |
| + | **CommandEvent |
| + | *net.minecraftforge.event.world |
| + | **ChunkEvent |
| + | **ChunkDataEvent |
| + | **WorldEvent |
| + | *net.minecraftforge.event.entity |
| + | **EntityEvent |
| + | **PlaySoundAtEntityEvent |
| + | *net.minecraftforge.event.entity.living |
| + | **LivingEvent |
| + | **LivingAttackEvent |
| + | **LivingDeathEvent |
| + | **LivingDropsEvent |
| + | **LivingFallEvent |
| + | **LivingHurtEvent |
| + | **LivingSetAttackTargetEvent |
| + | **LivingSpecialSpawnEvent |
| + | *net.minecraftforge.event.entity.minecart |
| + | **MinecartEvent |
| + | **MinecartCollisionEvent |
| + | **MinecartInteractEvent |
| + | **MinecartUpdateEvent |
| + | *net.minecraftforge.event.entity.player |
| + | **PlayerEvent |
| + | **AttackEntityEvent |
| + | **ArrowNockEvent |
| + | **ArrowLooseEvent |
| + | **EntityInteractEvent |
| + | **BonemealEvent |
| + | **EntityItemPickupEvent |
| + | **FillBucketEvent |
| + | **PlayerDestroyItemEvent |
| + | **PlayerSleepInBedEvent |
| + | **PlayerDropsEvent |
| + | **UseHoeEvent |
| + | *net.minecraftforge.event.entity.item |
| + | **ItemEvent |
| + | **ItemExpireEvent |
| + | **ItemTossEvent |