Cat_Anchor 发表于 2026-2-13 08:15:37

我如何升级格式版本与对应模式

本帖最后由 Cat_Anchor 于 2026-2-13 08:18 编辑

# 前言

在最新基岩版测试版 `26.10.23`(本文写于 2026 / 2 / 12)中,他们把方块标签的定义格式改了,从
```json
"tag:xxx:yyy": {}
```
改成了
```json
"minecraft:tags": [
"xxx:yyy"
]
```

我的万象添补附加包中有几百个方块,几乎每个都有对应的标签,它们有的用于分类,有的则是功能性的,例如 `minecraft:is_pickaxe_item_destructible` 可以让这个方块被镐子加速破坏,又例如 `complementary:negates_fall_damage` 会让这个方块抵消摔落伤害(此标签仅能在万象添补中使用)。这次要升级标签定义格式,怎么改?

---

# 第一阶段:手动查找替换

难道一个一个改吗?那未免太慢了。放到以前,这种格式更改足以让万象添补新版本卡住半天也出不来。以前的我对于这种更改,只能分批次更新,一些方块用新格式,另一些留在旧格式,在接下来的几个版本中把旧格式的方块一点一点升级上去。

又例如格式版本的升级,只是把 `format_version` 字段的值改成新的格式版本,看起来很简单。然而,面对几百个方块,这也需要一定时间才能手动查找替换完成。

面对这类问题,最早期的处理办法直接粗暴,就是手动查找替换。比如我要把 `1.20.40` 升级到 `1.20.50`,用 MT 管理器,那就是打开一个文件,点击右上角,在弹出的菜单中点击“搜索”,在下方弹出的菜单中按一下“替换”,再点击“全部”,最后保存文件,在屏幕边缘滑动退出。以上操作只是对于一个文件的,对于几百个文件,每一个我都要重复一遍这样的操作。这还只是一个查找替换项,如果我不仅要升级 `format_version` 字段,还要同时把 `minecraft:aim_collision` 改成 `minecraft:selection_box`,工作量就会几乎翻倍。

还有一些东西,是不能用简单的查找替换解决的。比如把 `minecraft:destroy_time` 格式的组件改成 `minecraft:destructible_by_mining` 格式的,那可是从直接赋值变成了使用对象,这是无法用查找替换解决的,因为值是动态的。这时候,我只能先查找替换一部分,之后手动修改,完成一次升级。

---

# 第二阶段:一键查找替换

后来,MT 管理器更新了一个功能,可以在快捷栏中直接打开搜索菜单,减少了一点工作量。之后又更新了点击按钮直接使用预设查找替换的功能,又减少了一些工作量。我曾经给添补附加包进行过一次大升级,彻底把旧格式改写为新格式,很大程度上依赖着一键查找替换的功能。

现在我还留着当时的“一键替换式版本升级按钮集”,我可以公布出来。

