欢迎光临散文网 会员登陆 & 注册

「MC筛种杂谈2」结构生成的位置选择,箱子位置和战利品的决定

2023-09-24 13:13 作者:De6ris  | 我要投稿

负一、宣群

    筛种、源码解读交流群956255985,欢迎。

零、上期课后题解

  • 一把金镐,在设置随机附魔(EnchantRandomly)时,得到效率5的概率

  • %5Cfrac%7B1%7D%7B6%7D%5Ctimes%20%5Cfrac%7B1%7D%7B5%7D%3D%5Cfrac%7B1%7D%7B30%7D%3D0.0333333%0A

  • 为什么说20附魔金苹果的古城箱子是不存在的

  • %5Cfrac%7B1%7D%7B6%7D%5Ctimes%20%5Cleft(%20%5Cfrac%7B1%7D%7B86%7D%5Ctimes%20%5Cfrac%7B1%7D%7B2%7D%20%5Cright)%20%5E%7B10%7D%5Ctimes%202%5E%7B48%7D%3D2.07016%5Ctimes%2010%5E%7B-9%7D%0A

  • 预测一个废弃传送门的箱子,有6个附魔金苹果的可能性

  • %5Csum_%7Bk%3D6%7D%5E8%7B%5Cleft(%20%5Cbegin%7Barray%7D%7Bc%7D%0A%09k%5C%5C%0A%096%5C%5C%0A%5Cend%7Barray%7D%20%5Cright)%20%5Cleft(%20%5Cfrac%7B1%7D%7B398%7D%20%5Cright)%20%5E6%5Cleft(%20%5Cfrac%7B397%7D%7B398%7D%20%5Cright)%20%5E%7Bk-6%7D%7D%5Csim%209%5Ctimes%2010%5E%7B-15%7D

  • 为什么桥类型的堡垒遗迹必出一个磁石

  • 因为第一个奖池抽奖次数是固定的1,且只有一个奖项——磁石。

  • mojang在1.20更新中,为许多结构增加了锻造模板的战利品,而不影响原有的战利品,这是怎么实现的

  • 在原有奖池后面添加了新奖池用以生成锻造模板,这并不影响之前的战利品对随机数生成器的使用,也就保持了原有的随机数序列,得到了一样的战利品。

一、结构生成的位置选择

    大部分结构遵循区域(Region)生成。一个结构的设定(setting)通常有三个要素:间距(spacing),间隔(separation),盐(salt),散布(spread)。

    spacing代表了区域的大小,每个区域内,只会生成一次该结构。separation进一步限制了一个区域内,有部分位置是无法生成结构的,这使得两个相邻区域内的两个结构不会距离过近。而salt相当于结构的标识符,几乎每个结构都拥有唯一的salt,下面也会讲解,salt还影响了位置的选取。spread有两种,线性(linear)和三角(triangular),前者在区域内均匀选取位置,后者则是均匀选取两次再取平均值,这样会更靠近区域的中心。

    例如,堡垒遗迹的spacing是27,separation是4,因此它的一个区域是27x27区块大小,也就是432x432方块大小,separation则表明一个区域中只有23x23区块大小是可以生成结构的。在下图中绿色代表可生成区域,红色代表不可生成。每块绿色区域至多生成一个结构。

堡垒遗迹的位置示意图(转自wiki)

这里我整理了各种结构的设定。

    十分方便的是,我们能利用库得知一种结构在一个种子中一个区域的位置。首先指定世界种子,然后new一个需要的结构(注意废门有主世界下界之分),然后调用getInRegion,填入世界种子,区域的X,Z坐标,再传入一个ChunkRand(随机数生成器)即可。

这串代码会输出Pos{x=9, y=0, z=3},是区块坐标,可以换算得到方块坐标(144, 0, 48)。

对于埋藏的宝藏和废弃矿井,可以发现spacing是1,separation是0,这表明它们每个Region就是一个区块的大小。

需注意,部分结构有可能会传回null,后续处理坐标时就要判断是否为null。

例如:我们要查找种子114514中,距离原点160以内的宝藏,那么计算过后就知道宝藏区块的坐标cx,cz满足:

-10%5Cle%20cx%20%3C%2010%2C%20-10%5Cle%20cz%3C10

写一个循环来遍历这些区块,并判断传回的值,当不是null时输出。

然后程序输出了这些值:

