基础部分
- 计划刻的概念与内容
- 常见的计划刻元件
- 简单实例分析
进阶部分
- 计划刻队列的维护
- 4gt侦测器高频的时序解析
- 深入解析比较器的计划刻执行逻辑
- 计划刻抑制
在Minecraft中,我们常常见到许多红石元件在被触发后并不是立即变化的,例如中继器、比较器。这些元件总是在被触发后延迟一段时间,再发生变化。
让我们以一个生活中的例子来看。上午,你收到了一封邮件,于是你计划下午去处理这封邮件,然后定了一个闹钟。到了下午,闹钟响了,你想到自己要处理邮件了,于是打开邮箱开始处理邮件。
必须要注意的是:这个“闹钟”并没有任何“文字注释”。它只负责在你的手机中、在正确的时间、提醒你一个人“有事情”。至于具体是什么事情,闹钟并不关心。 这个闹钟包含且只包含这些内容:
- 什么时候响
- 这是第几个闹钟
- 有多重要
- 在谁的手机上响
- 提醒谁
计划刻就是这样一个“闹钟”。红石元件在被触发后,为自己添加了一个计划刻。当计划刻执行时,就像是闹钟响了,红石元件就变化了。
由计划刻控制行为的红石元件,也就称为计划刻元件
像上文中的闹钟一样,计划刻只包含这些内容,我们称之为一个计划刻的信息结构:
- 执行时间
triggerTick
:在何时执行,或称延迟多久后执行1 - 子顺序
subTickOrder
:计划刻添加顺序 - 优先级
priority
:计划刻有多优先 - 位置
pos
:执行的坐标 - 方块种类
type
:哪一方块种类执行这个计划刻
位置和方块种类都是易于理解的属性。毕竟,方块自己的计划刻不能由其他方块乱执行 (如果你恰好在方块执行计划刻前把它推走或破坏掉换成其他方块的话) 、也不能在世界里到处乱跑。
执行时间,指的是宏观时序上计划刻的执行时间,也就是计划刻应该在哪一gt执行。例如,一个1挡位的中继器被触发后添加2gt后的计划刻,2gt后,该计划刻就会被执行。我们通常说的“计划刻元件的延迟”就是指计划刻在多少gt后执行。
子顺序,指的是相同时间内的计划刻添加顺序。例如,在同一gt内,中继器A先被触发,中继器B后被触发。那么,在子序列中,中继器A就在中继器B前面。
优先级,指的是计划刻的优先程度。优先级是一个-3~3的整数2,其中数值越小,优先级越高。也就是说,在同一gt内,优先级为-3的计划刻总是比优先级-2、-1、0的计划刻更先执行。
通常在讨论优先级时,“优先级更高”和“优先级数值更低”的意思是相同的。为了避免由“优先”这一概念和“优先级数值”造成的歧义,我们更推荐读者在向其他人说明时使用“某一元件的计划刻更优先”来表述。
同样的,就和上文中的闹钟一样:计划刻只是一个“提醒方块有事要做”的闹钟,它并不关心方块实际要做什么。一切执行计划刻时的行为都由方块自身控制,“执行计划刻的行为”并不在“计划刻的信息结构”中。
而当我们说“某一元件已存在一个计划刻时”,指的就是在当前位置、存在一个方块类型和当前方块相同的、且还没有被执行的计划刻。3
在前两篇中,我们已经学过了宏观时序的分析,并且认识了微时序。我们知道,宏观时序总是优于微时序的,计划刻也是同理。对于执行时间不同的计划刻,执行时间早的计划刻总是更先执行。对于执行时间相同的计划刻,优先级更优先的计划刻总是更先执行。对于优先级相同的计划刻,子序列更小的、也就是更早添加计划刻的总是更先执行。
所以,在比较计划刻执行顺序时,我们可以遵循这样的逻辑:
- 比较宏观时序,宏观时序更早即更先执行。
- 比较计划刻优先级,优先级更优先即更先执行。
- 比较计划刻添加顺序(子顺序),计划刻添加更早即更先执行。
这就像比数字一样,宏观时序就是百位,优先级就是十位,添加顺序就是个位。
那么,让我们来看看实际的例子。
已知在图示情况下,比较器的优先级为0,中继器的优先级为-1。比较器和中继器的延迟都为2gt。
- 如果在不同gt下,先按下比较器的按钮,再按下中继器的按钮,哪一个音符盒会先响起?
- 如果在同一gt内,先按下比较器的按钮,再按下中继器的按钮,哪一个音符盒会先亮起?
答案:
- 比较器先亮起。因为宏观时序上,比较器先亮起,而后间隔一定gt中继器才亮起。
- 中继器先亮起。因为在计划刻上,虽然比较器比中继器先添加计划刻,但是中继器的优先级为-1,比比较器的优先级0更优先,而计划刻优先级>计划刻添加顺序,所以中继器先亮起。
中继器和比较器统称为红石二极管或红石门(Redstone Gate)4
在刻与刻间时序中,我们已经初步认识了中继器和比较器。现在,让我们深入中继器的计划刻行为。
若中继器被锁定,则不会添加计划刻,也不会在执行计划刻时改变任何状态。 若中继器未被锁定,则具有以下行为:
添加计划刻行为:
- 当中继器受到NC更新时,它会检查自身状态。若自身不存在计划刻,且应当改变状态 (即自身没有亮起,但输入端有红石信号;或自身亮起,但输入端没有红石信号),那么添加计划刻。
- 中继器添加的所有计划刻的延迟都为
中继器挡位*2 gt
执行计划刻行为:
- 若中继器亮起,则立即熄灭。
- 若中继器未亮起,则立刻亮起。这一步不受输入端信号影响。
- 若此时没有输入信号,则再添加计划刻(用于熄灭)。
举个例子:
从表现上来看,举例来说,如果给一个2挡位中继器一个时长<=4gt
5的信号,中继器的行为如下:
- 受到NC更新,添加计划刻
- 4gt后,执行计划刻
- 检测到自身未亮起,于是立即亮起
- 检测到输入端无红石信号,添加计划刻(用于熄灭)
- 再4gt后,执行计划刻
- 检测到自身亮起,于是立即熄灭
这一例子中包含了中继器的全部计划刻行为。
特殊的优先级变化:
- 若中继器指向一个横放的红石二极管或指向一个红石二极管的输入端,则计划刻的优先级为
-3
。 - 否则,若中继器添加计划刻时处于亮起状态(即这一计划刻是用于熄灭的),则计划刻的优先级为
-2
。 - 否则,计划刻的优先级默认为
-1
。
添加计划刻行为 :
- 当比较器受到NC更新时,它会检查自身状态。若自身不存在计划刻,且应当改变状态 (即自身没有亮起,但输入端有红石信号;或自身亮起,但输入端没有红石信号),那么添加计划刻。
- 比较器添加的所有计划刻的延迟都为
2gt
。
执行计划刻行为:
比较器在执行计划刻时,实际上只做了一件事情:
- 根据比较器现在的输入状态和比较器模式,更新自己的输出能量等级。
这里的输出能量等级指的就是比较器经过计算后得出的输出能量等级 (具体计算方法见后文)。而这里的更新包括了更新能量等级和发出更新两件事。并且对于比较器来说,从表观上可能会有输出能量等级不发生变化的情况,但实际上此时比较器依然“更新”了自己的输出能量等级。
比较器还有相对复杂一点的更新行为——
比较器发出更新的行为:
- 在执行计划刻时,若比较器的充能属性改变 (即自身由熄灭变为亮起,或由亮起变为熄灭),则先发出NC更新,再发出PP更新。
- 如果比较器为比较模式,或比较器为减法模式且自己的输出能量等级发生变化,则发出NC更新。
举例来说,就是:
- 首先,这段内容全部建立在比较器确实执行了计划刻的前提下——
- 只要比较器为比较器模式,就算它的输出等级不改变,包括由0变成0,也会有一次NC更新。
- 如果比较器的输出能量等级由0(熄灭)变为1、2、3、4、5……14、15(亮起),或者由亮起变成熄灭,那么它会先发出一次NC更新,再发出一次PP更新,最后又发出一次NC更新。
- 如果比较器为减法模式,它的输出能量等级由1、2、3、4、5……变成任意一个其他的能量等级,只会有一次NC更新。
这些行为在一些特殊的布线中可能会有所应用。如果读者对这部分的理解感到困难,可以暂时只记忆比较器最常规的用法——即比较信号大小并判断是否输出、检测容器容量和减法模式,或者直接查表。
比较器模式 | 计划刻行为 | 更新行为 |
---|---|---|
比较模式 | 充能属性改变 | NC->PP->NC |
比较模式 | 充能属性未改变 | NC |
减法模式 | 充能属性改变 | NC->PP->NC |
减法模式 | 能量等级改变,充能属性未改变 | NC |
减法模式 | 充能等级和能量属性均未改变 | 不更新 |
比较器输出能量等级计算
如果信号输入是红石粉或者其他比较器,则继承输入的能量。
如果是容器,请查看此部分内容比较器信号强度计算。
特别的,当同时有容器信号和红石信号输入时,比较器会根据情况优先选择不同的信号输入来计算输出,这一现象也被称为容器屏蔽。
输入端 | 输出 |
---|---|
比较器输入端直接与容器相连 | 只计算容器的输入,忽略红石信号 |
比较器输入端隔着实体方块检测容器 | 当红石信号为15时,输出15信号强度,其他情况优先计算容器输入 |
特殊的优先级变化:
- 若比较器指向一个横放的红石二极管或指向一个红石二极管的输入端,则计划刻的优先级为
-1
- 否则,计划刻的优先级默认为
0
至此,我们已经可以分析上一章中的案例
左侧 | 右侧 | |
---|---|---|
gt0 | 按钮按下铁轨激活 侦测器添加2gt计划刻 |
按钮按下铁轨激活 侦测器添加2gt计划刻 |
gt2 | 侦测器亮起 侦测器添加2gt计划刻(优先级0) 比较器添加2gt计划刻(优先级-1) |
侦测器亮起 侦测器添加2gt计划刻(优先级0) 比较器添加2gt计划刻(优先级0) |
gt4 | 比较器计划刻优先级-1,侦测器计划刻0,比较器计划刻先执行,比较器亮起 侦测器熄灭 |
由于侦测器和比较器优先级相同,侦测器计划刻先添加,先执行侦测器计划刻,侦测器熄灭 比较器执行计划刻,由于此时侦测器已经熄灭,所以比较器不亮起 |
读者可以自行分析一下下面这个类似的案例,在按下按钮后,比较器是否会亮起。
添加计划刻行为:
- 侦测器在受到面前的方块发出的PP更新后,如果自身未亮起且当前位置不存在自身的计划刻6,则添加2gt后的计划刻。
执行计划刻行为:
- 若自身未亮起,则亮起,发出PP更新,再添加2gt后的计划刻,最后发出NC更新。
- 若自身亮起,则熄灭。
Footnotes
-
“延迟多久后执行”并不严谨。实际上,执行时间记录的是世界刻,“延迟
x
gt”就是执行时间的世界刻=当前世界刻+x
。当前世界刻>=执行时间的世界刻
时,计划刻执行。但这一区别并不影响大多数情况下的计划刻分析,区块卸载的情况除外。 ↩ -
但是目前并没有优先级为1、2、3的计划刻。它们只是在代码中被声明了。 ↩
-
由于后文说明需要,基础部分仅作简单表述。具体内容涉及计划刻队列的维护,参见进阶部分。 ↩
-
因为在源码中,它们继承自同一个抽象基类
AbstractRedstoneGateBlock
↩ -
准确来说,应为“在中继器执行计划刻(进行亮起)前熄灭的信号” ↩
-
由于计划刻的执行逻辑,在当前gt即将执行的计划刻不会视为“存在计划刻”。也就是说,如果在某一gt侦测器将会亮起,而在侦测器亮起前对侦测器发出PP更新,此时侦测器也会添加计划刻。该逻辑是4gt侦测器高频的核心原理。具体行为和实例详见进阶部分。 ↩