构造你的模组
本节我们将关注如何将你模组中的文件分类,以及这些文件分别该做什么。
打包
请给包起一个独一无二的名字。如果你有一个与项目相关的URL,你可以将其作为你的顶级包名。例如如果你持有“example.com”,那你就可以用 com.example 作为你的最顶级的包的名称。
重要: 如果你没有域名,则不要将域名用于你的顶级包的名称。你的包用任何名称都是完全可以的,比如你的名字、昵称或mod的名字。
在顶级包名(如果你有顶级包名的话)之后,你需要为你的模组起一个独一无二的名称,例如 examplemod 。在本例中,最后的包名看上去类似 com.example.examplemod 。
mcmod.info 文件
该文件定义了你模组的元数据(metadata)。该文件中的信息可以通过主游戏界面的Mods按钮来查看。一个info文件可以描述多个模组。当一个模组被 @Mod 记号标记时,它就可以定义 useMetadata 属性,该属性默认为 false 。当 useMetadata 为 true 时, mcmod.info 当中的元数据会重写曾经在记号中定义过了的所有信息。
mcmod.info文件使用JSON格式,JSON的根元素是一个对象列表,每个对象都可以描述一个modid。这个文件的存储位置应该像 src/main/resources/mcmod.info 这样。一个用于描述模组的基础信息的 mcmod.info 应当看上去像这样:
[{
"modid": "examplemod",
"name": "Example Mod",
"description": "Lets you craft dirt into diamonds. This is a traditional mod that has existed for eons. It is ancient. The holy Notch created it. Jeb rainbowfied it. Dinnerbone made it upside down. Etc.",
"version": "1.0.0.0",
"mcversion": "1.10.2",
"logoFile": "assets/examplemod/textures/logo.png",
"url": "minecraftforge.net/",
"updateJSON": "minecraftforge.net/versions.json",
"authorList": ["Author"],
"credits": "I'd like to thank my mother and father."
}]
默认的Gradle设置以 ${version} 代替了项目版本一项,并使用 ${mcversion} 来代替Minecraft的版本,但只有 mcmod.info 文件中这样做。因此请务必使用 mcmod.info 中的属性名而不是直接将这些值硬编码到源代码中去。下面是一个模组可以拥有的属性, 其中“必需”表示该属性没有默认值并且如果没有值的话会报错。除此之外,你还应当定义 description,version,mcversion,url 和 authorList 这几项。
属性名 | 类型 | 默认值/缺省设置 | 描述 |
---|---|---|---|
modid | string | 必需 | 这段描述所对应的modid。如果模组没有装载,有关改模组的描述会被忽略。 |
name | string | 必需 | 这个模组的名字(译者注:英文名字)。 |
description | string | "" | 关于这个模组的1~2段简要描述文字。 |
version | string | "" | 模组的版本。 |
mcversion | string | "" | Minecraft的版本。 |
url | string | "" | 指向模组主页的链接。 |
updateUrl | string | "" | 定义但未被使用,已被updateJSON项取代。 |
updateJSON | string | "" | 指向版本更新信息JSON的URL。 |
authorList | [string] | [] | 该模组的作者列表。 |
credits | string | "" | 可以提及任何在模组制作过程中要感谢的事物(译者注:比如为制作模组提供了帮助的人,其实就是致谢)。 |
logoFile | string | "" | 模组标志的路径。它会首先在classpath中被解析,因此应当将其放在一个不会引起命名冲突的地方,这个位置可以在你的assets文件夹中。 |
screenshots | [string] | [] | 一个应当在模组信息页面展示的图片列表,目前还没有实现。(译者注:没有实现的部分尽量不要去动,可能会导致不可预知的后果) |
parent | string | "" | 父模组的modid。这项将允许另一个模组的模块列在信息页的下方,效果可以参考Buildcraft。 |
useDependencyInformation | boolean | false | 如果该项的值为true并且有Mod.useMetadata的话,表格中接下来的三个依赖项将会生效,否则无效。 |
requiredMods | [string] | [] | 一个由modid构成的列表。如果有一个对应的模组缺失了,游戏将会崩溃。这项不会影响模组的装载顺序!要设置模组的装载顺序和需求,请在后一项中再创建一次对应的项。 |
dependencies | [string] | [] | 一个由modid构成的列表。列出的模组都会在此模组之前加载,如果为空则什么也不会发生(译者注:该模组依赖的模组列表,通常称为前置模组列表)。 |
dependants | [string] | [] | 一个由modid构成的列表。列出的模组都会在此模组之后加载,如果为空则什么也不会发生(译者注:依赖该模组的模组列表,通常称为后置模组列表)。 |
一个使用了很多属性的mcmod.info良好典范就是BuildCraft(https://gist.github.com/anonymous/05ad9a1e0220bbdc25caed89ef0a22d2)。
模组文件
概括一下,我们会从一个在你设置好模组信息之后的一个文件开始介绍,并将其放入你的包中。这就是你模组的入口点(译者注:Entry Point)并且会包含一些特殊的标号来如此标记它。
@Mod是什么?
这是一个向Forge模组装载器表明该类是一个模组入口点。该记号包含了多种与该模组有关的元数据,包括被指定接收@EventHandler事件的类。
以下是@Mod记号属性的一个表:
属性值 | 类型 | 默认值/缺省设置 | 描述 |
---|---|---|---|
modid | string | 必需 | 模组的一个独一无二的标识符。必须全部小写并且限制在64个字符以内。 |
name | string | "" | 这个模组的名字(译者注:英文名字)。 |
version | string | "" | 模组的版本。应当仅由数点间隔的数字组成,推荐按照Semantic Versioning(https://semver.org)。即使useMetadata项为true,最好也要把这个版本号写上。 |
dependencies | string | "" | 模组的依赖。指定依赖的方式在Forge的@Mod的javadoc中是这样描述的: ‘一个依赖字串可以用以下四种前缀开头:"before", "after", "required-before", "required-after";然后是":"和modid。 也可以通过"@"加版本范围来指定某个模组的版本范围*,这是可选的。 如果有一个必需的模组缺失了,或者有一个模组的版本不在当前指定的版本范围内,游戏将不会启动,并提示玩家所需要的模组版本。’ |
useMetadata | boolean | false | 如果属性为true,@Mod中的属性将被mcmod.info中的值覆盖。 |
clientSideOnly serverSideOnly | boolean boolean | false false | 如果有一个被设为true,该jar文件将会跳过另一端的部分(译者注:即被标记的这段代码不会在值为false的属性对应的运行端上运行),也不会在不运行的那一端加载。如果两个都为true的话,游戏会崩溃。 |
acceptableMinecraftVersions | string | "" | 该模组可以在指定范围的Minecraft中运行*,为空的话表示所有版本都可以运行。 |
acceptableRemoteVersions | string | "" | 设定一个远端版本范围来实现服务器可以认定为有效版本的版本范围*(译者注:一般为与该版本兼容的mod版本范围即可)。默认值""匹配当前版本(译者注:即该文件所属的jar的版本),"*"表示匹配任意版本。注意当使用"*"进行匹配时,连接的客户端即便没有这个模组也可被服务器接受。 |
acceptableSaveVersions | string | "" | 一个指定的兼容存档的版本范围信息*。如果你不遵循常规版本转换规则的话,请使用SaveInspectionHandler来替代。 |
certificateFingerprint | string | "" | 请参见jar签名的教程。 |
modLanguage | string | "java" | 编写该模组所使用的编程语言,只能是"scala"或者"java"。 |
modLanguageAdapter | string | "" | 该模组的语言适配器(language adapter)所在的路径。该类必须有默认构造方法并事项ILanguageAdapter接口。如果指定的类无法满足要求,Forge就会崩溃。如果设置了的话,它将重写modLanguage项。 |
canBeDeactivated | boolean | false | 该项还尚未实现。但是如果模组可以被停用的话(例如minimap),该项会被设为true并且模组将接收FMLDeactivationEvent来执行清理工作。 |
guiFactory | string | "" | 该模组的GUI工厂类的的路径(如果有的话)。GUI工厂是用来自定义设置界面的,必须实现IModGuiFactory接口。有关示例详见FMLConfigGuiFactory。 |
updateJSON | string | "" | 检查更新的JSON所在的URL,详见Forge Update Checker。 |
*所有的版本范围都使用 Maven Version Range Specification(https://maven.apache.org/enforcer/enforcer-rules/versionRanges.html)。
你将可以在Forge源码下载(https://files.minecraftforge.net/)中找到一个示例模组。
使用子包来保持代码整洁
与其把代码堆在一个类里并把所有东西都打在一个包里,我们建议将你的模组拆分到不同的子包(subpackage)当中。
一个常见的子包策略是将包内文件再分为common和client代码,分别来讲,common是在两端上都需要运行的部分,而client是能在客户端上运行的代码。在common包中可以有像Items(物品),Blocks(方块)和Tile Entities(块状实体)(它们也可以分别再各自分在一个包中)。像GUI和渲染器就可以放在client包中。
注意: 打包风格只是一个建议,尽管这是一个常用的风格。你可以随意用你已知的打包体系。
你可以通过将你的代码用子包分开的方法来更有组织地增加自己模组的内容。
类命名模式
一个常见的类命名模式能够较容易描述这个类的内容,并且也能够使得使用你的模组进行开发的其他人更加轻松。
例如:
- 一个叫做PowerRing的Item(物品)应当在item包中,并命名为ItemPowerRing。
- 一个叫做NotDirt的Block(方块)应当在block包中,并命名为BlockNotDirt。
- 最后,一个叫做SuperChewer的TileEntity(块状实体)应当在tile或者tileentity包中,并命名为TileSuperChewer。
在为你的类命名时考虑它是什么类别的对象能够使得识别一个类或通过这个类猜测它生成的对应对象变得更加容易。