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的基本框架完成了。