本文参考GTNH给出的源码

口袋世界球”指每次用异界漩涡和元始珍珠生成新口袋世界得到的区域,应当指出,这一系列区域事实上都在一个维度。

相应的,“口袋世界”指整个口袋世界维度

文章侧重研究口袋世界球内部生成方块的材质、生成的生物(如果有的话,我还没读到这部分),至于其形状、洞穴形状之类,碍于笔者精力有限,不是本文的重点。

“节点”指创造漩涡所用的节点

“节点总要素”即节点包含所有要素数目之和,如含有(39 Aer、40 Aqua、1 Ordo)的节点,节点总要素为80

多个条件并列时,用“/”表示“或”

“含有要素”总是指该要素>0的情况。


口袋世界球中心:x=0,y=128,z=256*口袋世界球数量(不算自己)


半径:

(节点总要素*0.75) < 32时(用浮点数计算,可能有些许误差),半径为32

32 <= (节点总要素*0.75) < 128 时,半径为 (节点总要素*0.75)

128 <= (节点总要素*0.75) 时,半径为127(确实不是128)



每次生成口袋世界球最多生成100个实体,放在一个计数器里。

口袋世界球生成完毕时,实体计数器归零。

口袋世界球生成在新线程进行,同时生成多个口袋世界可能会共享这一数值和口袋世界的随机生成器,这很可能是一个多线程BUG。





口袋世界球颜色:

    将节点所有要素的颜色(RGB)求加权平均数,权重为 

(该种类要素数/节点总要素数)(称为“要素权重”或“要素权值”,这一概念我们会接着用到),

RGB分开计算,记作“口袋世界球颜色”,这个颜色目前只会影响到异界要石的颜色。

(Aer:0xff ff 7e,Auqa:0x3c d4 fc。于是1Aer和3Aqua会得到RGB(向量形式):

(0xff*(1/4)+0x3c*(1/3), 0xff*(1/4)+0xd4*(3/4), 0x7e*(1/4)+0xfc*(3/4))

0x表示16进位制,小数用double计算,取整用java int cast)


然后决定口袋世界球群系

(优先级自上而下,区域为口袋世界球为中心、(切比雪夫)半径为上述半径的正方体区域)

污染要素->污染群系

异域亡灵要素->外域群系

魔法灵气要素->魔法森林群系

否则,进行如下群系判断:

记录"温度权值"和"湿度权值"(这两个数值只影响群系生成),初始值0.5(浮点数)。

对每种要素(如果包含在下方)有如下计算:

要素使得温度权值 +1*要素权值

光明能量移动要素使得温度权值 +0.5*要素权值

气候黑暗要素使得温度权值 -0.25*要素权值

秩序虚空要素使得温度权值 -0.5*要素权值

寒冰要素使得温度权值 -1*要素权值

计算之后,温度权值若小于0则改为0,若大于1则改为1

使得湿度权值 + 1*要素权值

气候史莱姆 使得湿度权值 + 0.5*要素权值

虚空混沌 使得湿度权值 - 0.25*要素权值

使得湿度权值 - 0.5*要素权值

同样的,计算之后,湿度权值若小于0则改为0,若大于1则改为1

然后做如下判断(优先级自上而下):

温度权值>0.8 -> 沙漠

温度权值>0.5 湿度权值<0.4 ->热带草原

温度权值>0.5 湿度权值>=0.4 ->丛林

温度权值>0.2 湿度权值<0.4 ->平原

温度权值>0.2 湿度权值>=0.4 ->森林

其它->冰原


"噪声值"计算(后续生成时会用到):

噪声值初始为50(暂且为双精度浮点数,但还要取整),最后若小于0则取0,大于100取100

混沌交换 -> +100*要素权值

移动飞行-> +50*要素权值

秩序旅行 -> -100*要素权值


若小于0则取0,大于100取100

最后,向下取整


"生命值"计算(后续生成时会用到):

生命值初始为0(暂且为双精度浮点数,但还要取整),最后若小于0则取0,大于100取100

生命治疗 ->+150*要素权值

植物树木野兽->+100*要素权值

灵魂史莱姆肉体作物->+50*要素权值

光明气候思维感官人类收获布匹->+25*要素权值

黑暗武器饥饿 -> -25*要素权值

亡灵-> -50*要素权值

毒药 -> -75*要素权值

死亡 -> -100*要素权值


若小于0则取0,大于100取100

最后,向下取整


决定地板材质(可以有多个):

(其实叫地层更为贴切)

(下述条件可以同时满足,比如同时有浮冰和腐化泥土)

层数下降:将层数减去 要素权重*口袋世界半径,默认层数在口袋世界中心

有 寒冰 要素 ->浮冰,噪声值群系生命值不在此处作用,并且接下来生成层数(简称层数)下降,下降值为:(该要素权重*口袋世界球半径)(向下取整)

有  要素 ->水,噪声值不作用,层数下降,下降值为:(该要素权重*口袋世界球半径/1.5)(向下取整)

有 污染 要素 -> 腐化泥土,层数下降,下降值为:(该要素权重*口袋世界球半径)(向下取整)

