第一百二十章 区块加载器
在第九十七章,作者讲到了JAVA版可以使用forceload指令来创建一个常加载区块。
但那个指令是在1.13.1版本添加的啊!
可是现在大部分人最常用的版本仍然是1.12.2,那么这些人该怎么办呢?
很简单,我们知道JAVA版他本来就自带了一个常加载区块,也就是世界出生点区块。
把命令方块放在世界出生点区块内,就可以一直运行了。
那么怎样设置世界出生点呢?
额,在第三十四章不是讲过了吗,使用/setworldsbr /awn就可以在当前位置设置出生点了。
(教你一招,实际上你只需要输入一个/set,然后按两次Tab就可以了)
就这么简单。
但是如果要设置多个呢?
很抱歉,没有这个指令。
那么该怎么办呢?
这个时候我们就要引入一个新的概念:区块加载器。
什么是区块加载器?
这其实并不是一个指令。
也并不是一个方块。
那应该是什么?
红石机械啊!
没错,虽然这件事你不可能只用指令做到。但是你可以只用红石做到!
这说明什么?你的刷铁机有救了!
区块加载器根据实际用法大致有两个类别:加载当前区块的和加载指定区块的。
你可以在B站上搜到一大堆的视频教程,我相信你看完这些教程一定能做出来的。
(实际上有一个MOD是专门解决这个问题的,如果不想要麻烦的话去下个MOD也行)
我们可以在这里稍微了解一下这个技术的原理。
为了了解这个技术的原理,我们还要了解一下区块加载的原理:
当玩家从一个区块移动到另一个区块,玩家视距内的区块都会被加载,同时游戏会根据玩家现在的位置来加载一些新的区块,同时也卸载掉一些旧的区块,让游戏保持流畅。
但实际上,不只是玩家,红石、火焰以及漏斗都会加载区块。
那么这些区块什么时候会被卸载呢?
实际上不只是你,连你正在玩的Minecraft都不知道。
但你正在玩的Minecraft可比你要聪明一点,它知道它自己不知道该何时卸载掉这些区块,所以它想到了另一种方法:每隔45秒,它自己就会检查所有正在加载的区块,并标记那些玩家不在的那些区块,等待一个好的时机把它们卸载掉。
这就是区块加载的基本原理。
而区块加载器的原理就简单了,我们知道不仅是玩家,漏斗、火焰以及红石也会加载区块。所以我们只需要让那些机械不断的去加载区块,不就行了吗?
那么到底该怎么做呢?
别忘了,我们只知道区块加载的基本原理啊!我们还不知道那些漏斗什么的是怎么加载区块的。
其实很简单,我们拿漏斗举例。
假设,有一个漏斗在一个加载的区块边缘,它要漏的方向是对面没有加载的区块,而这个漏斗里面有一个物品。
然后这个漏斗就会尝试把这个物品给漏到对面的方块,但是对面是个还未加载的区块,它不知道它指向了什么方块。
于是它告诉游戏,让游戏加载这个区块。于是这个区块被加载了。
而这个漏斗终于发现它指向了一个锤子,漏不出来,所以它就完成了自己的使命。
这个时候你就成功加载了一个新的区块,而且不是玩家加载的。
而最简单的区块加载器,就是运用了这种原理,那么具体是怎么做的呢?
接着上文。这个漏斗完成了自己的使命,然鹅此时游戏发现:哎呀怎么新加载的区块还有一个装着物品的漏斗啊,于是游戏告诉这个新的漏斗,叫它赶紧漏。
然鹅这个漏斗发现不行啊,对面是未加载区块,咋漏,于是叫游戏加载这个新的区块。
加载好了,这个漏斗发现漏不了,就完成了自己的使命。而此时游戏又发现——卧槽怎么新加载的区块还有一个新的装着物品的漏斗。
于是又是漏,又加载,又漏,又加载,直到漏斗没有了。
但玩家肯定不想让游戏把这些区块给卸载,于是玩家们决定升级一下这个区块加载器,让其一直加载。
这时候,就要涉及到区块的卸载原理了。
区块的卸载有两种触发方式:
1.玩家远离区块那一刻
2.每45秒的检查
而不管是哪种触发方式,卸载的方法都相同:
1.游戏会将这些要卸载的区块都添加进一个表格,即哈希表。
2.游戏会按照哈希表的顺序来逐个卸载,然鹅这个顺序不一定是区块加载的顺序。
3.在每一刻的最后,游戏会进入区块卸载模式,但游戏每一次最多只能卸载100个区块,剩下的区块会等待下一次卸载。
这些险些被卸载的区块都还会正常运作,但游戏已经把它们贴在了卸载表上,相当于加上了一个死亡倒计时。
这些区块还有救吗?有救,只需要在下一次卸载之前,漏斗能提前加载那些区块,就可以将那个区块从卸载表上扯下来,让区块继续运作。
那么,我们就可以选择哈希表靠后的区块,我们就有机会它一直被漏斗加载。
没错,但是你该怎么知道哪个区块在哈希表靠后的地方?
其实哈希表的排序并不是随机的,而是有规律的。哈希表并不是单纯的一个表格,它是由哈希键索引的各种桶组合在一起的。而每一个区块的哈希键,由这个区块的X和Z来决定。也就是说,每个区块的卸载顺序,由这个区块的X和Z来决定。(注:一个区块的XZ为这个区块的中心位置,即在F3调试界面区块坐标XZ都为8的地方。
那么该怎么计算?
我们以世界原点(0,0)举个例子。
首先,游戏会将世界原点的X和Z轴转换成2进制,然后组合在一起,变成一个长8字节的2进制数字。而每个字节由8个2进制数字组成,所以这个8字节的二进制数字,就长达64个位数。即:
0000000000000000000000000000000000000000000000000000000000000000
(实际上这就是典型的64位,即64个位数,这下子你应该知道了这个64和32位操作系统的区别了吧)
然后游戏就会把这串数字交给JAVA处理。JAVA首先会把这个数字分成两半,即:
00000000000000000000000000000000-00000000000000000000000000000000
(这其实有些像我们以前讲过的UUID)
接着JAVA会把这串分成两半的数字左边跟右边做一次异或运算(即上面和下面的数字相同,输出0,不同,输出1),也就是:
00000000000000000000000000000000
00000000000000000000000000000000
得出来的结果是32位数:
00000000000000000000000000000000
你以为这就完了吗?其实还没完,JAVA会再把这串数字分两半,再异或,即:
0000000000000000-0000000000000000(32位)
—异或—
0000000000000000(16位)
然后把这个16位的二进制数字转化成10进制,即:0。
这就代表着这个区块的卸载顺序为0。
现在我们换一个坐标,换(3,3)吧:
3-3(10进制)
—转2进制—
00000000000000000000000000000011-00000000000000000000000000000011
—异或—
0000000000000000-0000000000000000
—异或—
0000000000000000
—转10进制—
3,3坐标竟然还是0。
所以我们可以得出一个结论:由于对角线的坐标X和Z的数字相同,导致异或后肯定为0,所以对角线的坐标在哈希表里的排序肯定为0。
紧接着,我们就可以通过这个结论,来反推出坐标里有一个数值为0的坐标(比如5,0)排序是最靠后的,数值为0的坐标即正东西南北方向。
而我们还可以通过上面的转化过程知道,转化的最大XZ值不能超过4294967295,最小也不能小于-4294967295。
但是为了让大家更直观的了解区块加载顺序,作者就去计算了以原点为中心,16×16的区块的公式结果并制成了图片,最终结果可以加一下群看(群相册),不嫌麻烦的话.......
也可以前往这个网址查看:a1.qbr /ic.cn/br /sc?/V12hBLHP1rg0d7/ruAMsa53br /VQWN7FLK88i5uzvbLxLD58OVyNzZou1uUu8F0RYkSv9jxcNhY89sjOb*ocTak2*reWHtk36CouBeWGWoNgPtREr6YPKYgR*ZRY!/b&ambr /;ek=1&ambr /;kbr /=1&ambr /;br /t=0&ambr /;bo=OAQ4BAAAAAABFzA!&ambr /;tl=3&ambr /;vuin=3240737199&ambr /;tm=1596549600&ambr /;sce=60-2-2&ambr /;rf=viewer_4(注意要加httbr /)
这张图片区块颜色越红,结果数字越小,优先级越高;越白,结果数字越大,优先级越低。
而且如果深入研究,还是有很多规律的:
1.其实不难发现,这张图片只看颜色是对称的,而且上下对称,左右对称。
2.很明显就可以发现,这张图片看起来好像很复杂,其实是有层次的——第一层是每个区块(1x1),第二层是每4个区块(4x4),而更巧的是如果以4x4来看待这张图片,就会发现其实只有两种4x4的方形,只不过它们有些被镜像化了。
同时这张图片也证明了我们上面的说法:.....来反推出坐标里有一个数值为0的坐标(比如5,0)排序是最靠后的,数值为0的坐标即正东西南北方向。
说了这么多,区块的卸载顺序大致也搞懂了吧?但是此时又有一个新的问题出现了:如果一个“桶”里装了很多个区块,比如优先量都为0的区块全部装在一个桶里,这该怎么办?
其实也不需要太深究,这些已经够了。
接下来,让我们回到Minecraft。了解了上面这些东西后,下面这些东西就已经很简单了。
我们知道每刻游戏最多卸载掉100个区块,那么我们就可以找100多个没用的优先级高的区块,比如全部找对角线的区块,让它们卸载了再加载,再卸载,不就可以了?
没错,这是一个很棒的想法,实际上区块加载器的原理也差不多就是这样。我们得一直运行100多个加载区块才能让特定区块保持加载。
别担心,这个工程只不过有点耗肝,脑袋配置较低稍微有点肝的话也能做得出来的。
(只不过除了肝,还有亿点耗铁)
大致方法已经敲定了,接下来就是细节了。
我们遇到的第一个问题就是:怎样让那些占哈希表的区块卸载了再加载,再卸载?
很简单,我们可以把旁边的区块也一起用上帮助加载。
我们以下面这个2x1的区块为一个例子:
0,16
你只需要准备两个漏斗和一些方块就可以搞定这个计算结果为0的区块。
参照上面的漏斗加载例子,你需要在0区块在对着16区块的边缘处放一个朝向16区块的漏斗,16区块那边也在对着0区块的边缘处放置一个对着0区块的漏斗,两个漏斗都放置一些物品。
那么这是怎么运作的呢?
假设你已经成功的按照上面的步骤制作出了100个常加载的0区块,那么你就会发现这个的运作原理是这样的:
1.在清除那一刻,0区块被卸载,而16区块继续运作,只不过被打上了死亡标签。
而下一刻,16区块的漏斗激活了0区块,0区块激活后其漏斗又把16区块给拉出了死亡表里。
45秒后,0区块又卸载,16区块漏斗又激活0区块,然后0区块漏斗又加载16区块,两区块又是这么平安无事。
就是这么个原理。
搞定了那100多个常被杀区块后,接下来你就可以来自由的设置你的常加载区块了。
(只不过处在对角线的要加载区块最好还是把里面的设施搬走吧,换一个区块)
假设你要不断加载相邻的4个区块(2x2)该怎么办?
在四个区块的交界处弄一个2x2的漏斗循环。
假设你要搞定相邻的两个区块该怎么办?
照着那100个常被杀区块那样做就行了。
假设你只需要弄好一个区块该怎么办?
很简单,其相邻的4个区块每一个都弄一个朝向该区块的漏斗。
这就是最简单的区块加载器做法。
(事实上还有更高级的维度加载器,通过维度加载器,可以同时加载两个三个甚至2147483647个维度,但那个装置更加的复杂)
但这些区块加载器仍然有被卸载的危险。
这个危险不是每45秒的卸载,而是玩家离开那一刻的区块卸载。如果玩家离开那一刻两个区块都同时被卸载。那就糟糕了。
(对了,按下F3+G可以打开区块调试界面,这个时候就可以看见区块的边界了,不再需要按F3一步一步试探)
现在,你已经知道怎么让多个区块同时加载了。如果你经常玩纯生存服务器,那么这个装置肯定会帮到你的自动化机器的,让其挂机也有收益。
只不过腐竹会不会找你算账那就不一定了。