总览——浅谈Mincraft地形生成(SP 2)
使用数据包自定义世界生成的时候,几乎所有的文件都储存在worldgen文件夹中,而我们打开wiki中有关数据包文件夹目录结构的条目,可以看到worldgen文件夹下又有繁多的文件夹,而每一个文件夹都对应了世界生成中需要用到的一种文件。初次查看的时候,你可能会被这些突如其来的概念弄得晕头转向,因此我特别写了这一个章节,来帮助你在学习的过程中把所有的东西都串联起来!
世界生成的基本过程
首先,我们需要了解一下世界生成的基本过程,对世界生成有一个基本的整体性认知。
世界生成,World Generation,也就是我们经常说到的worldgen。当世界生成的时候,是分区块进行生成的,而每个区块生成的时候又分为多个加载阶段。在Java版中,区块生成的时候需要经历以下几个阶段:
- 未进行生成(Empty):区块还没有开始加载。
- 生成结构范围(Structure Starts):尝试计算结构是否能放置在这个区块,并计算出结构的范围和起始生成点。
- 计算结构引用(Structure References):计算区块内引用的结构片段,并保存在区块的数据内。
- 填充生物群系(Biomes):根据生物群系源计算区块内的所有生物群系单元,并保存在区块数据中)
到此,区块中仍然没有任何方块,仅仅是对区块生成需要的数据进行了计算。接下来才是区块中方块的填充过程。
- 填充初始噪声地形(Noise):计算区块内的密度函数,并根据其计算结果填充初始方块。计算含水层并放置液体,生成矿脉。这部分的内容都是噪声设置决定的。
- 应用表面规则(Surface):应用表面规则。此部分的内容在维度生成器中决定。
- 地形雕刻(Carvers):雕刻地形,将这部分方块替换为空气。一般用于生成矿洞等。
- 生成地物(Features):又称作世界装饰阶段(Decoration)。结构和地物按照固定顺序依次放置,高度图在此阶段完善。
此后的阶段内容都与自定义世界生成无关。
- 初始化光照计算(Initialize Light):初始化光照系统,计算区块内的光源。
- 计算初始光照(Light):初始化光照系统,计算区块内的光照数据。
- 生成初始实体(Spawn):进行初始动物生成。
- 区块生成完毕(Full):将原型区块转换为世界区块,并执行上面所有阶段中没有执行而延迟的方块更新。
在自定义世界中会用到的重点都在其中加粗标识。在了解了这些之后,我们就可以移步数据包看看自定义世界生成了。
自定义之路
一般来说,自定义世界有两种方式——一种是使用世界预设文件在生成世界的时候即定义(world_preset文件夹),一种是使用维度定义(dimension文件夹)。在本文中,我们直接从维度定义出发来讲解。
世界的生成是以维度为单位的,不同的维度中可以定义不同的地形生成方式。要定义一个维度,需要在dimension文件夹中定义维度文件,并在dimension_type文件夹中定义维度类型。前者定义了维度的生成方式,后者则定义了维度中的视觉效果、游戏机制等等。注意,这两个文件夹不在worldgen文件夹中,而是直接写在命名空间根目录下。
我们看向维度文件的格式。

注意这里有两个type字段,不要弄混。外层最上面的type字段表示维度类型,也就是我们之前在dimension_type中写入的文件。
在这里,维度类型的文件我们不会详细说,可以查看本系列中维度相关的章节学习了解。后续也是一样,本章节仅仅用于帮助读者在学习世界生成的过程中将学到的东西串联起来,并不是一篇完整的教程。
随后的区块生成器中的type字段我们一般会选择noise,因为我们需要用噪声生成更复杂的地形。而noise生成器又拥有这些字段:

生成器定义了两个重要的部分,第一个是生物群系源,决定了这个群系中的生物群系应该怎么分布,第二个噪声设置,则定义了地形应该如何生成。一般来说,我们不会把噪声设置单独放置一个文件,毕竟在不同文件之间跳来跳去总是很麻烦。
噪声设置
我们先看噪声设置。

