模组文件与决定以何种方式将你的模组打包进你的JAR包,Mods菜单中要显示什么信息,你的模组应该怎样加载进游戏有关。
gradle.properties
gradle.properties
文件里面有各种有关于你的模组的常见属性,例如模组id或者模组版本。在构建的时候,Gradle会读取这些文件中的值并且把他们内联到各个地方,例如neoforge.mods.toml
文件。这样,你只需要在一处更改值,他们就会为你应用到任何别的地方。
大部分值也会在MDK的gradle.properties
文件中以注释的形式来解释其作用。
属性 | 描述 | 例子 |
---|
org.gradle.jvmargs
| 允许你传递给Gradle更多JVM参数。最常见的是用来为Gradle分配更多/更少的内存空间。注意这是为Gradle本身分配的,不是Minecraft。 | org.gradle.jvmargs=-Xmx3G
|
org.gradle.daemon
| 决定了Gradle在构建的时候是否使用守护程序。 | org.gradle.daemon=false
|
org.gradle.debug
| 决定了Gradle是否设置为debug模式。debug模式主要意味着更多的Gradle日志输出。注意,这是Gradle本身的设置,不是Minecraft的。 | org.gradle.debug=false
|
minecraft_version
| 你的模组所基于的Minecraft版本。必须与neo_version 相匹配。 | minecraft_version=1.20.6
|
minecraft_version_range
| 本模组可以使用的Minecraft版本范围,作为一个Maven的版本命名范围。需要注意的是快照,预发布版本和正式版本候选并不能保证被正确的排序,因为他们并不遵循maven版本命名。 | minecraft_version_range=[1.20.6,1.21)
|
neo_version
| 你的模组所基于的NeoForge版本。必须与minecraft_version相匹配。查看NeoForge版本命名规则以获取更多关于NeoForge如何定义版本号的信息。 | neo_version=20.6.62
|
neo_version_range
| 本模组可以使用的NeoForge版本范围,以Maven版本范围。 | neo_version_range=[20.6.62,20.7)
|
loader_version_range
| 这个模组可以使用的模组加载器的版本范围,以Maven版本范围。要注意的是加载器的版本是与NeoForge的版本解耦的。 | loader_version_range=[1,)
|
mod_id
| 查看模组ID | mod_id=examplemod
|
mod_name
| 你的模组在自然语言下的显示名称。默认情况下,这个值只能在mod列表中看到,但是一些例如JEI的模组也会在物品的工具提示中显示这个值。 | mod_name=Example Mod
|
mod_license
| 你的模组提供了什么许可证。建议将其设置为你正在使用的SPDX identifier或者是一个通向许可证的链接。你可以访问https://choosealicense.com/来帮助你挑选你想要的许可证。 | mod_license=MIT
|
mod_version
| 你的模组的版本,在模组列表中会显示这个值。参考版本命名页面获取更多信息。 | mod_version=1.0
|
mod_group_id
| 请参考群组ID。 | mod_group_id=com.example.examplemod
|
mod_authors
| 模组的作者,会在模组列表中显示。 | mod_authors=ExampleModder
|
mod_description
| 模组的介绍文字,在模组列表中显示的是一个多行的字符串。换行符\n 可以正常使用。 | mod_description=Example mod description.
|
模组ID
模组ID是你的模组与其他模组相区分的主要方式。它在很多不同的地方都有用到,包括作为你的模组注册时的命名空间,并作为你的资源包和数据包的命名空间。如有同时存在两个具有相同id的模组,游戏不会加载。
因此,你的模组ID应该是独特且好记的。通常,它会是你的模组的显示名称(但是是小写的),或者是一些变体。模组ID只能包含小写字母,数字和下划线,并且长度必须控制在2-64个字符之内(包含两侧)。
ℹ️info
改变gradle.properties
文件中的这些属性会自动应用改动到任何地方,除了你的主要模组类中的@Mod 注释。因此你需要手动修改这些地方来与gradle.properties
里面的这些值相匹配。
群组ID
build.gradle
中的group
属性只有在你打算将你的模组发布到maven的时候才有意义,不过正确的设置这些属性总是个好的练习。你可以通过gradle.properties
中的mod_group_id
属性来修改它。
群组id应该设置在你的顶级包中,参考打包来获取更多信息。
// 在你的gradle.properties文件中
mod_group_id=com.example
在你的Java源文件(src/main/java
)中的包也应该遵循这个构造,带着一个子包代表模组id:
com
- example (群组属性中指定的顶级包)
- mymod (模组id)
- MyMod.java (由ExampleMod.java重命名而来)
neoforge.mods.toml
位于src/main/resources/META-INF/neoforge.mods.toml
的neoforge.mods.toml
文件,是一个TOML格式来定义模组元数据的文件。它也包含了一些关于模组该怎样加载进游戏的额外信息,同时也是显示在Mods菜单里面的信息。由MDK提供的neoforge.mods.toml
文件包含了解释每个入口的注释,在这里这些解释更详细。
neoforge.mods.toml
文件可以被分为三个部分:非模组特定属性(被链接到模组文件);模组属性(每个模组都有一个小节);以及依赖配置。一些与neoforge.mods.toml
相关联的属性是强制的;强制属性需要一个特定的值,不然会抛出一个异常。
ℹ️注意
在默认的MDK中,Gradle用gradle.properties
文件中的特定值替换了这个文件中的各种属性。例如,license="${mod_license}"
一行的意思是license
字段被替换成了来自gradle.properties
的mod_license
属性。像这样被替换掉的值应该在gradle.properties
中改变,而不是这里
非模组特定属性
非模组特定属性是与JAR本身有关系的,指示了如何加载模组和任何附加的全局元数据。
属性 | 类型 | 默认 | 描述 | 例子 |
---|
modLoader
| string | 强制的 | 模组使用的语言加载器。可以用来支持主动语言结构,像是主文件的Kotlin目标,或者决定入点的不同方式,像是一个接口或者方法。NeoForge提供了Java加载器“javafml”以及低代码/无代码加载器“lowcodefml”。 | modLoader="javafml"
|
loaderVersion
| string | 强制的 | 语言加载器可以接受的版本范围,以Maven版本范围的方式表达。对于javafml 和lowcodefml 来说,目前版本是1。 | loaderVersion="[1,)"
|
license
| string | 强制的 | 这个JAR中的模组使用的许可证。建议将其设置为你正在使用的SPDX identifier或者是一个通向许可证的链接。你可以访问https://choosealicense.com/ 来帮助你挑选你想要的许可证。 | license="MIT"
|
showAsResourcePack
| boolean | false
| 当设置为true 的时候,模组的资源在资源包菜单会被显示为一个独立的资源包,而不是被合并到“Mod Resources”资源包里面。 | showAsResourcePack=true
|
showAsDataPack
| boolean | false
| 当设置为true 的时候,模组的资源在数据包菜单会被显示为一个独立的数据包,而不是被合并到“Mod Data”数据包里面。 | showAsDataPack=true
|
services
| array | []
| 这是你的模组用到的一组服务。它会被用在为你的模组创建的模块里,这个模块是基于NeoForge实现的Java平台模块系统 | services=["net.neoforged.neoforgespi.language.IModLanguageProvider"]
|
properties
| table | {}
| 这是一个用于替换的属性表。StringSubstitutor 会用它来把 ${file.<key>} 替换成对应的内容。 | properties={"example"="1.2.3"} (can then be referenced by ${file.example} )
|
issueTrackerURL
| string | nothing | 用于报告和追踪模组bug的网址。 | "https://github.com/neoforged/NeoForge/issues"
|
ℹ️注意
services
属性的作用和在模块里写 uses
指令是一样的,都是用来加载某种类型的服务。
另一种方法是在 src/main/resources/META-INF/services
文件夹里创建一个服务文件。文件名要用服务的完整名称,文件内容则是要加载的服务的名称(可以参考 AtlasViewer 模组的例子)。
模组特定属性
模组的专属属性要用 [[mods]]
标题来指定。这是一个表格的数组;在这个标题下面的所有键值对都会归到这个模组,直到遇到下一个标题为止。
# examplemod1的属性
[[mods]]
modId = "examplemod1"
# examplemod2的属性
[[mods]]
modId = "examplemod2"
属性 | 类型 | 默认 | 描述 | 例子 |
---|
modId
| string | 强制的 | 查阅模组ID | modId="examplemod"
|
namespace
| string | 模组id的值 | 这是用来覆盖的模组命名空间。它必须是一个合法的模组ID,但可以加上点或短横线。目前还没用到。 | namespace="example"
|
version
| string | "1"
| 这是模组的版本号,最好用类似 Maven 的版本格式。如果设成 ${file.jarVersion} ,它就会被 JAR 文件清单里的 Implementation-Version 属性值替换掉(开发环境会显示 0.0NONE )。 | version="1.20.2-1.0.0"
|
displayName
| string | value of modId | 这是模组在屏幕上显示的名字(比如模组列表、模组不兼容提示里)。 | displayName="Example Mod"
|
description
| string | '''MISSING DESCRIPTION'''
| 这是模组的介绍,会在模组列表里显示。最好用多行文本字符串来写。这段文字还可以翻译成其他语言,想了解更多可以看“翻译模组元数据”这部分。 | description='''This is an example.'''
|
logoFile
| string | nothing | 这是模组列表上用的图片的文件名和扩展名。文件位置必须从 JAR 文件或源代码根目录开始的绝对路径(比如主源代码的 src/main/resources )。文件名只能包含小写字母(a-z)、数字(0-9)、斜杠(/)、下划线(_)、点(.)和短横线(-)。所有允许的字符是 [a-z0-9_.-] 。 | logoFile="test/example_logo.png"
|
logoBlur
| boolean | true
| 用 GL_LINEAR* (true)还是 GL_NEAREST* (false)来渲染 logo 图片。简单地说,就是缩放 logo 的时候要不要让它变模糊。 | logoBlur=false
|
updateJSONURL
| string | nothing | 这是个网址,指向一个 JSON 文件,用来给更新检查器用的,它可以检查你玩的模组是不是最新的。 | updateJSONURL="https://example.github.io/update_checker.json"
|
features
| table | {}
| 请查阅特性。 | features={java_version="[17,)"}
|
modproperties
| table | {}
| 这是一个和这个模组相关的键值对表格。NeoForge 自己不用,主要是给其他模组用的。 | modproperties={example="value"}
|
modUrl
| string | nothing | 指向模组下载页面的 URL。目前未使用。 | modUrl="https://neoforged.net/"
|
credits
| string | nothing | 这是在模组列表里显示的模组贡献者和感谢名单。 | credits="The person over here and there."
|
authors
| string | nothing | 这是在模组列表里显示的模组作者。 | authors="Example Person"
|
displayURL
| string | nothing | 这是模组在模组列表里显示的那个介绍页面的网址。 | displayURL="https://neoforged.net/"
|
enumExtensions
| string | nothing | 这是用来扩展枚举的 JSON 文件的路径。 | enumExtensions="META_INF/enumextensions.json"
|
featureFlags
| string | nothing | 用于特性标志的 JSON 文件的文件路径。 | featureFlags="META-INF/feature_flags.json"
|
这个特性系统让模组可以要求在加载的时候,某些设置、软件或者硬件必须可用。如果哪个要求没达到,模组就加载不了,还会告诉用户缺了什么。现在 NeoForge 提供了这些特性:
特性 | 描述 | 例子 |
---|
javaVersion
| 允许使用的 Java 版本范围,用的是 Maven 的版本表示法。这应该和 Minecraft 支持的版本一致。 | features={javaVersion="[17,)"}
|
openGLVersion
| 允许使用的 OpenGL 版本范围,用的是 Maven 的版本表示法。Minecraft 最低要求是 OpenGL 3.2。如果你的模组需要更新的 OpenGL 版本,就在这里设置。 | features={openGLVersion="[4.6,)"}
|
访问转换器的专用属性
访问转换器的专属属性要用 [[accessTransformers]]
标题来指定。这是一个表格的数组;在这个标题下面的所有键值对都会归到这个访问转换器,直到遇到下一个标题为止。访问转换器标题可以不写;但是一旦写了,里面的东西就都得填上。
属性 | 类型 | 默认 | 描述 | 例子 |
---|
file
| string | 强制的 | 参阅添加AT | file="at.cfg"
|
Mixin 的配置属性
Mixin 的配置属性要用 [[mixins]]
标题来指定。这是一个表格的数组;在这个标题下面的所有键值对都会归到这个 Mixin 配置,直到遇到下一个标题为止。[[mixins]]
标题可以不写;但是一旦写了,里面的东西就都得填上。
属性 | 类型 | 默认 | 描述 | 例子 |
---|
config
| string | 强制的 | mixin配置文件的位置 | config="examplemod.mixins.json"
|
依赖配置
模组可以设置它们需要哪些其他模组才能运行,NeoForge 会在加载模组前检查这些依赖。这些依赖配置要用 [[dependencies.<modid>]]
这种表格数组来写,其中 modid
是指需要这个依赖的模组的 ID。
属性 | 类型 | 默认 | 描述 | 例子 |
---|
modId
| string | mandatory | 这是作为依赖加进来的模组的 ID。 | modId="jei"
|
type
| string | "required"
| 这个选项用来设置依赖的类型:“required” 是默认的,意思是如果缺了这个依赖,模组就加载不了;“optional” 意思是即使缺了这个依赖,模组也能加载,但是还是会检查一下这个依赖是不是兼容的;“incompatible” 意思是如果装了这个依赖,模组就不能加载;“discouraged” 意思是即使装了这个依赖,模组也能加载,但是会给用户一个警告。 | type="incompatible"
|
reason
| string | nothing | 这是一个可选的给用户看的消息,用来解释为什么需要这个依赖,或者为什么它不兼容。 | reason="integration"
|
versionRange
| string | ""
| 允许使用的语言加载器版本范围,用的是 Maven 的版本表示法。如果是空字符串,就表示匹配所有版本。 | versionRange="[1, 2)"
|
ordering
| string | "NONE"
| 这个设置用来决定模组是必须在这个依赖之前("BEFORE")还是之后("AFTER")加载。如果顺序无所谓,就写 "NONE"。 | ordering="AFTER"
|
side
| string | "BOTH"
| 这个依赖需要在哪个地方存在:“CLIENT”(客户端)、“SERVER”(服务器)或者“BOTH”(两边都要)。 | side="CLIENT"
|
referralUrl
| string | nothing | 指向依赖项下载页面的 URL。目前未使用。 | referralUrl="https://library.example.com/"
|
❗危险
两个模组的加载顺序可能由于循环依赖而导致崩溃,例如,如果模组 A 必须在模组 B 之前(“BEFORE”)加载,同时模组 B 又必须在模组 A 之前(“BEFORE”)加载。
模组入口点
搞定了 neoforge.mods.toml
之后,我们得给模组弄个入口点。入口点其实就是模组开始运行的地方。用哪个入口点是由 neoforge.mods.toml
里用的语言加载器决定的。
javafml
与 @Mod
javafml
是 NeoForge 给 Java 用的一个语言加载器。入口点要用一个带 @Mod
注解的公共类来定义。@Mod
里面的值必须是 neoforge.mods.toml
文件里写好的模组 ID 之一。然后,所有的初始化代码(比如注册事件或者添加 DeferredRegisters
)都写在这个类的构造函数里面。
主模组类只能有一个 public
的构造函数,不然会抛出 RuntimeException
错误。构造函数可以随便用下面这些参数,顺序也无所谓,而且这些参数也不是一定要有。但是,不能有重复的参数。
类型 | 描述 |
---|
IEventBus
| 这是模组专用的事件总线(用来注册东西、处理事件之类的)。 |
ModContainer
| 保存此模组元数据的抽象容器 |
FMLModContainer
| 这是 javafml 实际用来装模组元数据的容器,它是 ModContainer 的扩展。 |
Dist
| 模组当前运行的物理环境。 |
@Mod("examplemod") // 必须与neoforge.mods.toml中的一个mod id匹配
public class ExampleMod {
// 这是一个有效的构造函数,它只用了两种参数类型。
public ExampleMod(IEventBus modBus, ModContainer container) {
// 在此写初始化逻辑
}
}
默认情况下,@Mod
注解会在客户端和服务器都加载。你可以通过设置 dist
参数来改变这个行为。
// 必须与neoforge.mods.toml中的一个mod id匹配
// 这个模组的类只会在客户端加载
@Mod(value = "examplemod", dist = Dist.CLIENT)
public class ExampleModClient {
// 有效的构造函数
public ExampleModClient(FMLModContainer container, IEventBus modBus, Dist dist) {
// 在此写客户端逻辑
}
}
ℹ️注意
在 neoforge.mods.toml
里写的一个条目不一定需要有个对应的 @Mod
注解。反过来,neoforge.mods.toml
里的一个条目也可以对应好几个 @Mod
注解,比如说你想把通用的代码和只有客户端才用的代码分开写。
lowcodefml
lowcodefml
是一种语言加载器,它可以让你把数据包和资源包当成模组来发布,不需要写任何代码。之所以叫 lowcodefml
而不是 nocodefml
,是因为以后可能会加一些只需要写一点点代码的功能。