3.2 ModID和其他信息
前面章节说过,这行代码和下面的代码是等价的:
注解也是类的一种,而上述代码就是声明注解的实例的方式。
我们注意到,有的注解的实例没有后面的括号,这是因为它没有字段需要赋值,或者说它的所有字段都有默认值,比如之前看到的@EventHandler注解,但目前这个@Mod注解后面需要指定一些字段。现在打开Mod类的声明,先对一个注解的字段及其默认值有一个直观的认识。
按住Ctrl键,同时把鼠标指针移动到@Mod的位置,然后单击,便能打开下面的画面:
目前不知道@Retention,@Target的含义,不过没关系,能知道它们是@Mod类本身的两个注解。我们也可以容易地猜出来public@interface Mod这一行的作用是声明一个名为Mod的注解,而@interface的作用是声明注解的特殊标志。
这个以/*开头,*/结尾的(注:严格来说,这个是以/**开头,以*/结尾的,这里我们不讨论两者细微的差别)就是注释,这个注释说明的就是下面这一行代码:
很明显,这里声明的是一个被称为ModID的对象,将它和主类对比,可以得出:为针对Mod主类的@Mod注解定义了modid,它的值是examplemod。
如果读者并不了解Java,那么可能不理解这里讲的内容。先看上图中的注释写了什么,如下所示。
把这段话翻译成中文,再进行归纳。
● ModID是一个Mod的标识符,也就是说,是一个Mod的身份。
● ModID中的英文字母需要全部是小写,最长的长度也不得超过64个字符。
● ModID可能会被用于其他Mod来识别Mod,同时为Mod添加的新物品、方块等都将有ModID的标识。
● ModID将会有一个自动分配的Resource Domain,同时所有的用途都将受到ModID的限制。
这里提到了一个概念:Resource Domain,后面章节将提到它的使用方法。
把ModID改成想要的名字,比如将其设置为fmltutor:
能够很容易得知,这个字段决定的正是ModID的值。我们接着往下看:
这里指定了一个Mod的名称(Name),一个会直接暴露给玩家看的Mod名称。Mod的名称可以出现很多字符,大写英文字母、横线、空格也都可以。
指定一个名称,并将它设置为"FMLTutor":
我们注意到和name有关的声明后面还有一个default,这是在指定name的默认(Default)值,也就是说,下面两行代码是等价的:
换言之,之前为name指定的是空字符串,现在指定的是有意义的名字。然后再看后面的内容:
这个指定的是Mod的版本号(Version Number),默认值是空字符串,我们指定的是1.0。对于版本号,可以施行的标准有很多,不过有一个名为语义化版本(Semantic Versioning)的标准十分流行,感兴趣的读者可以自行查找语义版本的相关资料。后面的内容在这里就不再赘述了,只叙述几个重点的问题:
● dependencies指的是Mod所要求的和其他Mod的关系,默认值为空字符串,代表没有要求,本书不涉及。
- 在相应的要求不被满足时,FML也会抛出一个错误而不是继续加载这个Mod。
- 实际上在生成Mod时,Forge会默认添加一个要求:运行Mod的版本必须不低于当前使用的Forge版本。
● clientSideOnly决定Mod是否只会在客户端加载,这通常用于客户端专用的Mod,默认为false,代表在客户端和服务端都加载。
● serverSideOnly决定Mod是否只会在服务端加载,这通常用于服务端专用的Mod,默认为false,代表在客户端和服务端都加载。
● acceptedMinecraftVersions指的是Mod接收的Minecraft版本,当版本不符时,FML会抛出一个错误而不是继续加载这个Mod。
- 1.12.2(本书)表示该Mod只支持Minecraft 1.12.2版本。
- [1.9,1.10.2]表示该Mod支持从1.9(包含)到1.10.2(包含)的所有Minecraft版本。
- [1.11,1.12)表示该Mod支持从1.11(包含)到1.12(不包含)的所有Minecraft版本,也就是1.11、1.11.1和1.11.2三个版本。
- [1.9,)表示该Mod支持从1.9(包含)之后出现的所有Minecraft版本。
- (,1.7.10],[1.10,)表示该Mod支持1.7.10(包含)之前出现的所有Minecraft版本和从1.10(包含)之后出现的所有Minecraft版本。
可以指定本书所针对的Mod只支持1.12.x的版本,也就是[1.12,1.13):
现在就已经整理完成@Mod注解了。
3.2.1 mcmod.info
原则上一个@Mod注解,能把自己的Mod和其他Mod区分开已经可以了,但如果仅使用这一注解会遇到什么样的问题?
● 缺少必要的解释说明信息,比如一个Mod的简介说明,以及它的作者(或作者们)。
● 如果想要通过一个Mod的JAR获取到Mod的基本信息,那么就需要检查其中的所有包中的所有的类,然后一个一个地找是否带有@Mod注解,这样十分麻烦而且效率也低。
在前面的章节中也已经提到过了,在通常情况下一个Mod会有一个对应的mcmod.info文件,这个文件位于资源文件夹的根目录,是描述Mod的关键文件,在生成Mod之后,它位于JAR的根目录。这样,如果想要了解一个Mod的相关信息,只需要检查这个Mod的mcmod.info文件就可以了。我们现在用IntelliJ IDEA打开这个文件:
这是一个JSON(JavaScript Object Notation)文件。JSON文件是一种十分简单的用于存储信息的文件。在Minecraft和Forge中会被大量用到。如果读者之前有过制作资源包的经历,那么对这个文件应该有一些印象。这个文件的格式十分简单,想要详细了解的读者可以自行前往相关网站查阅相关的资料,如JSON标准的维护方所提供的介绍网站等,这里不再赘述。
● 首先要修改modid,使它和之前在@Mod注解里的modid一致(fmltutor)。
● 然后把name修改成和@Mod注解里一样的值(FML Tutor)。
● 后面的内容就可随意了,只不过需要注意的一点是,version和mcversion的值千万不要修改,因为它们将会在生成Mod的JAR时被自动替换。下面的代码是本书针对Mod所使用的mcmod.info:
这个文件将在什么时候用到呢?启动Minecraft客户端,然后单击“Mods”按钮,找到自己的Mod。
大部分mcmod.info中的信息,都显示在这里了。
3.2.2 构建Mod的相关选项
现在虽然修改了ModID,但是可以注意到生成的文件的默认名称仍然是modid-1.0.jar。需要修改这个名称。
打开build.gradle这一文件,并找到以下三行代码。
● 第一行代码设置了Mod的版本号,请将其与@Mod注解中的数据保持一致。
● 第二行代码设置了Mod的包名,虽然这个包名的用途已经超出了本书的范围,但是仍然建议设置一下。
● 第三行代码设置了Mod在构建完成后的文件名前缀,在大部分情况下,它的名称应该和Mod的名称保持一致。
以//开头的部分是注释,IntelliJ IDEA也设置成了浅灰色以提醒开发者。因此可以直接删掉注释。
将这三行代码修改成下面这种形式:
现在再执行gradlew.bat clean,然后执行gradlew.bat build,我们就可以看到最后生成的Mod文件名已经发生变化了:
3.2.3 资源管理
狭义上的资源指的是只有在resources目录下才会有的资源文件,这些文件大多可以和资源包里的文件对应起来,比如贴图材质、方块物品模型和合成表等。广义上的资源指所有Minecraft中有独立意义的概念,比如方块、物品和生物等。
无论是哪一种资源,在Minecraft中都是通过ResourceLocation管理的,它在代码中对应的是net.minecraft.util.ResourceLocation类。一个ResourceLocation通常会有一个资源域(Resource Domain)和一个资源路径(Resource Path)。对于资源域,每个Mod的所有资源的资源域都和ModID是一致的,而对于Minecraft游戏本体(有时它被称为Vanilla),它的所有资源的资源域都以minecraft开头。
通常表示一种ResourceLocation的方式是把资源域和资源路径通过冒号连接起来的,比如:
● minecraft:lava代表一个岩浆方块。
● minecraft:feather代表一个羽毛物品。
● minecraft:polar_bear代表一个名为北极熊的生物。
● immersiveengineering:ore代表沉浸工程里的矿物方块。
对于资源文件,特定的ResourceLocation会对应着资源文件中的特定位置。
● 资源域决定了资源将位于的目录下,如果resource_domain是资源域,那么资源应位于assets/resource_domain目录下。
● 资源路径决定了资源的文件名,如果resource_path是资源路径,那么资源的名称可以是resource_path.json,或者是resource_path.png,或者直接就是resource_path,这将视情况而定。
可以翻看Minecraft资源包,或者直接打开游戏本体文件(versions/1.12.2/1.12.2.jar),就能很容易地知道它们的所有资源都位于assets/minecraft目录下,而且大量文件的文件名和方块物品生物等的名字都是重合的。
对于ResourceLocation,其资源域和资源路径都应该采用所有字母均为小写,单词之间也通过下画线连接的形式。有时简单地把单词连接起来,不使用下画线分隔也是可以的(比如immersiveengineering,它和immersive_engineering都是可以的)。一个明显的推论是,由于ModID和资源域相同,因此也应该遵守这一约定。当然,fmltutor是满足这种形式的。
如果读者之前有制作过资源包的经验,那么应该对resources目录下的另一个文件并不陌生,这个文件就是pack.mcmeta。前面的章节也提到过,该文件是用来描述资源包的。可以直接打开:
● _comment是注释,与具体内容无关。
● description就是这个资源包的描述,虽然这个描述根本看不到,而只有相关内容出错时,才会用到这个描述,但是也可以把它进行整理。
● pack_format指的是这个资源包的版本,在Minecraft 1.8.9及之前是1,Minecraft 1.9到1.10.2是2,而Minecraft 1.11及以后就是3了。至于不同的版本号有什么不同,_comment已经解释清楚了,这里就不再赘述了。
把pack.mcmeta修改成想要的形式:
到此,所有和Mod相关的描述性信息都已经修改完了。