有 布匹 要素 -> 白色羊毛,群系生命值不作用,层数下降,下降值为:(该要素权重*口袋世界球半径)(向下取整)

有 肉体 要素 -> 血肉方块群系生命值不作用,层数下降,下降值为:( 布匹 要素权重*口袋世界球半径)(向下取整)(这可能是个BUG)

有  要素 -> 

        (对于群系:沙漠->沙子;其它->泥土)

            秩序>混沌 -> 石头(向下5格)、群系生命值不作用

            混沌>=秩序 -> 圆石(向下5格)、群系生命值不作用

            层数下降,值为(  要素权重*口袋世界球半径/1.5)(向下取整)

有  要素->地狱岩,群系生命值不作用,层数下降,下降值为:(该要素权重*口袋世界球半径)(向下取整)

有 装备 要素->黑曜石,群系生命值不作用,层数下降,下降值为:(该要素权重*口袋世界球半径)(向下取整)

以上都没有->尘埃


生成地板:

这一部分的具体生成会略过,因为不如去看源码。

上述群系不作用则为null,生命值噪声值不作用则为0

当噪声值作用时,取口袋世界的随机数生成器,用于创建minecraft自带噪声生成器(NoiseGeneratorOctaves),NoiseGeneratorImproved个数为10(MCP的源码不便展示,略过)

生成的一系列噪声值总是非负的。

本文只强调当噪声值作用时,该层的高度是不均匀的。


对顶端方块:

    尝试生成水时,如果是寒冷群系(对于原版是温度值<0.2,但又不是上述的温度权值),生成冰。

    否则:

        正常生成水

        实体计数器<100且生命值 >40 时有1%的概率生成鱿鱼,并且使实体计数器+1

        生命大于0时有1%概率在水上方生成睡莲

    尝试生成泥土时,生命值为0则正常生成,否则:

        生成草方块。

        生命值大于20/作物要素>0/收获要素>0 时,2%的几率:

            从下述事件中取其一,它们权重相同:

                该方块设置为耕地,上方设置为萝卜

                该方块设置为耕地,上方设置为土豆

                该方块设置为耕地,上方设置为小麦

                上方设置为西瓜

                上方设置为南瓜

                上方设置为甘蔗

                该方块设置为菌丝地,上方为蘑菇

                该方块设置为菌丝地,上方为红蘑菇

                上方为水银花

                上方为纤毛菇

        如果上述条件不满足(没碰上上述的2%概率一并算作不满足),生命值>=15/树木要素>0时,2%的几率

                在上方生成6种(1.7.10只有6种)原版树苗或2种神秘时代树苗中的一个。

        如果上述条件不满足(没碰上上述的2%概率一并算作不满足),10<=生命值/植物要素>0时,5%的概率

                生成 (原版9种花(1.7.10)、具有无效数据值(于是不能用于原版合成)但看起来是罂粟的7种花、枯萎的灌木、草)中的一个(不是草和蕨,这可能是一个bug)

    尝试生成沙子时:

        生命值>20时,1%的几率在上方生成火焰草。

        若生命值>10,且没有生成火焰草,2%的几率在上方生成仙人掌。

    尝试生成血肉方块时:

        1/300的几率:

            在上方生成2*3*2(长*宽*高)或3*2*2的大脑团

    若为寒冷群系,生成方块为正常方块(不透明、体积为整个方块、不是红石,可以被mod改写),在上方生成雪

    若生命值>=50/有野兽要素,实体计数器小于100,1%的概率:

        从牛、羊、鸡、猪、马、豹猫、狼中选一项生成(权重相同),使实体计数器+1。

    有毒药交换金属机械要素之一时,实体计数器<100,1%的概率:

        生成水银史莱姆,实体计数器+1

    有史莱姆肉体饥饿要素之一时,实体计数器<100,1%的概率:

        生成血肉史莱姆,实体计数器+1

     有史莱姆要素时,实体计数器<100,1%的概率:

        生成史莱姆,实体计数器+1

    (生成实体总在该方块上方)

    有异域要素时,1/200的概率:

        该格生成黑曜石瓦块,上方三格生成黑曜石图腾

    有合成要素,1/200的几率

        该格上方生成奥术基座

    有污染要素,1%的几率:

        该格为腐化草丛

    有污染要素,实体计数器<100,1/200的概率:

        上方生成腐化触手怪,实体计数器+1

    有污染要素,实体计数器<100,1/200的概率:

        上方生成腐化孢子巢穴,实体计数器+1

对顶端以下直接生成,一直生成到大约球底部(可能会生成到球外一两格)。


生成洞穴:

记录口袋世界球的“固态值”,初始为0.5

将“固态值”减去飞行要素权重的0.5倍,减去虚空要素权重。

加上秩序要素权重的0.25倍,加上合成陷阱要素权重的0.5倍

然后,固态值小于0则改为0,大于1则改为1.

决定洞穴数量,记为N,为((半径^3)*(固态值+0.1)/10000),java int cast取整(即去掉小数部分)

地、水、火、风、秩序、混沌、 金属、死亡、亡灵、感官、贪婪 要素的权重记到一张表(要素权重<=0不计),

