Forge是什么
- Minecraft是商業軟件,源代碼不公開
- MCP項目反編譯了Minecraft,為我們提供了Minecraft的“源代碼”,即便並不是Mojang工作室寫的那樣
- Forge是MinecraftForge和Forge Mod Loader(FML)的總稱。MinecraftForge基於MCP,提供了Minecraft中的各種機制的實現接口,如事件系統,物品注冊等等。而FML,顧名思義,Mod加載器,開始游戲加載界面右下角不斷敲打的鐵砧就是它了。
Side
Minecraft擁有雙客戶端/服務端的結構,具體來說,就是:
- Minecraft有顯然的物理客戶端,即我們運行的Minecraft本體,還有顯然的物理服務端,即多人服務器運行的server.jar。
- 在每一個物理客戶端內部,還有所謂的邏輯客戶端和邏輯服務端,比如,所有的游戲邏輯放在邏輯服務端,而實體渲染等放在邏輯客戶端。
事件
和 Java 中 AWT 和 Swing 類似,Minecraft 中的行為也是事件驅動的,我們需要為事件掛載事件監聽器,當相應事件觸發時,對應的監聽器中的代碼就會執行。
Mod開發中有兩大類事件:
-
FML事件(FML 生命周期)
主要分為 preinit,init 和 postinit 等,顧名思義,就是加載 Mod 的三個階段,通常來講,preinit 階段進行物品、方塊等的注冊,init 階段進行合成表的注冊,postinit 進行 Mod 之間的關聯處理。
-
Forge事件
Forge 事件需要掛載到事件總線上,主要有:
- 一般事件總線(MinecraftForge.EVENT_BUS)
- 礦物生成總線(MinecraftForge.ORE_GEN_BUS)
- 地形生成總線(MinecraftForge.TERRAIN_GEN_BUS)
掛載方法:
EventListener 類
@SubscribeEvent public static void onSomeEventHappened(AEvent event) { // 當然這個 AEvent 要換成某個存在的事件。 } // 注冊 MinecraftForge.EVENT_BUS.register(EventListener.class);
或者
@SubscribeEvent public void onSomeEventHappened(AEvent event) { // 當然這個 AEvent 要換成某個存在的事件。 } // 注冊 MinecraftForge.EVENT_BUS.register(new EventListener());
有沒有感覺很熟悉呢?
public void actionPerformed(ActionEvent e){ // TODO } new JButton().addActionListener(this);
個人認為,Minecraft Forge 的事件系統就可以類比 AWT/Swing 里的監聽器來理解。
其中,注解
@SubscribeEvent
表明下面的方法是一個事件監聽器,也就是說監聽器方法的名字不是固定的,監聽的事件由參數指定。此外,也可以這么寫,用於將事件直接注冊到 EVENT_BUS 上:
// 這個注解的意思是“將這個類注冊到事件總線中去,該事件監聽器屬於 mymod 這個 Mod” // 它相當於 MinecraftForge.EVENT_BUS.register(MyEventListener.class) @Mod.EventBusSubscriber(modid = "mymod") public final class MyEventListener { @SubscribeEvent public static void onEventFired(ACertainEvent event) { } }
Mod的基本框架
-
首先,在src/main/java/目錄下新建項目所在包,比如
moonfan.mymod
-
在mymod包內新建Java類,建議類名即Mod名的駝峰命名形式,這就是Mod的主類了,這里就是 MyMod.java 。
-
復制以下代碼,包名和modid自行修改。
MyMod.java
@Mod(modid = MyMod.MODID, name = MyMod.NAME, version = MyMod.VERSION, acceptedMinecraftVersions = "1.12.2") public class MyMod { public static final String MODID = "mymod"; public static final String NAME = "My Mod"; public static final String VERSION = "1.0.0"; @Mod.Instance(MyMod.MODID) public static MyMod instance; @SidedProxy(clientSide = "moonfan.mymod.client.ClientProxy", serverSide = "moonfan.mymod.common.CommonProxy") public static CommonProxy proxy; @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { proxy.preInit(event); } @Mod.EventHandler public void init(FMLInitializationEvent event) { proxy.init(event); } @Mod.EventHandler public void postInit(FMLPostInitializationEvent event) { proxy.postInit(event); } }
- @Mod 和 @Mod.Instance 注解對mod信息進行引用
- 前面介紹了Forge中的Side概念,@SidedProxy即為對Common(Server)和Client的引用,這是之后要創建的兩個類。
- 前面介紹了Forge的事件系統,@Mod.EventHandler 則標識了三個FML事件,三個方法分別對應三個事件,調用proxy的對應方法。
-
新建
moonfan.mymod.common.CommonProxy
和moonfan.mymod.client.ClientProxy
類,且ClientProxy繼承自CommonProxy:CommonProxy.java
public class CommonProxy { @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { // TODO } @Mod.EventHandler public void init(FMLInitializationEvent event) { // TODO } @Mod.EventHandler public void postInit(FMLPostInitializationEvent event) { // TODO } }
ClientProxy.java
public class ClientProxy extends CommonProxy { @Override public void preInit(FMLPreInitializationEvent event) { super.preInit(event); } @Override public void init(FMLInitializationEvent event) { super.init(event); } @Override public void postInit(FMLPostInitializationEvent event) { super.postInit(event); } }
這樣,Mod的基本框架完成了。