MCDOC格式
Mcdoc 是一种用于描述 Minecraft 数据结构的模式格式,包括其 CODEC
、JSON
和 NBT
。
本文档定义了 mcdoc 格式的语法和语义。
Contents
- 1 项目根目录
- 2 语法语法
- 3 注释
- 4 文档注释
- 5 整数
- 6 浮点数
- 7 类型化数字
- 8 数字范围
- 9 字符串
- 10 命名空间ID
- 11 标识符
- 12 路径
- 13 类型
- 14 文件结构
- 15 类型别名语句
- 16 使用语句
- 17 注入
- 18 分派语句
- 19 属性
- 20 类型实例化
- 21 实例化后处理
- 22 类型可赋值性
- 23 标识
- 24 制作
项目根目录
通常,工作区(mcdoc 解释器操作的目录:对于命令行工具,这可能是工作目录;对于像 VS Code 这样的代码编辑器,这可能是侧边栏资源管理器中显示的根目录)被视为 mcdoc 项目的根目录。
但是,如果在工作区下存在一个名为 mcdoc
的文件夹,并且工作区内的所有 mcdoc
文件都存储在该目录下,则该目录将被视为根目录。
语法语法
以下是本文档用于描述 mcdoc 语法的语法——如果你愿意,可以称之为“语法语法”。
符号 | 含义 |
---|---|
str | 字面量 str |
U+xxxx | 代码点为 xxxx 的 Unicode 字符 |
A* | A 重复零次或多次 |
A+ | A 重复一次或多次 |
A? | A 重复零次或一次 |
A | B | A 或 B |
[A B C] | 字面量 A 、B 或 C 之一 |
[A-Z] | A 到 Z 之间的任何字面量 |
(A) | 一般分组 |
notA | 任何不是 A 的内容 |
Aexcept: B | A ,除了 B |
Alookahead: B | A 后跟 B ,但只消耗 A |
Anochild: B | A ,但 B 不应是其子项 |
NAME | 引用的标记规则 |
Name | 引用的解析规则 |
标记规则语法不能包含任何空白(空格、制表符、CR
或 LF
)或标记之间的个别部分。
解析规则语法可以包含空白和注释。
所有语法规则应为贪婪的(即尽可能多地消耗字符)。
注释
语法
COMMENTS COMMENT* COMMENT // lookahead: not/ (notEOL)* (EOL | EOF) EOL End of line: CR (Unicode U+000D) or LF (Unicode U+000A). EOF End of file.
在 mcdoc 中,可以使用注释来编写只有查看或编辑 mcdoc 文件的用户才能看到的信息。它们会被 mcdoc 解释器忽略。
要编写注释,只需写下两个正斜杠 (//
)——之后的所有内容,直到行尾,都被视为注释的一部分。注释可以放在允许空白的任何地方。但是,注释不能以三个斜杠 (///
) 开头,因为这保留用于文档注释。
// 这是一个注释。 struct Foo { Bar: boolean, // 这是另一个注释。 }
文档注释
语法
Prelim DocComments Attributes DocComments DOC_COMMENT*
尽管这是一条语法规则,但在各个 DOC_COMMENT
之间不允许有常规注释。只应允许空白(包括换行)。
语法
DOC_COMMENT /// (notEOL)* (EOL | EOF)
文档注释在语法上类似于注释——它们以三个斜杠 (///
) 开头。文档注释块可以为紧随其后的组件提供人类可读的文档。与常规注释不同,文档注释只能放在枚举定义、枚举字段、结构体定义、结构体字段和类型别名前,作为 [prelim] 的一部分。
文档注释块的文本内容应被视为 MarkDown 内容,前导的三个斜杠(以及如果所有行都共享一个前导空格,则最多一个前导空格)应被剥离。
/// 这个文档注释描述了结构体 Foo。 /// 外部工具,如 VS Code,可能会在用户悬停在名称 "Foo" 上时显示这段文本。 struct Foo { /// 这是另一个描述字段 "Bar" 的文档注释。 Bar: boolean, // 这只是一个常规注释,因为它只以两个斜杠开头。 }
由于文档注释块的内容被视为 MarkDown,因此某些字符可能具有特殊含义。例如,如果你在文档注释中写 <foo>
,它可能在显示给用户时消失,因为它可能被 MarkDown 解析器解释为 XML 标签。用反斜杠 (\
) 转义这些特殊字符(例如 \<foo>
) 可以解决这个问题。
整数
语法
INTEGER 0 | [- +]? [1-9] [0-9]*
整数表示一个完整的数字。
0 +123 -456
浮点数
语法
FLOAT [- +]? [0-9]+ FLOAT_EXPONENT? | [- +]? [0-9]* . [0-9]+ FLOAT_EXPONENT? FLOAT_EXPONENT [e E] [- +]? [0-9]+
浮点数表示一个小数。可以使用字母 e
(不区分大小写)表示科学记数法。
1 +1.2 -1.2e3 // -1.2×10^3
类型化数字
语法
TYPED_NUMBER INTEGER [b B s S l L]? | FLOAT [d D f F]?
类型化数字在语法上类似于在 SNBT
中使用的数字。它是一个正常的数字,后跟一个表示其类型的后缀:
后缀 (不区分大小写) | 类型 |
---|---|
b | Byte |
s | Short |
l | Long |
f | Float |
d | Double |
(无后缀,整数) | Integer |
(无后缀,小数) | Double |
1b // Byte 1 1 // Integer 1 1.2 // Double 1.2 1.2d // Double 1.2 1.2e1f // Float 12
数字范围
语法
FLOAT_RANGE RANGE_DELIMITER? FLOAT | FLOAT RANGE_DELIMITER FLOAT? RANGE_DELIMITER .. | ..< | <.. | <..< INT_RANGE RANGE_DELIMITER? INTEGER | INTEGER RANGE_DELIMITER INTEGER?
数字范围表示一个数字范围。其语法源自 Minecraft 命令中的数字范围,并额外支持使用严格小于符号 (<
) 表示排他性结束。mcdoc 中有两种类型的范围:浮点数范围,由浮点数组成;整数范围,由整数组成。
1 // 精确为 1 1..1 // 精确为 1 1..2 // 在 1 和 2 之间(包括两端) 1<..<2 // 在 1 和 2 之间(排除两端) 4.2.. // 大于或等于 4.2 4.2<.. // 大于 4.2 ..9.1 // 小于或等于 9.1 ..<9.1 // 小于 9.1
字符串
语法
STRING " (not[" \ UNICODE_CC] | (\ [b f n r t \ "]))* " UNICODE_CC Unicode 控制字符。
字符串表示一系列字符。它必须用双引号 ("
) 包围。某些字符需要用反斜杠 (\
) 转义。
转义序列 | 含义 |
---|---|
\" | 双引号(" , Unicode U+0022) |
\\ | 反斜杠(`\, Unicode U+005C) |
\b | 退格(Unicode U+0008) |
\f | 换页(Unicode U+000C) |
\n | 换行(Unicode U+000A) |
\r | 回车(Unicode U+000D) |
\t | 制表符(Unicode U+0009) |
"foo" // 表示 foo 的字符串 "bar\"qux\\baz" // 表示 bar"qux\baz 的字符串
命名空间ID
语法
RES_LOC RES_LOC_CHAR* : RES_LOC_CHAR* (/ RES_LOC_CHAR*)* RES_LOC_CHAR [a-z 0-9 - _ .]
命名空间ID在语法上类似于 Minecraft 的命名空间ID,不同之处在于必须存在一个冒号 (:
) 以消除与标识符的歧义。
minecraft:foo :foo // 这也表示 minecraft:foo,并且在 Minecraft 中是合法的。 spyglassmc:bar
标识符
语法
IDENTIFIER ((IDENT_START) (IDENT_CONTINUE)*)except: RESERVED_WORDS IDENT_START Any character in the Unicode general categories “Letter (L)” or “Letter Number (Nl)” IDENT_CONTINUE IDENT_START | U+200C | U+200D | (any character in the Unicode general categories “Non-Spacing Mark (Mn)”, “Spacing Combining Mark (Mc)”, “Decimal Digit Number (Nd)”, or “Connector Punctuation (Pc)”) RESERVED_WORDS any | boolean | byte | double | enum | false | float | int | long | short | string | struct | super | true
标识符是 mcdoc 中赋予类型定义的区分大小写的名称。它可以包含任何 Unicode 字母、数字和下划线 (_
),但不能以数字开头。并且不能使用保留字。
struct Foo { // Foo 是一个标识符。 B_1: boolean, // B_1 是一个标识符。 }
路径
语法
PATH (::)? PATH_SEGMENT (:: PATH_SEGMENT)* PATH_SEGMENT IDENTIFIER | super
路径用于在 mcdoc 项目中定位类型定义。双冒号 (::
) 用作路径分隔符。
如果路径以双冒号开头,则为绝对路径,从项目根目录解析。否则为相对路径,从当前文件的绝对路径解析。
文件的绝对路径是通过连接所有父文件夹的名称直到根目录,以及文件自身的名称(不包括 .mcdoc
文件扩展名)与路径分隔符连接起来,并在前面加上路径分隔符。名为 mod.mcdoc
的文件是特例,它们不会成为路径的一部分。
类型定义的绝对路径是其所在文件的绝对路径与类型定义的标识符通过路径分隔符连接起来的结果。
如果多个文件/类型定义具有相同的路径,则仅最早加载的生效;所有后续的应被 mcdoc 解释器警告并忽略。
对于相对路径,可以使用关键字 super
向上移动一级。
/ foo.mcdoc foo/ bar.mcdoc mod.mcdoc qux.mcdoc
foo.mcdoc
的绝对路径是::foo
。bar.mcdoc
的绝对路径是::foo::bar
。mod.mcdoc
的绝对路径是::foo
(因为mod.mcdoc
是特例)。qux.mcdoc
的绝对路径是::qux
。
如果 /foo/bar.mcdoc
的内容是:
struct Foo {} type Bar = super::super::qux::Something
struct Foo
的绝对路径是::foo::bar::Foo
。- 类型别名
Bar
的绝对路径是::foo::bar::Bar
。
相对路径的解释如下:
/foo/bar.mcdoc
的绝对路径是::foo::bar
。给定的相对路径是super::super::qux::Something
。- 遇到关键字
super
,向上移动一级到::foo
。剩余相对路径是super::qux::Something
。 - 再次遇到
super
,向上移动一级到::
。剩余相对路径是qux::Something
。 - 遇到标识符
qux
,向下移动到::qux
。剩余相对路径是Something
。 - 遇到标识符
Something
,向下移动到::qux::Something
。相对路径已解析。
因此,类型别名 Bar
指向文件 /qux.mcdoc
中名为 Something
的类型定义。
类型
语法
Type Attributes UnattributedType (IndexBody | TypeArgBlock)* UnattributedType KeywordType | StringType | LiteralType | NumericType | PrimitiveArrayType | ListType | TupleType | Enum | Struct | ReferenceType | DispatcherType | UnionType TypeArgBlock < > | < Type (, Type)* ,? >
类型是 mcdoc 格式的基本组成部分。它定义了实际数据值必须符合的模式,以确保数据有效。
mcdoc 可用于描述各种数据格式。本节将仅提供一些 JSON 数据作为每种类型的示例。
any 类型
语法
KeywordType any | boolean
any
类型是 mcdoc 类型系统的顶层类型。任何其他类型(包括 any
本身)都可以赋值给 any
。any
不能赋值给除 any
之外的任何其他类型。
null true [0, 1, 2, 3] { "foo": "bar" }
boolean 类型
boolean
类型表示期望一个布尔值(false
或 true
)。
false true
string 类型
语法
StringType string (@ INT_RANGE)?
string
类型表示期望一个字符串值。可选的范围定义了字符串长度的范围。
"foo" "bar"
字面量布尔类型
语法
LiteralType false | true | STRING | TYPED_NUMBER
字面量布尔类型是两个布尔值(false
和 true
)之一,数据必须与其完全匹配才有效。
false true
字面量字符串类型
字面量字符串类型是一个字符串值,数据必须与其完全匹配才有效。
"" "foo"
字面量数字类型
字面量数字类型包括一个数值和一个类型,数据必须与其完全匹配才有效。
-1 1.2f 42L
数字类型
语法
NumericType byte (@ INT_RANGE)? | short (@ INT_RANGE)? | int (@ INT_RANGE)? | long (@ INT_RANGE)? | float (@ FLOAT_RANGE)? | double (@ FLOAT_RANGE)?
数字类型表示数据必须是该类型。如果提供了可选范围,则数据还必须在该范围内。
byte short@1.. float @ 4.2..9.1
原始数组类型
语法
PrimitiveArrayType byte (@ INT_RANGE)? [] (@ INT_RANGE)? | int (@ INT_RANGE)? [] (@ INT_RANGE)? | long (@ INT_RANGE)? [] (@ INT_RANGE)?
原始数组类型表示数据必须是某些数值的集合。第一个可选范围定义了值必须在的范围,而第二个可选范围定义了集合大小的范围。
byte[] // 字节集合。 byte#0..1[] // 0 或 1 的字节集合。 int[] # 4 // 4 个整数的集合。 long#0..[] # 3.. // 3 个或更多非负长整数的集合。
列表类型
语法
ListType [ Type ] (@ INT_RANGE)?
列表类型表示数据必须是某种其他类型的集合。可选范围定义了集合大小的范围。
[byte] // 字节集合。 [[string]] // 字符串集合的集合。 [struct Foo {}] // 结构体集合。
与 NBT 不同,JSON 不区分原始数组和列表——它只有一种数组类型。因此,对于 JSON 验证,byte[]
和 [byte]
基本上是相同的。
元组类型
语法
TupleType [ Type , ] [ Type (, Type)+ ,? ]
元组类型表示数据必须是按指定顺序排列的某些其他类型的集合。
为了区分只包含一个元素的元组类型与列表类型,需要在类型后面添加一个尾随逗号(,)。或者,可以使用大小为 1 的列表类型来表示包含一个元素的元组(例如 [byte] @ 1
)。
[byte,] // 一个字节的元组。 [string, boolean] // 一个字符串后跟一个布尔值的元组。
元组类型通常对 NBT 结构没有用,因为 NBT 没有混合类型的集合。
枚举
语法
Enum Prelim enum ( ENUM_TYPE ) IDENTIFIER? EnumBlock EnumBlock { } | { EnumField (, EnumField)* ,? } EnumField Prelim IDENTIFIER = ENUM_VALUE SYNTAX (TOKEN) ENUM_TYPE byte | short | int | long | string | float | double ENUM_VALUE TYPED_NUMBER | STRING
虽然预期枚举的值是 TYPED_NUMBER,但用户可以不带适当后缀地编写数字,因为 mcdoc 解释器能够从枚举定义中推断出正确的类型。
结构体
语法
Struct Prelim struct IDENTIFIER? StructBlock StructBlock { } | { StructField (, StructField)* ,? } StructField Prelim StructKey ?? : Type | Attributes ... Type StructKey STRING | IDENTIFIER | [ Type ]
结构体定义了由键值对组成的类似字典的结构的模式,如 JSON 对象或 NBT 复合标签。如果键重复,后一个的类型将覆盖前一个的类型。可以在键和冒号(:)之间添加一个问号(?)以指示可选字段。
struct Tag { replace?: boolean, values: [string], }
扩展操作符(三个点,…)后跟结构体类型,可以用于重用另一个结构体的字段。
struct Player { ...Mob, // 重用 Mob 结构体中的字段。 abilities: Abilities, CustomName: (), // 将 CustomName 从 Mob 结构体中重写为空联合。 }
虽然结构体定义中不直接允许类型参数,但可以在类型别名定义的右侧内联一个结构体。
type Tag<V> = struct { replace?: boolean, values: [V], } type BlockTag = Tag<#[id=block] string> type EntityTypeTag = Tag<#[id=entity_type] string> type FunctionTag = Tag<#[id=function] string> type ItemTag = Tag<#[id=item] string>
引用类型
语法
ReferenceType PATH
分派器类型
语法
DispatcherType RES_LOC IndexBody
联合类型
语法
UnionType ( ) | ( Type (| Type)* |? )
一对空括号表示从结构体定义中删除该字段。
类型索引
语法
IndexBody [ Index (, Index)* ,? ]
可以在方括号内放置多个索引,以从目标中访问多个类型。
示例. 从分派器访问多个类型
minecraft:entity[ender_dragon, wither] → 生成一个联合类型,包括末影龙和凋零的类型。 minecraft:entity[[id], allay] → 生成一个联合类型,包括动态获取的 id 实体类型和小精灵的类型。
索引
STATIC_INDEX_KEY | DynamicIndex DynamicIndex [ ACCESSOR ]
语法
STATIC_INDEX_KEY %fallback | %none | %unknown | IDENTIFIER | STRING | RES_LOC ACCESSOR ACCESSOR_KEY (. ACCESSOR_KEY)* ACCESSOR_KEY %key | %parent | IDENTIFIER | STRING
索引可以从分派器访问类型或从现有结构体获取字段类型,既可以是静态的(即用户在 mcdoc 文件中直接提供键),也可以是动态的(即用户指定一种方法在运行时从给定数据结构获取键)。
示例. 静态和动态索引
struct Foo { id: string, cow_data: minecraft:entity[cow], dynamic_entity_data: minecraft:entity[[id]], command: minecraft:block[command_block][Command], dynamic_memories: minecraft:entity[[id]][Brain][memories], }
- 静态索引在分派器上。
- 动态索引在分派器上。
- 静态索引在分派器上,接着是结构体上的静态索引。
- 动态索引在分派器上,接着是两个结构体上的静态索引。
默认情况下,所有情况(包括两个可变的特殊键 %none 和 %unknown)使用回退案例。
示例. 特殊静态键:%fallback
type AnyEntity = minecraft:entity[%fallback]
%fallback
键用于访问分派器的回退案例。不能在分派语句的左侧使用,因为回退案例是自动生成的,不能手动声明。
示例. 特殊静态键:%none
struct RandomIntGenerator { type?: ("uniform" | "binomial" | "constant"), ...minecraft:random_int_generator[[type]], } dispatch minecraft:random_int_generator[uniform, %none] to struct { min?: int, max?: int }
- type 在这里定义为可选。
- 运行时使用 type 的值作为动态索引。
%none
对应的案例被分派到结构体,因此当运行时没有提供 type 的值时,随机整数生成器仍然可以正确验证为 uniform 生成器。
示例. 特殊静态键:%unknown
dispatch minecraft:block[%unknown] to ()
%unknown
对应的案例用于在访问分派器时使用未知键。
示例. 特殊访问器键:%key
struct DebugStick { DebugProperty: struct { [#[id=block] string]: mcdoc:block_state_name[[%key]], // 获取存储在键中的块状态名称的类型。 }, }
该结构体可以用于验证以下数据:
{ "DebugProperty": { "minecraft:anvil": "facing", "minecraft:oak_fence": "east" } }
示例. 特殊访问器键:%parent
struct Item { id: #[id=item] string, tag: struct ItemTag { BlockStateTag: mcdoc:block_item_states[[%parent.id]] }, }
TODO
文件结构
语法
File (Struct | Enum | TypeAlias | UseStatement | Injection | DispatchStatement)*
mcdoc 文件由结构体、枚举、类型别名语句、使用语句、注入语句和分派语句组成。
类型别名语句
语法
TypeAlias Prelim type IDENTIFIER TypeParamBlock? = Type TypeParamBlock < > | < TypeParam (, TypeParam)* ,? > TypeParam IDENTIFIER
类型别名可以创建以引用另一个复杂类型,从而提高代码的可读性和可重用性。
示例. 类型别名
type Integer = (byte | short | int | long) type Float = (float | double) type Number = (Integer | Float)
有时我们可能希望创建具有大致相同结构但在某些小方面有所不同的不同类型定义。与其重复代码,不如创建一个带有类型参数的“模板”类型别名。类型别名语句的右侧可以引用这些类型参数,当类型别名在其他地方实例化时,这些参数将被实际类型替换。
示例. 带有类型参数的类型别名
type NumericRange<T> = ( T | [T, T] | struct { min: T, max: T } ) type FloatRange = NumericRange<float> type IntegerRange = NumericRange<int> type NaturalRange = NumericRange<int @ 0..>
- 类型参数 T 在尖括号中声明。
- 类型参数 T 现在可以在右侧引用。
- 当在其他地方引用 NumericRange 类型别名时,必须为类型参数提供实际类型。
绑定类型参数
所有路径引用通过路径中描述的规则解析,类型参数引用也不例外。当在类型别名语句中声明类型参数时,它会被暂时绑定到当前模块,直到语句结束。因此,就像其他类型定义一样,类型参数在模块范围内应该是唯一的。
示例. 重复的类型参数标识符
// 文件 '/example.mcdoc' struct T {} type List<T> = [T] //注1 // ^ // WARNING: Duplicated declaration for "::example::T"
- 注1: T 的声明被警告并忽略,右侧的 T 实际上引用的是上面定义的结构体 T。
type List<T> = [T] // 注1 type Struct<T> = struct { value: T }
- 注1: 这是可以的,因为尽管 T 也在 List 类型别名语句中声明,但该声明的效果仅在该语句结束前有效。
使用语句
语法
UseStatement use PATH (as IDENTIFIER)?
TODO
注入
语法
Injection inject (EnumInjection | StructInjection) EnumInjection enum (ENUM_TYPE) PATH EnumBlock StructInjection struct PATH StructBlock
TODO
分派语句
语法
DispatchStatement Prelim dispatch RES_LOC IndexBody nochild: DynamicIndex TypeParamBlock? to Type
分派器用于从给定索引分派到特定类型。每个分派器的案例可以通过分派语句声明,并通过分派器类型访问。
分派器以资源位置命名,因此与其他需要导入才能在外部文件中使用的 mcdoc 值不同,分派器本质上是全局的,可以在 mcdoc 项目中的任何地方访问。
回退分支
当使用未知索引访问分派器时,会在运行时生成一个包含分派器下注册的所有类型的联合作为回退分支。该联合标记为“nonexhaustive”元数据。
TODO
属性
语法
Attributes Attribute* Attribute #[ IDENTIFIER ] | #[ IDENTIFIER = Value ] | #[ IDENTIFIER TreeValue ] Value Type | TreeValue TreeValue ( TreeBody? ) | [ TreeBody? ] | { TreeBody? } TreeBody PositionalValues ,? | NamedValues ,? | PositionalValues , NamedValues ,? PositionalValues Value (, Value)* NamedValues NamedValue (, NamedValue)* NamedValue (IDENTIFIER | STRING) = Value | (IDENTIFIER | STRING) TreeValue
示例. 属性示例(非最终版)
以下所有示例在当前属性提案下在语法上是合法的。然而,哪些应该在语义上合法仍在讨论中。
struct Foo { #[id=item] id1: string, id2: #[id=item] string, // id1 和 id2 可能都会被支持并具有等效效果。 blockStateValue1: ( #[serializable] string | byte | short | int | long | float | double ), #[serialize_to=string] blockStateValue2: (string | byte | short | int | long | float | double), evilUUID1: ( #[until("1.16", uuid_string_to_compound)] #[parser=uuid] string | #[until("1.17", uuid_compound_to_array)] MostLeastCompound | int[] @ 4 ), #[history{ (#[parser=uuid] string, until="1.16", updater=uuid_string_to_compound), (MostLeastCompound, until="1.17", updater=uuid_compound_to_array), }] evilUUID2: int[] @ 4 }
类型实例化
类型实例化是将用户定义的类型转换为数据验证器易于使用的类型的过程。用户定义的类型可以根据实例化的目的分类如下:
索引类型
- 具有索引的类型。
自包含类型
- 包含所有验证所需信息的类型。包括任意类型、布尔类型、字符串类型、字面量布尔类型、字面量字符串类型、字面量数字类型、数值类型、原始数组类型和枚举。
容器类型
- 提供部分信息但需要其子类型信息以完成验证的类型。包括列表类型、元组类型和结构体。
引用类型
- 引用类型。
分派器类型
- 分派器类型。
联合类型
- 联合类型。
不同类别的用户定义类型使用不同的程序进行实例化。
实例化索引类型
首先实例化不带索引的部分,然后在实例化类型上解析索引。重复此过程,直到所有索引都解析完毕。
实例化自包含类型
自包含类型无需实例化。
实例化容器类型
容器类型无需实例化。其子类型在需要时懒加载实例化。
实例化引用类型
取消引用路径。如果有类型参数,使用提供的实际类型替换模板类型中的所有出现。然后根据实例化规则再次实例化结果类型。
实例化分派器类型
分派类型。然后根据实例化规则再次实例化结果类型。
联合类型
联合的每个成员类型单独实例化。
实例化后处理
类型按照上述规则实例化后,应在返回前进行简化。
类型简化
TODO
简化联合类型时,任何可以分配给另一个成员的成员将从联合中移除。
遮蔽类型
TODO
虽然将 (string | "foo" | "bar")
简化为 string
是合理的,但我们会失去一些原始类型的更具体的信息,这些信息可以被自动补全器等处理器使用。因此,对于某些特殊情况,在简化过程中修剪的类型可能会在简化类型的 shadowedTypes
属性下访问。
类型可赋值性
mcdoc 中的类型可以看作集合。类型 A 可赋值给类型 B 当且仅当 A 是 B 的子集。any
是包含所有其他类型的通用集合,而空联合 ()
是空集合。unsafe
(实际上,any
是 TypeScript 的 unknown
,unsafe
是 TypeScript 的 any
。一个配置规则还将被添加,使 any
等同于 unsafe
,默认启用,因此大多数用户不必处理繁琐的验证机制,因为 vanilla-mcdoc 可能会使用 any
而不是 unsafe
作为标记的数据,这会使其在健全的类型系统下非法分配到其他地方。我稍后会更新文档和代码以添加 unsafe
类型)。
TODO
TODO: 数据验证器钩子可以贡献额外的类型可赋值性规则。例如:
- 对于 JSON:
byte = short = int = long = float = double
- 对于 NBT:
boolean = (byte @ 0..1) ⊂ byte
标识
“Mcdoc” 是一个普通名词,只有在语法上需要时才应将其首字母大写(例如在句子的开头)。
制作
mcdoc 格式受到 Yurihaia 创建的 nbtdoc 格式的启发,并根据 MIT 许可证授权。Misode、MulverineX、NeunEinser 和 vdvman1 也为 mcdoc 格式提供了宝贵的反馈。
本文档由Alumopper翻译。