SAC的单线程编码全物品
SAC_Official
2021年11月21日 13:38

〇、序言

        一年多前,SAC 的传统全物品视频的评论中,脆脆鲨​留下了这个评论。当时由于我们仍停留在传统全物品的框架中,所以这并没有使我们真的去寻思制作一个传统架构下的推容全物品,但这句话确实使我开始思考全物品有没有更好的发展方向。

        平时,我们的全物品很少有休息的时候,经常会有人扔几十大箱盒的混杂物品进去分类,导致 mspt 瞬间升高,这显然是不太好的,但这并不是主要问题。在降低静态卡顿方面,虽然BE暂时没有游戏机制内可控的区块加载与卸载方式,但把假人扔进矿车推走还是可以的。

        由于我们曾经的全物品配置是每种物品一大箱的容量,以及几十个只有 50 万容量的大宗物品分类打包,这显然是不够的,因此我经常需要手动打包和搬运一些物品。这意味着这个全物品必须存在人为的操作才能持续运行,这是传统全物品的通病,也成为了亟待解决的问题。

        所以我不禁思考,有没有一种全物品,可以根据箱子内物品的多少,自动判断应该打包还是只以单独的物品形式分类,应该送入全物品内还是送到仓库内,由此从去年我便开始了编码全物品的筹备工作。

        编码全物品一代在去年年底完成,但因为BE某些非常神秘的特性,在创造服设计的全物品放在生存服的建造位置上就会因为一系列的区块问题而无法使用,以及某些部件的噪音无法消除,还有其他的极小概率问题等等,所以我很难把它看作一个完成品。

        1.5 代在今年 8 月开始重新布线,大概用了一周时间,基本解决了所有我认为是问题的问题,虽然仍留有一些不足,但我想将那些问题留给未来二代的乱序执行超标量多线程编码全物品了。

一、需求

        首先,我们可以很明显的看出任何试图让玩家在全物品内进行百米赛跑的行为都是非常诡异的,雪茄形的全物品不仅外型和内部布局很难说得上美观,而且取物品也不方便,同时一眼望到头的设计也没有其它的便利用途,就像试图给每种附魔书和刷怪蛋添加不同材质加以区分,玩家并不会因此而不去挨个寻找。因此我们对全物品布局的安排是三向全物品加一向不可堆叠分类&全药水。

        全物品必须有着良好的拓展性或足够多的分类种类,以便应对版本更新。

        全物品单片的箱子数量为 10 ,布局必须保证 PC 玩家站在单片中间也能开到前后单片的所有箱子。还需有足够的空间摆放占位方块。

        无任何需要人工操作的按钮,拉杆,等一系列繁琐措施。

        每个部件尽量只完成某一单独任务。

        扩展可拓展的模块时尽量不需修改已搭建好的可拓展模块。

        每个部件的对接者并不需要明白所有部件的原理,仅需理解提供的接口。

        除物品解码器外,其他模块无物品以外的活动实体。

二、工作流程

        全物品大致可以被分成 10 个较为独立的小模块,不过要注意的是,这是流程上的分类而不是实际的元件的。

        物品预处理除了自适应打包以外,都可以作为传统全物品的流程使用,可以将自适应打包替换成预分类。

        解码器在这一代中仍旧采用的是矿车的形式,我所采用的编码是 4 维的:

%5Cbegin%7Bbmatrix%7D%0A%E4%BE%A7%E4%BD%8D%E7%BD%AE%20%5C%5C%0A%E6%B0%B4%E9%81%93%E4%BD%8D%E7%BD%AE%20%5C%5C%0A%E5%8D%95%E7%89%87%E4%BD%8D%E7%BD%AE_1%20%5C%5C%0A%E5%8D%95%E7%89%87%E4%BD%8D%E7%BD%AE_2%5C%5C%0A%5Cend%7Bbmatrix%7D%0A%5Cin%20%5Cleft%20%5B0%2C2%20%20%5Cright%20%5D%20%5Ccdot%20%5Cleft%20%5B%201%2C10%20%5Cright%20%5D%20%5Ccdot%20%5Cleft%20%5B%200%2C15%20%5Cright%20%5D%20%5Ccdot%20%5Cleft%20%5B%200%2C1%20%5Cright%20%5D%5Ccap%5Cmathbb%7BN%7D%20%5E4%20

        侧位置的数值在 0~2 ,分别代表了全物品的三侧;水道位置的数值在1~10,分别代表了 10 个水道。单片位置 1 与 2 需要结合起来看,1的数值在0~15,2在0~1;当 2 为 0 时,1 代表了前 16 个单片,为 1 则是后 16 个。

        那么总体算下来,侧位置只需要编码0~1,其余就是2,需要至少12个大箱子;侧位置只编码1~9,需要至少18个大箱子;单片位置需要至少32个大箱子,因为这样可以用单片位置是否有编码来判定物品总体是否有编码。总体算下来至少需要62个大箱子。

