本篇教程的视频

本篇教程的源代码

GitHub地址:

本篇教程目标

  • 搞清结构由哪几个文件组成
  • 学会用结构方块保存一个 nbt
  • 学会写 structure / template_pool / structure_set / 群系标签 四份 json
  • 知道每个参数调错了会有什么症状

介绍

村庄、遗迹、神殿,这些在游戏里都叫结构

结构比较特别的一点是:它是纯数据的,不用写一行代码

你只要准备好一个建筑,存成 nbt,再配四个 json,世界生成的时候就会把它摆进去

单体结构和多体结构

结构分两种

单体结构:一个 nbt,一摆就是一整栋,比如沙漠神殿、海底废墟的单个残骸

多体结构:很多 nbt 拼起来,靠「拼图方块」互相咬合,比如村庄、远古城市

这期我们做单体,也就是最简单的「一栋房子」

拼图那套东西复杂得多,等你单体玩明白了再往上走

准备工作:做一个 nbt

造一个房子

先在游戏里搭个小建筑,注意别超过 48×48×48

因为结构方块最大只能框这么大,这也是单体结构的上限

用结构方块保存

结构方块没有物品,只能打命令拿

1
/give @s minecraft:structure_block

用法是:在建筑的一个角放一个结构方块,切到 Corner(角落模式),填个名字(只能是小写字母和数字)

再到对角线的位置放第二个,切到 Save(保存模式),填同一个名字

点一下 Detect(检测),会出来一个白框,看看建筑是不是完整框住了

没问题就点 Save

保存之后,文件在存档目录下

1
saves/<存档名>/generated/minecraft/structures/<名字>.nbt

把这个文件拿走,就是我们需要的 nbt

三个小方块

保存的时候顺便认识三个东西,后面做结构很有用

结构空位(structure_void):白框里的紫色小方块就是它。它的意思是「这个位置是空气,而且生成的时候别被水填」

用结构空位右键紫色方块,会变成粉色,意思是「这个位置可以被水填」

屏障(barrier):看不见的墙,变身红色,用来挡住玩家

光源方块(light):变身黄色,用来打光,默认亮度 15,右键能调

做大场景的时候,光源方块比插火把方便多了

写数据文件

四份 json,路径一个都不能错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
src/main/resources/data/tutorial
├── structure
│ └── house.nbt
├── worldgen
│ ├── structure
│ │ └── house.json
│ ├── structure_set
│ │ └── houses.json
│ └── template_pool
│ └── house
│ └── start_pool.json
└── tags
└── worldgen
└── biome
└── has_structure
└── house.json

注意 structure 是单数,worldgen 下面那个也是单数

这两个地方最容易写错一个 s,然后游戏一点提示都没有,结构就是不生成

一、结构本身

data/tutorial/worldgen/structure/house.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"type": "minecraft:jigsaw",
"biomes": "#tutorial:has_structure/house",
"step": "surface_structures",
"spawn_overrides": {},
"start_pool": "tutorial:house/start_pool",
"size": 1,
"start_height": {
"absolute": 0
},
"project_start_to_heightmap": "WORLD_SURFACE_WG",
"max_distance_from_center": 80,
"use_expansion_hack": false
}

我们来逐一了解里面的参数

  • type 是 minecraft:jigsaw,看着奇怪,但单体结构也用它。原版还有desert_pyramid这种专用类型,那是硬编码的,我们用不了
  • biomes指向群系标签,也就是tags里面的文件
  • step是生成阶段,surface_structures是「地表结构」的生成阶段
  • start_pool指向模板池,即template_pool里面的文件
  • size 是拼图的层数,单体结构给 1 就够
  • start_height 是高度偏移,0 表示贴着地表
  • project_start_to_heightmap 是用哪张高度图对齐,WORLD_SURFACE_WG 就是「最高的非空气方块」;这两个配合起来的意思是:找到地表高度,再加 start_height,就是结构的落点
  • use_expansion_hack 是老版本村庄的兼容开关,我们给 false
  • spawn_overrides 是「结构内刷什么怪」,我们给空对象,表示用群系默认

二、模板池

data/tutorial/worldgen/template_pool/house/start_pool.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "tutorial:house/start_pool",
"fallback": "minecraft:empty",
"elements": [
{
"weight": 1,
"element": {
"location": "tutorial:house",
"processors": "minecraft:empty",
"projection": "rigid",
"element_type": "minecraft:single_pool_element"
}
}
]
}

模板池就是「候选建筑列表」

单体结构只有一个元素,所以 weight 随便写

其他参数:

  • location指向我们的结构nbt文件
  • processors是方块替换规则(比如把石头换成苔石),minecraft:empty为空
  • projection是贴合方式,rigid表示原样摆放,terrain_matching会跟着地形变形(生成道路、废弃建筑倒是可以用)
  • element_type用single_pool_element,就是「一整个 nbt」

三、结构集

data/tutorial/worldgen/structure_set/houses.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"placement": {
"type": "minecraft:random_spread",
"salt": 1684213507,
"separation": 8,
"spacing": 32
},
"structures": [
{
"structure": "tutorial:house",
"weight": 1
}
]
}

结构集决定「多久出现一次」

  • spacing 是平均间隔,单位是区块,32 就是平均每 32 个区块一个
  • separation 是最近间隔,8 就是两个结构至少隔 8 个区块;注意,separation 必须小于 spacing,不然会崩
  • salt 是这张表的随机种子,每个结构集必须唯一,随手写个大数就行
  • weight 是「多个结构共用一个结构集时的权重」,我们只有一个,写 1

四、群系标签

data/tutorial/tags/worldgen/biome/has_structure/house.json

1
2
3
4
5
6
7
8
{
"values": [
"minecraft:plains",
"minecraft:sunflower_plains",
"minecraft:meadow",
"#minecraft:is_forest"
]
}

这个标签决定「哪些群系能有这个结构」

可以直接写群系id(注意不要写错,其他模组的也是),也可以写 # 开头的群系标签,比如 #minecraft:is_forest 就把所有森林一网打尽

如果这里写的群系和 structure 里 biomes 指向的标签对不上,结构就是不会出现

测试

由于我们这篇教程是纯手写的,需要仔细检查,确认无误后,我们启动游戏进行测试

如果你写的这些文件有问题,要么世界里面找不到,要么点开新建世界界面就会直接崩溃

常见问题(大肥鱼总结版)

  • /locate 说找不到结构:structure_set 没写、salt 和别的撞了,或者 biomes 标签里的群系你根本没遇到
  • 结构全埋在土里/悬空:调 start_height,负数往下沉、正数往上抬
  • 结构一半卡在山坡里:把 project_start_to_heightmap 改成 WORLD_SURFACE_WG(默认就是),或者干脆选平原群系
  • 结构完全不生成:structure 目录名写成了 structures(多了个 s),或者 worldgen 下面也多了个 s
  • 启动直接崩,报 separation must be smaller than spacing:结构集里这两个数调反了
  • 房子是破的、缺一块:保存 nbt 的时候白框没框全,回去重新 Detect 一次
  • 房子里灌满了水:nbt 里该用结构空位的地方用了空气,水就流进去了
  • 结构互相叠在一起:spacing 太小,或者 separation 也太小
  • 换了 nbt 但游戏里还是老的:template_pool 里 location 的名字没改,或者改了没重新打包
  • 想让它只长在特定生物群系:改第四份文件的标签,别的都不用动