AlbertBlue
本帖最后由 Lightning_Reed 于 2017-2-6 09:24 编辑

当你在地图生成时输入种子 107038380838084或者164311266871034的时候,地图就会出现矿洞和地牢无限重复BUG
如下







youtube上看到的,顺便把视频搬过来了
https://www.bilibili.com/html/player.html?aid=8432741&wmode=transparent&as_wide=1&page=1
https://www.bilibili.com/html/player.html?aid=8432741&wmode=transparent&as_wide=1&page=2
当然地图种子是一位玩家算出来的
原理如下


由于本人不懂java所以看不懂  详情请看23楼  一位大佬给出了详细的解释

一个种子是X轴无限重复 一个是Z轴无限重复 地狱的矿洞也是同样的现象,地狱堡垒不是,用这地图生存可以说...








670116890
密集恐惧症感觉要命啊

Because.
这是特性





--------“如果没有体会到同样的痛苦的话,是无法真正理解对方的。”
            “即便真正理解了,也不意味着一定能志同道合。”
            “这就是,事实。”



YPXxiaoK
没错,但是如果用这地图生存的话。。

葉子の
Jeb:这叫特性!
从何bug说起?

背着书包丶
什么鬼 这太。。

BlackLanter
天生可以拿来做地图

博中
我更想知道,为什么会这样?

Smokey_Days
实际上这个是彩蛋233=w=

2387729849
楼主这个种子是只要一移动就开始乱动吗?
如果是,可能是楼主的硬件问题

AlbertBlue
2387729849 发表于 2017-2-5 22:53
楼主这个种子是只要一移动就开始乱动吗?
如果是,可能是楼主的硬件问题 ...

不是,你自己试试就知道了,地图生成的BUG,而且其他人也是这样。

3705
这个地图不会是mojang玩坏的吧。。。
“bugjump”:特性!都说了我们出的是特性!!!

月lonely
如果拿这个地图搞服务器的话....

TNT嘉音
应该是1.7以上的种子吧。

smallord
貌似这bug已经有老多实况主拍视频了......我3个月就知道了.....不过混乱出现我真的感到意外..

2639358455
不知官方是怎么想的

AWA5189456
没一颗树咋生存呐

AWA5189456
AWA5189456 发表于 2017-2-6 14:40
没一颗树咋生存呐

等等废弃矿...好吧

sheephot
66666这到底是多小的概率啊

