一列泥土
Minecraft 菜单角落里那张 128×128 的小图,十年没人知道是在哪里拍的。后来给出答案的,是山坡上比旁边深了一格的一列泥土。
Minecraft 的菜单里,有一张很小的图,文件名叫 pack.png:一道瀑布,一片山崖,一小段沙滩,一头猪。只有 128×128 个像素。很多人看过它无数次,但十年里没有人知道,它是在哪个世界的哪个地方拍的。
2020 年 1 月,YouTube 上一个叫 SalC1 的人发了一个视频,问的就是这件事。到 9 月,一群素不相识的人给出了答案。
我今天凌晨在 B 站刷到这个故事的翻译版,视频没有字幕,就把音频转成文字读完了。最让我喜欢的,是答案里“在哪”的那一半。
种子和地方
Minecraft 的世界是从一个数生成的,叫种子。同一个种子,同一个版本,生成的世界一模一样。反过来却不行:给你一张山的照片,没有办法直接算出种子,只能一个一个种子去试。
种子是 64 位的,但游戏用的 Java 随机数生成器只保留 48 位。所以在那些老版本里,地形只取决于其中 48 位,一共 2⁴⁸,约 281 万亿个可能。
试种子之前,还得知道该在世界的哪里比对。一张照片里的山,可能在世界上的任何地方。而“在哪”看起来也要先知道种子才能回答:地形是种子决定的,不知道种子,就不知道哪里会长出这座山。
解开这个死结的,是图里那些不归种子管的东西。
不归种子管的东西
先是水。视频里说,Minecraft 的水面上有很淡的纹路,在每一个世界里都朝同一个方向。所以图里的水是一个指南针,能看出画面沿着哪条轴。
然后是云。老版本的天空里,所有的云来自同一张贴图,在整个世界上一遍一遍地重复铺开。每个世界的云都一样。在贴图里找到图中那几朵云的位置,就知道镜头朝哪边。云还会飘,但只沿着 x 轴飘,每秒 0.6 格,从不沿 z 轴动。所以 z 坐标可以直接读出来:瀑布在 z = −31。
x 就不行了。云一直在飘,它们在哪,取决于这个世界打开了多久才按下截图。没有人知道这个时间。团队能给出的只是一个公式:x 大约等于 134 减去“世界打开的秒数 × 0.6”。瀑布落在一条大约 160 格长的线上,不知道在哪一格。
一列泥土
给出 x 的,是泥土。
在那个版本里,草方块下面有一层泥土,再往下才是石头。这层泥土有多厚,由两样东西相加决定。一样是平滑的噪声,由种子决定,变化很慢,这里三格深,隔壁也差不多三格深,慢慢变薄。另一样是一点很小的随机扰动,它不来自种子,只由坐标决定。同一个坐标,在每一个世界里,这一点扰动都一样。
pack.png 的山坡上,泥土的厚度是渐变的,这是平滑噪声该有的样子。但有一列泥土,比紧挨着的那一列深了一格。平滑的噪声做不出这样的跳变,那一点扰动可以。
于是不用知道种子,也能检验任何一个 x:算出那一点扰动在这个 x 上该不该让泥土多出一格,不该,这个 x 就是错的。一列泥土排除掉了一半的候选。他们又用沙滩做了同样的事:沙子和泥土的分界线参差不齐,他们标出每一块确定是沙还是土的方块,看哪些 x 对得上。最后一直对得上的只剩一个:x = 116.
到 2020 年 8 月中,两个坐标都有了。
我喜欢这一步,是因为它绕开了那个死结。种子决定了这座山,但这座山上有一点东西不归种子管,在所有 2⁴⁸ 个世界里都一样。他们就用这一点,在不知道是哪个世界的情况下,先找到了“在哪”。
三十秒
x = 116 还顺便回答了另一个问题。把它代回云的公式:134 − 116 = 18, 18 ÷ 0.6 = 30。截下这张图的人,当时在这个世界里大约待了 30 秒。
关于这个人,这几乎是唯一知道的事。视频说,团队去问过 Notch,他不记得这张图,也不确定是不是自己拍的。Minecraft@Home 的项目页也说,Notch 和 Dinnerbone 都试着帮忙,但手里没有,也不记得任何东西。十年后,一群人从云的位置读出了这个人在那个世界里待了多久,却不知道这个人是谁。
种子
知道了“在哪”,才轮到种子。
他们先试了瀑布和旁边的树:瀑布的泉眼和树都是按种子摆放的,知道它们的位置,就能反推哪些种子会把它们放在那里。这一次没成功。Minecraft@Home 的项目页说,原因后来查出来是代码里的一个错误;视频给的理由是,陡坡上的树可能没长出来,用树做筛子不可靠。
最后用的还是沙滩。一个种子在 x = 116, z = −31 这一段海滩上的沙土图案,可以直接从种子的噪声算出来,不用生成整个世界。沙子也不像树,不会“没长出来”。把 281 万亿个种子挨个算一遍,一台电脑大约要一年半。约 3700 名志愿者把自己的电脑借给了 Minecraft@Home, 3 天跑完。剩下不到 70 万个种子的沙滩是对的。这些再在一台电脑上逐个检查生物群系和地面高度。
2020 年 9 月 5 日,世界协调时 4:04,搜索进行到最后 5% 的时候,一个种子通过了全部检查:3257840388504953787。跑出它的是两位志愿者的电脑,他们在网上叫 niraami 和 zombie67。
用这个种子在 Alpha 1.2.2 里生成世界,站在 x 约 49, z 约 0 的地方,朝瀑布看过去,山崖,瀑布,沙滩,都和图里一样。
那头猪
只少了那头猪。
Minecraft@Home 的问答里说,在这个版本里,动物不受种子影响。
图里的每一样东西,都有自己的来处。山和瀑布来自种子;那一格多出来的泥土来自坐标,在每个世界里都一样;云的位置来自时间,告诉我们有人在那里待了三十秒。这些都能重新算出来。只有那头猪不来自任何一个能算的东西。它是图里唯一只发生过一次的事。
参考
- Pack.PNG, Minecraft@Home. 2020 年 1 月 SalC1 发起,Notch 和 Dinnerbone 不记得,8 月中用泥土厚度定出坐标,瀑布和树的搜索因代码错误没成功,最后用海滩上沙和土的混合做筛子,2⁴⁸ 个种子一台电脑约 1.5 年,约 3700 名志愿者 3 天,不到 70 万个候选,2020 年 9 月 5 日 4:04 UTC,最后 5%, niraami 和 zombie67,种子和山的坐标 (X = 116, Z = −31),动物不受种子影响,出自此页。
- Bilibili 视频 BV1joJy6rE1R,是 YouTube 频道 07 Archives 视频的翻译版(原发布日期 2026 年 10 月 7 日,据简介)。视频没有字幕,我把音频下载下来,用本地的语音识别转成文字读的,转写完就删了音频。以下说法只来自这个视频,依据语音识别,我没有找到别的出处:水面纹路指示方向;云来自一张重复铺开的贴图,只沿 x 轴以每秒 0.6 格飘动;x ≈ 134 − 0.6 × 秒数和 160 格的线;泥土厚度 = 平滑噪声 + 只由坐标决定的扰动,以及那一列深一格的泥土排除了一半的候选;用沙滩定出 x;陡坡上的树可能长不出来;最后检查生物群系和地面高度;站在 x 约 49, z 约 0 (这一句视频简介里也有)。
- “扰动只由坐标决定”的旁证:一个论坛帖子引用的反编译代码(Minecraft Forum)里,生成地形的
provideChunk用this.rand.setSeed((long)par1 * 341873128712L + (long)par2 * 132897987541L)给每个区块的随机数生成器设种子,只用了区块坐标,不含世界种子。那段是 1.6.4 的反编译代码,不是 Alpha 1.2.2 的;帖子里也没有泥土厚度的那一行。所以这只能说明“老版本里有一个只看坐标的随机数”,不能直接证明 pack.png 那个版本的泥土就是这样算的。 - 30 秒是我按视频给的公式算的:(134 − 116) ÷ 0.6 = 30。视频里也给出了这个结果。
- 2⁴⁸ ≈ 2.81 × 10¹⁴,即约 281 万亿。
勘误
暂无。