关于比较器更新
当比较器被 NC 更新 或 比较器更新 触发时,它会“意识到”自己该改变了。
这是 Minecraft 中文维基在介绍 CUD 原理时的一段描述。 在不少教程中,“比较器更新”常常被与 NC 更新、PP 更新分开讲解。 这样做的初衷,是为了让“比较器更新”这个概念更容易被理解。 但同时,它也让许多人误以为——比较器更新是与 NC、PP 并列、相互独立的一种更新类型。
你是不是也这样认为呢?
如果你仔细阅读过 Minecraft 中文维基关于方块更新的条目,就会注意到其中这样一段话:
比较器更新 —— 方块结束 NC 更新后,会向水平方向或红石导体后方的红石比较器传播 NC 更新。
看到了吗? 比较器更新其实也是一种 NC 更新。 那么,它与普通的 NC 更新究竟有何不同? “比较器更新”到底是什么呢?
所以,它是什么?
仔细寻找后,我们可以发现, 实现比较器更新的方法在 Yarn 映射中叫 world.updateComparators, 而在 Mojang 映射中则叫 level.updateNeighbourForOutputSignal:
public void updateNeighbourForOutputSignal(final BlockPos pos, final Block changedBlock) {
for (Direction direction : Direction.Plane.HORIZONTAL) {
BlockPos relativePos = pos.relative(direction);
if (this.hasChunkAt(relativePos)) {
BlockState state = this.getBlockState(relativePos);
if (state.is(Blocks.COMPARATOR)) {
this.neighborChanged(state, relativePos, changedBlock, null, false);
} else if (state.isRedstoneConductor(this, relativePos)) {
relativePos = relativePos.relative(direction);
state = this.getBlockState(relativePos);
if (state.is(Blocks.COMPARATOR)) {
this.neighborChanged(state, relativePos, changedBlock, null, false);
}
}
}
}
}我们来分析这段代码:
for (Direction direction : Direction.Plane.HORIZONTAL)表示只遍历水平四个方向(东南西北),与垂直方向无关。 这很好理解,毕竟比较器的输入输出都是水平的。BlockPos relativePos = pos.relative(direction);对于每个方向,以触发更新的方块位置pos为基准,取得该方向上的直接邻格位置。if (this.hasChunkAt(relativePos))检查该邻格所在区块是否已加载。BlockState state = this.getBlockState(relativePos);读取邻格方块状态,用于判断它是否是比较器或红石导体。if (state.is(Blocks.COMPARATOR)) { ... }如果邻格本身就是比较器,则直接调用neighborChanged(即常规的 NC 更新方法)。else if (state.isRedstoneConductor(this, relativePos)) { ... }否则,如果该邻格是红石导体(其实指实心方块,Mojang 的命名在这里略显误导): 向相同方向再前进一格relativePos = relativePos.relative(direction);, 再次检查那一格是否是比较器,如果是,同样调用neighborChanged去触发更新。
现在,我们对“比较器更新”的定义就一目了然了: 它并不是一种特殊的 NC 更新传播规则。
可以这样总结:
比较器更新 是一种向某个方块相邻,或相邻的实心方块后方的比较器发送 NC 更新的特殊更新机制。
