跳到主要内容
信息

本文使用DeepSeek翻译自GitHub,原文出处

https://github.com/SpaceWalkerRS/alternate-current/blob/main/README.md

Alternate Current

Alternate Current 是一个高效且非位置依赖(non-locational)的红石粉实现方案。其主要目标是通过优化功率计算和减少发出的形状更新(shape update)与方块更新(block update)数量,来降低红石粉造成的卡顿。作为这些改变的副作用,红石粉网络的方块更新顺序变得可预测且直观,而非位置依赖和混乱无序。

性能


使用 Alternate Current 后,红石粉对 MSPT(每刻毫秒数)的贡献降低了高达 20 倍,同时保持了高度的原版(Vanilla)兼容性。其极少的代码修改使其侵入性极低,因此它是原版红石粉的一个简单易用的替代品。

工作原理


Alternate Current 使用的算法在设计时考虑了以下目标:

  1. 最小化红石线(wire)检查周围环境以确定其功率等级(power level)的次数。
  2. 最小化发出的方块更新和形状更新的数量。
  3. 以确定性的(deterministic)、非位置依赖的顺序发出方块更新和形状更新,修复漏洞 MC-11193。

在原版(Vanilla)中,红石粉之所以卡顿,是因为它在第 1 点和第 2 点上表现不佳。

原版红石线会递归更新,每条线都是孤立地计算其功率等级,而不是在其所属网络的上下文中计算。这意味着网格中的一条线在稳定到其最终值之前,其功率等级可能会变化六次以上。这个问题在 1.13 及以下版本中更为严重,当时一条线每次只能将其功率等级降低 1。

除此之外,每次功率等级变化时,一条线会发出 42 次方块更新和最多 22 次形状更新。

在这 42 次方块更新中,有 6 次是更新自身,这不仅冗余,而且是卡顿的主要来源,因为它们导致线不必要地重新计算其功率等级。一个方块在曼哈顿距离(Manhattan distance)为 2 的范围内只有 24 个邻居,这意味着剩余的 36 次方块更新中有 12 次是重复的,因此也是冗余的。

在 22 次形状更新中,只有 6 次是绝对必要的。另外 16 次是发送给斜上方和斜下方的方块。这些更新在红石线改变其连接关系时是必要的,但在其功率等级改变时则不需要。

原版红石粉在第 3 点上同样表现不佳,尽管这更多是一个体验问题而非卡顿问题。其更新的递归性质,加上每条线更新其邻居时所依赖的位置相关顺序,使得线网络的邻居被更新的顺序极其不一致且看似随机。

Alternate Current 通过以下方式解决了这些问题:

(1) 最小化功率计算次数 为了确保一条线尽可能少地计算其功率等级,我们移除了原版红石粉更新时的递归性质。相反,我们构建一个连接线的网络,找出那些接收来自网络“外部”("outside")红石能量的线,并从那里开始传播能量。这有几个优点:

  • 每条线检查来自非线组件(如电源、中继器等)的能量最多一次,检查来自附近线的能量最多两次。
  • 每条线只会在世界中设置一次其功率等级。这很重要,因为调用 Level.setBlock 甚至比调用 Level.getBlockState 更昂贵。

(2) 最小化更新次数 有两种显而易见的方法可以减少方块更新和形状更新的数量:

  • 去除 18 次冗余的方块更新和 16 次冗余的形状更新,这样每条线在功率等级改变时只发出 24 次方块更新和 6 次形状更新。
  • 只在一条线达到其最终功率等级时才发出方块更新和形状更新,而不是在每个中间阶段都发出。

对于单条线来说,这两种优化是你能做的最好的,但对于整个网格,你还可以做得更好! 由于我们计算的是整个网络的功率,向其中的线发送方块更新和形状更新是冗余的。移除这些更新可以将方块更新和形状更新的数量减少高达 20%。

(3) 确定性的更新顺序 为了使网络邻居的方块更新顺序具有确定性,我们必须做的第一件事是替换掉原版线更新其邻居时所依赖的位置相关顺序。相反,我们将其基于能量流动的方向。算法的这一部分深受 theosib 的 'RedstoneWireTurbo' 启发。你可以在 theosib 在 Mojira 上的评论中阅读更多相关内容,或者查看其在 carpet mod 中的实现

其核心思想是根据一条线从邻近线接收到的能量来确定能量流经该线的方向。例如,如果一条线接收到的唯一能量来自其西边的邻近线,那么可以说流经该线的能量方向是向东。

我们使线对其邻居的方块更新顺序取决于所确定的能量流动方向。这不仅完全消除了位置依赖性(locationality),甚至在许多情况下也消除了方向性(directionality)。然而,与 'RedstoneWireTurbo' 不同的是,我决定在模棱两可的情况下保留方向性元素,而不是引入随机性,尽管这一点很容易改变。

虽然这个改变修复了单条线的方块更新顺序,但我们仍然需要解决整个网络的总体方块更新顺序。事实证明这是一个简单的修复,这要归功于我们之前的一个改变:我们在网络中搜索接收来自外部能量的线,并从那里开始传播能量。如果我们让每条线以依赖于能量流动方向的顺序将能量传递给邻近线,我们最终会得到一个非位置依赖且很大程度上非方向性的线更新顺序。