模组文件(Mod Files)
模组文件负责决定哪些模组会被打包进你的 JAR 文件、在 "Mods" 菜单中显示哪些信息,以及你的模组应如何在游戏中加载。
gradle.properties
gradle.properties 文件包含了你的模组的一些常用属性,例如模组 ID(mod id)或模组版本(mod version)。在构建过程中,Gradle 会读取这个文件中的值,并在多个地方进行内联替换,比如在 neoforge.mods.toml 文件中。这样,你只需在一个地方修改属性值,所有相关配置都会自动同步更新。
大多数属性在 MDK 的 gradle.properties 文件 中也有注释进行详细说明。
| 属性(Property) | 描述(Description) | 示例(Example) |
|---|---|---|
org.gradle.jvmargs | 允许你为 Gradle 传递额外的 JVM 参数。最常见的用途是为 Gradle 分配更多或更少的内存。注意,这只影响 Gradle 本身,不影响 Minecraft。 | org.gradle.jvmargs=-Xmx3G |
org.gradle.daemon | 构建时 Gradle 是否应使用守护进程(daemon)。 | org.gradle.daemon=false |
org.gradle.parallel | Gradle 是否应通过分叉 JVM 实现并行执行项目。 | org.gradle.parallel=false |
org.gradle.caching | Gradle 是否应复用之前构建任务的输出结果。 | org.gradle.caching=false |
org.gradle.configuration-cache | Gradle 是否应复用之前构建的配置信息。 | org.gradle.configuration-cache=false |
org.gradle.debug | 是否将 Gradle 设置为调试模式。调试模式主要会增加 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 | 你的模组的人类可读显示名称。默认情况下,该名称只会在模组列表中显示,但像 JEI 这样的模组也会在物品提示中突出显示模组名称。 | mod_name=Example Mod |
mod_license | 你的模组所使用的许可证。建议填写你所用的 SPDX 标识符 和/或许可证链接。你可以访问 https://choosealicense.com/ 来选择合适的许可证。 | mod_license=MIT |
mod_version | 你的模组版本号 ,会显示在模组列表中。更多信息请参阅版本管理页面。 | mod_version=1.0 |
mod_group_id | 参见 Group ID。 | mod_group_id=com.example.examplemod |
mod_authors | 模组作者,会显示在模组列表中。 | mod_authors=ExampleModder |
mod_description | 模组描述,作为多行字符串显示在模组列表中。可以使用换行符(\n),会被正确替换为换行。 | mod_description=Example mod description. |
模组 ID(Mod ID)
模组 ID(mod ID)是区分你的模组与其他模组的主要方式。它被广泛用于各种场景,包括作为你的模组注册表(Registry)的命名空间,以及作为你的资源包和数据包的命名空间。如果有两个模组使用相同的 ID,游戏将无法加载它们。
因此,你的模组 ID 应当独特且易于记忆。通常,它会是你的模组显示名称的小写形式,或者是其变体。模组 ID 只能包含小写字母、数字和下划线,长度必须在 2 到 64 个字符之间(含边界值)。
在 gradle.properties 文件中更改此属性会自动同步到其他地方,除了主模组类中的 @Mod 注解。那里的值需要你手动修改,使其与 gradle.properties 文件中的值保持一致。
组 ID(Group ID)
虽然 build.gradle 文件中的 group 属性只有在你计划将模组发布到 maven 时才是必须的,但始终正确设置它是一种良好习惯。你可以通过 gradle.properties 文件中的 mod_group_id 属性来配置这一点。
组 ID 应设置为你的顶级包名。更多信息请参见打包(Packaging)。
# 在你的 gradle.properties 文件中
mod_group_id=com.example
你的 Java 源码目录(src/main/java)下的包结构也应遵循这一规范,内部包名代表模组 ID:
com
- example (在 group 属性中指定的顶级包)
- mymod (模组 ID)
- MyMod.java (重命名后的 ExampleMod.java)
neoforge.mods.toml
neoforge.mods.toml 文件位于 src/main/resources/META-INF/neoforge.mods.toml,采用 TOML 格式,用于定义你的模组元数据。它还包含有关模组如何被加载进游戏的附加信息,以及会在“模组”菜单中显示的相关信息。MDK 提供的 neoforge.mods.toml 文件包含了对每一项的注释,本文将更详细地进行说明。
neoforge.mods.toml 文件可分为三部分:与具体模组无关的属性(与模组文件关联)、模组属性(每个模组一个分区)、依赖配置(每个模组或模组组的依赖分区)。neoforge.mods.toml 文件中的某些属性是强制性的;这些必填属性必须指定值,否则会抛出异常。
在默认的 MDK 中,Gradle 会将此文件中的各种属性替换为 gradle.properties 文件中指定的值。例如,license="${mod_license}" 这一行表示 license 字段会被 gradle.properties 中的 mod_license 属性替换。像这样被替换的值应在 gradle.properties 中修改,而不是直接在这里更改。
非模组专属属性(Non-Mod-Specific Properties)
非模组专属属性是与 JAR 文件本身关联的属性,用于指示如何加载模组(mod)以及包含其他全局元数据。
| 属性(Property) | 类型(Type) | 默认值(Default) | 描述(Description) | 示例(Example) |
|---|---|---|---|---|
modLoader | string | 必填 | 模组(mod)所使用的语言加载器(loader)。可用于支持其他语言结构,比如将主文件写为 Kotlin 对象,或用不同的方法确定入口点(entrypoint),如接口或方法。NeoForge 提供了 Java 加载器 "javafml" 和低代码/无代码加载器 "lowcodefml"。 | modLoader="javafml" |
loaderVersion | string | 必填 | 语言加载器可接受的版本范围,采用 Maven 版本范围 表达。例如 javafml 和 lowcodefml 目前的版本为 1。 | loaderVersion="[1,)" |
license | string | 必填 | 本 JAR 内模组所采用的许可证(license)。建议填写你所用的 SPDX 标识,和/或许可证的链接。你可以访问 https://choosealicense.com/ 来帮助选择合适的许可证。 | license="MIT" |
showAsResourcePack | boolean | false | 当设为 true 时,模组的资源将在“资源包(Resource Packs)”菜单中作为单独的资源包显示,而不是与“模组资源(Mod Resources)”包合并。 | showAsResourcePack=true |
showAsDataPack | boolean | false | 当设为 true 时,模组的数据文件将在“数据包(Data Packs)”菜单中作为单独的数据包显示,而不是与“模组数据(Mod Data)”包合并。 | showAsDataPack=true |
services | array | [] | 模组所使用的服务(service)数组。这会被 NeoForge 对 Java 平台模块系统(Java Platform Module System)实现时,作为模块的一部分进行消费。 | services=["net.neoforged.neoforgespi.language.IModLanguageProvider"] |
properties | table | {} | 替换属性(substitution property)表。StringSubstitutor 会用它将 ${file.<key>} 替换为对应的值。 | properties={"example"="1.2.3"}(可 通过 ${file.example} 引用) |
issueTrackerURL | string | 无 | 用于报告和跟踪模组问题的网址(URL)。 | "https://github.com/neoforged/NeoForge/issues" |
services 属性在功能上等同于在模块中指定 uses 指令,它允许加载指定类型的服务。
另外,你也可以在 src/main/resources/META-INF/services 文件夹下,通过服务文件来定义。服务文件的文件名应为服务的全限定名,文件内容则为要加载的服务名称(参见 AtlasViewer 模组的这个示例)。
模组专用属性(Mod-Specific Properties)
模组专用属性与通过 [[mods]] 标头指定的模组相关联。这是一个表数组;所有的键/值属性都会附加到该模组,直到下一个标头为止。
# examplemod1 的属性
[[mods]]
modId = "examplemod1"
# examplemod2 的属性
[[mods]]
modId = "examplemod2"
| 属性(Property) | 类型(Type) | 默认值(Default) | 描述(Description) | 示例(Example) |
|---|---|---|---|---|
modId | string | 必填 | 参见 模组 ID。 | modId="examplemod" |
namespace | string | modId 的值 | 模组的命名空间(namespace)覆盖。必须也是一个有效的 模组 ID,但可以包含点号或短横线。目前未被使用。 | namespace="example" |
version | string | "1" | 模组的版本,推荐采用 Maven 版本格式的变体。如果设置为 ${file.jarVersion},则会被 JAR 包 manifest 文件中的 Implementation-Version 属性值替换(在开发环境下显示为 0.0NONE)。 | version="1.20.2-1.0.0" |
displayName | string | modId 的值 | 模组的显示名称。当需要在界面上展示模组时(如模组列表、模组不匹配时)使用。 | displayName="Example Mod" |
description | string | '''MISSING DESCRIPTION''' | 在模组列表界面显示的模组描述。推荐使用 多行文本字面量。该值支持国际化,详情见 模组元数据翻译。 | description='''This is an example.''' |
logoFile | string | 无 | 在模组列表界面使用的图片文件名及扩展名。路径必须是以 JAR 或源码集根目录为起点的绝对路径(如主源码集为 src/main/resources)。有效的文件名字符包括小写字母(a-z)、数字(0-9)、斜杠(/)、下划线(_)、点号(.)和短横线(-)。完整字符集为 [a-z0-9_-.]。 | logoFile="test/example_logo.png" |
logoBlur | boolean | true | 渲染 logoFile 时是否使用 GL_LINEAR*(true)或 GL_NEAREST*(false)。简单来说,就是在缩放 logo 时是否进行模糊处理。 | logoBlur=false |
updateJSONURL | string | 无 | 一个指向 JSON 的 URL,供 更新检查器 使用,以确保当前游玩的模组为最新版本。 | updateJSONURL="https://example.github.io/update_checker.json" |
features | table | {} | 参见 特性。 | features={java_version="[17,)"} |
modproperties | table | {} | 与该模组关联的键值对表。NeoForge 不使用,主要供模组自身使用。 | modproperties={example="value"} |
modUrl | string | 无 | 指向模组下载页面的 URL。目前未被使用。 | modUrl="https://neoforged.net/" |
credits | string | 无 | 在模组列表界面显示的致谢和鸣谢信息。 | credits="The person over here and there." |
authors | string | 无 | 在模组列表界面显示的作者信息。 | authors="Example Person" |
displayURL | string | 无 | 在模组列表界面显示的模组展示页面的 URL。 | displayURL="https://neoforged.net/" |
enumExtensions | string | 无 | 用于 枚举扩展 的 JSON 文件路径。 | enumExtensions="META_INF/enumextensions.json" |
featureFlags | string | 无 | 用于 特性标志 的 JSON 文件路径。 | featureFlags="META-INF/feature_flags.json" |
功能(Features)
功能系统允许模组在加载时声明对某些设置、软件或硬件的需求。如果某项功能未被满足,模组加载将会失败,并告知用户相关的需求。目前,NeoForge 提供了以下功能:
| 功能(Feature) | 描述(Description) | 示例(Example) |
|---|---|---|
javaVersion | 可接受的 Java 版本范围,格式为 Maven 版本范围。应当与 Minecraft 支持的 Java 版本一致。 | features={javaVersion="[17,)"} |
openGLVersion | 可接受的 OpenGL 版本范围,格式为 Maven 版本范围。Minecraft 需要 OpenGL 3.2 或更高版本。如果你希望要求更高版本的 OpenGL,可以在这里指定。 | features={openGLVersion="[4.6,)"} |
访问转换器专用属性(Access Transformer-Specific Properties)
访问转换器专用属性(Access Transformer-specific properties)通过 [[accessTransformers]] 头部与指定的访问转换器绑定。这是一个 表数组;所有键/值属性会被绑定到该访问转换器,直到下一个头部出现。访问转换器头部是可选的;但一旦指定,内部所有元素都是必需的。
| 属性(Property) | 类型(Type) | 默认值(Default) | 描述(Description) | 示例(Example) |
|---|---|---|---|---|
file | string | 必填 | 详见 添加 ATs。 | file="at.cfg" |
Mixin 配置属性(Mixin Configuration Properties)
Mixin 配置属性(Mixin Configuration Properties)通过 [[mixins]] 头部与指定的 mixin 配置绑定。这是一个 表数组;所有键/值属性会被绑定到该 mixin 配置块,直到下一个头部出现。mixin 头部是可选的;但一旦指定,内部所有元素都是必需的。
| 属性(Property) | 类型(Type) | 默认值(Default) | 描述(Description) | 示例(Example) |
|---|---|---|---|---|
config | string | 必填 | mixin 配置文件的位置。 | config="examplemod.mixins.json" |
依赖配置(Dependency Configurations)
模组(Mod)可以指定其依赖项,NeoForge 会在加载模组前检查这些依赖配置。这些配置通过 表数组 [[dependencies.<modid>]] 创建,其中 modid 是使用该依赖的模组标识符。
| 属性(Property) | 类型(Type) | 默认值(Default) | 描述(Description) | 示例(Example) |
|---|---|---|---|---|
modId | string | 必填 | 被添加为依赖项的模组(mod)的标识符。 | modId="jei" |
type | string | "required" | 指定该依赖项的性质:"required"(默认值)表示如果缺少此依赖,则阻止该模组加载;"optional" 表示如果缺少依赖不会阻止模组加载,但仍会验证依赖的兼容性;"incompatible" 表示如果存在该依赖,则阻止模组加载;"discouraged" 表示即使存在该依赖仍允许模组加载,但会向用户发出警告。 | type="incompatible" |
reason | string | 无 | 可选的用户提示信息,用于说明为何需要此依赖,或为何与其不兼容。 | 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 | 无 | 指向依赖项下载页面的 URL。目前未被使用。 | referralUrl="https://library.example.com/" |
两个模组(mod)的 ordering(加载顺序)可能因为循环依赖而导致崩溃,例如,如果模组 A 必须在模组 B 之前("BEFORE")加载,同时模组 B 也必须在模组 A 之前("BEFORE")加载,就会出现这种情况。
模组入口点(Mod Entrypoints)
现在 neoforge.mods.toml 文件已经填写完成,我们需要为模组提供一个入口点(entrypoint)。入口点本质上是执行模组的起始位置。具体的入口点由 neoforge.mods.toml 中使用的语言加载器(language loader)决定。
javafml 与 @Mod
javafml 是 NeoForge 为 Java 编程语言提供的语言加载器。入口点通过一个带有 @Mod 注解(annotation)的公共类(public class)来定义。@Mod 的值必须包含在 neoforge.mods.toml 中指定的某个模组 id。从这里开始,所有初始化逻辑(例如 注册事件 或 添加 DeferredRegister)都可以在该类的构造函数中指定。
主模组类(main mod class)只能有一个公共构造函数,否则会抛出 RuntimeException。构造函数可以包含以下 任意 参数,顺序不限;这些参数都不是强制要求的,但不允许有重复参数。
| 参数类型 | 描述 |
|---|---|
IEventBus | 模组专用事件总线(用于注册、事件等) |
ModContainer | 保存该模组元数据的抽象容器 |
FMLModContainer | 由 javafml 定义的实际容器,保存该模组的元数据,是 ModContainer 的扩展 |
Dist | 该模组正在加载的 物理端 |
@Mod("examplemod") // 必须与 neoforge.mods.toml 中的某个模组 id 匹配
public class ExampleMod {
// 合法的构造函数,仅使用了两个可用的参数类型
public ExampleMod(IEventBus modBus, ModContainer container) {
// 在这里初始化逻辑
}
}
默认情况下,@Mod 注解会在 两端 都加载。可以通过指定 dist 参数来改变这一行为:
// 必须与 neoforge.mods.toml 中的某个模组 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 是一种语言加载器(language loader),用于将数据包(datapacks)和资源包(resource packs)作为模组(mods)分发,而无需在代码中编写入口点(entrypoint)。之所以命名为 lowcodefml 而非 nocodefml,是因 为未来可能会有一些小的扩展需要极少量的编码。