三、功能模块

1.外观以及内部设计

    主要参与 : ΘΣΦΓΥΔΝ​, 陌子尘​

    沿用了传统全物品的设计,几乎没有改动。

2.物品预处理系统

    主要参与 : ΘΣΦΓΥΔΝ​, wang​, minor_fat​

3.空盒合成

    主要参与 : minor_fat​

    这个模块也是沿用的传统全物品的设计。

4.自适应分类打包机组

    主要参与 : wo555​

    技术指标:

        ① 堆叠完成后的成品需保证 8 漏斗同时输入的速度。

        ② 休眠时静音。

    接口:

        输入:

            ① 一条水道用于输入被打包物品。

            ② 一个漏斗输入空盒。

        输出:

            ① 一条水道用于输出未处理殆尽的物品。

            ② 一个漏斗输出打包后的盒子。

动态​

5.解码器

    主要参与 : wo555​, 豆子​, ΘΣΦΓΥΔΝ​, P94​

    技术指标:

        ① 无论以何种方式编码,最终输出物品的水道位置 (1~10) ,侧位置 (0~2) ,单片位置 (0~15, 0~1) 。

        ② 编码用时尽可能短。

    接口:

        输入:

            ① 一个漏斗用于输入潜影盒,一次仅输入一个。

        输出:

            ① 一个水道输出查询的潜影盒。

            ② 4 个红石信号分别代表水道位置 (1~10) ,侧位置 (0~2) ,单片位置 (0~15, 0~1) 。

            ③ 一个水道输出无编码的潜影盒。

6.总控

    主要参与 : wo555​

    技术指标:

        ① 判定时间短。

    接口:

        输入:

            ① 一个漏斗用于输入潜影盒,一次仅输入一个。

            ② 箱子信号 H 。

            ③ A=7,B=13 。

        输出:

            ① 若 H<A ,物品卸货后从水道 a 输出,卸货的空盒从水道 d 输出。

            ② 若 A<=H<=B ,且潜影盒满,潜影盒直接从水道 a 输出。

            ③ 若 A<=H ,且潜影盒不满,从水道 b 输出。

            ④ 若 B<H ,且潜影盒满,从水道 c 输出。

7.查询&入箱单元&潜影盒缓存

    主要参与 : wo555​, P94​, ΘΣΦΓΥΔΝ​

        技术指标:

            ① 通过输入的箱子位置,返回箱子信号,并可以将物品送入箱内。

        进阶要求:

            ① 物品需在约单漏斗速下完成入箱。

    接口:

        输入:

            ① 一个水道输入待入箱物品。

            ② 侧位置 (0~2) ,水道位置 (1~10) ,单片位置 (0~15,0~1) 。

            ③ 单片开启信号。

            ④ 潜影盒缓存输出信号。

            ⑤ 一个水道输入需要缓存的潜影盒。

        输出:

            ① 箱子的信号。

            ② 缓存的潜影盒。

动态​

8.潜影盒搜索

    主要参与 : wo555​, wang​

    技术指标:

        ① 体积小,速度快。

        ② 可搜索 16/64 堆叠物品

    接口:

        输入:

            ① 输入一个内有待搜索物品的潜影盒。

            ② 输入 0~10 个需要被搜索的潜影盒。

        输出:

            ① 当被搜索的盒子中的物品与待搜索物品相同时, 从 A 水道输出这个潜影盒与有待搜索物品的潜影盒, 其余潜影盒从 B 水道输出。

            ① 若没有与待搜索物品相同的盒子时从 B 水道输出所有潜影盒。

9.潜影盒合并

    主要参与 : 豆子​

    技术指标:

        ① 可自主比较盒子大小, 将信号强度小的盒子并入大的盒子。

    进阶要求:

        ① 可并行处理多种合并。

    接口:

        输入:

            ① 两个非满盒。

        输出:

            ① 一个水道输出空盒。

            ② 一个水道输出其余盒子(并非全为满盒)。

10.缓存控制器

    主要参与 : P94​

    技术指标:

        ① 结构紧凑, 一次只投掷一个盒子。

        ② 工作指示信号熄灭时即可投掷潜影盒。

        ③ 在缓存无潜影盒时, 不做任何操作。

        ④ 在缓存从空到有潜影盒时, 如果全物品没有工作, 则投掷潜影盒。

    接口:

        输入:

            ① 工作指示信号。

            ② 潜影盒。

        输出:

            ① 潜影盒。

            ② 单片开启信号。