| 查找 | 替换 |
| - | - |
| burn\_odds | destroy\_chance\_modifier |
| flame\_odds | catch\_chance\_modifier |
| "minecraft:rotation": | "minecraft:transformation": { "rotation": |
| properties | states |
| minecraft:block\_light\_emission | minecraft:light\_emission |
| 1.17.0 | 1.20.70 |
| minecraft:entity\_collision | minecraft:collision\_box |
| "minecraft:destroy\_time": | "minecraft:destructible\_by\_explosion":{"explosion\_resistance":3},"minecraft:destructible\_by\_mining":{"seconds\_to\_destroy": |
| minecraft:block\_light\_absorption | minecraft:light\_dampening |
| minecraft:pick\_collision | minecraft:selection\_box |

可以看出,当时的工程放到现在多少带点不可解读的性质。其中有一些细节,比如爆炸抗性的补充,其实主要是当时的背景,是我现在没法三言两语说清楚的。

---

# 第三阶段:多文件查找替换

又过了一会儿,我想到了多文件查找替换的功能。MT 管理器至今没有支持多文件的一键查找替换,不过我还是从网上找到了一个 App。它没有告诉我文件的输出路径,我试了一次,还以为它没有用,差点就错怪它了。到现在,它还是发挥着一些作用。

这时候,我要升级格式版本,就可以直接把要升级的文件复制到公共路径,运行那个程序,把输出的文件覆盖回去,再删掉公共路径的临时文件。但是面对一些精确的替换问题,它没法把查找的内容替换成空字符串,会提示“请输入替换内容”,这是不好的一点。`string.replace('要删掉的字符串', '')` 是个稀松平常的操作,我不理解为什么要对“替换成空字符串”做限制。

更大的问题是,它还是没法解决我们上面提出的把 `minecraft:destroy_time` 升级为 `minecraft:destructible_by_mining` 的问题。其实最关键的地方在于,要想解决一切类似的难题,解析 JSON 才是正道。不把 JSON 字符串解析成可以操作的 JavaScript 对象(毕竟 JSON 就是 JavaScript Object Notation,JavaScript 对象表示法),就没法根除这种问题。

---

# 第四阶段:妙妙工具

于是,截至写下本文时最新最现代的方法,诞生了。使用这种方法,我们不仅可以解析 JSON,随意对 JSON 做很多复杂的操作,甚至能以这种方法为基底,实现一套替换文件的逻辑。

我可以在这里公开一份模式文档,是内部开发时使用的致力于解决独特问题的替换规则的示例文档的一部分。

```json
[{
        "template": "templates/template1.json", // template 字段指定了模板的位置,这是相对于压缩包根目录而言的。每个模板都是一个有效的 JSON 文件。
        "outputs": [{ // outputs 字段指定了这个模板的多个批量生产的结果,是一个数组。数组中对象的数量决定了原始模板会生产出多少份文件。
                "replacements": [{ // replacements 指定要对 JSON 文件进行哪些替换。
                        "type": "find_replace", // type 表示这个替换的类型,find_replace 表示查找替换,即查找 target 指向的值,将这个值转为字符串,查找指定字符串(全局查找),再用指定字符串替换掉。如果 target 指向数组或者对象,应该首先 JSON.stringify,最后 JSON.parse。
                        "target": {}, // target 指定了要操作的 JSON 结构路径,target 后面的对象就相当于文件的 JSON 的根对象;要表示指定对象,我们只需要在 target 中重新写一遍指向指定对象的数据结构,并把最终的值用 {} 表示。本文之后会有示例。
                        "find_value": "test", // find_value 指定了 type 为 find_replace 时,要查找的字符串。如果是对象或数组,应该首先 JSON.stringify,最后写入最终结果时 JSON.parse。
                        "replace_value": "experiment" // replace_value 指定了 type 为 find_replace 时,查找到的字符串要替换成的字符串。如果是对象或数组,应该首先 JSON.stringify,最后写入最终结果时 JSON.parse。
                }, { // replacements 指定要对 JSON 文件进行哪些替换。
                        "type": "override", // type 表示这个替换的类型,override 表示覆写原值,即查找 target 指向的值,将这个值转为字符串,然后直接用 value 提供的值覆盖旧值。如果 target 指向数组或者对象,应该首先 JSON.stringify,最后 JSON.parse。
                        "target": {}, // target 指定了要操作的 JSON 结构路径,target 后面的对象就相当于文件的 JSON 的根对象;要表示指定对象,我们只需要在 target 中重新写一遍指向指定对象的数据结构,并把最终的值用 {} 表示。本文之后会有示例。
                        "value": "test" // value 指定了 type 为 override 时,覆盖旧字符串的新字符串。如果是对象或数组,应该首先 JSON.stringify,最后写入最终结果时 JSON.parse。
                }],
                "file_path": "outputs/example1.json" // file_path 表示这个 replacement 操作完成后,要输出的文件路径以及文件名,相对于压缩包根目录而言,而且带后缀。
        }]
}, {
        "template": "templates/template2.json"
        // ...
        // 此处与上一个 template 结构相同,表示本文件可以定义多个模板。
}]
```

从此以后,升级格式版本只需要以下 JavaScript 代码。

```js
const result = {};
for (const filename in files) result = files.replace(/1\.21\.120/g, '1.21.130');
```

这里用的是全局查找,但是一般来说格式版本在一个文件中只会出现一次。然而为了保险,我们还是使用全局查找。

这种最新的方法,被我称为“妙妙工具”。官方做的几乎任何模式更改都可以用一段 JavaScript 代码表示,使用这个工具,我们可以让 JavaScript 代码帮我们处理文件,快速得到最终结果。

以前,最特殊的时候,我还尝试过录制一套屏幕操作的动作,让程序帮我自动操作手机。然而这种方法准确度很差,替换不了十几个文件,微小的偏移量就积累起来,造成极大的误差了。

不过现在,手动地一个一个查找替换的时代是一去不复返了。

---

# 后记

最让我感到讽刺的是,一些应用程序把 PDF 文件转换为图片的功能要付费。使用上面提到的逻辑思考,我们完全可以免费实现这个功能,快速又方便,图片质量完全可以自己调整,PDF 文件从来都不需要上传到哪里去。

明明非常基础的功能,一些人却不得不面对付费的窘境。对此,我只好抱着深深的无奈了。

坐牢眼珠子 发表于 2026-2-16 02:38:19

按照要求更改了格式,我的方块直接失效了是什么情况🤔

甚至旧写法好歹只是标签没有生效,用新写法却是整个方块都没了,即便我把方块和附加包版本号都调成1.26.10

坐牢眼珠子 发表于 2026-2-17 01:23:41

坐牢眼珠子 发表于 2026-2-16 02:38
按照要求更改了格式,我的方块直接失效了是什么情况🤔

甚至旧写法好歹只是标签没有生效,用新写法却是整个 ...

我反馈到bugs.mojang.com了

M397749490 发表于 2026-2-17 16:34:24

建议楼主发布到“教程中心”版块
页: [1]
查看完整版本: 我如何升级格式版本与对应模式