版本管理(Versioning)
本文将详细介绍 Minecraft 和 NeoForge 的版本管理方式,并为模组(mod)版本管理提供一些推荐做法。
Minecraft
Minecraft 采用了 语义化版本号(semantic versioning)。语义化版本号,简称 "semver",格式为 主版本号.次版本号.修订号(major.minor.patch)。例如,Minecraft 1.20.2 的主版本号是 1,次版本号是 20,修订号是 2。
自 2011 年 Minecraft 1.0 发布以来,主版本号一直保持为 1。在此之前,版本管理方案经常变动,曾出现过如 a1.1(Alpha 1.1)、b1.7.3(Beta 1.7.3)等版本,甚至还有 infdev 这样的版本,完全没有遵循清晰的版本号规则。由于主版本号 1 已经维持了十多年,再加上社区内 "Minecraft 2" 的玩笑,普遍认为这个主版本号几乎不会改变。
快照版(Snapshots)
快照版(Snapshot)不遵循标准的 semver 规则。它们的命名格式为 YYwWWa,其中 YY 表示年份的最后两位(如 23),WW 表示当年的第几周(如 01)。例如,快照版 23w01a 就是 2023 年第 1 周发布的快照。
后缀 a 用于同一周内发布多个快照的情况(第二个快照会命名为 23w01b,以此类推)。Mojang 过去有时会用到这种命名方式。类似的后缀还用于像 20w14infinite 这样的快照,例如 2020 年无限维度愚人节玩笑。
预发布版与候选发布版(Pre-releases and Release Candidates)
当一个快照周期接近尾声时,Mojang 会开始发布所谓的预发布版(pre-releases)。预发布版通常被认为已经功能完备,主要用于修复 bug。其命名方式为对应版本的 semver 后缀 -preX。例如,1.20.2 的第一个预发布版命名为 1.20.2-pre1。通常会有多个预发布版,依次命名为 -pre2、-pre3 等。
同样地,当预发布周期结束后,Mojang 会发布候选发布版 1(Release Candidate 1),即在版本号后加上 -rc1,比如 1.20.2-rc1。Mojang 的目标是发布一个可以直接作为正式版的候选版,如果没有新的 bug,这个候选版就会成为正式版。但如果出现了意外的 bug,还会有 -rc2、-rc3 等后续候选版,其命名方式与预发布版类似。
NeoForge
NeoForge 采用了一种改编过的语义化版本号系统:主版本号对应 Minecraft 的次版本号,次版本号对应 Minecraft 的修订号,修订号则是 NeoForge 的“实际”版本号。例如,NeoForge 20.2.59 就是 Minecraft 1.20.2 的第 60 个 NeoForge 版本(从 0 开始计数)。开头的 1 被省略,因为几乎不可能会改变,具体原因见上文。
在 NeoForge 的某些地方也会用到 Maven 版本范围,例如在 neoforge.mods.toml 文件中指定 Minecraft 和 NeoForge 的版本范围。这些范围大部分情况下与 semver(语义化版本)兼容,但并不完全一致(例如 pre 标签不会被考虑在内)。
模组(Mods)
没有绝对最佳的版本管理体系。不同的开发风格、项目规模等因素都会影响你选择何种版本管理方式。有时候,不同的版本体系也可以组合使用。本节将为你概 述一些常用的版本管理系统,并给出实际例子。
通常,一个模组文件的命名格式为 modid-<version>.jar。例如,如果我们的模组 id 是 examplemod,版本号是 1.2.3,那么最终的模组文件名就是 examplemod-1.2.3.jar。
版本管理体系只是建议,并不是强制性的规则。尤其是在何时“提升”版本号以及如何提升方面更是如此。如果你想采用不同的版本管理方式,完全没有问题。
语义化版本(Semantic Versioning)
语义化版本("semver")由三部分组成:major.minor.patch(主版本.次版本.修订号)。当代码库发生重大变更时,主版本号会提升,通常对应于主要的新特性或重要的 bug 修复。引入了次要特性时提升次版本号,仅包含 bug 修复时则提升修订号。
通常大家默认,所有 0.x.x 版本都属于开发阶段;首次正式发布时,版本号应提升到 1.0.0。
实际上,“次版本号用于特性,修订号用于 bug 修复”这条规则经常被忽略。一个很典型的例子就是 Minecraft 本身,它用次版本号表示主要特性,修订号表示次要特性,而 bug 修复则出现在快照(snapshot)中(见上文)。
根据模组的更新频率,这些数字可能较小也可能很大。例如,Supplementaries 当前的版本号是 2.6.31(撰写时)。三位甚至四位数的修订号,尤其是 patch 部分,是完全可能的。
“简化版”与“扩展版”语义化版本
有时候你会看到只有两位数字的 semver,这就是所谓的“简化版”语义化版本,或称“2 部分”语义化版本。它的版本号只采用 major.minor(主版本.次版本)格式。这通常用于只添加少量简单对象、很少需要更新(除了 Minecraft 版本升级)的小型模组,这类模组经常会一直停留在 1.0。
“扩展版”语义化版本,或称“4 部分”语义化版本,则包含四个数字(例如 1.0.0.0)。具体格式可能是 major.api.minor.patch,也可能是 major.minor.patch.hotfix,或者完全不同——没有统一标准。
对于 major.api.minor.patch 这种格式,major 版本号与 api 版本号是分离的。这意味着 major(特性)位和 api 位可以独立递增。 这种方式常见于那些为其他模组开发者暴露 API 的模组。例如,Mekanism 目前的版本是 10.4.5.19(撰写本文时)。
对于 major.minor.patch.hotfix 这种格式,补丁级别被拆分为两个部分。这是 Create 模组采用的方式,目前的版本是 0.5.1f(撰写本文时)。需要注意的是,Create 使用字母来表示 hotfix,而不是第四个数字,以便与常规 semver 保持兼容。
Reduced semver、expanded semver、2-part semver 和 4-part semver 并不是官方术语,也不是任何标准化格式。
Alpha、Beta、Release
和 Minecraft 本身类似,模组开发通常也采用经典的软件工程版本阶段:alpha/beta/release。其中,alpha 表示不稳定/实验性版本(有时也称为 experimental 或 snapshot),beta 表示半稳定版本,而 release 表示稳定版本(有时也称为 stable 而不是 release)。
有些模组会用主版本号(major)来表示 Minecraft 版本的升级。例如 JEI,它使用 13.x.x.x 对应 Minecraft 1.19.2,14.x.x.x 对应 1.19.4,15.x.x.x 对应 1.20.1(没有为 1.19.3 和 1.20.0 发布版本)。也有模组在模组名称后添加标签,比如 Minecolonies,其当前版本为 1.1.328-BETA(撰写本文时)。
包含 Minecraft 版本号
在文件名中包含该模组适用的 Minecraft 版本是很常见的做法。这样可以让终端用户更容易地确定模组适用于哪个 Minecraft 版本。通常会将 Minecraft 版本号放在模组版本号的前面或后面,其中前者更为常见。例如,JEI 版本 16.0.0.28(撰写本文时的最新版)适用于 1.20.2,可以命名为 jei-1.20.2-16.0.0.28 或 jei-16.0.0.28-1.20.2。
包含模组加载器(Mod Loader)
你可能已经知道,NeoForge 并不是唯一的模组加载器,许多模组开发者会在多个平台上开发。因此,需要一种方法来区分同一个模组、同一个版本、但针对不同模组加载器的文件。
通常,这通过在文件名中包含模组加载器来实现。例如:jei-neoforge-1.20.2-16.0.0.28、jei-1.20.2-neoforge-16.0.0.28 或 jei-1.20.2-16.0.0.28-neoforge 都是可行的命名方式。对于其他模组加载器,可以将 neoforge 替换为 forge、fabric、quilt 或你在 NeoForge 之外使用的其他加载器名称。
关于 Maven 的说明
Maven 是用于依赖管理的系统,其版本控制方式在一些细节上与 semver(语义化版本控制)不同(尽管整体仍采用 major.minor.patch 这一模式)。相关的 Maven 版本范围(Maven Versioning Range, MVR) 系统在 NeoForge 的某些地方被使用(参见 上文)。在选择你的版本控制方案时,务必确保它与 MVR 兼容,否则其他模组将无法依赖于你模组的特定版本!