主线
主线承载了主要生物群系生成任务。
第一阶段
原始层
主线的第一阶段并非用实际上的生物群系来标记区元的,而是用 1、2、3、4 来表示大陆区元的温度(分别表示炎热、温暖、凉爽、寒冷);海洋、深海和蘑菇岛仍然使用生物群系 id 表示(混合表示法)。
主线的原始层 90% 被海洋覆盖,剩下 10% 是炎热大陆,是随机分布的。特别地,区元0, 0
一定是炎热大陆。这就是你出生在大陆上比直接被扔进海里的概率高的原因之一(另一个原因是基于生物群系的出生点选择)
锯齿放大化,这是唯一一次又是使用锯齿放大化,而不是普通的放大化。
放大化
放大化(Zoom)将原本占有一个区元的生物群系扩散到 2 x 2 的四个区元。注意这个放大化和放大化世界类型没有关系,反倒是和巨型生物群系世界类型有关系,后面会提到。有的时候翻译总是那么捉弄人,就像上文提到的区域和区元一样,不是吗?
如图所示(m ≥ 0, n ≥ 0,负半轴与此图水平、垂直镜像),方格外的坐标表示的是放大化之后的区元坐标,方格里面标有坐标的表示的是放大化之前对应的区元坐标,表示与原该坐标对应生物群系一致。接下来游戏会分别生成 A、B、C 三个区元的生物群系。我们不妨把n, m
、n, m + 1
、n + 1, m
、n + 1, m + 1
的生物群系分别记为 a、b、c、d。A 的生物群系即在 a 和 b 中随机选择一个,B的生物群系即在 a 和 c 的生物群系中随机选择一个。对于 C 的处理,两种放大化各有不同。如果是锯齿放大化,则直接随机选择四个其中的一个。如果是普通的放大化,则按照少数服从多数的原则进行挑选,具体规则如下:
- 如果存在三个相同的(如 a = b = c),那么就选择这一种(a)。
- 否则如果存在两个相同的,且另外两个各自不同(如 a = b 且 c ≠ d),那么就选择这一种(a)。
- 否则就不存在“多数”了,所以只能直接随机选择四个其中的一个。
扩张
实际上扩张不总是陆地在扩张,如果有有兴趣的朋友可以去细致对比一下:有的时候是海洋扩张了。不过总体来看陆地扩张较多。
这种层在第二阶段也被使用,与第一阶段的混合表示法不同,第二阶段的幻数直接表示生物群系。
- 如果自己不是海,四周(象)其中一个是海,那自己就会变成海(除非自己是寒冷,就还是寒冷)。
- 否则如果四周(象)也是海,那自己就还是海。
- 否则变为炎热,有一定概率变为四周(象)的生物群系。
最后这一分支计算比较复杂,不便于口述,干脆直接代码奉上(其中context.nextInt(n)
生成一个位于[0, n)
的随机数,ceneter
为原区元)。
int i = 1;
int ret = HOT;
if (!isShallowOcean(northeast) && context.nextInt(i++) == 0) ret = northeast;
if (!isShallowOcean(northwest) && context.nextInt(i++) == 0) ret = northwest;
if (!isShallowOcean(southwest) && context.nextInt(i++) == 0) ret = southwest;
if (!isShallowOcean(southeast) && context.nextInt(i++) == 0) ret = southeast;
return context.nextInt(3) == 0 ? ret : ret == COLD ? COLD : center;
放大化。
三次扩张。如果看过 1.6 生物群系图的朋友应该能看出这其实就是整个世界的雏形了。从图可看出,所有海洋都是联通的,海洋总面积过半。
抽干海洋
这一层_可以认为_是在 1.7 加入的。不难看出,前面扩大陆地这么多次,不如这一次来的效率高。图可看出,与之前恰恰相反:几乎所有陆地都是联通的,陆地总面积过半
降温
将原本有的炎热大陆群系变为冰冷和凉爽,各有 1/6 的概率。剩下的 2/3 陆地还是炎热。
扩张
转化:凉爽化。
转化:温暖化。
转化:稀有化。
转化
这个名字非常平庸,我胡乱起的。主要原因是第三个和前两个几乎毫无联系。
凉爽化:如果自己是炎热,且周围(車)是凉爽或寒冷,就变成温暖。
温暖化:如果自己是寒冷,且周围(車)是炎热或温暖,就变成凉爽。
稀有化:如果自己不是海,就有 1/13 的几率进行不可描述之事:
value |= 1 + context.nextInt(15) << 8 & 0xF00;
其中 value 就是这个区元的生物群系 id。注意运算符优先级哦。可以看出,这个数字的高位被标记了一下。后面这个标记的数字会派上用场。我用另一种颜色的像素来表示这样的区元。
两次放大化
扩张
蘑菇岛
把 1% 的四周(象)也是海洋的海洋区元变为蘑菇岛区元。
加入深海
将四周(車)也是海洋的海洋区元变为深海区元。
河流支线:水源
第二阶段
生物群系层
生物群系层(BiomeLayer) 是最为关键的一层之一。这一次实际上选择了具体的生物群系。前面的海洋、深海、蘑菇岛不变,其余区元按下列规则选择生物群系:
- 先选择行:如果之前区元的低位不属于下表第一列中任何一个,即为蘑菇岛。
- 除寒冷之外,若之前区元高位有(转化:稀有化中提到的)数字,则取稀有列,否则取普通列。寒冷只有普通列。
- 行和列都确定了,选中格子后随机选择格子中的一个生物群系。后面括号里的数字代表权值,没有数字默认为 1
之前区元 | 普通 | 稀有 |
---|---|---|
炎热 | 沙漠(3) 热带草原(2) 平原 | 恶地高原 繁茂的恶地高原(2) |
温暖 | 森林、黑森林、山地、平原、桦木森林、沼泽 | 丛林 |
凉爽 | 森林、山地、针叶林、平原 | 巨型针叶林 |
寒冷 | 积雪的冻原(3) 积雪的针叶林 | - |
如果前面的区元图只是一块干巴巴的面包片,这一层浇上去的便是五彩的酱汁。
竹林
把 10% 的丛林变成竹林
两次放大化
加入边缘
加入丘陵
边缘(Edge)丘陵(Hills)海滩(Shore) 是 MC 插入在两种不同生物群系中间用于过渡的生物群系,海滩会在后文中提到,下面讲解的是边缘和丘陵。
在介绍他们之前,需要先介绍两个概念
相似生物群系
在 1.15 之前,相似生物群系的概念还比较复杂。1.16 对此作出了简化。
Mojang 把生物群系分为了若干个相似组,一个生物群系只属于一个相似组,相似组里的所有生物群系互相相似。
相似组的划分基本上与生物群系类别的划分一致(后者参见附录)。但是有几点不同:
- 参与相似比较的生物群系均为主世界生物群系,故无
THEEND
和NETHER
相似组 - 类别
MESA
中的生物群系被进一步细分为两个相似组:
生物群系 | 类别 | 相似组 |
---|---|---|
badlands | MESA | MESA |
wooded_badlands_plateau | MESA | BADLANDS_PLATEAU |
badlands_plateau | MESA | BADLANDS_PLATEAU |
eroded_badlands | MESA | MESA |
modified_wooded_badlands_plateau | MESA | MESA |
modified_badlands_plateau | MESA | MESA |
注:1.16.5 offical 使用 isSame
描述相似属实欠妥。本文译作“相似”而不是相同。
变种生物群系
曾几何时,某些生物群系之间存在特殊的从属关系,被作为主世界生物群系生成时的参考之一。我们说:从属生物群系是被从属生物群系的变种(Mutation),被从属生物群系是从属生物群系的亲本(Parent)。例如向日葵草原是草原的变种,草原是向日葵草原的亲本。
这个 1.7 就加入的特性在 1.13 时被弱化,1.16 则几乎完全移除,只留下一个简单的对应关系(参见附录)。
一般来说,变种生物群系要比亲本更少见,更有特色,因而更能吸引冒险家的青睐。其中最著名莫过于变种丛林边缘(Modified Jungle Edge,MJE)——它苛刻的生成条件,使其成为 MC 中自然生成的最稀有的生物群系。结合本文内容,尤其是接下来的两节,你能分析一下原因吗?
边缘
边缘层有一个奇妙的传奇往事,是关于那个神秘的山地边缘的。1.16 之后相关内容被删干净了,如果想了解更多,参见废稿。
现在的逻辑是:如果与山地相似,就维持现状,否则:
如果自己是... | 且四周(車)任意一个不相似于... | 自己就变为... |
---|---|---|
繁茂恶地高原 | 自己 | 恶地 |
恶地高原 | 自己 | 恶地 |
巨型针叶林 | 自己 | 针叶林 |
如果自己是... | 且四周(車)任意一个是... | 自己就变为... |
---|---|---|
沙漠 | 积雪的冻原 | 繁茂的山地 |
沼泽 | 沙漠、积雪的针叶林或积雪的冻原 | 平原 |
沼泽 | 丛林或竹林 | 丛林边缘 |
如果都这些尝试都失败了,就维持现状。
丘陵
丘陵层一个二元层,一个参数是主线层,另一个是河流层。主线层的生物群系记为a
。前文提到,河流层生成的是[0+2, 299999+2)
之间的一个随机噪声,而丘陵层使用的数据是该层减 2,即[0, 299999)
,并对 29 取模记为r
。
第一次尝试成功的条件是:如果a
不是浅海且不是变种生物群系,同时r
为 1 (概率约为1/29)。
如果成功:
- 如果
a
有变种就变为a
的变种 - 如果
a
没有变种就保持a
不变
如果失败,则进入第二次尝试:
- 当
r
不为 0 时,就有 1 / 3 的概率进入第二次尝试,并根据a
选择对应的丘陵生物群系记为h
。如果没有对应的h
,这次尝试也会失败。把h
记为ret
。 - 当
r
为 0 时,直接进入第二次尝试,并根据a
选择对应的丘陵生物群系及其变种记为h
和mh
。如果没有对应的h
,或者h
没有变种,这次尝试也会失败。把mh
记为ret
。
如果四周(車)至少有 3 个区元的生物群系相似于a
,尝试成功,该区元变为ret
。如果上述尝试都失败,就保持a
不变。
下表是经过我整理后得出,在这里可能出现的原生物群系与对应丘陵生物群系的对照表。和上文相同,后面括号里的数字代表权值,没有数字默认为 1。
原生物群系 | 丘陵生物群系 |
---|---|
沙漠 | 沙漠丘陵 |
森林 | 繁茂丘陵 |
桦木森林 | 桦木森林丘陵 |
黑森林 | 平原 |
针叶林 | 针叶林丘陵 |
巨型针叶林 | 巨型针叶林丘陵 |
积雪的针叶林 | 积雪的针叶林丘陵 |
平原 | 繁茂山地、森林(2) |
积雪的冻原 | 积雪的冻原丘陵 |
丛林 | 丛林丘陵 |
竹林 | 竹林丘陵 |
海洋 | 深海 |
山地 | 繁茂山地 |
热带草原 | 热带高原 |
与恶地高原相似 | 恶地 |
1 / 3 的深海 | 平原、森林 |
向日葵平原
把 1/57 的平原变为向日葵平原
生物群系大小
上图连续放大了四次,其中前两次还夹带了私活,这一阶段实际上是根据世界生成的一个重要参数——生物群系大小(BiomeSize) 进行的。原版的默认(Default) 世界类型这个数字是 4,而巨型生物生物群系(LargeBiomes) 世界类型这个数字是6。根据前面对放大化的解释可以知道,巨型生物群系的生物群系的面积将会是默认的 16 倍,即 x 和 z 方向各 4 倍。
在第一次放大化完成之后,将会再进行最后一次扩张。详解见上文扩张一节。
在第二次放大化完成之后(如果生物群系大小仅为 1,则在扩张完成后),添加海滩生物群系。
海滩
生成海滩的前提是自己不是海、不是沼泽。原则是:现在第一列找到自己的类别,判断周围的条件,如果失败就不再尝试、维持现状。唯一的例外是丛林有两次机会。
自己 | 周围(車) | 海岸 |
---|---|---|
蘑菇岛 | 任意一个是浅海 | 蘑菇岛海岸 |
类别为丛林 | 任意一个不兼容丛林1 | 丛林边缘 |
类别为丛林 | 任意一个是海洋 | 沙滩 |
山地或繁茂山地 | 任意一个是海洋 | 石滩 |
降水类型为雪 | 任意一个是海洋 | 积雪的沙滩 |
恶地或 繁茂的恶地高原 | 任意一个类别不是恶地 且全都不是海洋 | 沙漠 |
其它 | 任意一个是海洋 | 沙滩 |
1兼容丛林的生物群系有:类别为丛林的生物群系、森林、针叶林、海洋
平滑
平滑层会根据四周(車)的生物群系改变自己的生物群系,规则如下:
- 若东等于西且南等于北,则随机选择西或北
- 若仅东等于西,则选择西
- 若仅南等于北,则选择北
- 上述尝试都失败,维持现状。
混合河流
如果主线是海洋,或河流支线不是河流(7),就维持原状,否则根据下表选择一个河流。
原生物群系 | 河流生物群系 |
---|---|
积雪的冻原 | 冻河 |
蘑菇岛或蘑菇岛海滩 | 蘑菇岛海滩 |
其他 | 河流 |
混合海洋
创建、合并了海洋支线,使主线层的海水有了温度。可惜这幅图中无法体现,因为刚好没出现其他温度的海洋。
混合规则:如果周围特定区元(如上图所示,紫色为自己,紫色和红色为检测区元,相邻两个非黑区元间隔了三个区元,即步长为4)有非海洋区元,暖水海洋变为温水,冻洋变为冷水海洋。否则,如果主线层是深海,还会对海洋支线层传来的浅海转变为对应的深海生物群系。
注意:暖水海洋不会进行这样的转换,这也就是原版有暖水深海却不会生成的原因。
至此,所有层的工作都完成了。所得的便是每一个区元的生物群系。
完成:实时放大化
最后,当细化到某个具体的方块时,我们还需要一次实时放大化。这一部分我们在 1.6 节 就已经讲过了,这里不再赘述。