Time_Paradox
居然把混乱骗进来了(滑稽

Kelcoin
唯一的BUG就是帧数过高的BUG
这是特性!!

憨怂蚂蚁
那不就有无限多的矿了

土球球
本帖最后由 ustc_zzzz 于 2017-2-7 10:25 编辑

这一现象的代码解释?其实楼主的第一个视频的1分20秒已经给出解释了。。。
其实这要是硬说是Mojang往里塞的彩蛋也不是不可以。。。这件事和Java的随机数生成有关。

Minecraft中,地形生成以区块为单位,我们先看看作用在每个区块上的,生成相关地下地形的代码:
  1.     public void generate(World worldIn, int x, int z, ChunkPrimer primer)
  2.     {
  3.         int i = this.range;
  4.         this.world = worldIn;
  5.         this.rand.setSeed(worldIn.getSeed());
  6.         long j = this.rand.nextLong();
  7.         long k = this.rand.nextLong();

  8.         for (int l = x - i; l <= x + i; ++l)
  9.         {
  10.             for (int i1 = z - i; i1 <= z + i; ++i1)
  11.             {
  12.                 long j1 = (long)l * j;
  13.                 long k1 = (long)i1 * k;
  14.                 this.rand.setSeed(j1 ^ k1 ^ worldIn.getSeed()); // 设置单独为区块所用的种子
  15.                 this.recursiveGenerate(worldIn, l, i1, x, z, primer); // 针对该区块的具体的生成
  16.             }
  17.         }
  18.     }
复制代码

(该代码由MCP生成,对应的类为“net.minecraft.world.gen.MapGenBase”)

我们知道计算机只能生成伪随机数,比如说对于MC而言,设置一个种子就可以保证每次生成的世界是几乎相同的,这是因为对于计算机的随机数生成器而言,设置一个种子就能保证每次生成的随机数序列是一致的,对于MC依赖的Java而言,如果我们设置种子为1和2,那么生成的随机数序列为:
  1. 1:-4964420948893066024,7564655870752979346,3831662765844904176,6137546356583794141。。。
  2. 2:-4959463499243013640,-1817970389778669801,9164759175887871693,-260524486875061426。。。
复制代码

如果设置为其他数:
  1. 4:-4969378402838085704,-1499461942424923123,-1501433639903096045,-5911126865076967316。。。
  2. 5:-4971030886054769832,1628080142987304160,9018696937790626762,8519392794254051655。。。
  3. 0:-4962768465676381896,4437113781045784766,-6688467811848818630,-8292973307042192125。。。
复制代码

当我们设置种子为107038380838084和164311266871034时,神奇的事情发生了:
  1. 107038380838084:0,18177319682724942,3258481617619292844,1684752427500229010。。。
  2. 164311266871034:7884338545699851846,0,18177319682724942,3258481617619292844。。。
复制代码

正如各位看官所见到的那样,两个种子分别生成的随机数序列的第一个数和第二个数分别为0。

我们现在把这件事再代入到代码中看看:
  1.         this.rand.setSeed(worldIn.getSeed());
  2.         long j = this.rand.nextLong();
  3.         long k = this.rand.nextLong();
复制代码

第一行代码设置了Java的随机数发生器的种子为世界的种子,第二行代码和第三行代码分别取了随机数发生器生成的随机数序列的第一个数和第二个数,也就是说,对于这两个种子而言,j和k中的一个肯定为0。
然后是后面的代码片段:
  1.                 long j1 = (long)l * j;
  2.                 long k1 = (long)i1 * k;
  3.                 this.rand.setSeed(j1 ^ k1 ^ worldIn.getSeed());
复制代码

j1和k1本身应该随代表区块位置的l和i1变化的,但是由于后面的乘数j和k变成了0,所以说对于任何一个区块,种子107038380838084会导致j1永远为0,而种子164311266871034会导致k1永远为0。
后一行代码重新设置了随机数发生器的种子,用于单独为专门的区块生成,如果这一值对于任何x坐标一致或者z坐标一致的区块都是一样的,生成的结果也可想而知了吧= =
如果各位看官只是想大概了解一下怎么回事的话,看到这里就可以了,如果有想了解到底为什么是这两个随机数的,请继续往下看。

================一点也不好看的分割线================


关于为什么不是其他的数,偏偏是这两个数,我们就要从伪随机数的生成算法开始说起了。
目前而言,最主流的随机数生成算法是一种名为线性同余法的算法,该算法首先生成一个种子(x为setSeed的输入):
  1. seed = f(x)
复制代码

在Java中f(x)有(%为取余数操作,^为异或操作):
  1. f(x) = (x ^ a) % c
复制代码

然后每次生成随机数的时候执行下面的操作,并将seed准备用作输出:
  1. seed = (a * seed + b) % c = g(seed)
复制代码

其中a、b、和c都是常数,不同的随机数生成器实现对这三个常数的定义不同,对于Java而言,这三个常数分别是:
  1. a = 25214903917,b = 11,c = 281474976710656
复制代码

这样可以保证生成的随机数位于0(包含)和281474976710656(2的48次方,不包含)之间,也就是48bit。
但是呢,储存MC的种子的整数大小为64bit,48bit不够用啊?所以每次生成的时候其实是生成了两个整数,每个整数各取32bit拼在一起:
  1. seed1 = g(seed)
  2. seed2 = g(seed1)
  3. return floor(seed1 / 65536) * 4294967296 + floor(seed2 / 65536)
复制代码

其中floor为向下取整函数,65536是2的16次方,4294967296是2的32次方。
所以说,我们要先找到一个seed,使得seed1和seed2都小于65536,实际上这样的解只有一个:
  1. seed1 = 0,seed2 = 11
复制代码

现在我们需要找到一个数seed,它满足:
  1. g(seed) = (a * seed + b) % c = 0
复制代码

具体的找法,读者可以去搜索“扩展欧几里得算法”得到解答,这里本人已经把它解出来了:
  1. seed = 107048004364969
复制代码

对于f(x)的处理就很简单的,异或过来的再异或回去不就得了,所以我们得到了x:
  1. x = seed ^ 25214903917 = 107038380838084
复制代码

正好和楼主提供的世界种子一致。
对于第二个种子,我们要保证生成的第二个随机数是0,也就是说,seed = g(seed)的操作要多进行两次:
  1. seed1 = g(g(g(seed)))
  2. seed2 = g(seed1)
复制代码

同时有:
  1. seed1 = 0,seed2 = 11
复制代码

具体的求解读者可以亲自试一下。反正答案上面早就有了2333

展望:
这两个种子可以做到每个区块都是一致的,但如果随机数序列中生成了“2的63次方”的话,那么是不是每两个区块就会重复一次呢?如果能够生成“2的62次方”,是不是四个区块就会重复一次呢?本人目前还没有得到解答,有兴趣的读者可以尝试一下。

1903863054
那末影遗迹会是这么样的?

山雀雀
感觉这个没法修复吧。。

孤独的MCer
这个bread也拍过视频了吧

Jim_rong
拿来做地图蛮好的,咕咕咕

马龙游笙
我只拍了个短片http://www.mcbbs.net/forum.php?mod=viewthread&tid=654682

2877606721
一不小心就掉虚空...

wh2426669379

用这bug做个服务器不错

Soul丶233
= =这也算不上是什么BUG的吧。

Zevn
好像不是无限重复?中间断断续续的

Rilet
算出来的...神啊

joycy
这些其实都是巧合,有些是特性

1677343686
emmmmm,一会去试试

yuen27787231
有時候我生地圖時也會不知道為何會穿了一個16X16的無底洞

2529110944
这叫特性

超人152
这。。。。。厉害了

cf6513272991
拿这个地图搞服务器的话....

liaoyongkang
加载不吃来,看不了

Dante_7
670116890 发表于 2017-2-6 11:21
密集恐惧症感觉要命啊

但是强迫症却感觉很舒服~

liguanlei10
厉害啊 无线复制粘贴

liguanlei10
一个矿坑就多少狂了 更何况一排

liguanlei10
emmmmmmmmm

860813
或许这个地图也是一个彩蛋吧,我尝试用一下这个地图生存一下,感觉玩起来挺好玩的。

大大大神
太....太强大了,这要是生存是不是能找到一大堆矿车箱子!前期不就不愁发育了吗!

357k
图片ban了看不到

第一页 上一页 下一页 最后一页