新增MCSTRUCTURE结构文档

This commit is contained in:
EillesWan 2023-03-12 17:43:52 +08:00
parent 3db35b24ab
commit fb4cd07dc6

View File

@ -0,0 +1,172 @@
**此文档译自https://wiki.bedrock.dev/nbt/mcstructure.html**
# `.MCSTRUCTURE`文件结构
mcstructure 文件是未经压缩的 [NBT 文件](https://wiki.vg/NBT#Specification),也正如《我的世界:基岩版》的所有 NBT 文件一样,其皆以小端字节序(又称小端序)存储。以下是此类文件的 NBT 标签结构:
<style>img{width: 3%;}</style>
[nbt-tag-types]: https://static.wikia.nocookie.net/minecraft_zh_gamepedia/images/d/d0/Nbtsheet.png/revision/latest
[int]: https://foruda.gitee.com/images/1678607417066876136/a1771588_9911226.png
[string]: https://foruda.gitee.com/images/1678607425650690164/1a6315b0_9911226.png
[list]: https://foruda.gitee.com/images/1678607435868247552/890a21c3_9911226.png
[compound]: https://foruda.gitee.com/images/1678607445511007209/448e8cec_9911226.png
![Integer][int] 整型 `format_version`: 当前总为 `1`
![List][list] 列表 `size`: 整数列表用于表示结构大小
- ![Integer][int] 整型: 结构X轴长
- ![Integer][int] 整型: 结构Y轴长
- ![Integer][int] 整型: 结构Z轴长
![Compound][compound] 复合 `structure`: 实际存储结构的数据组
- ![List][list] 列表 `block_indices`: 结构中存储的方块索引包含两个列表第一个为实际方块数据第二个列表对应第一个列表中的方块之内含层(second layer)的方块数据每一个方块都以一个整型数据即在方块池(palette)详见下文中的索引下标(index)的形式存储方块的存储是一维列表将结构中每个方块依照从 Z 轴到 Y 轴到 X 轴且沿轴正方向的顺序一字排开形成列表例如若结构大小为 `[2,3,4]`则每一层即包括内含层也是一样的顺序的24个方块这个数量是由结构大小决定的即结构尺寸的乘积分别对应着如下相对坐标位置的方块`[(0,0,0), (0,0,1), (0,0,2), (0,0,3), (0,1,0), (0,1,1), (0,1,2), (0,1,3), (0,2,0), (0,2,1), (0,2,2), (0,2,3), (1,0,0), (1,0,1), (1,0,2), (1,0,3), (1,1,0), (1,1,1), (1,1,2), (1,1,3), (1,2,0), (1,2,1), (1,2,2), (1,2,3)]`若索引下标为 `-1` 则表示此处无方块即对应结构空位则此处在结构加载时就会保留其原有方块在我们用结构方块保存结构时这种现象会发生同时方块的内含层中也大多是无方块的同时两个层的方块共享一个方块池
- - ![List][list] of ![Integer][int] 整型列表: 首层(primary layer)方块列表
- - ![List][list] of ![Integer][int] 整型列表: 内含层方块列表此层通常为空但若您存储的是白蛇传中的水漫金山场景就另当别论了
- ![List][list] of ![Compound][compound] 复合列表 `entities`: NBT 存储的实体列表其存储格式与在地图文件中存储实体的形式一致类似 `Pos` `UniqueID` 这样的独立于不同世界中的标签亦会被保存下来但是我的世界加载这样的标签时会将它们覆写为实际值
- ![Compound][compound] 复合 `palette`: 理论上可以包含多种不同名字的方块池(palette)似乎这样设计是可能要支持以后的对于同一种结构的变体形态但可惜的是目前游戏内仅保存和加载名称为 `default` 的方块池
- - ![Compound][compound] 复合 `自定名称` : 单方块池目前名称别自定自定了没用只能是 `default`
- - - ![List][list] 列表 `block_palette`: 方块及其状态(Block State)之列表即包含了方块索引中那些索引下标(index)所指代之方块
- - - - ![Compound][compound] 复合: 单方块及其状态
- - - - - ![String][string] 字符串 `name`: 方块ID(identifier)形如 `minecraft:planks`
- - - - - ![Compound][compound] 复合 `states`: 方块之状态(state)以键值对的形式出现例如`wood_type:"acacia"``bite_counter:3``open_bit:1b`其值将转换为 NBT 可接受的类型如在游戏内枚举出的值(enum values)将转换为字符串(string)标量(scalar numbers)将被转换为整型(integer)布尔值(boolean values)会被转为字节型(byte)
- - - - - ![Integer][int] 整型 `version`: 兼容版本(Compatibility versioning number)当前此文撰写时对应的版本号是 `17959425`对应游戏版本 1.19
- - - ![Compound][compound] 复合 `block_position_data`: 包含结构中各个方块的附加数据(additional data)每一个键(key)皆为`block_indices` 中的下标索引(index)表示其对应的方块数据类型当然为整型(integer)此处不会保有多层方块的指代难道你见过草方块里包含着一个指令方块的吗
- - - - ![Compound][compound] 复合 `方块索引(index)`: 单方块附加数据(additional block data)以方块之方块索引而对应着此方块
- - - - - ![Compound][compound] 复合 `block_entity_data`: NBT 存储方块实体数据(block entity data)其存储格式与在地图文件中存储实体的形式一致同上述实体标签的理其位置标签(position tag)亦会被保存下来但是我的世界加载这样的标签时会将它们覆写为实际值不过这时候也不会有其他什么东西跟这玩意手拉手出现了 *\>译注此处原文为No other objects seem to exist adjacent to this one at this time.应该是说`entities`那么多其他的独立于各个世界的标签相比在方块实体中的算少的了*
![List][list] 列表 `structure_world_origin`: 结构最初保存时的起始点坐标(position)以三个整型(integer)组成的列表的形式出现坐标的值即结构方块保存时的坐标加上我们在结构放开里填写的偏移数据这个坐标用于计算(determine)加载时实体的位置一个实体的新的绝对坐标由其原始坐标减去结构最初保存时的起始点坐标后再加上加载起始点的坐标计算而来
- ![Integer][int] 整型: 结构原 X 坐标
- ![Integer][int] 整型: 结构原 Y 坐标
- ![Integer][int] 整型: 结构原 Z 坐标
以下是一些例子以Python的数据结构为例
```python
# 大小为 1x3x1 (XYZ) 的
# 从下往上分别是一个指令方块、一个铁块和一个空气方块的
# 结构 NBT 数据
{
'format_version': TAG_Int(1, 'format_version'),
'size': [TAG_Int(1, None), TAG_Int(3, None), TAG_Int(1, None)],
'structure': {
'block_indices': [
[TAG_Int(0, None), TAG_Int(1, None), TAG_Int(2, None)],
[TAG_Int(-1, None), TAG_Int(-1, None), TAG_Int(-1, None)]
],
'entities': [],
'palette': {
'default': {
'block_palette': [
{
'name': TAG_String('minecraft:command_block', 'name'),
'states': {
'conditional_bit': TAG_Byte(0, 'conditional_bit'),
'facing_direction': TAG_Int(1, 'facing_direction')
},
'version': TAG_Int(17959425, 'version')
},
{
'name': TAG_String('minecraft:iron_block', 'name'),
'states': {},
'version': TAG_Int(17959425, 'version')
},
{
'name': TAG_String('minecraft:air', 'name'),
'states': {},
'version': TAG_Int(17959425, 'version')
}
],
'block_position_data': {
'0': {
'Command': TAG_String('help 4', 'Command'),
'CustomName': TAG_String('', 'CustomName'),
'ExecuteOnFirstTick': TAG_Byte(0, 'ExecuteOnFirstTick'),
'LPCommandMode': TAG_Int(0, 'LPCommandMode'),
'LPCondionalMode': TAG_Byte(0, 'LPCondionalMode'),
'LPRedstoneMode': TAG_Byte(0, 'LPRedstoneMode'),
'LastExecution': TAG_Long(0, 'LastExecution'),
'LastOutput': TAG_String('', 'LastOutput'),
'LastOutputParams': [],
'SuccessCount': TAG_Int(0, 'SuccessCount'),
'TickDelay': TAG_Int(0, 'TickDelay'),
'TrackOutput': TAG_Byte(1, 'TrackOutput'),
'Version': TAG_Int(25, 'Version'),
'auto': TAG_Byte(0, 'auto'),
'conditionMet': TAG_Byte(0, 'conditionMet'),
'conditionalMode': TAG_Byte(0, 'conditionalMode'),
'id': TAG_String('CommandBlock', 'id'),
'isMovable': TAG_Byte(1, 'isMovable'),
'powered': TAG_Byte(0, 'powered'),
'x': TAG_Int(1, 'x'),
'y': TAG_Int(1, 'y'),
'z': TAG_Int(1, 'z')
}
}
}
}
},
'structure_world_origin': [TAG_Int(0, None), TAG_Int(0, None), TAG_Int(0, None)],
}
```
```python
# 大小为 2x2x2 (XYZ) 的
# 全是白色羊毛的
# 结构 NBT 数据
{
'format_version': TAG_Int(1, 'format_version'),
'size': [TAG_Int(2, None), TAG_Int(2, None), TAG_Int(2, None)],
'structure': {
'block_indices': [
[
TAG_Int(0, None),
TAG_Int(0, None),
TAG_Int(0, None),
TAG_Int(0, None),
TAG_Int(0, None),
TAG_Int(0, None),
TAG_Int(0, None),
TAG_Int(0, None)
],
[
TAG_Int(-1, None),
TAG_Int(-1, None),
TAG_Int(-1, None),
TAG_Int(-1, None),
TAG_Int(-1, None),
TAG_Int(-1, None),
TAG_Int(-1, None),
TAG_Int(-1, None)
]
],
'entities': [],
'palette': {
'default': {
'block_palette': [
{
'name': TAG_String('minecraft:wool', 'name'),
'states': {'color': TAG_String('white', 'color')},
'version': TAG_Int(17959425, 'version')
}
],
'block_position_data': {}
}
}
},
'structure_world_origin': [TAG_Int(0, None), TAG_Int(0, None), TAG_Int(0, None)]
}
```
源代码可参照此处作者金羿