## FML生命周期事件
FML生命周期事件,顧名思義,就是FML加載、關閉、和Mod加載等等相關的事件,這些希望監聽對應事件的方法使用`@EventHandler`注解修飾,并且應在被`@Mod`注解修飾的主類下,Forge會尋找并注冊僅含一個參數并且參數符合特定類型的方法。如下面三個FML生命周期事件是最常用的:
* `FMLPreInitializationEvent`
* `FMLInitializationEvent`
* `FMLPostInitializationEvent`
這三個事件的使用方法已經講過,此處不再贅述。
還有下面兩個事件:
* `FMLConstructionEvent`在Mod開始加載時觸發。
* `FMLLoadCompleteEvent`在Mod加載完成時觸發。
除上面這些之外,還有下面的這些比較常用的用于服務端的FML生命周期事件:
* `FMLServerAboutToStartEvent`
* `FMLServerStartingEvent`
* `FMLServerStartedEvent`
* `FMLServerStoppingEvent`
* `FMLServerStoppedEvent`
想必讀者已經可以猜出來這五個事件的異同,并了解這些事件被觸發的條件了。
## 注冊事件
Forge的事件系統一直在Forge中占有十分重要的地位,可以這么說,沒有事件,就沒有Mod。大家可以注意到,主類的`preInit`,`init`,`postInit`方法,全部都是事件驅動的。換句話說,理論上一個Mod的開發教程本身應該從事件講起。
Forge的事件系統幾乎涵蓋了方方面面,從服務端到客戶端,從世界生成到物品方塊行為,從玩家行為到一般實體行為,等等。
Forge的事件系統分為兩類,一類是FML生命周期事件,一類是Minecraft事件。
Forge本身提供了很多Minecraft事件,這些事件基本上可以完成對Minecraft大部分物品、方塊、實體等特性的修改,并且這些事件的數量還在不斷地上升。開發者只需要注冊一個包含監聽這些事件的方法的類,Forge就會掛鉤上這些方法。這些方法使用`@SubscribeEvent`注解進行修飾,Forge尋找并掛鉤這些方法的方式和上面的FML生命周期事件類似,只不過由于掛鉤的方式不同,調用的時候效率要更高。
首先我們創造一個類。在包`net.xiaobang.bm.common`下新建一個文件`EventLoader.java`:
`src/main/java/net/xiaobang/bm/common/EventLoader.java`
~~~
package net.xiaobang.bm.common;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
public class EventLoader {
public EventLoader(FMLInitializationEvent e) {
MinecraftForge.EVENT_BUS.register(this);//注冊本類的所有事件
/*
除此之外,Forge還提供了需要在MinecraftForge.TERRAIN_GEN_BUS上注冊的地形生成事件,需要在
MinecraftForge.ORE_GEN_BUS上注冊的礦物生成事件等等。
*/
}
@SubscribeEvent//當forge注冊所有事件的時候,會掃描具有此注解的方法,再掛鉤。Forge會根據方法的參數類型
//來區分不同的事件,比如onPlayerInteract方法掛鉤的就是玩家在和物品或方塊互動的時候觸發的事件PlayerInteractEvent
public void onPlayerInteract(PlayerInteractEvent event){//玩家點擊事件
if (!event.world.isRemote)//判斷是否是客戶端調用此事件,event.world.isRemote與event.entityPlayer.isServerWorld同理
System.out.println("玩家" + event.entityPlayer.getDisplayName() + "左鍵/右鍵了一下");
}
}
~~~
(注釋寫不下,寫這里了)`@SubscribeEvent`注解有兩個參數,其中一個是`receiveCanceled`,與是否取消該事件相關,默認為`false`,這個參數不太常用,我們不去管它。還有一個參數是`priority`,比較常用,表示事件的優先級,可能的情況有五種:
* `EventPriority.HIGHEST`
* `EventPriority.HIGH`
* `EventPriority.NORMAL`
* `EventPriority.LOW`
* `EventPriority.LOWEST`
默認的優先級是`EventPriority.NORMAL`,當然,如果想自定優先級,往往都會選擇`EventPriority.HIGH`,和`EventPriority.HIGHEST`。如果沒有特殊需求,這一項最好默認。
最后在CommonProxy注冊EventLoader:
**`src/main/java/net/xiaobang/bm/common/CommonProxy.java`**(部分)
~~~
public void init(FMLInitializationEvent event)
{
new CraftingLoader();
new EventLoader();
}
~~~
最后的最后,打開游戲嘗試一下把。
## Event類解析
Forge提供的所有事件,都是`cpw.mods.fml.common.eventhandler.Event`類的子類。當前Forge版本下這個類的所有的子類的用法zzzz大佬在他的教程[附錄](https://fmltutor.ustc-zzzz.net/%E9%99%84%E5%BD%95A-%E4%BA%8B%E4%BB%B6%E5%88%97%E8%A1%A8)(高版本)中列出了一張表,以供讀者參考。這一部分針對Event類本身。
Event類添加了下面幾個公開方法:
* `public boolean isCancelable()`
返回該事件是否可以被取消。
* `public boolean isCanceled()`
返回該事件是否已被取消。
* `public void setCanceled(boolean cancel)`
設置該事件是否被取消。
* `public boolean hasResult()`
返回該事件是否有結果,添加了`@HasResult`注解的事件默認為`true`,否則為`false`。
* `public Result getResult()`
返回該事件的結果,有`Result.DENY`,`Result.DEFAULT`,`Result.ALLOW`三種,默認為`Result.DEFAULT`。
* `public void setResult(Result value)`
為該事件設置一個結果。
* `public ListenerList getListenerList()`
獲取所有注冊該事件的監聽器。
* `public EventPriority getPhase()`
獲取該事件的優先級,上面已有說明。
* `public void setPhase(EventPriority value)`
設置該事件的優先級,上面已有說明。
(以上大部分來自zzzz大佬的教程)