跳转至

认识JSON

附加包的绝大多数配置文件都以JSON格式书写。读懂JSON格式、会写JSON文件,是编写附加包最基础的前提。这一节专门为对JSON还比较陌生的读者准备;如果你已经熟悉JSON,可以跳过本节,直接阅读认识附加包

从一个文件说起

打开任意附加包里的manifest.json,你会看到类似这样的内容:

manifest.json
{
  "format_version": 2,
  "header": {
    "name": "Demo Resource Pack",
    "description": "示例资源包",
    "uuid": "0575c61f-a5da-4b7f-9961-ffda2908861e",
    "version": [1, 0, 0],
    "min_engine_version": [1, 21, 0]
  },
  "modules": [
    {
      "type": "resources",
      "uuid": "53644fac-a276-42e5-843f-a3c6f169a9ab",
      "version": [1, 0, 0]
    }
  ]
}

暂时不必关心这个文件的具体作用,我们用它来学习JSON的基本结构。

对象

整个文件从{开始、到}结束,这对花括号括住的内容叫做一个对象(Object)。对象是JSON里最基础的结构,JSON文件的根内容通常就是一个对象。

对象里可以包含任意数量的字段(Field)。每个字段由一个键(Key)和一个值(Value)组成,中间用英文冒号:分隔。相邻字段之间用英文逗号,分隔:

{
  "name": "小明",
  "height": 170,
  "weight": 60
}

这里有三个字段,"name""height""weight"分别是键,"小明"17060是对应的值。键必须用英文直引号"括起来,而且在同一个对象里键不应该重复。注意最后一个字段后面不要加逗号——多余的逗号会导致某些解析器报告格式错误。

空白字符与缩进

键、值、冒号、逗号和括号之间允许出现任意数量的空格、制表符和换行符,这些统称为空白(Whitespace)字符。计算机在解析JSON时会完全忽略这些空白,因此下面两种写法对计算机来说完全等价:

{"name":"小明","height":170,"weight":60}
{
  "name": "小明",
  "height": 170,
  "weight": 60
}

日常编写推荐使用展开写法,并保持统一的缩进(Indentation)风格——通常是每级缩进2个或4个空格,或1个制表符(Tab)。整齐的缩进能帮助你迅速判断括号是否成对、字段是否在正确的层级内。

逗号与排版习惯

从解析角度看,逗号只要位于相邻字段之间即可;但从维护角度看,推荐始终把逗号放在当前字段结尾,并保持每个字段独立成行。这样做能明显降低多人协作时的阅读成本,也更容易在代码评审中定位某一处改动。

一个实用约定

建议在同一项目里固定一种缩进方案(例如统一2个空格),不要混用Tab和空格。JSON本身允许混用,但混用后通常会让差异比对和复制粘贴排错变得更困难。

六种数据类型

字段的值(以及数组里的元素)可以是以下六种类型之一。

数字

数字直接书写,不加引号,支持整数和浮点数(小数):

{
  "format_version": 2,
  "power": 3.5,
  "knockback": 0
}

字符串

字符串是用英文直引号"括住的一段文本,引号内可以是任何字符,也可以为空(空字符串写成""):

{
  "identifier": "demo:my_block",
  "description": "这是一段描述文字",
  "note": ""
}

使用英文直引号

字符串必须用英文直引号",不能使用中文弯引号"",否则JSON解析会失败。

数组

数组用方括号[]表示,里面包含若干元素(Element),元素之间用逗号分隔。元素没有名字,只有顺序,每个元素所处的位置叫索引(Index)索引从0开始计数

{
  "version": [1, 0, 0],
  "tags": ["stone", "ore"]
}

数组元素可以是任何类型,包括对象。下面"modules"数组的元素就是一个对象:

"modules": [
  {
    "type": "resources",
    "uuid": "53644fac-a276-42e5-843f-a3c6f169a9ab",
    "version": [1, 0, 0]
  }
]

嵌套对象

字段的值可以是另一个完整的对象,形成嵌套结构:

{
  "header": {
    "name": "我的包",
    "uuid": "..."
  }
}

"header"的值就是一个嵌套对象。最外层那个对象叫做根对象(Root Object)。可以按需无限嵌套,附加包里许多组件的写法都是多层嵌套的对象。

布尔值

布尔值只有两个,全部小写,不加引号:

  • true:真、是、开启
  • false:假、否、关闭
{
  "enabled": true,
  "experimental": false
}

空值

null表示"什么都没有",全部小写,不加引号。在附加包里不常见,但某些接口允许用它明确地表示"不设置":

{
  "loot": null
}

注释

标准JSON规范不支持注释,但Minecraft的JSON解析器允许两种注释写法,且这两种写法只在Minecraft环境中有效,某些通用工具可能不认识它们。

单行注释——//之后到行尾的内容都会被忽略:

{
  "format_version": 2,  // 格式版本
  "header": {}
}

多行注释——/**/之间的所有内容都会被忽略,可以跨多行:

{
  /* 以下字段描述包的基本信息
     可以跨多行书写 */
  "name": "我的包"
}

利用注释记录字段用途和修改思路,能大幅降低日后维护的难度。

保存为文件

JSON文件本质是纯文本文件,扩展名为.json,内容是一个完整的JSON对象(或数组),以UTF-8编码保存。建议使用支持JSON语法高亮的代码编辑器,例如VS Code(配合Minecraft相关扩展还可以获得架构验证和自动补全功能)。

常见格式错误速查

遇到内容日志报告JSON解析失败时,可以优先检查以下几点:

  • 最后一个字段末尾多了一个逗号
  • 少写或多写了一个引号
  • 花括号{}或方括号[]没有成对出现
  • 使用了中文引号"或中文冒号
  • 字符串内含有未转义的特殊字符(如\"