用户:MashKJo/1.12.2模组开发教程/3.Mod主类与代理详解
从这一节开始,我们终于可以真正地写代码了!
你可能会注意到,在路径src/main/java
路径下有com.example.examplemod
这个包,在这个包里有个文件ExampleMod.java。这是Forge给你做的示例,删掉即可。
然后你再根据你的项目具体情况创建一个新的包,由于笔者要写的是Mod开发教程的示例代码,因此笔者把包名定为net.tutorial_mod
,并在该包下创建Mod主类源文件:
src/main/java/net/tutorial_mod/TutorialMod.java:
package net.tutorial_mod; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.SidedProxy; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; @Mod(modid = TutorialMod.MODID, name = TutorialMod.NAME, version = TutorialMod.VERSION) public class TutorialMod{ public static final String MODID = "tutorial_mod"; public static final String NAME = "Tutorial Mod"; public static final String VERSION = "1.0"; @Mod.Instance public static TutorialMod INSTANCE; @SidedProxy(clientSide = "net.tutorial_mod.client.ClientProxy", serverSide = "net.tutorial_mod.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); } }
src/main/java/net/tutorial_mod/CommonProxy.java:
package net.tutorial_mod; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; public class CommonProxy{ public void preInit(FMLPreInitializationEvent event){ } public void init(FMLInitializationEvent event){ } public void postInit(FMLPostInitializationEvent event){ } }
src/main/java/net/tutorial_mod/client/ClientProxy.java:
package net.tutorial_mod.client; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.tutorial_mod.CommonProxy; 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主类打上了@Mod
这个注解,这个注解用于告知FML:这个类是一个Mod的主类,这里我们还传入了三个参数:modid、Mod的英文名称和Mod的当前版本,且这三个参数实际上以静态字段的形式存在于我们的Mod主类中。其中,modid要求只包含小写字母、数字、下划线,且长度不得超过64个字符。FML会自动将这个类实例化。
不过我们有的时候还需要获取我们的模组主类的实例,这个时候,@Mod.Instance
的作用就体现出来了:它会将相应的对象赋给被它修饰的字段。
那么,Mod.EventHandler
的作用又是什么?这牵扯到后面的事件的相关知识。不过这里先提一下:这三个被它修饰的方法实际上都是事件监听器,分别对应FML加载Mod的三个阶段:PreInitialization、Initialization和PostInitialization。在这三个阶段中,FML会自动执行对应监听器中的代码。注意:按照约定俗成的一个惯例,跨Mod交互应该在PostInitialization阶段完成。
所以那个proxy又是什么?这是为了区分物理端之间的不同而出现的。我们要让我们的模组做到在物理客户端和物理服务端上的表现不同,比如:不在物理服务端进行渲染操作。所以我们使用@SidedProxy
注解给proxy字段自动赋值,FML会根据当前物理端决定到底实例化哪个类并赋给它,而Mod主类中的三个监听器方法全部代理给proxy来做,本身看不见任何实现。
可能有读者会疑惑:怎么没有ServerProxy,而是给物理服务端用CommonProxy?之前说过,我们的模组里不该有@SideOnly(Side.SERVER)
的代码啊,所以实际上物理服务端该执行的代码,物理客户端一定会执行。因此,直接给物理服务端用CommonProxy就行。
另外,读者应该注意到了,ClientProxy.java被笔者新建了一个文件夹client来存放。这种只在物理客户端有意义的类,通常就会放在client文件夹中,这是一个好习惯。