11.入箱控制器

    主要参与 : wang​

    技术指标:

        ① 接入信号为 1 或 10 时,物品每 6t 发射一次,当16一组的物品投掷 16*5 个时或当 64 一组的物品投掷64*5个时停止 48s+刚才投掷物品数量*0.4s+bias 之后继续投掷。信号在投掷物品以及投掷物品之后的 48s 一直开启,之后信号关闭  刚才投掷物品数量*0.4s+bias 。bias 取 5s。

        ② 接入信号为4或7时,物品每 6t 投掷一次。从物品开始投掷输出信号,直到物品投掷完成并过 48s 后不输出信号。

        ③ 其余信号 4t 投掷一次。从物品开始投掷输出信号,直到物品投掷完成并过 48s 后不输出信号。

        ④ 流程完毕输出一个脉冲。

    接口:

        输入:

            ① 水道信号。

            ② 16 一组或 64 一组的物品不满一盒或潜影盒 1 个。

        输出:

            ① 物品。

            ② 单片开启信号。

            ③ 工作指示信号信号。

四、成品

        在得到了这些模块后,我们就可以将它们按照流程图拼接起来了。

        一定程度上,这个成品还是达到了部分预期的,我并不期望它的布线有多工整,空间利用率有多高,也暂不考虑速度如何--毕竟在正常使用过程中的平均输入速度永远不可能大于分类的速度。我更希望它最终面向用户的界面是简洁明了的,使用体验是轻松愉快的。我不是很喜欢那些为了数据而数据的产品,不考虑使用感受的产品最终只能成为开发者自我感动的玩具。

        最后,在全物品中有个模块未被制作,即千万物品仓库。我们并没有把仓库与全物品合并,而是在末地。另外仓库并没有设计完成,仍有不少问题,不过预计我们会得到一个动态卡顿同样十分低的千万物品仓库。

        由于 BE 的很多神秘特性,有许多的元件是必须就地设计的,因为与绝对坐标相关,因此单个零件拆出来很少有值得借鉴的意义,整个全物品挪动到其他坐标还有可能会无法工作。

五、结论

        值得注意的是,由于我们在设计潜影盒缓存的流程时,并没有使用 pallapalla 按顺序取潜影盒和使用填充物品的方式,而是使用潜影盒搜索的方式,因此我们不需要准备和分类数量相等的多个不相等的填充物,而且还可以使我们给同一个箱子编码近乎无限种物品且不串盒。但由于大箱子的容量限制,一个大箱子内编码的物品数量不宜超过 54 。也就是说我们的编码全物品也同时可以作为一个巨大的多物品分类储存,且能自动打包,及其它一系列流程。理论上限为 3×10×32×54=51840 种物品,应当是够了。

    那么可能有人就要问了,为什么全物品要兼具多物品分类的能力?这就不得不提到 MCBE 的神秘特性了:

        上面的图片中,展示了两种蘑菇方块,6 面全是皮的是 1.16 以后生存挖到会掉落的,6 面全是内部的是老版本生存挖到会掉落的,然而我们并没有任何必要将它单独分出来。

        如果上面的例子由于物品材质不一样,可能说服不了你的话,下面的例子就更诡异了。

        上图中的两个旗帜你能分辨出区别吗?实际上,上面的两个旗帜,一个是合成得到的,另一个是放下后打掉得到的,这个放下后打掉得到的旗帜,在物品栏中看不到任何区别,但是带有了一个 type=0 的 NBT 标签。而且,在旧版用不同熔炉烧出来的烤鳕鱼所带的 NBT 也不相同。显然,我们根本就不希望再去单独拿一个箱子分类它,我们会希望这种东西就应该被分类在同一个箱子内,而且打包时分别打包,这便是我们的全物品支持多物品分类的重要原因。

六、展望

        本代全物品由于使用的是单线程的方式,因此速度确实并不是很快,仍有很大的提升空间,但并不影响使用。

        这一问题预计会在二代得到解决,同时应该会被解决的还有 BE 矿车在移动时有一定概率消失的问题,我们考虑在二代改用潜影盒解码器。并且会提高发射宽度,增加重排序缓冲区,拆分单片,增加入箱控制器数量,增加并行度等一系列的措施提高速度,不过完成可能还需要一定的时间。

七、鸣谢

        JE:

            pallapalla    提供了编码全物品的主要思路。

        BE:

            陌子尘​ (SAC)    遗留了传统全物品的装饰与部分物品排布;

            minor_fat​ (SAC)    遗留了传统全物品的空盒合成部分与4倍速可锁卸货;

            wo555​ (SAC)    完成了自适应分类,解码器锁存,总控,全物品单片,潜影盒搜索;

            P94​ (SAC)    完成了解码器的无轨矿车,译码器,缓存控制器;

            豆子​ (SAC)    完成了潜影盒合并;

            wang​ (SAC)    完成了入箱控制器,缓存,不可堆叠分离,空盒分离;

            ΘΣΦΓΥΔΝ​ (SAC)   完成了绝大多数布线工作以及物品续命器,全药水,不可堆叠分类,流程设计,文案。

感谢 MOJANG STUDIOS 提供 Minecraft