红石与更新顺序
从信号查询、红石线传播到计划刻、活塞事件与准连接,理解 Minecraft 为什么会因为更新顺序不同而产生不同的机器行为。
前几章已经把红石依赖的底层机制拆开了。《游戏循环、Tick 与调度》说明世界不是连续时间,《方块更新、光照与流体》说明局部变化通过 Neighbor Update、Scheduled Tick 和队列向外传播,《物品、库存与配方系统》则让 Comparator、Hopper 和 Crafter 有了可以读取和操作的数据。
红石把这些机制集中到同一套装置里。
拉下一个 Lever,看起来只是“通电”。程序却必须依次回答:
- 这个 Block 向哪个方向输出多少信号?
- 相邻实心方块会不会继续把信号传出去?
- Redstone Dust 的强度应该更新成多少?
- Repeater 是现在变化,还是预约未来变化?
- Piston 收到通知以后,是立刻移动,还是先排入别的执行阶段?
- 如果两个组件都在同一个 Tick 内发生变化,谁先看到谁?
因此红石真正困难的地方并不是 0–15 这十六个数字,而是:
信号值、邻居通知、延迟调度和执行顺序怎样共同决定最终状态?
这一章只讨论实现,不写搭建教程,也不会一开始就把红石宣布成“虚拟机”或把任何怪癖预设成不可触碰。先把信号和时序讲清楚,再讨论为什么一些历史行为后来很难改变。
本文主要以 Java Edition 26.3 的默认规则为参照。需要特别说明的是:Mojang 自 1.21.2 起仍然保留一个可选的 Redstone Experiments Feature Flag;26.3 中 RedstoneWireBlock 仍同时存在默认与实验性两套 Wire Evaluator,因此实验行为不能和普通世界混写。1 2 3
1一个组件为什么会认为自己被供电?
最容易误解红石的地方,是把“充能”想成每个方块内部都保存了一个统一的电量。
Java 当前实现更接近按需查询:组件需要知道自己是否有信号时,会查看周围 Block State 向特定方向能提供什么 Redstone Signal,再根据方块是否能够导电等规则组合结果。
1.1信号首先是一个 0–15 的整数
Redstone Dust 的 POWER 是一个 0–15 的 Block State 属性。信号源可以输出 15,Wire 从邻近 Wire 接收到的强度则逐格衰减。当前 RedstoneWireEvaluator 会把来自普通 Block Signal 与邻近 Wire 的结果组合起来,得到该位置新的 Wire Strength。4
概念上可以简化成:
new wire power
=
max(
signal from non-wire sources,
strongest neighboring wire - 1
)并把结果限制在 0–15。
这解释了 Redstone Dust 最基本的传播距离,却还没有解释“为什么隔着一个实心方块也能继续供电”。那需要下一层查询。
1.2“弱 / 强充能”更适合看成两类信号查询
社区通常使用 weak power / strong power、软充能 / 强充能来解释红石。
这个模型很有用,但从当前 Java 代码看,更精确的对应是:
BlockState.getSignal(...):该 Block 向某一面提供的普通 / weak signal;BlockState.getDirectSignal(...):该 Block 向某一面提供的 direct / strong signal;BlockState.isRedstoneConductor(...):这个方块能不能把进入自身的 Direct Signal 纳入对外查询。5 6
SignalGetter.getSignal(pos, direction) 的核心关系可以概念化为:
于是所谓“一个实心方块被强充能以后,可以继续让旁边装置读到信号”,不是因为世界给这个方块永久写入了:
powered = true而是下一位读取者查询它时,SignalGetter 发现这是一个 Redstone Conductor,于是把进入这个位置的 Direct Signal 也考虑进去。
供电很多时候是查询结果,不是独立存档状态
某些红石组件确实会把 POWERED 或 POWER 保存进自己的 Block State,但“一块普通石头现在被强充能”并不需要给 Stone 增加一个新的 Block State。它可以由周围信号在查询时推导出来。
这也是为什么“强 / 弱”并不是“15 比 7 更强”。它们首先描述传播能力不同的信号路径,信号数值本身仍然可以是 0–15。
1.3不同 Source 可以对不同方向给出不同答案
Lever、Button、Torch、Repeater、Observer 并不是统一地向六个方向输出同一个值。
例如当前实现中,一个组件可以:
- 普通信号向多个方向输出;
- Direct Signal 只输出到特定方向;
- 完全不向自己的输入面输出;
- 只在
POWERED状态时成为 Signal Source。
因此“这个方块有没有电”本身就是过度简化的问题。
更有用的问题是:
从这个方向查询它时,它给出多少 Signal?
这让方向成为红石语义的一部分,而不仅是方块贴图朝向。
1.4Comparator 还多了一套 Analog Output
Comparator 并不只读取普通 Redstone Signal。
Container 等方块还可以提供 getAnalogOutputSignal;Comparator 会根据面对的方块读取这类模拟输出,再进行 Compare 或 Subtract。当前 ComparatorBlock 仍通过自己的 getInputSignal / getOutputSignal 路径处理这类输入。7 8
这让箱子填充程度、唱片机状态等世界数据能够被映射到 0–15。
从架构上看,它相当于给 Block 增加另一种接口:
world state
↓
analog measurement
↓
0..15 signal
↓
redstone network红石因此不只是“电源和导线”,也是其他游戏系统把状态暴露给自动化的一条通道。
2Redstone Dust 怎样传播信号?
Redstone Wire 看起来最接近传统电线,但实现上它同时承担三件事:
- 保存当前
POWER; - 根据附近环境决定自己向哪边连接;
- 当强度变化时通知相关方块。
这三个职责彼此关联,却不是同一件事。
2.1连接形状会影响它向哪里输出
当前 RedstoneWireBlock 保存 North / South / East / West 四个 RedstoneSide 属性,以及 0–15 的 POWER。连接可以是 NONE、SIDE 或 UP。2
也就是说,Wire 的视觉形状不是纯客户端装饰。
Mojang 在 20w18a 曾专门调整这一点,让 Redstone Wire 的视觉连接与实际供电方向更加一致:看起来连接的一侧会供电,没有视觉连接的一侧则不再按旧行为偷偷供电。9
20w21a 又加入了单格 Wire 在 Cross 与 Dot 之间切换的能力,其中 Dot 不给四周方块供电。10
这两次变化说明一个很重要的实现原则:
如果玩家需要从世界几何推断系统行为,显示状态与逻辑状态最好尽量共享同一份数据。
否则同一根 Wire 会出现“看起来没连,却实际上给电”的双重语义。
2.2Wire 的强度变化会继续触发 Neighbor Update
Wire 计算出新强度以后,事情还没有结束。
周围的 Repeater、Piston、Lamp、Door 之所以会响应,是因为 Wire 的变化继续引发 Neighbor Update。默认 Java 26.3 的 DefaultRedstoneWireEvaluator 仍然按局部递归式方式更新 Wire;RedstoneWireBlock 也保留对邻近 Wire 与邻居方块的更新入口。2 11
因此一条长 Wire 的变化不是:
计算一个数组
→ 一次提交而更像:
这正是上一章 Update Cascade 在红石中的具体表现。
2.3“信号传播”与“邻居被通知”是两张图
这两个概念很容易混在一起。
Signal Graph 回答:
谁能从谁那里读到多少 Signal?
Update Graph 回答:
某个状态变化以后,谁会被通知重新检查?
很多普通电路里,两张图看起来几乎一致,于是玩家感觉“有电就会动”。
但准连接和 BUD 恰恰来自:
能读到 Signal 的范围,与能收到 Update 的范围并不总是完全相同。
这也是为什么红石不能只用一个简单的“信号 Flood Fill”解释。
3为什么有些组件立刻变化,有些必须等待?
红石把上一章的各种调度方式全部用上了。
Wire 可以在更新链中立即重新计算;Repeater / Comparator 等 Diode 会通过 Scheduled Tick 延迟变化;Observer 把检测到的 Shape Change 转成短脉冲;Piston 则进一步使用 Block Event。
所以“一个 Redstone Tick”不是所有红石组件共享的唯一执行阶段。
3.1Repeater 把延迟做成 Scheduled Tick
Repeater 的作用不只是把输出恢复到 15。
它还显式保存:
- Facing;
- Delay;
- Powered;
- Locked。
当前 RepeaterBlock 继承 DiodeBlock。当输入变化时,DiodeBlock 会检查是否应该切换状态,再按对应 Delay 安排 Scheduled Tick;Repeater 的侧面输入还能决定 LOCKED。12 8
这意味着 Repeater 的基本语义是:
而不是立即把输入复制到输出。
因此 Delay 首先属于游戏时间调度,其次才是玩家口中的“电路延迟”。
3.2Comparator 复用 Diode 时序,但输入语义不同
Comparator 和 Repeater 都建立在 DiodeBlock 上,因此共享一部分输入、侧输入、Scheduled Tick 与定向输出基础设施。
但 Comparator 的核心问题不是:
输入是否大于零?
而是:
- 主输入是多少?
- 侧输入是多少?
- 当前是 Compare 还是 Subtract?
- 前方方块是否提供 Analog Output?
所以同一种“延迟组件框架”可以承载完全不同的信号运算。
这是一种值得借鉴的分层:
调度方式可以复用,计算规则不必复用。
3.3Observer 把 Block State / Shape Change 变成脉冲
Observer 更像一个边沿检测器。
当前 Java 的 ObserverBlock 会在它观察的方向收到 updateShape 时安排后续 Tick,再从背面输出一个短暂 Signal。13
因此 Observer 并不是每 Tick 扫描:
watchedState != oldState ?它复用了方块更新基础设施:
这和 BUD 有历史关系,但两者不是同一个实现机制。后面会专门区分。
3.4Piston 使用的不是普通 Scheduled Tick,而是 Block Event
Piston 收到 Neighbor Update 后,会先调用 checkIfExtend 判断自己当前是否应该伸出或收回。
真正移动方块并不会在这个函数里立刻完成。服务端会排入 Block Event,随后在 ServerLevel 的 Block Event 阶段执行 PistonBaseBlock.triggerEvent。14 15
这让一次 Piston 行为天然分成:
因此 Piston 的“响应时间”不能只看 Signal 什么时候变化,还要看 Block Event 在当前 Server Tick 的哪个阶段被排入。
这会直接把我们带到红石最难的一层:同一个 Tick 内部的顺序。
4同一个 Tick 里,谁先更新为什么会改变结果?
上一章已经说明:同一个 Tick 并不等于所有系统同时发生。
红石把这个事实推到了最明显的位置。
如果两个 Piston 同时发现自己应该动作,或者一条 Wire 同时向多个方向传播变化,那么:
- 谁先收到 Neighbor Update;
- 谁先重新计算自己的 Signal;
- 谁先预约 Scheduled Tick;
- 谁先进入 Block Event;
都可能改变中间状态。
4.1读取顺序、通知顺序和执行阶段不是同一件事
Java 当前至少存在三类容易混淆的顺序:
- Signal Query Order:某个位置为了判断自己是否有电,按什么顺序查询周围方向;
- Neighbor Update Order:一个 Block 变化以后,按什么顺序通知邻居;
- Scheduler / Event Order:已经排队的 Scheduled Tick 或 Block Event 在什么时候执行。
当前 26.3 的默认实现里,SignalGetter、NeighborUpdater 和 Block Shape Update 分别拥有自己的方向顺序。技术上它们甚至不是同一个数组。16
这意味着:
“先看谁”和“先告诉谁”本来就是两个问题。
如果把它们都笼统叫作 Redstone Update Order,很容易把一个组件为什么先触发解释错层。
4.2更新顺序决定中间状态能不能被观察到
假设 A 和 B 都会影响 C。
如果顺序不同,C 读取到的就可能是两版不同的中间世界:
最终稳定状态可能完全相同,但 C 在中间是否产生过 Pulse、是否预约过一次 Tick、是否排入过 Block Event,都可能不同。
因此红石时序问题常常不是:
最后 Signal 是多少?
而是:
在传播过程中的哪个瞬间,哪个组件读取了哪一版世界?
这正是同步数字电路和事件驱动系统里都会遇到的问题,只不过 Minecraft 没有给所有方块提供一个统一的 Clock Edge。
4.3默认 Wire 传播仍然带着历史递归结构
Java 26.3 默认世界使用 DefaultRedstoneWireEvaluator。
当前实现会从变化位置开始重新计算单格 Wire Power,再由方块更新继续向外展开。这个过程继承了很多历史时序特性,也意味着网络改变时,中间状态会在递归传播中逐步出现。11 17
这些中间状态通常只存在于同一个 Server Tick 内,客户端甚至可能根本看不到。
但其他服务端组件可以看见。
因此:
“玩家没有看到闪一下”不等于这一瞬间没有进入过游戏逻辑。
这也是为什么某些红石装置会利用极短的状态窗口。
4.4Redstone Experiments 正是在试验另一种传播顺序
24w33a 引入的 Redstone Experiments 尝试重写 Wire 的这部分行为。
实验模式的主要变化包括:
- 一整条受影响 Wire Network 会先计算新的 Signal Strength;
- 然后再产生 Block Updates;
- Wire 越靠近 Power Source,越早发出更新;
- 邻居更新顺序根据更新传播方向构造 Orientation;
- 目标之一是减少“机器换个方向或换个坐标就变行为”的情况。18
24w34a 又把分叉时的大部分随机选择改成 Left-first,只在缺乏方向上下文时保留少量随机性。19
当前 26.3 的代码仍然同时包含:
DefaultRedstoneWireEvaluator
ExperimentalRedstoneWireEvaluator并由 RedstoneWireBlock.useExperimentalEvaluator(...) 根据 World Feature Flag 选择。2 20
不要把实验 Redstone 当成 Java 26.3 默认行为
Redstone Experiments 在 26.3 仍然是独立 Feature Flag。普通世界继续使用默认 Wire Evaluator。讨论更新顺序时必须先说明 World 是否启用了实验,否则两套结论会互相矛盾。
这个实验本身很值得开发者观察,因为它把一个长期隐式的设计问题变得非常清楚:
为了更高性能和方向一致性,可以先算完整网络再发通知;但改变通知顺序,会直接改变依赖旧时序的机器。
这不是单纯的优化问题,也不是单纯的玩法问题,而是两者碰在了一起。
5准连接为什么会出现?
Quasi-connectivity,通常简称 QC,是 Java Redstone 最容易被说成“玄学”的行为之一。
但从当前实现看,它的原因非常具体。
5.1Piston 不只检查自己周围,还会检查上方位置周围
当前 PistonBaseBlock.getNeighborSignal 先检查 Piston 自己周围的信号,然后还会检查Piston 上方那一格周围的信号。21
Power Source 并不需要直接接触 Piston。关键在于 Piston 的激活查询覆盖了两层位置:
这不是所有 Block 的通用规则。当前 Java 中,Piston、Dispenser、Dropper 属于这类会向上多检查一层的少数机制;Crafter 并不因此自动获得 QC。21 22
所以更准确的说法是:
准连接不是 Redstone 世界的一条全局电学定律,而是少数组件的 Activation Query 范围更大。
5.2QC 的关键不是“隔空供电”,而是查询范围
如果把 QC 解释成:
Signal 可以穿过空气。
会立刻遇到很多反例。
真正发生的只是:Piston 在判断自己是否应该动作时,除了询问“我的位置周围是否有信号”,还会询问“我上方那一格的周围是否有信号”。只要其中一个查询成立,激活条件就成立。
因此“空气被供电”也只是方便描述,不意味着 Air Block 本身获得了新的持久化 Power State。
5.3MC-108 把这个行为正式留在了 Java
Quasi-connectivity 很早就被报告为 Bug。旧 Mojira 的 MC-108 描述的正是 Piston / Dispenser / Dropper 会被“对其上方空间供电”的 Source 激活。
该 Issue 最终被标记为 Resolved: Works As Intended。22
这件事的重要性不在于证明:
任何 Bug 一旦有人使用,就永远不能修。
它只说明一个现实:
当一个实现行为已经长期稳定、可重复,并且官方明确选择保留,它就开始承担兼容接口的角色。
后面讨论技术债时还会回到这一点。
6QC 为什么经常和 BUD 一起出现?
准连接本身只回答:
如果现在检查,Piston 应不应该激活?
它没有保证:
Power Source 变化时,Piston 一定会立即收到 Neighbor Update。
这两个条件的差异,才会产生很多经典的 BUD 行为。
6.1“应该变化”不等于“已经知道应该变化”
考虑一个 Piston:
- 上方某个位置进入了能让它 QC-powered 的状态;
- 这个变化并没有直接通知到 Piston;
- Piston 因此仍保留旧状态;
- 之后附近任意一次相关 Neighbor Update 到达;
- Piston 再执行
getNeighborSignal; - 此时它才发现自己早就应该动作。
于是系统会经历一段“逻辑条件已经改变,但组件状态还没追上”的窗口:
这就是许多 Block Update Detector 行为的根。
6.2Signal Graph 和 Update Graph 的错位在这里真正显现
前面已经区分了两张图。
在 QC BUD 中:
Piston 的查询能力已经“看见”更大的范围,但 Update Notification 并没有完全覆盖这个查询范围。
所以出现:
该变,但还没被叫来检查。
这比“Piston 有一个神秘的 BUD Mode”更接近真实实现。
6.3BUD 和 QC 不是同义词
QC 是一种特殊 Activation Query。
BUD 描述的是:
利用 Update 到达与状态查询之间的关系,侦测附近某种变化。
QC 很容易制造 BUD 条件,但并不是所有 BUD 都依赖 QC,也不是所有 QC 用法都在做 BUD。Minecraft Wiki 和旧 Bug Tracker 也长期把两者区分。23
这一区分很重要,因为 Observer 出现以后:
- QC 没有消失;
- BUD 的需求也没有完全消失;
- Observer 更不是“把所有 BUD Bug 正式化之后旧机制就没用了”。
6.4Observer 是显式传感器,不是 QC 的替代实现
Java Observer 主要依赖被观察面的 Shape / Block State Update,并通过 Scheduled Tick 输出 Pulse。
它的输入范围、检测事件与输出时序都写在自己的 Block 行为中。
QC BUD 则来自:
- 某组件的 Signal Query 范围;
- Neighbor Update 的传播;
- 两者之间的差异。
因此两者即使都能回答:
附近发生变化了吗?
也不是同一个 API。
这正好体现一个成熟系统经常出现的情况:
后来的显式功能可以覆盖旧技巧的一部分用途,却不一定复制旧机制的所有语义。
7Piston 为什么是更新顺序最好的放大镜?
Redstone Lamp 只需要改变亮灭。
Piston 会真正重写世界。
一次 Piston 动作可能:
- 找出一串要推动的 Block;
- 拒绝不可推动对象;
- 破坏某些允许被破坏的 Block;
- 处理 Slime / Honey 粘连;
- 临时创建 Moving Piston;
- 推动碰撞到的 Entity;
- 最后把临时状态落成新的 Block State。
因此时序上的一个微小差异,很容易在 Piston 上变成明显的结构差异。
7.1检查 Signal 和执行移动是两个阶段
收到 Neighbor Update 时,PistonBaseBlock.checkIfExtend 只负责:
- 查询现在是否应该伸缩;
- 如果需要伸出,先让
PistonStructureResolver判断能不能移动; - 把对应 Block Event 加入队列。14
真正执行动作时,triggerEvent 还会重新确认条件。
因此它更像一次分成两个阶段的提交:
这种两阶段提交是很多零刻、短脉冲和 Piston 时序现象的基础。
7.2PistonStructureResolver 负责回答“这一整组方块能不能移动”
Piston 不只是检查正前方一个 Block。
当前 PistonStructureResolver 会构建:
toPush;toDestroy;
并沿 Slime / Honey 的粘连关系继续扩展移动集合。普通 Piston 一次移动最多处理固定上限的 Block,而不同 Block 还能通过 Push Reaction、Block Entity 等规则拒绝移动。15
这里体现的是另一个很通用的架构原则:
复杂操作先做可行性分析,再一次性提交,不要移动到一半才发现后面有 Obsidian。
这与数据库 Transaction 的动机类似,只是对象变成了空间中的 Block 集合。
7.3Moving Piston 是一种临时运行时表示
和上一章 Falling Block 类似,正在被推动的 Block 暂时不适合继续作为普通静态 Block State。
Minecraft 会写入 Moving Piston 占位,并用 PistonMovingBlockEntity 保存真正被搬运的 Block State、进度和运动信息。15
于是一次移动会在静态与动态表示之间往返:
这再次说明:
静态世界表示和动态过渡表示可以不同。
Piston 只是在 Redstone 驱动下大量使用了这一模式。
8Java 与 Bedrock 为什么不能共用一份红石时序说明?
很多基础概念两版相似:
- Signal Strength;
- Dust;
- Repeater;
- Comparator;
- Piston;
- Observer。
但复杂 Redstone Build 并不能因此保证跨版本行为一致。
Microsoft 当前面向 Creator 的 Java / Bedrock 差异文档直接指出:复杂 Redstone Circuit 可能表现不同,其中一个明确原因就是 Bedrock 不支持 Quasi-connectivity,而 Java 支持;Piston 行为与 Update 方式也存在差异。24
8.1QC 就是最清晰的实现分叉
Java:
Piston activation query
includes space aboveBedrock:
no Java-style quasi-connectivity旧 Bedrock Issue MCPE-14664 也把“没有 QC”标为 Works As Intended。25
因此不能把 Java 的:
“只要上方空间被供电,Piston 就会认为自己应该动作”
写成 Minecraft 全产品线共同规则。
8.2Update Order 也不是可以直接翻译的细节
即使两个版本最后都支持同样的 Block 和 0–15 Signal,一个 Build 仍可能依赖:
- 谁先更新;
- Pulse 保留多久;
- Piston 在哪个阶段响应;
- Observer 检测什么 Update;
- 同 Tick 内是否保留某个中间状态。
这些差异很难靠“把 Java Tick 换算成 Bedrock Tick”解决。
因为问题不是时间单位不同,而是:
事件图本身不同。
所以本书后面的 Bedrock 章节会把它作为“另一套实现”看待,而不是把 Java 的源码规则翻译成 C++ 名字。
9为什么更新顺序会变成兼容问题?
红石最棘手的长期维护问题,不是每一条规则本身都多复杂,而是这些规则已经被玩家组合成了大量依赖时序的机器。
如果修改的是一个纯视觉效果,玩家重新适应即可。
如果修改的是:
- Wire 通知邻居的顺序;
- Piston 什么时候排入 Block Event;
- Observer 哪类变化能看到;
- 某个机制是否还具备 QC;
- 短 Pulse 是否会被某个阶段捕获;
那么改变的可能不是一个方块,而是一整类机器。
9.120w18a / 20w21a 展示了“修正语义”也会改变机器
20w18a 的 Redstone Wire 改动目标非常清楚:让 Block State、Rendering 和 Behavior 更一致。Wire 看起来连接到哪一侧,就真正向哪一侧供电。9
从 API 设计角度,这是一种很合理的收敛。
但任何依赖旧语义的 Contraption 都可能受到影响。
20w21a 随后允许单格 Redstone Dust 在 Cross 与 Dot 之间切换,并明确 Dot 不向四周供电。10
这不是简单的“官方修错了又改回来”,而更像一次接口重设计:
- 先让视觉状态与逻辑状态对齐;
- 再给玩家一个明确可控的状态,表达“这一格 Wire 是否向四周说话”。
相比保留一个看不见的例外,显式 Block State 更容易理解、保存和测试。
9.2Redstone Experiments 把兼容成本直接写进了实验说明
24w33a 的 Redstone Experiments 试图同时改善:
- Wire 性能;
- 更新顺序;
- 旋转 / 坐标相关行为;
- 网络整体重新计算方式。18
官方也明确提醒,这类变化可能影响已有 Contraption。
到了 1.21.2 的正式说明中,Redstone Experiments 仍然是可选实验,并直接列出一个 Known Issue:减少 Wire 的额外 Neighbor Updates 会影响依赖 Quasi-connectivity 的装置,官方计划以后再处理。26
这段历史非常有代表性。
从实现角度看:
少发不必要的 Neighbor Update,当然更便宜。
从已有世界看:
有些玩家恰好就在利用那些“本来不必要”的 Update。
于是性能优化触碰了行为兼容。
26.3 仍然保留默认与实验 Evaluator 两套实现,也说明这个权衡并没有被简单地以“新的一定更正确”结束。3 20
9.3稳定行为会逐渐变成事实上的接口
一个行为是否来自最初设计意图,并不能完全决定它后来是否重要。
更实际的兼容判断通常要问:
- 行为是否 deterministic?
- 玩家是否能稳定复现?
- Wiki / 教程是否把它作为基础机制传播?
- 大量长期世界是否依赖它?
- 官方过去是否明确承诺或选择保留?
- 修正它能得到什么收益?
- 有没有迁移方案或显式替代机制?
QC 就是典型例子。
MC-108 记录了它最初作为 Bug 被报告的历史,但最终 Resolution 是 Works As Intended。22
这不需要被升格成:
“只要是稳定 Bug,就永远不应该修。”
更准确的工程结论是:
当 emergent behavior 已经成为外部内容的依赖,修改它的成本就必须按 API change 评估,而不能只按内部代码清理评估。
9.4回归测试不能只测单个 Block
如果只给 Repeater 写测试:
input on
→ after delay
→ output on并不能保证大型机器兼容。
红石真正需要的回归层次至少包括:
Unit:
单个组件规则
Integration:
多个组件的更新顺序
Structure:
典型 Piston / Observer / QC Contraption
Transform:
旋转、镜像、不同坐标后行为是否仍符合目标
Performance:
大型 Wire Network 的更新预算24w33a 的实验甚至把“希望机器不再依赖 global orientation”作为明确目标之一。18
这提醒自研沙盒开发者:
可编程式玩法的测试对象不是只有 API 函数,还包括玩家已经搭出来的结构。
当程序本身就是世界中的几何时,Structure Test 就很接近 Integration Test。
10从红石系统可以抽象出什么?
如果只看外观,红石像一套简化电路。
如果只看玩家创造,又很容易把它直接叫作编程语言。
从实现角度看,它更具体:
- Block 提供定向 Signal Query;
- Wire 维护离散 Signal Strength;
- Neighbor Update 负责通知;
- Scheduled Tick 提供延迟;
- Block Event 提供另一类提交阶段;
- Piston 把信号转换成世界几何修改;
- Comparator 把其他系统状态映射成模拟值;
- Observer 把 Block State 变化转换成 Pulse;
- Update Order 决定同一 Tick 中哪个中间状态能被看见。
这些机制组合以后,才产生玩家能够利用的逻辑行为。
10.1红石没有一个中央“电路求解器”
系统里没有一个每 Tick 都运行的:
solveAllRedstoneCircuits()去扫描整张世界。
它更像上一章描述的局部事件系统:
这也是它能够存在于巨大世界里的原因:没有活动的 Redstone 网络几乎没有运行时传播成本。
10.2但“局部”不等于“简单”
一条 Wire 只读取邻域,一个 Piston 只查询有限范围,一个 Repeater 只预约自己的 Tick。
可当这些局部状态机互相触发以后,就会出现:
- Feedback Loop;
- Clock;
- Pulse;
- Memory;
- Sequencing;
- Conditional Routing。
复杂性来自组合后的状态空间,而不是某个组件本身拥有复杂代码。
这和 Cellular Automata、Event-driven System、Digital Logic 都有相似之处,但不必强行把红石归类成其中任何一种。
真正有用的认识是:
简单的局部规则,只要拥有稳定的时间和传播语义,就足以构成比单个规则复杂得多的系统。
10.3可预测性来自“规则稳定”,不来自“规则像现实”
Redstone Dust 不需要符合真实电阻定律。
Piston 也不需要符合刚体动力学。
玩家真正需要的是:
- 同样输入能重复得到同样结果;
- Delay 能被计数;
- Signal Strength 能被测量;
- 更新条件能被学习;
- 已经建立的机器不会无缘无故换语义。
因此红石的工程质量不能只用:
它像不像真实电路?
来判断。
更合适的问题是:
这套离散规则是否可观察、可组合、可复现,并且升级时有明确的兼容策略?
11这一章留下什么
Redstone 的“电”不是一个存进世界所有 Block 的统一状态。组件在需要时查询周围 Signal;普通 Signal、Direct Signal 与 Redstone Conductor 共同形成玩家常说的弱 / 强充能。Redstone Wire 再把 0–15 的 Signal 变成能够沿空间传播的局部网络。
真正让 Redstone 变复杂的是时间。Wire 可以立即展开 Neighbor Update;Repeater 与 Comparator 使用 Scheduled Tick;Observer 把 Shape Change 转换成延迟 Pulse;Piston 则先判断,再把真正的世界修改排入 Block Event。同一个 Tick 内部仍然存在多个执行阶段,而中间状态可以被其他组件读到。
Quasi-connectivity 也不需要神秘化。Java 的 Piston、Dispenser、Dropper 会把 Activation Query 扩展到上方空间;如果这个“能看见的范围”和 Neighbor Update 实际通知到的范围不一致,就可能出现“按规则应该变化,却还没收到通知”的状态,这正是很多 QC / BUD 行为的来源。Bedrock 没有 Java 这套 QC,因此两版的高级 Redstone 不能共享一份时序说明。24
最后,更新顺序本身也是行为的一部分。Mojang 对 Redstone Wire 的多次重构,以及至今仍以 Feature Flag 存在的 Redstone Experiments,都说明一个成熟沙盒必须同时面对两个目标:让实现更一致、更高效,也让已经建立在旧行为上的世界尽可能可理解地继续运行。
对开发者来说,最值得继承的是几条边界:Signal Query 与 Neighbor Notification 分离;即时传播与延迟调度分离;逻辑判定与世界提交分离;默认规则与实验规则分离;内部实现优化与外部行为兼容分离。 当这些边界清楚以后,红石就不再是一堆“玄学特性”,而是一套可以被逐层分析的事件驱动模拟。
第二部到这里收束。前五章已经回答了世界生成以后最重要的运行时问题:时间怎样推进,方块变化怎样传播,Entity 怎样移动与决策,Item 怎样被保存与加工,Redstone 又怎样把这些局部系统组织成可编程的因果链。下一章开始进入客户端:服务器中的这份世界状态,怎样最终变成玩家看到、听到并操作到的画面与反馈。
注释
-
Mojang Studios,《Minecraft Java Edition 26.3》,2026-09-15。见 https://feedback.minecraft.net/hc/en-us/articles/48913133328013-Minecraft-Java-Edition-26-3 ↩
-
Java 26.3
RedstoneWireBlock当前保存四向RedstoneSide、POWER,并同时引用默认 / 实验 Redstone Wire Evaluator;类中保留useExperimentalEvaluator。见 NeoForge 26.3 映射 Javadoc:https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/block/RedstoneWireBlock.html ↩ ↩2 ↩3 ↩4 -
Java 26.3 当前仍保留
FeatureFlags.REDSTONE_EXPERIMENTS;对应 World Feature Flag 在服务器 API 中也仍可见。见 https://aldak.netlify.app/javadoc/26.3.x/index-files/index-18 与 https://purpurmc.org/javadoc/org/bukkit/FeatureFlag.html ↩ ↩2 -
Java 26.3
RedstoneWireEvaluator定义getBlockSignal、getIncomingWireSignal与 Wire Signal 更新接口,子类为DefaultRedstoneWireEvaluator与ExperimentalRedstoneWireEvaluator。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/redstone/RedstoneWireEvaluator.html ↩ -
Java 26.3
SignalGetter提供getSignal、getDirectSignal、getDirectSignalTo、hasNeighborSignal、getBestNeighborSignal等 Redstone 查询。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/SignalGetter.html ↩ -
Java 26.3
BlockStateBase当前分别暴露isRedstoneConductor、isSignalSource、getSignal、getDirectSignal与getAnalogOutputSignal。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/block/state/BlockBehaviour.BlockStateBase.html ↩ -
Java 26.3
ComparatorBlock继承DiodeBlock,实现自己的getInputSignal/getOutputSignal和 Comparator Mode。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/block/ComparatorBlock.html ↩ -
Java 26.3
DiodeBlock当前统一承担定向输入、侧输入、Scheduled Tick、输出和 Neighbor 检查等 Repeater / Comparator 共享基础设施。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/block/DiodeBlock.html ↩ ↩2 -
Mojang Studios,《Minecraft Java Edition Snapshot 20w18a》,2020-04-29。该快照明确将 Redstone Wire 的 Block State、Rendering 和 Behavior 对齐,让视觉连接侧与实际供电侧一致。见 https://feedback.minecraft.net/hc/en-us/articles/360042479372-Minecraft-Java-Edition-Snapshot-20W18A ↩ ↩2
-
Mojang Studios,《Minecraft Java Edition Snapshot 20w21a》,2020-05-20。该快照加入单格 Redstone Wire 的 Cross / Dot 切换,Dot 不向周围方块供电。见 https://feedback.minecraft.net/hc/en-us/articles/360043476792-Minecraft-Java-Edition-Snapshot-20W21A ↩ ↩2
-
Java 26.3
DefaultRedstoneWireEvaluator仍作为 Redstone Wire 的默认强度更新实现;ExperimentalRedstoneWireEvaluator是独立实现。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.html ↩ ↩2 -
Java 26.3
RepeaterBlock当前拥有DELAY、LOCKED,继承DiodeBlock的 Scheduled Tick 与信号处理。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/block/RepeaterBlock.html ↩ -
Java 26.3
ObserverBlock当前通过updateShape、startSignal与 Scheduledtick处理观察与输出。见 https://aldak.netlify.app/javadoc/26.3.x/net/minecraft/world/level/block/observerblock ↩ -
Java 26.3
PistonBaseBlock当前包含checkIfExtend、getNeighborSignal、triggerEvent、moveBlocks与PistonStructureResolver相关入口。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/block/piston/PistonBaseBlock.html ↩ ↩2 -
How Java Minecraft Works,《Pistons and block events》,按 Java 26.3 源码追踪 Piston 从 Neighbor Update、Block Event、Structure Resolver 到 Moving Piston Block Entity 的执行阶段。见 https://minecraftdocs.dev/systems/blocks/pistons-and-block-events ↩ ↩2 ↩3
-
How Java Minecraft Works,《Signal and dust》,按 Java 26.3 核对
SignalGetter.DIRECTIONS、NeighborUpdater.UPDATE_ORDER与BlockBehaviour.UPDATE_SHAPE_ORDER,三者分别承担读取、邻居通知与 Shape Update 顺序。见 https://minecraftdocs.dev/systems/blocks/signal-and-dust ↩ -
How Java Minecraft Works,《Signal and dust》,按 Java 26.3 源码追踪
SignalGetter、RedstoneWireBlock、默认与实验 Wire Evaluator 的信号计算与更新链。见 https://minecraftdocs.dev/systems/blocks/signal-and-dust ↩ -
Mojang Studios,《Minecraft Java Edition Snapshot 24w33a》,2024。Redstone Experiments 首次公开实验 Wire Network 两阶段更新、方向相对的 Neighbor Order 与降低坐标 / 朝向依赖等目标。见 https://feedback.minecraft.net/hc/en-us/articles/29296154589581-Minecraft-Java-Edition-Snapshot-24w33a ↩ ↩2 ↩3
-
Mojang Studios,《Minecraft Java Edition Snapshot 24w34a》,2024。实验 Wire Update 在等距分叉时改为 Left-first,减少随机行为。见 https://feedback.minecraft.net/hc/en-us/articles/29460715867277-Minecraft-Java-Edition-Snapshot-24w34a ↩
-
Java 26.3
ExperimentalRedstoneWireEvaluator当前仍实现calculateCurrentChanges、causeNeighborUpdates与 Orientation-aware propagation。见 https://aldak0.ru/javadoc/26.3.x/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.html ↩ ↩2 -
How Java Minecraft Works,《Pistons and block events》,按 Java 26.3 核对
PistonBaseBlock.getNeighborSignal:Piston 会检查自身邻域,以及上方位置的邻域;Dispenser / Dropper 也具有对应的上方查询行为。见 https://minecraftdocs.dev/systems/blocks/pistons-and-block-events ↩ ↩2 -
Mojang Bug Tracker,MC-108,《Droppers, Dispensers and Pistons activate when blocks are providing power diagonally or two blocks above》。该 Issue 当前为 Resolved / Works As Intended。见 https://bugs-legacy.mojang.com/browse/MC-108 ↩ ↩2 ↩3
-
Minecraft Wiki,《Tutorial:Quasi-connectivity》。该文区分 Quasi-connectivity 与 BUD,并记录 QC 适用于 Java 的 Piston / Dispenser / Dropper。见 https://minecraft.wiki/w/Tutorial%3AQuasi-connectivity ↩
-
Microsoft Learn,《Differences between Minecraft Bedrock Edition and Minecraft Java Edition》。官方 Creator 文档明确指出 Bedrock 不支持 Quasi-connectivity,复杂 Redstone Circuit、Piston 与 Update 行为可能与 Java 不同。见 https://learn.microsoft.com/en-us/minecraft/creator/documents/differencesbetweenbedrockandjava ↩ ↩2
-
Mojang Bug Tracker,MCPE-14664,《There is no quasi connectivity》,Resolved / Works As Intended。见 https://bugs-legacy.mojang.com/browse/MCPE-14664 ↩
-
Mojang Studios,《Minecraft Java Edition 1.21.2》。正式版说明仍将 Redstone Changes 保持为可选 Experiment,并明确 Known Issue:减少 Wire 的额外 Neighbor Updates 会影响 QC-based contraptions。见 https://www.minecraft.net/en-us/article/minecraft-java-edition-1-21-2 ↩