顺序由TC4被加载后节点内要素种类确定(每次TC4启动后都可能不同,因为Aspect对象的hashCode在TC4被加载时确定,HashMap的keySet顺序尚不清楚,java未对此作出规定。这顺序和内存地址相关,事实上是难以确定的),

然后生成N个洞穴。

用[a,b]表示a到b的闭区间,但可以有a=b,x于区间[a,b]上 等价于 a<=x<=b

洞穴大小[10,19]*[10,19](x*z,两个都是区间,均匀分布),


x和z偏移量:

[0,半径*1.5(向下取整) - 1]-半径*0.75(向下取整)。

    忽略一点误差则为[-半径*0.75(向下取整),+半径*0.75(向下取整)]

y偏移量:

-半径*0.5

这些偏移量在噪声生成器用到


在某一选定区域内生成洞穴,区域内被选中覆盖的方块不能是水,否则跳过这个方块。

1/50的概率,生成装饰物,下方一格不能是空气,否则跳过。

这里要用到上面的要素“表”,将要素拿出来,要素权重作为长度,按上述(难以确定的)顺序画成一条线,如果长度不足1,将其长度补为1。

口袋世界生成机制的大致分析-第1张图片

黑色表示这一段没有被要素覆盖。黄色表示风要素,绿色表示地要素,蓝色表示水要素,只是举例子。

在这条长度为1的线上面随机(用口袋世界的随机数生成器)取一点,落在哪一段上,就用哪个要素生成装饰物。

基础要素->对应魔晶,如地之魔晶

死亡/亡灵要素->骷髅头

感官->青金石块

贪婪->金块/绿宝石块(等可能)

金属->金块/铁块(等可能)



生成“口袋”(确切地,生成矿石):


选择“口袋”种类:

以下要素及其要素权重会记录在一张表:

地、水、火、风、秩序、混沌、金属水晶灵魂魔法灵气能量 、树、血肉、感官、矿藏、工具、贪婪、腐化、毒药、交换、思维、人类、饥饿、合成

规则同上,生成口袋的步骤尝试 (半径^3)/200 次,用java int cast取整(这里向下取整)

地、水、风、秩序、混沌:生成对应蕴魔石,

火:50%几率生成对应蕴魔石,50%几率生成岩浆。

金属:

50%几率生成铁矿

40%几率生成金矿

10%几率生成水银

魔力、灵气:六种基本蕴魔石之一,每种均匀分布

水晶:石英块

灵魂:灵魂沙

能量:红石块

树:50%几率生成橡木原木,50%几率生成琥珀矿石

血肉:血肉方块

感官:青金石矿

矿藏、工具:40%铁矿,10%金矿,10%钻石矿,10%绿宝石矿,10%青金石矿,20%为(六种蕴魔石、琥珀、水银)之一(这20%的一项中所有矿均匀分布)

贪婪:40%金矿,20%钻石矿,20%绿宝石矿,40%青金石矿

腐化:陈年污点

毒药:死亡之水(数据值为16,但有效数据值只有0~3,16无法用setblock得到,这很可能是个bug)

交换:朱砂

思维:50%书架,50%大脑块

人类:1/3书架,1/3大脑块,1/3血肉方块

饥饿:血肉方块

合成:工作台


选定材质后生成“口袋”(矿石),用到了噪声,随机长宽都在1~4之间(均匀分布),但不覆盖水和空气



作者未完成部分:

drawRavines(xCenter, yCenter, zCenter, data, world, aspects, noise);
drawClouds(xCenter, yCenter, zCenter, data, world, aspects, noise);
drawSurfaceFeatures(xCenter, yCenter, zCenter, data, world, aspects, noise, life);
drawUndergroundFeatures(xCenter, yCenter, zCenter, data, world, aspects, noise, life);
drawLeviathanBones(xCenter, yCenter, zCenter, data, world, aspects, noise);

这意味着手册中(用指令解锁全部研究)的云和大型化石是不会生成的


添加药水效果(没有实装,仅存在于口袋世界数据):

对于部分大于0的要素,有:

移动:速度

飞行:跳跃提升

治愈:生命恢复

旅行:速度

工具:急迫

武器:力量

装甲:抗性提升


生成额外包层:

每生成一次包层(球壳),接下来的包层半径-1

初始为口袋世界球半径-1

只要要素大于0就会尝试生成

异域:荒古石头

黑暗:黑曜石

异域:荒古石头(确实写了两次!)

水晶:玻璃

寒冷:浮冰

[GTNH版本移除]气候/风/水 至少一种:云,这会导致性能问题


生成口袋世界球壳:

和额外包层类似,但最后生成。


生成进入平台:

球中心生成5*5的奥术石块,平台上方两格改为空气

平台上方生成返回用的异界漩涡

玩家进入时会被置于此处。


说多也不多,之前花了一早上,现在花了半小时。接下来我只要加点要素图标?但是我懒得加,因为我可能要按f12。就放着吧,希望读者对这些要素是熟悉的。

习题:在同一口袋世界球中生成岩浆、玻璃、血肉方块,可以使用节点力学合成节点,或用NBT编辑器编辑节点