可见这些区块有可能生成宝藏。但事实上没有生成,为什么呢?因为游戏还需要检查相应位置处的群系是否允许生成该结构。对于宝藏,它要求沙滩或者积雪沙滩。我们拥有相应的方法来检查群系。对canSpawn方法传入位置和一个主世界群系(overworldBiomeSource)即可。

经过修改,我们的代码不会输出任何内容,因为确实不存在这样的宝藏。

二、箱子位置和战利品的决定

    先从最简单的单箱子结构开始讲解。对宝藏,它的箱子位置所在的区块,就是宝藏结构所在的区块。例如,种子10410544844143616的(2,-4)区块处拥有一个宝藏。MC的逻辑是:宝藏结构先生成,然后生成装饰品,箱子就属于装饰品。因此先将rand的种子设置为装饰种子(decoratorSeed),这个装饰种子的计算方法:对世界种子,区块的起始点的方块坐标,结构对应的装饰盐(salt)进行一些混合运算,具体公式可查看筛种库的源码。需注意,在这里<< 4起到了乘16的作用,就相当于把区块坐标变成了方块坐标;而30001是宝藏的装饰盐,这与上文的位置盐需要区分。之后我会贴出装饰盐的列表。随后对rand呼叫nextLong,这就是lootTableSeed了。可见是-7766255326570070266。

    顺便讲解如何方便地用lootTableSeed得到最终战利品。先创建战利品背景(lootContext),传入lootTableSeed,然后调出内置的战利品表,对它使用generate方法,传入lootContext。

    可见该宝藏有16个TNT和其它若干物品。

    废弃传送门也类似。只需把salt改成40005,以及调整战利品表。但箱子可能会罕见地跨越区块,这导致装饰种子被改成了另一个区块所对应的,因此战利品也被改变了。

    对多箱子结构,例如沙漠神殿,它的四个箱子位置所在的区块,都等同于沙漠神殿结构所在的区块。那么我们直接对rand呼叫四次nextLong,它们每一个对应一个箱子。

    对复杂的结构,如掠夺者前哨站,它的箱子所在区块与整个结构的朝向有关,因此我们需要额外写一个“前哨站生成器”来模拟朝向,并得到最终箱子所在区块。

    对更复杂的结构,如猪灵堡垒,村庄,我们也需要额外写一个生成器(Generator)来模拟得到各个箱子所在的区块坐标,以及对应的战利品表。

    例如,在这段代码中,我检查了(0,0)区域是否有猪灵堡垒,然后使用setCarverSeed来确定雕刻种子,随后nextInt决定朝向和种类。2代表藏宝室种类,若不是2我将结束。然后调用下界群系(netherBiomeSource)来确定它是否会因为位于玄武岩三角洲而取消生成。

    接下来我使用Xinyu神带领我们写的BastionGenerator来模拟整个猪堡生成,得到了猪堡所有的片段(piece)的位置,种类,朝向。然后我判断是否存在藏宝室底部两个箱子的片段。这些都不重要,我想向你们呈现的是最后一段,如何得到猪堡所有箱子的位置和内容。

    我们调用generateLoot方法,就得到了一个列表。列表中的每个元素都是一对坐标和一列物品。然后我遍历这个列表,看看是否有一个箱子拥有钻石镐。这很好理解。

三、各种结构的装饰盐

    值得注意的是,这个表格同时也起到提示世界生成顺序的作用。这能解释许多关于结构被“顶掉”的事情。例如,埋藏的宝藏的生成在废弃矿井之后,因此它可能顶掉废弃矿井的内容。

    宝藏结构生成时,会用原先该位置的方块覆盖宝藏箱子的各面。这里原先存在的是洞穴蜘蛛的刷怪笼,因此刷怪笼被复制为五个了。然而复制时并没有携带nbt数据,导致刷怪笼只能使用默认nbt数据——猪刷怪笼。此外,因为宝藏箱子继承了原先洞穴蜘蛛刷怪笼的nbt数据,这又使箱子忘记了自己是箱子,因此无法被人打开,而且内容也是空的。

    这么神奇的种子是怎么发现的呢?本期点赞过0,投币过0,收藏过0,转发过0,我之后就会写一篇文章来讲解五猪刷怪笼发现的历史。但下期我想先写一下如何通过反转lootTableSeed来得到逆天战利品。54黑曜石,16TNT,都是来源于此。

「MC筛种杂谈2」结构生成的位置选择,箱子位置和战利品的决定的评论 (共 条)

分享到微博请遵守国家法律