噪声设置的json文件很长,但是我们可以将它分为三个部分。
第一个部分是noise_router之前的内容(不包括),是一些地形生成的杂项,比如说海平面高度、含水层、矿脉相关的设定,对应了前文世界生成基本过程中的一些内容。noise字段决定了一些会应用到密度函数计算中的一些参数,在你学习密度函数的时候应该会注意到。
第二个部分是noise_router字段。这是一个对象,而我在上图中将这个对象折叠掉了,不然json的结构太长不方便截图了。我把这个字段的内容单独放在下面的图里:

这里是噪声设置引用密度函数的地方。在地形生成方面,我们主要关注的是final_density也就是最终密度,这里直接决定了世界地形是怎么生成的。此外,我们还可以看到后面有一些生物群系相关的密度函数项,这些密度函数用于计算在不同位置上和生物群系生成相关的参数,比如大陆性、温度、湿度、侵蚀度等等,这些字段是将生物群系和地形样貌绑定的关键。在最终密度中的密度函数中,其实引用了大量生物群系密度函数。例如大陆性密度函数,当这个值高的时候,最终密度函数对应的地形高度也会高,而计算得到的大陆性高,对应的也是陆地生物群系;当这个值低的时候,最终密度函数对应的地形高度也会低,而对应的也是海洋陆地群系。因此,在为自己的维度添加生物群系的时候,也可以用这样的方法将生物群系的生成和地形的生成联系起来。
而第三部分则是表面规则,用于在用密度函数生成完出初始地形后,按照指定的规则修改初始方块。尽管主世界表面规则很长,但是它仍然是你学习表面规则的重要资料。
说完了这三部分,你可能会想,噪声设置怎么没有噪声呀?这是因为,噪声并不会被直接调用,而是先在密度函数中被引用,然后密度函数再被维度的噪声设置引用。密度函数对噪声起到了进一步的修改作用,让噪声地形更加丰富多样化。
生物群系
在维度设置中,我们还会定义生物群系的生成方式,即生物群系源。生物群系源同样也有不同的类型,但是一样的,我们一般会选择multi_noise类型。

其中定义了每种生物群系的参数。在上文噪声设置中的生物群系密度函数就会对每个位置计算出相应的生物群系参数值,然后选择这个位置生成什么生物群系。
当然,你也可以自定义自己的生物群系并在这里被引用。生物群系定义在worldgen/biomes下,其文件格式如下图所示:

除了定义了生物群系是不是下雨、生物群系中生成什么动物以及环境属性以外,生物群系还定义了在这个群系中会使用哪些雕刻器,以及会生成哪些地物,这两个就是和我们自定义世界生成息息相关的字段。前者引用了自定义雕刻器,后者引用了自定义地物,自定义地物在本系列中有专门的章节说明,自定义雕刻器暂时还没有,具体的内容就请移步对应的章节或者对应的wiki页面啦,这里不多赘述,不然就变成超长的总教程了。
结构
维度相关的内容就说完了,从生物群系到地形生成,我们似乎已经大致了解了地形生成的一切——什么,你说有东西没说?对啦,结构。结构并不是定义在维度设置中的,而是以结构集的概念被单独定义的。
结构集定义在worldgen/structure_set文件夹中。它包含了一系列的结构,同时定义了这些结构应该怎么在世界生成阶段分散在世界中而生存。在世界生成阶段,每个维度都会尝试计算所有可用的结构集,在结构集计算的坐标上挑选可能的结构。如果当前位置的概率不通过,或不符合生物群系要求,或诸如地形限制等其他因素导致计算失败,则此处不会放置结构;否则,游戏会在区块内记录将要生成的结构片段,待区块加载时生成结构。locate structure命令在搜索结构的时候也是以结构集进行搜索的。

而结构集中的结构则定义在worldgen/structure文件夹中。结构有很多种类型,但是对于自定义结构而言,我们只需要关注jigsaw类型的结构。这种结构将会引用模板池,并利用拼图方块生成结构。相关的内容在SP章节中有介绍,同时我也在B站烤制搬运过外网Up制作的优秀教程,因此这里不多赘述。

到此为止,相信你已经对自定义世界生成的相关内容有了一个基本的概念。在你探索自定义世界生成的过程中,除了去翻阅mojang写下的原版世界生成以外,也不要忘记使用可视化编辑器构建一些小例子来了解各种密度函数、各种设置字段的作用。希望本章节能对你被世界生成繁多的配置文件弄的一团浆糊的思路有所帮助!