Create: Schematic Compute
🎮 12 Programmable Blocks · 102 Node Types · Formula Syntax Highlighting & Autocomplete · Multiplayer Collaboration 十二种可编程方块 · 102种节点 · 公式语法高亮与自动补全 · 多人实时协作 Drag, connect, and build logic — just like Unreal Engine Blueprints! 拖拽连接,构建逻辑 — 像虚幻引擎蓝图一样直观! Created by StarryNight_Luo (y15173334444)
Table of Contents / 目录
- Overview / 简介
- Blocks / 方块
- Multiplayer Collaboration / 多人协作
- Formula Script Node / 公式脚本节点
- BUS System / BUS 总线系统
- Node Reference / 节点参考
- Controls / 操作指南
- Sable Physics Integration / Sable 物理集成
- Schematic Support / 蓝图兼容
- Recipes / 合成配方
- Block Properties / 方块属性
- Technical Highlights / 技术亮点
- Changelog / 更新日志
- FAQ / 常见问题
- Installation / 安装
- Links / 链接
📖 Overview / 简介
🇬🇧 Create: Schematic Compute is a Create mod addon that introduces 12 programmable blocks + 1 portable terminal with a visual node-based programming system. Instead of writing complex redstone circuits, simply drag and connect nodes to build logic — just like Unreal Engine Blueprints or Blender Geometry Nodes. Each computer runs at 20Hz (every game tick) for real-time control. All 12 blocks support real-time multiplayer collaborative editing with live cursor tracking and node lock protection. The FORMULA script editor features syntax highlighting (9 token colours), intelligent autocomplete (functions, variables, @output), real-time validation with error badges, and named constants (PI)/(E).
🇨🇳 机械动力:蓝图计算机 是一个机械动力附属模组,添加了十二种可编程方块和一个便携终端,采用可视化节点图编程系统。无需搭建复杂红石电路,只需拖拽连接节点即可构建逻辑——就像虚幻引擎的蓝图系统或 Blender 的几何节点一样直观。每台设备拥有独立的节点图,以 20Hz(每游戏刻) 的频率运行,适合实时控制应用。全部 12 种方块支持多人实时协作编辑,带实时光标追踪和节点锁定保护。FORMULA 公式脚本编辑器 支持语法高亮(9 种词法颜色)、智能自动补全(函数、变量、@output)、实时校验与错误徽章、以及命名常量 (PI)/(E)。
🖥️ Blocks / 方块
🖥️ Holographic Monitor / 全息显示器
3D floating display / 3D 悬浮显示方块
| Feature / 功能 | Description / 说明 |
|---|---|
| 🖼️ Display Nodes / 显示节点 | TEXT, DATA, IMAGE, IMAGE_SEQUENCE / 文本、数值、图片、动画 |
| 🎨 16×16 Pixel Editor / 16×16像素编辑器 | Multi-frame animation + undo/redo / 多帧动画+撤销重做 |
| 📋 Layer Panel / 图层面板 | Drag-drop reorder + 24×24 thumbnails / 拖拽排序+缩略图预览 |
| 🎯 3D Positioning / 3D定位 | X/Y/Z + Roll/Pitch/Yaw freely adjustable / 自由调整位置和旋转 |
| 📡 Signal-Driven / 信号驱动 | IMAGE position/rotation via input signals / 通过输入信号驱位置旋转 |
| 📡 Redstone Input / 红石输入 | Read Redstone Link signals / 从红石链接网络读取信号 |
🖥️ Blueprint Computer / 蓝图计算机
Redstone Link controller / 红石链接控制器
| Feature / 功能 | Description / 说明 |
|---|---|
| 📡 Redstone I/O / 红石I/O | Read/Write Redstone Link network / 读写红石链接网络 |
| 🔗 Private Signal / 私有信号 | Named channel cross-computer communication / 命名通道跨计算机通信 |
| 🚌 Bus System / 总线系统 | BUS_IN/BUS_OUT multi-band data sharing / 多频段数据共享 |
| 📦 Encapsulation I/O / 封装导入导出 | File browser import/export .nbt files / 文件浏览器导入导出 |
⚡ Speed Proxy / 转速代理控制器
Speed Controller direct control / 转速直控
| Feature / 功能 | Description / 说明 |
|---|---|
| 🔄 Speed Control / 转速控制 | Set adjacent Speed Controller RPM (-256~256) / 设置相邻转速控制器RPM |
| 🔗 Private Signal / 私有信号输入 | Named channel cross-computer coordination / 命名通道跨计算机联动 |
⚙️ Programmable Transmission / 可编程变速器
In-line programmable gearbox / 轴上可编程变速
| Feature / 功能 | Description / 说明 |
|---|---|
| 🎚️ Target RPM / 目标转速 | Scroll-set absolute output RPM; graph TX_OUT node overrides while running / 滚轮设定绝对输出转速,图运行时由 TX_OUT 节点接管 |
| 🔀 Face-Relative Direction / 面相对转向 | Output CW/CCW follows the placed face, creative-motor style / 输出逆/顺随放置面(创造马达同款语义) |
| ↕️ 3-Axis Placement / 三向放置 | Horizontal or vertical in-line placement; wrench on side face rotates the axis / 水平/竖直线上放置,扳手点侧面换轴 |
| ⚙️ Bearing Visuals / 轴承动画 | Two independent shaft stubs: input follows network, output follows target / 两端独立轴头动画:输入随网络、输出随目标 |
| 🤝 Stress Network Member / 应力网络成员 | First-class driven member — no input power, no output / 官方应力网络一等成员,无输入动力则无输出 |
🔧 CNC Gearbox / 数控齿轮箱
Driven clutch + motion quota / 从动离合器 + 运动配额
| Feature / 功能 | Description / 说明 |
|---|---|
| 🔌 Clutch / 离合器 | Output face carries a shaft only while engaged; idle auto-disengages / 仅接合时输出面对外传轴,空闲自动分离 |
| 📜 Command Stack / 指令栈 | FIFO motion commands: rotate (degrees) / move (meters) / wait / FIFO 运动指令:旋转(度)/ 直线(米)/ 等待 |
| 🎯 Motion Quota / 运动配额 | Open-loop travel booking, fires a completion pulse at zero / 开环行程记账,配额归零自动打完成脉冲 |
| 🔄 Encoder / 编码器 | Rotary (degrees) + linear (meters) accumulation for graph readback / 旋转(度)+ 直线(米)累计供图读取 |
| ↕️ 3-Axis + Wrench / 三向 + 扳手 | Wrench on end face flips the input, side face rotates the axis / 扳手点端面翻转输入端、点侧面换轴 |
🔌 Program Computer / 编程计算机
Sequential logic / 时序逻辑专用机
| Feature / 功能 | Description / 说明 |
|---|---|
| 📡 Redstone I/O / 红石I/O | Redstone Link network communication / 红石链接网络通信 |
| 🔗 Private Signal / 私有信号 | PRIVATE_IN/PRIVATE_OUT named channel I/O / 命名通道I/O |
| ⏱️ Sequential Nodes / 时序节点 | Delay/Latch/T Flip-Flop/Gate/Pulse Extend/Loop/Fuse/Accumulator/Integrator / 延时/锁存器/T触发器/闸门/脉冲延长/循环/保险/累计器/连续积分器 |
🪑 Control Seat / 控制座椅
Sit-able controller / 可乘坐控制器
| Feature / 功能 | Description / 说明 |
|---|---|
| ⌨️ 58 Key Bindings / 58键绑定 | Click-to-bind UI / 点击绑定 |
| 🖱️ Dual Mode / 双模式 | Joystick (mouse delta) / View Angle (rotation difference) / 摇杆/视角差 |
| 🎮 Gamepad / 手柄 | Dual stick + 15 buttons + analog triggers LT/RT / 双摇杆+15键+模拟扳机 |
| 🔄 Sable Compatible / Sable兼容 | Two camera modes (FIXED / VIEW_DIFFERENCE), world-orientation tracking via quaternion / 双相机模式,四元数世界朝向追踪 |
| 🚪 Controls / 操作 | Right-click sit / Shift+Right-click editor / ~ dismount / TAB mode / ESC release |
📐 Attitude Sensor / 姿态传感器
Physics structure orientation / 物理结构姿态读取
| Feature / 功能 | Description / 说明 |
|---|---|
| 📐 ATTITUDE / 姿态 | Block world-space pitch and roll (facing × sub-level rotation) / 方块自身世界姿态俯仰与横滚(朝向 × 子世界旋转) |
| 🧭 FORWARD / 前方朝向 | World-space forward yaw/pitch / 结构世界空间朝向 |
| ⚡ ACCELERATION / 加速度 | Block-local X/Y/Z acceleration (structure motion in block axes) / 方块本地加速度(结构运动按方块朝向分解) |
| 🚀 VELOCITY / 速度 | Block-local velocity ×2 m/s (structure motion in block axes) / 方块本地速度(结构运动按方块朝向分解) |
| 🔄 POSE_CONVERT / 姿态换算 | Coordinate conversion / 坐标系转换 |
📡 3D Holographic Radar / 3D全息显示雷达
Real-time scanner / 实时实体扫描器
| Feature / 功能 | Description / 说明 |
|---|---|
| 📡 Scan Range / 扫描范围 | 1-128 blocks configurable / 1-128格可配置 |
| 🎯 Target Lock / 目标锁定 | Manual right-click + auto closest / 手动右键锁定+自动最近 |
| 🖥️ Display Style / 显示风格 | Classic XYZ axes / Holographic (white cube + blue plane) / 经典/全息 |
| 📊 TARGET_OUT | Output X/Y/Z/entity ID/distance / 输出坐标/实体ID/距离 |
| 🔍 Filters / 过滤 | Show/hide players, mobs, Sable structures / 独立显示玩家/生物/Sable |
📱 Portable Terminal / 便携终端
Handheld remote editor / 手持远程编辑器
| Feature / 功能 | Description / 说明 |
|---|---|
| 📡 Device Scan / 设备扫描 | Scan 1-128 blocks for programmable blocks / 扫描1-128格可编程方块 |
| ✏️ One-Click Edit / 一键编辑 | Open native GUI instantly / 即时打开原生GUI |
| 📦 All 12 Blocks / 全12方块 | Monitor, Blueprint, Program, Radar, Seat, Sensor, SpeedProxy, Transmission, CNC Gearbox, Kinetic Gauge, Amplifier, Speaker |
| 🔄 Sable Compatible / Sable兼容 | Sub-level scanning with rotation correction / 子世界扫描+旋转修正 |
🎛️ Kinetic Gauge / 动力传感器
In-line kinetic readout + graph host / 轴上传动读数 + 节点图宿主
| Feature / 功能 | Description / 说明 |
|---|---|
| 📊 Built-in Readout / 内置读数 | Speed digits + stress bar (green→yellow→red, overload blink) + percentage, painted on the panel / 转速数字 + 应力条(绿→黄→红,超载闪烁)+ 百分比,直接画在面板上 |
| 🖥️ Graph Display / 图形接管 | DATA/TEXT nodes in its graph take over the panel (server-authoritative eval snapshot) / 图里的 DATA/TEXT 节点接管面板(服务端求值快照权威) |
| 📈 STRESS / 应力状态 | 4 outputs — ratio (0-1, >1 overloaded), used (SU), unused (0-1), left (SU) / 四个输出——占比、已用(SU)、未用、剩余(SU) |
| ⚡ RPM / 转速 | 1 output — signed network speed (0 unpowered/overloaded) / 一个输出——带符号网络转速(无动力/过载为 0) |
| 🔄 3-Axis Placement / 三轴放置 | Floor/ceiling placement points the display at the player (all 4 yaws, vertical state placeable directly); wall placement uses the clicked face; auto-aligns to a shaft-bearing face / 贴地贴顶正对玩家(四向可选,竖置可直接放出);贴墙用点击面;贴轴自动对齐 |
| 🔧 Wrench / 扳手 | Shaft end: roll 90° through the four same-shaft poses (shaft fixed); top/bottom: yaw 90° keeping the current tilt; other faces: Create's IWrenchable default / 轴端面:同轴四态滚转 90°(轴不动);点上/下:保持当前俯仰偏航 90°;其余面:Create 官方默认 |
| ⚙️ Shaft Pass-Through / 贯通传轴 | Passes rotation along its own axis and reads the network it sits in / 自身沿旋转轴贯通传轴,并读取所在动力网络的转速与应力 |
| 🧩 Two Model Variants / 双模型变体 | Lectern panel for horizontal shafts, flat panel for vertical shafts; text always upright / 水平轴用讲台面板,竖直轴用平板屏,文字永远直立 |
🎛️ Amplifier Computer / 功放计算机
Audio graph host with program-computer timing / 音频图宿主 + 编程计算机时序
| Feature / 功能 | Description / 说明 |
|---|---|
| 🎵 Audio Nodes / 音频节点 | MUSIC · AMP · WSHAPE · AUDIO_OUT · CHANNEL · SPEAKER_PLAY / 曲目 · 功放 · 波形整形 · 频段发布 · 声道拆分 · 播放 |
| 🎚️ Dynamics Curve / 力度曲线 | XY curve on the AMP node: note loudness → output level, chain gain applies after / AMP 节点 XY 曲线:音符力度→输出力度,链上增益随后叠加 |
| 🌊 Wave Shaper / 波形整形 | Per-sample shaping curve, identity curve = true bypass / 逐采样整形曲线,恒等曲线 = 真旁路 |
| 📡 Band Publish / 频段发布 | Publish audio to bus / private bands for speaker graphs to subscribe / 发布音频到总线/私有频段,供电音图订阅 |
| ⏱️ Timing / 时序 | Program-computer capability for play/stop triggers and delay staging / 编程计算机能力,供起停触发与延时编排 |
🔊 Speaker / 音响
Band-subscribed playback terminal / 频段订阅式播放终端
| Feature / 功能 | Description / 说明 |
|---|---|
| 🔉 Dumb Terminal / 哑终端 | Player-authored graph BUS_IN --audio wire--> SPEAKER_PLAY passes through identically; channel splitting belongs to the upstream CHANNEL / 图由玩家自己摆放(典型 BUS_IN --音频线--> SPEAKER_PLAY)恒等直通,声道拆分归上游 CHANNEL |
| 🔊 World Playback / 世界发声 | Plays the subscribed band at its own position / 在自身坐标播放订阅频段 |
| ⚙️ Playback Settings / 播放设置 | Gain (0-4) · audible radius (1-4096, default 48) · mute, in the editor panel / 编辑器面板设增益(0-4)、可听半径(1-4096,默认 48)、静音 |
| 🔴 Redstone Mute / 红石静音 | Redstone high silences the speaker / 红石高电平静音 |
👥 Multiplayer Collaboration / 多人协作(v1.2.4+)
Real-time collaborative graph editing for all 12 block types. Multiple players can edit the same graph simultaneously. 全部 12 种方块支持多人实时协作编辑同一节点图。
| Feature / 功能 | Description / 说明 |
|---|---|
| 🖱️ Live Cursor Tracking / 实时光标 | Colored crosshairs with player names / 彩色十字准星+玩家名 |
| 📦 Remote Drag / 远程拖拽 | Smooth animated node movement / 平滑动画节点移动 |
| 🔗 Wire Preview / 连线预览 | Live bezier curve while dragging / 实时贝塞尔曲线预览 |
| 👤 Player List / 玩家列表 | Right-side vertical list, host highlighted / 右侧竖向列表,房主高亮 |
| 🔒 Node Lock / 节点锁定 | IMAGE nodes protected during pixel edit / 像素编辑时锁定IMAGE节点 |
| 🚪 Auto-Close / 自动关闭 | UI closes when block destroyed / 方块破坏时自动关闭 |
| ⚡ Join/Leave / 加入离开 | Appear immediately on open, disappear on close / 打开即现,关闭即消 |
📝 Formula Script Node / 公式脚本节点
Multi-line script editor (v1.2.0+) — assignments, control flow, vec3, named outputs, comments, line continuation.
多行脚本编辑器 — 支持赋值、控制流、vec3、命名输出、注释、续行。完整语法见 docs/formula-syntax-manual.md。
🧮 Syntax Overview / 语法速览
赋值与输入引脚 / Assignments & input pins — any name assigned anywhere is an internal variable; every other name that is read becomes an input pin. 任何处被赋值的名字是内部变量,其余被读取的名字成为输入引脚:
x = a + 1 -- x 内部变量 / internal; a 成为输入引脚 / input pin
@output x
→ 1 input pin + 1 output / 1 输入 + 1 输出
控制流 / Control flow — repeat / while / if / else / break / continue:
acc = 0
repeat 100 { acc = acc + 1 }
if (acc > 50) { acc = 0 } else { acc = 1 }
@output acc
比较与逻辑 / Comparison & logic — < > <= >= are exact; ==/!= use a 1e-6 tolerance; && || ! judge truthiness as !=0. < > <= >= 精确;==/!= 1e-6 容差;&& || ! 以 !=0 判真。
vec3 与向量函数 / vec3 & vector functions:
v = vec3(3, 4, 0)
@output length(v) -- 5
@output yaw(v) -- 角度制,与 DIRECTION 节点一致 / degrees, mirrors DIRECTION
@output v -- vec3 自动展开为 v.x/v.y/v.z 三个输出引脚 / expands into 3 scalar pins
Vector functions: vec3 length normalize dot cross dist yaw pitch; component access v.x/y/z. 向量函数:vec3 length normalize dot cross dist yaw pitch;分量访问 v.x/y/z。
函数表 / Functions(角度均按度 / trig in degrees):
15 个标量函数 / 15 scalar functions — sin cos tan asin acos atan2 sinh cosh sqrt ln log exp sec csc cot
7 个向量函数 / 7 vector functions — vec3 length normalize dot cross dist yaw pitch
中文输入即转 / CJK input converts live — ()→()、×→*、≥→>=,full-width letters/digits/spaces convert to half-width as you type. ()→()、×→*、≥→>=、全角字母/数字/空格即输即转半角。
预算池 / Budget pool — loop-heavy scripts spread across ticks: a thin progress bar below the node shows solve progress; outputs freeze during the spread and update only on completion (emit-on-done); the warm edit-panel toggle controls whether an input change keeps iterating or strictly freezes. 循环重负载脚本跨 tick 分摊:节点下方进度条显示解算进度,spread 期间输出冻结、完成才更新(emit-on-done);warm 编辑区开关控制输入变更时继续迭代还是严格冻结。典型应用见下方火控弹道解算示例。
🎯 火控弹道解算示例 / Fire-Control Ballistic Solver Example
Segment-collision aim solver aligned with the CreateBigCannons 5.11.x ballistic model (semi-implicit Euler dt=1/20, linear drag, per-tick segment hit test matching the in-game raycast), validated against the CBC tick-model golden reference — landing error ≤ 0.24 blocks across five scenarios.
弹道反解火控,对齐 CreateBigCannons 5.11.x 弹道模型(半隐式欧拉 dt=1/20、线性阻力、逐 tick 线段碰撞判定,与游戏内 raycast 同语义),对照 CBC tick 模型金标准五组场景对拍通过(落点误差 ≤ 0.24 格)。
Full paste-ready script: docs/examples/ballistic_solver.formula — ~2.5k–9k interpreter steps per solve (~65–250× leaner than the v1 600k-step Newton solver), spread across ticks by the budget pool with a progress bar. Parameters baked in for a size-7 barrel · 8 charges · HE/AP shell (v0=160 b/s, g=20 b/s², fd=0.2); the script header table shows how to re-derive them for other charges or shell types.
完整可粘贴脚本:docs/examples/ballistic_solver.formula(每次解算约 2.5k–9k 步,较 v1 的 60 万步牛顿法精简 65–250 倍,由预算池跨 tick 分摊、带进度条)。参数已内化:7 系炮管 · 8 装药 · HE/AP 弹(v0=160、g=20、fd=0.2),脚本头部表格给出换装药/弹种的换算方法。
-- 输入:mx,my,mz 炮口 / tx,ty,tz 目标(参数已内化,见脚本头部参数表)
-- inputs: mx,my,mz muzzle / tx,ty,tz target (ballistic params baked in, see the header table)
-- 输出:ay 射向角[0,360) / ap 射角 / hit 可达 / vx0,vy0,vz0 初速向量
-- outputs: ay aim yaw [0,360) / ap aim pitch / hit reachable / vx0,vy0,vz0 velocity vector
ay = atan2(tx - mx, 0 - (tz - mz))
if (ay < 0) ay = ay + 360
cy = cos(ay)
sy = sin(ay)
-- 俯仰粗扫描(46 点 × 4°,记录低伸首谷+全局最优谷)+ 线段碰撞弹道模拟(半隐式欧拉 dt=1/20,距离持续增大 20 步提前终止)
-- pitch coarse scan (46 pts × 4°, flat-first + best valleys) + segment-collision simulation (semi-implicit Euler dt=1/20, early exit after 20 steps of increasing distance)
p = -89.899
bestwd = 1000000
repeat 46 {
vx = v0 * cos(p) * sy
vy = v0 * sin(p)
vz = v0 * cos(p) * (0 - cy)
-- ... 400 步线段碰撞模拟(完整脚本见上方链接) ... / 400-step segment simulation (full script linked above)
p = p + 4
}
-- 细扫(0.5° × 17 点)+ 割线精化(≤10 轮),先低伸解、失败回退高抛解
-- fine scan (0.5° × 17 pts) + secant refinement (≤10 rounds), flat-first with high-arc fallback
@output ay
@output ap
@output hit
→ 6 inputs + 6 outputs / 6输入 + 6输出
🎨 Syntax Highlighting / 语法高亮
Real-time colour-coded editing with 9 token categories. 9 种词法分类的实时彩色标注。
| Token Type / 词法类型 | Colour / 颜色 | Examples / 示例 |
|---|---|---|
| Functions / 函数 | 🟡 Yellow / 黄色 | sin, cos, sqrt, exp |
| Constants / 常量 | 🩷 Pink / 粉色 | (PI), (E) — 仅分组括号内视为字面量 |
| Identifiers / 标识符 | 🩵 Light Cyan / 浅青 | x, speed, myVar |
| Numbers / 数字 | 🟠 Orange / 橙色 | 3.14, 42, 0.5 |
| Operators / 运算符 | ⬜ Grey / 灰色 | +, -, *, /, ^, % |
| Parens / 括号 | ⬜ Grey / 灰色 | (, ) |
| Comments / 注释 | 🟢 Green / 绿色 | -- this is a comment |
| @output / 输出 | 🟣 Purple / 紫色 | @output |
| Assignment / 赋值 | 🟣 Purple / 紫色 | = |
| Unknown / 未知 | 🔴 Red / 红色 | Invalid characters / 非法字符 |
🔍 Autocomplete / 自动补全
Type to trigger suggestions near the caret, rendered above all pins. 输入即触发,候选框显示在光标下方、所有引脚上方。
| Trigger / 触发方式 | Behaviour / 行为 |
|---|---|
| Type identifier char / 输入标识符字符 | Filtered dropdown: functions, constants, current variables / 过滤候选:函数、常量、当前变量 |
Type @ / 输入 @ |
Immediately suggests @output / 立即建议 @output |
Tab / Enter |
Accept selected candidate / 接受选中候选项 |
↑ ↓ |
Navigate candidates / 导航候选项 |
Esc / any other key |
Close popup / 关闭候选框 |
| Click candidate / 点击候选项 | Accept and insert / 接受并插入 |
| Zoom-aware / 缩放感知 | Popup scales with graph zoom level / 候选框随图缩放 |
✅ Real-Time Validation / 实时校验
Issues shown as red ⚠ badge on the node title bar. Hover the badge to see details. 错误以红色 ⚠ 徽章显示在节点标题栏,悬停查看详情。
| Check / 校验项 | Type / 类型 |
|---|---|
| Bracket matching / 括号匹配 | Error / 错误 |
| Unknown function / 未知函数 | Error / 错误 |
| Function arity / 函数参数数量不符 | Error / 错误 |
| Invalid assignment / 无效赋值 | Error / 错误 |
| Duplicate output names / 重复输出名 | Warning / 警告 |
| @output invalid start / @output 起始非法 | Warning / 警告(表达式输出合法,如 @output length(v)) |
| Red border on MLE / 输入框红色边框 | Visual feedback / 视觉反馈 |
📐 Named Constants / 命名常量
(PI) and (E) in grouping parentheses are literal constants (π ≈ 3.14159, e ≈ 2.71828).
Bare PI / E or PI / E inside function calls like sin(PI) are treated as variable references (create input pins).
(PI) 和 (E) 在分组括号内视为字面常量。裸 PI/E 或函数调用内的 sin(PI) 视为变量(创建输入引脚)。
-- (PI) = literal π, not a variable / 字面量π,不是变量
-- sin(PI) = PI is a variable input / PI 是变量输入
result = (PI) + sin(PI)
@output result
→ 1 input pin (PI) + 1 output / 1 输入引脚 + 1 输出
🚌 BUS System / BUS 总线系统
Global named-channel communication across computers. Like publish-subscribe message bus. 全局命名通道跨计算机通信系统,类似发布-订阅消息总线。
| Feature / 功能 | Description / 说明 |
|---|---|
| 🚌 BUS_OUT / 总线输出 | Write values to named channel with bands / 写入命名通道+频段 |
| 🚌 BUS_IN / 总线输入 | Read band values from channel / 从通道读取频段值 |
| 📋 Band System / 频段 | Named sub-fields per channel / 每通道命名字段 |
| 🔢 Ref Counting / 引用计数 | Auto-cleanup when no BUS_OUT references / 无引用时自动清理 |
| ⚠️ Conflict Detection / 冲突检测 | Reject duplicate channel names / 拒绝重名通道 |
🧩 Node Reference / 节点参考(102 种)
📦 Values / 数值
| Node / 节点 | Description / 说明 |
|---|---|
| Constant / 常量 | Outputs constant value / 输出常量值 |
| Redstone Input / 红石输入 | Reads from Redstone Link / 从红石链接网络读取 |
| Private Signal Input / 私有信号输入 | Reads float from named channel / 从命名通道读取浮点数 |
| Bus Input / 总线输入 | Reads bus channel bands / 从总线通道读取频段值 |
📊 Kinetic Readings / 动力读数 (Kinetic Gauge / Transmission / CNC Gearbox)
| Node / 节点 | Description / 说明 |
|---|---|
| Stress Status / 应力状态 | Kinetic network stress, 4 outputs: ratio (0-1, >1 overloaded), used (SU), unused (0-1), left (SU); all 0 with no network or zero capacity / 动力网络应力,四个输出:占比(0-1,超载 >1)、已用(SU)、未用(0-1)、剩余(SU);无网络/零容量全 0 |
| Speed (RPM) / 转速 | Network rotation speed, signed (negative = reversed), 0 when unpowered/overloaded / 网络转速,带符号(负=反转),无动力/过载为 0 |
⚙️ Transmission & Gearbox / 变速器·齿轮箱 (Programmable Transmission + CNC Gearbox / 可编程变速器·数控齿轮箱)
| Node / 节点 | Description / 说明 |
|---|---|
| Target Speed / 目标转速 | Passthrough desired output RPM; the rev toggle negates it and the host transmission writes the target / 透传期望输出转速,rev 取反,宿主变速器写入目标 |
| Move / 移动 | Command stack: rising edge enqueues "move N meters" (value = param, wire-overridable) / 指令栈:上升沿入队「移动 N 米」(数值=参数,可连线覆盖) |
| Rotate / 转动 | Command stack: rising edge enqueues "rotate N degrees" / 指令栈:上升沿入队「转动 N 度」 |
| Wait / 等待 | Command stack: rising edge enqueues "wait N ticks" / 指令栈:上升沿入队「等待 N 刻」 |
| Clutch / 离合 | Standing clutch intent / 常接合意图 |
| Encoder / 编码器 | Motion feedback: angle (deg) · linear position (m) · actual speed (RPM); reset is body input pin 0 (level-triggered) / 运动反馈:角度(度)·线性位置(米)·实际转速(RPM);清零为节点体 0 号输入引脚(电平触发) |
🔢 Basic Math / 基础运算
| Node / 节点 | Description / 说明 |
|---|---|
| Add / 加法 | A + B |
| Subtract / 减法 | A - B |
| Multiply / 乘法 | A × B |
| Divide / 除法 | A ÷ B (0 if B=0) |
| Modulo / 模运算 | A % B |
| Power / 次幂 | A ^ B |
| Root / 次方根 | B-th root of A |
| Absolute Value / 绝对值 | |input| |
| Ceil / 向上取整 | Round up |
| Floor / 向下取整 | Round down |
📐 Advanced Math / 高级运算
| Node / 节点 | Description / 说明 |
|---|---|
| Formula / 公式 | Multi-line script editor / 多行脚本编辑器 |
| Round / 保留N位小数 | Round to N decimals / 保留N位小数 |
| Comparison Router / 比较路由 | |A-B| smart routing / 智能信号分流 |
| Pose Convert / 姿态换算 | Pitch/Yaw/Roll coordinate conversion / 姿态角转换 |
| Split / 分割 | Positive/negative signal split / 正负信号分离 |
Trig / 三角函数(度): Sine · Cosine · Tangent · Arc Sine · Arc Cosine · Arc Tangent 2 · Hyperbolic Sine · Hyperbolic Cosine
Other / 其他: Square Root · Natural Log · Base-10 Log · Exponential · Secant · Cosecant · Cotangent · Angle Unwrap · Direction (3-in 3-out)
🧠 Logic / 逻辑
| Node / 节点 | Description / 说明 |
|---|---|
| Greater Than / 大于 | A > B |
| Less Than / 小于 | A < B |
| Greater or Equal / 大于等于 | A ≥ B |
| Less or Equal / 小于等于 | A ≤ B |
| Equals / 等于 | A = B |
| AND Gate / 与门 | A > 0.5 and B > 0.5 |
| OR Gate / 或门 | A > 0.5 or B > 0.5 |
| Bool / 布尔 | Boolean with invert toggle / 布尔(可反转) |
| Gate / 闸门 | Signal gate with Set/Reset/Toggle / 信号门 |
| Relay A / 继电器A | SPDT relay — contact false→A, contact true→B / 双掷继电器 |
| Relay B / 继电器B | SPST relay — out = contact ? B : A / 单掷合并继电器 |
🎛️ Control / 控制
| Node / 节点 | Description / 说明 |
|---|---|
| PID Controller / PID控制器 | SP/PV PID (scalable output, anti-windup) / SP/PV 双输入 PID(输出可缩放,抗积分饱和) |
| Power PID / 动力PID | PID with base power input / 带基础动力PID |
| Clamp / 限制 | Min/Max clamp / 限幅 |
| Map Range / 映射范围 | Range mapping / 范围映射 |
📤 Output / 输出
| Node / 节点 | Description / 说明 |
|---|---|
| Redstone Output / 红石输出 | Write to Redstone Link (0~15) / 写入红石链接 |
| Private Signal Output / 私有信号输出 | Write to named channel / 写入命名通道 |
| Bus Output / 总线输出 | Writes to bus channel / 写入总线通道 |
| Speed Control / 转速控制 | Speed Controller RPM (-256~256) / 转速控制 |
⏱️ Sequential / 时序 (Program Computer only / 仅编程计算机)
| Node / 节点 | Description / 说明 |
|---|---|
| Delay / 延时 | Delay N ticks / 延时N tick |
| Latch / 锁存器 | Set/Reset latch, configurable default / 可配置默认状态 |
| T Flip-Flop / T触发器 | Toggle flip-flop, configurable default / 可配置默认状态 |
| Pulse Extender / 脉冲延长 | Extend input pulse N ticks / 脉冲延长N tick |
| Loop / 循环 | Fire pulse every interval, repeat count times / 循环脉冲 |
| Safety Timer / 保险 | Trigger (rising edge) or held-high input → 2-tick pulse → cooldown; held-high repeats as pulse generator / 触发(上升沿)或持续高电平 → 2 tick 脉冲 → 冷却;持续高电平自动循环(脉冲发生器) |
| Accumulator / 累计器 | Rising-edge step counter / 累计器 |
| Continuous Integrator / 连续积分器 | Continuous integration, configurable limit / 连续积分器 |
🎮 Input / 输入 (Control Seat + Attitude Sensor / 控制座椅+姿态传感器)
| Node / 节点 | Description / 说明 |
|---|---|
| Keyboard Key / 键盘按键 | 58 bindable keys / 58键绑定 |
| Mouse Joystick / 鼠标摇杆 | Dual mode: incremental (mouse delta) / absolute (stick with memory). Toggle in edit panel. / 双模式:增量/绝对值,编辑区切换 |
| View Angle / 视角差 | View angle delta / 视角差 |
| Mouse Button / 鼠标按键 | Left/Right mouse buttons / 鼠标按键 |
| Gamepad Joystick / 手柄摇杆 | Dual stick LX/LY/RX/RY / 双摇杆 |
| Gamepad Button / 手柄按键 | 15 buttons / 15按键 |
| Gamepad Trigger / 手柄扳机 | Analog triggers LT/RT (0~1) / 模拟扳机 |
| World View / 世界视角 | Player absolute world view direction / 玩家绝对视角 |
| Attitude / 姿态 | Block world-space pitch and roll (facing × sub-level rotation) / 方块自身世界姿态俯仰与横滚(朝向 × 子世界旋转) |
| Forward / 前方朝向 | World-space forward yaw/pitch / 结构朝向 |
| Acceleration / 加速度 | Block-local X/Y/Z acceleration (structure motion in block axes) / 方块本地加速度(结构运动按方块朝向分解) |
| Velocity / 速度 | Block-local velocity ×2 m/s (structure motion in block axes) / 方块本地速度(结构运动按方块朝向分解) |
| World Position / 世界坐标 | World position with offset / 世界坐标(可偏移) |
| Target Output / 目标输出 | Radar target X/Y/Z/entityId/distance / 雷达目标 |
🖼️ Display / 显示 (Monitor + Control Seat HUD / 全息显示器+控制座椅抬头显示)
| Node / 节点 | Description / 说明 |
|---|---|
| Text / 文本 | Text display with color / 文字显示 |
| Data Display / 数值显示 | Float value display / 数值显示 |
| Image / 图像 | 16×16 pixel image, signal-driven position / 像素图片 |
| Image Sequence / 图像序列 | Multi-frame animation, signal-driven frame / 多帧动画 |
| Pitch Ladder / 俯仰梯 | AR HUD pitch ladder (Control Seat), range & interval params / AR HUD 俯仰梯(控制座椅),range/interval 参数 |
🎵 Audio / 音频 (Amplifier Computer + Speaker / 功放计算机·音响)
| Node / 节点 | Description / 说明 |
|---|---|
| Music / 曲目 | Song host + transport: NBS playback, loop, play/stop / 曲目宿主+传输:NBS 播放、循环、起停 |
| Amplifier / 功放 | Gain 0-4 plus a dynamics curve (note loudness → output level) / 增益 0-4 + 力度曲线(音符力度→输出力度) |
| Wave Shaper / 波形整形 | Per-sample shaping curve; identity curve = true bypass / 逐采样整形曲线;恒等曲线 = 真旁路 |
| Audio Output / 音频输出 | Publish audio to a named band / 发布音频到命名频段 |
| Channel Split / 声道拆分 | Split multi-channel audio to standard layouts (stereo/quad/5.1/7.1) / 多声道音频按标准布局拆分(立体声/四声道/5.1/7.1) |
| Speaker Play / 播放 | Playback sink: hands the source to the host speaker / 播放下沉:把音源交给宿主音响发声 |
📦 Structure / 结构
| Node / 节点 | Description / 说明 |
|---|---|
| Encapsulation / 封装 | Nest sub-graphs inside a node / 嵌套子图 |
| ENCAP_INPUT / 封装输入 | External input pin / 外部输入引脚 |
| ENCAP_OUTPUT / 封装输出 | External output pin / 外部输出引脚 |
🔧 Debug / 调试 (All blocks / 全部方块)
| Node / 节点 | Description / 说明 |
|---|---|
| Comment / 便利贴 | Sticky-note annotation, resizable (80~8000×40~6000), scrollable, 3-color customizable. Drag header to move, parent-move contains nodes. Pure visual — skipped during evaluation. Press C with nodes selected to wrap. / 可调大小/滚动/三色自定义。拖拽顶部移动,父级移动携带内部节点。纯视觉辅助。选中节点按 C 包裹。 |
| Signal Generator / 信号发生器 | Test signal source with XY curve preview + Y-axis range label, manual control-point curve or custom f(x) formula, frequency-generate or input-driven output modes, percentile-based robust auto-scale / 测试信号源,XY曲线预览+Y轴范围标注,手动控制点曲线或自定义f(x)公式,频率发生/指定模式输出,百分位数稳健自动缩放 |
| Signal Probe / 信号探针 | Real-time signal monitor with 100-tick trend chart, percentile-based robust auto-scale (p1-p99), freeze/clear / 实时信号监视,100 tick趋势图,百分位数稳健自动缩放(p1-p99),冻结/清除 |
Signal Generator Modes / 信号发生器模式:
| Mode / 模式 | Description / 说明 |
|---|---|
| 🎯 Manual Curve / 手动曲线 | Drag control points on XY chart. Double-click to add, right-click to delete, drag X/Y freely (X clamped between neighbors, server-sorted). Points synced via multiplayer collaboration. / XY图上拖拽控制点。双击添加,右键删除,XY双向自由拖拽(X被相邻点夹持,服务端排序)。多人协作同步。 |
| 📐 Custom f(x) / 自定义公式 | Enter formula expression using variable x (0~1). Supports all math functions (trig in degrees), auto full-width paren conversion. Speed/amplitude disabled — formula controls everything. / 输入公式表达式,变量 x(0~1)。支持全部数学函数(三角函数用度),自动全角括号转换。speed/amplitude 禁用。 |
| 🔄 Frequency Generate / 频率发生 | X auto-advances 0→1 cyclically. Speed control (manual mode only). Current X position shown as sky-blue marker on chart. / X自动0→1循环推进。speed控制速度(仅手动模式)。天蓝色标记线显示当前X位置。 |
| 🎯 Input-Driven / 指定模式 | X set by dragging sky-blue marker line on chart. No EditBox — pure drag interaction. / 拖拽天蓝色标记线设置X值。无输入框,纯拖拽交互。 |
Signal Probe Features / 信号探针功能:
- 100-tick ring buffer trend chart with percentile-based robust auto-scale (p1-p99)
- Percentile filtering replaces fixed ±5 clipping — correctly displays large-range data (e.g. 0~360)
- Right-click: Freeze/Unfreeze, Clear History
- Shows "---" when blueprint not running
🎮 Controls / 操作指南
| Action / 操作 | Input / 按键 |
|---|---|
| Add node menu / 添加节点 | Right-click empty / 右键空白 |
| Two-column layout / 双列布局 | Click the state-label button on the menu title row (1 Col/2 Col), gold = two columns on / 点击菜单标题行右侧状态文字按钮(单列/双列),金色=双列开启 |
| Edit params / 编辑参数 | Left-click → ▶ / 左键→▶ |
| Connect / 连接 | Drag output pin → input pin / 拖拽输出→输入 |
| Delete node / 删除节点 | Hover + X / 悬停+X |
| Delete connection / 删除连线 | TAB + Left-click / TAB+左键点击 |
| Delete selected / 删除选中 | Delete |
| Box select / 框选 | TAB + drag / TAB+拖拽 |
| Duplicate / 复制 | Ctrl + D |
| Undo / 撤回 | Ctrl + Z |
| Redo / 重做 | Ctrl + Y |
| Wrap in Comment / 注释包裹 | Select nodes + C / 选中节点+C |
| Edit Comment text / 编辑注释文本 | Double-click comment body / 双击注释节点 |
| Resize Comment / 调整注释大小 | Drag bottom-right corner / 拖动右下角 |
| Scroll Comment / 滚动注释 | Ctrl + Scroll / Ctrl+滚轮 |
| Zoom / 缩放 | Scroll wheel / 滚轮 |
| Pan / 平移 | Left-drag blank canvas (drag on a node = move it) / 左键拖拽空白处(节点上拖拽=移动节点) |
| Open editor (most blocks) / 打开编辑器 | Right-click / 右键 |
| Speaker — Playback settings (gain/radius/mute) / 播放设置(音量/半径/静音) | Second-row button in the speaker editor / 音响编辑器第二行按钮 |
| Control Seat — Sit / 乘坐 | Right-click (empty hand) / 右键(空手) |
| Control Seat/Radar — Editor / 编辑器 | Shift + Right-click / Shift+右键 |
| Control Seat — Dismount / 下马 | ~ |
| Control Seat — Switch mode / 切换模式 | TAB |
| Control Seat — Release mouse / 释放鼠标 | ESC |
| Signal Gen — Add control point / 添加控制点 | Double-click XY chart / 双击XY图 |
| Signal Gen — Delete control point / 删除控制点 | Right-click control point / 右键控制点 |
| Signal Gen — Drag control point / 拖拽控制点 | Left-drag (X clamped, Y free) / 左键拖拽 |
| Signal Gen — Drag X marker / 拖拽X标记 | Left-drag sky-blue line (input mode) / 左键拖拽天蓝色线 |
| Signal Gen — Switch mode / 切换模式 | Click toggle button (confirm with second click) / 点击切换按钮(二次点击确认) |
| Probe — Freeze/Unfreeze / 冻结解冻 | Double-click probe node / 双击探针节点 |
| Probe — Clear/Clear History / 清除历史 | Right-click probe node / 右键探针节点 |
| Bookmark — Open panel / 打开书签面板 | Click ★ bottom-right / 点击右下角★ |
| Bookmark — Add / 添加书签 | [+] in panel or Ctrl+M / 面板内[+]或Ctrl+M |
| Bookmark — Rename / 重命名 | Click ✎ on bookmark row / 点击书签行✎ |
| Bookmark — Delete / 删除 | Click × on bookmark row / 点击书签行× |
| Bookmark — Jump / 跳转 | Click → or name / 点击→或名称 |
| Bookmark — Reorder / 拖拽排序 | Drag name area to new position / 拖拽名称区域到新位置 |
| Bookmark — Reset view / 重置视角 | [↺] in panel or Home key / 面板[↺]或Home键 |
All editor actions above are rebindable — editor settings (top-right button) → Keys tab. / 上表编辑器动作均可在编辑器设置(右上角按钮)→「键位」标签页重绑。
🔄 Sable Physics Integration / Sable 物理集成
Deep integration with Sable physics engine for rotating structures. / 与Sable物理引擎深度集成,支持旋转结构。
| Block / 方块 | Feature / 功能 |
|---|---|
| Control Seat / 控制座椅 | Entity yaw tracks sub-level rotation / 实体yaw追踪子世界 |
| Attitude Sensor / 姿态传感器 | Read logicalPose() quaternion / 读取姿态四元数 |
Thread safe / 线程安全: Shared fields
volatile. Without Sable / 无Sable: Control Seat fully functional, Sensor outputs 0 / 控制座椅完全可用,传感器输出0
💾 Schematic Support / 蓝图兼容
All 12 blocks support Create's Schematicannon — graphs and state fully preserved. / 全部十二种方块支持蓝图大炮,图与状态完整保留。
Uses Create's IMergeableBE + SafeNbtWriter / 采用 Create 官方接口
📦 Recipes / 合成配方
| Block / 方块 | Materials / 材料 |
|---|---|
| 🖥️ Monitor / 全息显示器 | Redstone Link×2 + Precision Mechanism + Glass Pane×2 + Brass Casing + Glowstone Dust×2 |
| 🖥️ Blueprint / 蓝图计算机 | Redstone Link×2 + Precision Mechanism + Glass Pane×2 + Repeater + Comparator + Brass Casing×2 |
| ⚡ Speed Proxy / 转速代理 | Brass Ingot×4 + Cogwheel + Glass Pane×2 + Comparator + Andesite Casing |
| 🔌 Program / 编程计算机 | Andesite Casing×4 + Repeater + Glass Pane×2 + Comparator + Andesite Alloy |
| 🪑 Control Seat / 控制座椅 | Heavy Weighted Pressure Plate + Iron Ingot×2 + Brass Casing + Redstone + Redstone Link×4 |
| 📐 Attitude Sensor / 姿态传感器 | Iron Ingot×6 + Repeater + Comparator + Brass Casing×2 |
| 📡 Radar / 雷达 | Monitor×2 + Iron Ingot×4 + Brass Casing + Redstone Block×2 |
| 📱 Portable Terminal / 便携终端 | Redstone Link×4 + Blueprint Computer + Glass Pane×4 |
| 🎛️ Kinetic Gauge / 动力传感器 | Iron Ingot×4 + Shaft×4 + Brass Casing |
⚙️ Block Properties / 方块属性
| Property / 属性 | Value / 值 |
|---|---|
| Hardness / 硬度 | 1.0 (hand breakable / 空手可破坏) |
| Hand break / 空手破坏 | Drops without NBT / 掉落无NBT |
| Wrench right-click / 扳手右键 | Rotate FACING / 旋转方向 |
| Wrench Shift+right-click / 扳手Shift+右键 | Pick up with full NBT / 收回保留NBT |
| 🎛️ Kinetic Gauge wrench / 动力传感器扳手 | Shaft end: roll through the 4 same-shaft poses (shaft fixed); top/bottom: tilt-preserving yaw; others: Create's default / 轴端面:同轴四态滚转(轴不动);点上/下:保倾偏航;其余面:官方默认 |
🔧 Technical Highlights / 技术亮点
| Feature / 特性 | Description / 说明 |
|---|---|
| 👥 Multiplayer Collaboration / 多人协作 | Real-time editing, cursor tracking, node lock / 实时编辑、光标追踪、节点锁 |
| ⚡ Server-Authoritative Eval / 服务端权威评估 | Client receives EvalSnapshot — no local evaluator / 客户端接收快照,无本地评估器 |
| ⚡ Topological Sort Eval / 拓扑排序求值 | O(1) input query cache / O(1) 输入查询缓存 |
| 🚀 GC-Friendly / GC友好 | Reused evaluator instances / 重用求值器 |
| 🔄 Signal Bus / 信号总线 | Global named-channel communication / 全局命名通道通信 |
| 🧹 PID Anti-Windup / PID抗饱和 | Integral capping / 积分上限钳制 |
| 🛡️ Cycle Detection / 环检测 | Compile-time circular dependency check / 编译时循环引用检测 |
| 🎮 GLFW Raw Input / GLFW原始输入 | Bypass Minecraft keybinding system / 绕过MC键位系统 |
| 🔄 Sable Integration / Sable集成 | BlockEntitySubLevelActor sub-level pose reading / 子世界姿态读取 |
📜 Changelog / 更新日志
完整变更日志已拆分至 CHANGELOG.md —— 每个版本一个 <details> 块。
The full changelog now lives in CHANGELOG.md — one <details> block per release.
| Version | 标题 / Title |
|---|---|
| v1.2.6 | 功放电脑 + 音响 + NBS 钢琴卷帘编辑器(双视图 · 选择/剪贴板 · 拖移搬移 · 逐音符力度/声像/细音高 · 层面板与重排 · 静音 · 配色收编)· 与门节点 · 曲线双节点(AMP 力度曲线 + WSHAPE)· 闸门/T 触发器/锁存器当前态手动切换 / Amplifier Computer + Speaker + NBS Piano Roll Editor (dual views, selection & clipboard, drag-to-move, per-note velocity/panning/pitch, layer panel & reorder, mute, themed palette) · AND gate node · curve duo (AMP dynamics curve + WSHAPE) · manual current-state toggle on Gate / T Flip-Flop / Latch |
| v1.2.5.2 | 修复:动力传感器扳手旋转(同轴滚转 · 点上/下保倾偏航)· 贴地放置修正 · 倒置朝下时屏幕读数翻正 · 行走时视角摇晃导致 HUD 虚像晃动 · 切换游戏语言后 HUD 文字变乱线 · 节点分类重构 · 视口裁剪 / 菜单命中 · 数控齿轮箱轴面常在 / 扳手回归官方 · 变速器过载后输出恢复 · 输出指令正反转与负行程 · 编码器清零改节点体引脚 · PID/PID_POWER 积分死区 · 频道名旧草稿回写(#10)· 去掉整图保存覆盖(#17)· 封装子图节点数据同步 · 封装子图展开状态跨玩家同步 · 参数输入框实时同步 · 封装子图顶栏合并 · 占用封装禁删 · 键位系统扩容(删除连线 + 像素编辑器动作)· 统一键鼠序列绑定 · 旧键位配置迁移 · 删节点撤销/重做恢复连线(pinId + 占用检测)· 变速器代理态显示(值盒「(代理)」+ 滚轮拒收) / Fix: Kinetic Gauge Wrench Rotation (Shaft Roll · Tilt-Preserving Yaw) · Floor Placement · Inverted Mount Text Upright · View Bobbing Wobble & Garbled HUD Text After a Language Switch · Node Category Refactor · Viewport Cull / Menu Hit · CNC Gearbox Shaft Faces Always Present / Wrench Back to Official · Transmission Output Recovers After Overload · Output-Command Forward-Reverse & Negative Travel · Encoder Reset on the Node Body · PID/PID_POWER Integral Deadband · channel-name stale-draft write-back (#10) · drop whole-graph save overwrite (#17) · sub-graph node data sync · sub-graph expansion state sync across players · live param-box sync · sub-graph top-bar merge · occupied-encapsulation delete guard · display-mode top-bar merge · display lock follows selection · smooth remote display-layout drags · key-binding system gains delete-wire and pixel-editor actions · unified sequence bindings (legacy key-binding configs migrate) · undo/redo node-delete restores wires (pinId + occupancy check) · transmission proxy display (value-box "(proxy)" + wheel refused while node-driven) |
| v1.2.5.1 | 动力传感器(kinetic_gauge,Create 表同款 3 轴放置 · STRESS/RPM 节点 · 蓝屏显示)· 编辑器输入焦点与选中高亮修复 · GUI 巨型文件拆分(HUD 裁剪数学 / 显示编辑器 / 设置界面 tab) |
| v1.2.5 | 公式语言升级:控制流 + vec3 + 预算池 / GUI 架构迁移 / 像素编辑器 / 可编程变速箱 |
| v1.2.4.1 | 回归审计 · 总线系统 · 封装状态 · 公式一致性 · Sable 加固 |
| v1.2.4 | 多人协作 + 调试工具链 + 公式编辑器体验 |
更早版本(v1.2.3 及以前)见 CHANGELOG.md。
Older releases (v1.2.3 and earlier): see CHANGELOG.md.
❓ FAQ / 常见问题
Node editor laggy? / 节点编辑器卡顿?
Editor drawing is viewport-culled (v1.2.5.2): only on-screen nodes cost render time. 1024 nodes on screen runs fine — node count and PID count are no longer practical limits. / v1.2.5.2 起编辑器绘制做了视口裁剪(只画屏内节点):同屏 1024 个节点也无压力,节点数量与 PID 数量不再是实际限制。Speed Proxy not working? / 转速代理不工作?
Place directly adjacent to a Speed Controller. / 放置在转速控制器相邻面。State lost after schematic? / 蓝图放置后状态丢失?
Use Create 6.0.10+. Full NBT interfaces registered. / 确保使用Create 6.0.10+。Can computers communicate? / 计算机可以通信吗?
Yes — Private Signal I/O (named channels) or BUS_IN/BUS_OUT (banded). / 可以——私有信号I/O或BUS总线。📥 Installation / 安装
| Dependency / 依赖 | Version / 版本 |
|---|---|
| Minecraft | 1.21.1 |
| NeoForge | 21.1.233+ |
| Create | 6.0.10+ |
Sable is optional / Sable 为可选
- Install NeoForge + Create / 安装 NeoForge + Create
- Place
.jarinmodsfolder / 将.jar放入mods - Launch! / 启动!
🌐 Links / 链接
- GitHub: github.com/y15173334444/create-schematic-compute
- Modrinth: modrinth.com/mod/create-schematic-compute
- License / 许可证: MIT © 2026 StarryNight_Luo
⭐ If you enjoy this mod, star us on GitHub! / 喜欢请在GitHub点⭐! Unleash Create's potential with visual programming! / 用可视化编程释放机械动力的潜力!🚀
All Versions
+ Add Version### ✨ New / 新增
- 🎵 **功放电脑 + 音响 / Amplifier Computer + Speaker**(
create_schematic_compute:amplifier_computer/speaker):两个新方块接上 **CSC 混音音频引擎**——服务端排程、音符展开时烘焙层音量/声像、事件带目标时刻由客户端墙钟定点播放(2s 预播吸收服务端停顿);功放开盖屏 16 频段频谱 + 增益曲线 + 声道拆分(聚合/立体声/4.0/5.1/7.1),音响按世界位置发声、带增益/静音/红石静音。 / Two new blocks on the **CSC mixing audio engine**: server-side scheduling with layer volume/panning baked at note expansion, target-timed events placed on the client's wall clock (a 2 s pre-roll absorbs server stalls); the amplifier's lid screen shows a 16-band spectrum with a gain curve and channel split (mix / stereo / quad / 5.1 / 7.1), and the speaker voices audio at its world position with gain / mute / redstone-mute controls. - 🎹 **NBS 钢琴卷帘编辑器 / NBS Piano Roll Editor**:双击 MUSIC 节点打开——钢琴卷帘(点放/擦除/拖拽涂抹)+ 层面板 + 传输条(播放/停止/循环/速度)+ 试听 + .nbs 导入导出(v1–v5 读 / v5 写);**双样式视图**(卷帘 tick×键 / 层列 tick×层 + 底部钢琴条);**选择 + 剪贴板**(框选 / Ctrl 点选 / 复制剪切粘贴,与 OpenNBS 等社区编辑器**跨窗互贴**);**拖移搬移**(拖到新格搬移、同格改音高、选区随拖);**逐音符力度/声像/细音高**(Set 弹窗 + 悬停微调);层面板逐行自包含 + 细调弹窗 + 层重排;图标化顶栏、卷帘键位列表与谱面 1:1 对齐、层总览面板、层静音开关、导入弹窗滚动条;13 个 NBS 命令入键位系统(播放/撤销/导入导出等可绑)。 / Double-click a MUSIC node: a piano roll (place / erase / drag-paint) with a layer panel, transport bar and audition, plus .nbs import/export (v1–v5 read / v5 write); **dual views** (roll tick×key / lane tick×layer with a piano strip); **selection & clipboard** (marquee / Ctrl-click / copy-cut-paste with **cross-window pasting** into OpenNBS-style editors); **drag-to-move** (a new cell relocates, the same cell retunes, selections travel); **per-note velocity / panning / fine pitch** (Set dialog + hover micro-adjust); self-contained layer rows with a detail popup and layer reorder; an icon top bar, a roll key list aligned 1:1 with the score, a layer overview picker, per-layer mute and an import-dialog scrollbar; thirteen NBS commands join the key-binding system.
- 🎛️ **曲线双节点 / Curve duo**:AMP 力度曲线(x = 音符力度、y = 输出力度,拖点/双击加/右键删)+ 新节点 **WSHAPE 波形整形**(逐样本 LUT 骑 AudioRef 下发、起音时固化进采样,恒等曲线 = 真旁路)。 / The AMP dynamics curve (x = note velocity, y = output level) plus the new **WSHAPE wave shaper** (a per-sample LUT riding the AudioRef, baked into the sample at voice start; an identity curve is a true bypass).
- 🎛️ **新节点:与门 / New node: AND Gate**:与或门完全镜像(2 入 1 出,A、B 都 >0.5 输出 1,NaN 判假),级联可拼多输入。 / A strict mirror of OR (two ins one out, 1 only when both exceed 0.5, NaN counts false); chain gates for more inputs.
- 🎛️ **闸门 / T 触发器 / 锁存器当前态手动切换 / Manual current-state toggle**:三个时序节点的编辑区可手动拨当前态,调试更顺手。 / The three sequential nodes gain an edit-area toggle for their current state — handier for debugging.
### 🐛 Fixes / 修复
- 🐛 **NBS 编辑器实测反馈一批 / NBS editor field-feedback batch**:卷帘右键按下在空格上误放音符(改走擦除路径);右键点空白取消选择;导入换曲后速度框滞留旧值(失焦曾把旧速度写回新曲上传);钢琴条选中标记两缺陷(画序反写 + F/F# 黑白键身份颠倒,卷帘键行着色同修);导入弹窗滚轮滚动 + 真滚动条 + 文件计数;层名输入框点别处 / Esc 取消(此前滞留吃按键)。 / RMB press on blank cells placed notes (now erases); right-click on blank clears the selection; the tempo box kept the previous song's value after an import and committed it back on blur; the piano-strip selection marker hid under an inverted draw order and the F/F# black-key identity was swapped (the roll's key-row shading fixed with it); the import dialog gained wheel scrolling, a real scrollbar and a file count; the layer-name box cancels on an outside click / Esc instead of lingering and eating keystrokes.
### ⚠️ Behaviour changes / 语义变更
- 同列第二笔不再换键挪移**:同一 tick 列画第二笔时第一笔的音符原地不动,新音符落到下一个未锁定空层成和弦(没有空层自动扩一层);挪音符/改音高只走拖动手势与悬停滚轮。 / The same-column second stroke no longer relocates the first note — it stacks on the next free unlocked layer as a chord (growing the song when none is free); moving and retuning are exclusively the drag gesture and the hover wheel.
- 层「试听」钮改为静音开关**:试听只播一个音、意义有限,改为是/否静音(播放展开整层跳过;静音是编辑期状态,不随 .nbs 导出/上传)。 / The layer audition button — which only ever played one note — became a mute toggle: playback expansion skips the layer; mute is editor-side state and never rides the .nbs file or uploads.
- NBS 编辑器配色收编主题系统**:面板/按钮/悬停/网格/播放头等改走用户颜色配置(换主题即时生效),默认观感略有变化(按钮井更深、dim 文字转灰、播放头/选中统一 accent)。 / The NBS palette now rides the user colour config (theme switches apply live); defaults shift slightly — deeper button wells, grey dim text, and playhead/selection share the accent colour.
### 📦 Requirements / 依赖
- Create 6.0.10+**(必需 / required)
- Sable**(可选 / optional)
- NeoForge 21.1.233+ · Minecraft 1.21.1
### 📥 Install / 安装
1. Minecraft 1.21.1 + NeoForge 21.1.233+(或更高) / Minecraft 1.21.1 with NeoForge 21.1.233 or newer
2. 把 jar 放进
mods/,并安装 Create 6.0.10+ / Drop the jar into mods/ and install Create 6.0.10+3. 完整变更日志见 [CHANGELOG.md](https://github.com/y15173334444/create-schematic-compute/blob/main/CHANGELOG.md#v126) / Full changelog: [CHANGELOG.md](https://github.com/y15173334444/create-schematic-compute/blob/main/CHANGELOG.md#v126)
- SHA-256**
dab6835f4b8e0b16274ca06a5366196107d611f21f4e826331bc0d61a14d06b3·create-schematic-compute-1.2.6.jar
<summary><b>v1.2.5.2</b> — 修复:动力传感器扳手旋转(同轴滚转 · 点上/下保倾偏航)· 贴地放置修正 · 倒置朝下时屏幕读数翻正 · 行走时视角摇晃导致 HUD 虚像晃动 · 切换游戏语言后 HUD 文字变乱线 · 节点分类重构 · 视口裁剪 / 菜单命中 · 数控齿轮箱轴面常在 / 扳手回归官方 · 变速器过载后输出恢复 · 输出指令正反转与负行程 · 编码器清零改节点体引脚 · PID/PID_POWER 积分死区 · 频道名旧草稿回写(#10)· 去掉整图保存覆盖(#17)· 封装子图节点数据同步 · 封装子图展开状态跨玩家同步 · 参数输入框实时同步 · 封装子图顶栏合并 · 占用封装禁删 · 键位系统扩容(删除连线 + 像素编辑器动作)· 统一键鼠序列绑定 · 旧键位配置迁移 · 删节点撤销/重做恢复连线(pinId + 占用检测)· 变速器代理态显示(值盒「(代理)」+ 滚轮拒收) / Fix: Kinetic Gauge Wrench Rotation (Shaft Roll · Tilt-Preserving Yaw) · Floor Placement · Inverted Mount Text Upright · View Bobbing Wobble & Garbled HUD Text After a Language Switch · Node Category Refactor · Viewport Cull / Menu Hit · CNC Gearbox Shaft Faces Always Present / Wrench Back to Official · Transmission Output Recovers After Overload · Output-Command Forward-Reverse & Negative Travel · Encoder Reset on the Node Body · PID/PID_POWER Integral Deadband · channel-name stale-draft write-back (#10) · drop whole-graph save overwrite (#17) · sub-graph node data sync · sub-graph expansion state sync across players · live param-box sync · sub-graph top-bar merge · occupied-encapsulation delete guard · display-mode top-bar merge · display lock follows selection · smooth remote display-layout drags · key-binding system gains delete-wire and pixel-editor actions · unified sequence bindings (legacy key-binding configs migrate) · undo/redo node-delete restores wires (pinId + occupancy check) · transmission proxy display (value-box "(proxy)" + wheel refused while node-driven)</summary>
### 🔧 动力传感器扳手 / Kinetic Gauge Wrench
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🧰 **行为变更**:三语义 | ① <b>轴端面</b>(点击轴 ∥ 旋转轴)→ 同轴四态按角点序(右上→右下→左下→左上)滚转 90°,**轴不动**——对官方的有意偏离(官方端面点击会翻轴断连);② <b>点上/下</b> → 沿当前倾侧偏航 90°,屏幕保持朝上/朝下不翻面(第二处偏离);③ <b>其余面</b> → 与 Create
IWrenchable 默认逐字相同(绕所点面的轴转;facing 同轴面翻 axis_along_first)。环表提纯在 KineticGaugeStates.nextInShaftRoll/nextInYaw(纯函数),KineticGaugePlacementTest 钉死每步绕轴 90°、getClockWise 同向、4 步闭合 / ① shaft-end: roll through the four same-shaft states in corner order, 90° per step, shaft fixed (deliberate deviation — official pivots the shaft); ② Y-face: yaw staying on the current tilt (second deviation); ③ other faces verbatim Create's IWrenchable default. Rings are pure functions in KineticGaugeStates, pinned for 90° steps, getClockWise sense and 4-cycle closure. || 🐛 Y 轴滚转环序 **(bug 修复)** | 竖置轴的滚转环曾写成 NW→SW→NE→SE——第 2/4 步是 180° 对角跳(「互不重合」钉子查不出顺序错)。现改为 getClockWise 环(NW→NE→SE→SW),并由环序钉子(每步法线绕轴恰转 90°)锁死 / The vertical-shaft roll ring hopped 180° on steps 2 and 4; now a getClockWise cycle, locked by ring-order pins. |
| 🐛 横置点上/下偏航 **(bug 修复)** | ① 竖置 facing 点上/下以前只在两个
along_first 态来回 → 现沿朝下环保倾偏航(倒置屏不翻回朝上);② 四个横置朝向里有两个屏幕朝下反了 → 重排 blockstate:**W/N/E/S 全部 x=0 上仰讲台**(up-west/north/east/south),偏航四步屏幕都朝玩家。KineticGaugePlacementTest 钉死 / Vertical-facing Y-click used to toggle two states; horizontal yaw had two inverted screens. Table now gives all four horizontals an up-tilted lectern pose. || 🐛 同轴四态旋转重合 **(bug 修复)** |
up+false 与 west+false 曾同为 x=0,y=0,north+true 与 up+true 同为 x=0,y=90 —— 扳手绕轴循环里连着两步长得一样(实测「右上→右上→左下→右下」)。现同一旋转轴的 4 个状态落到 4 个互不重合的 (model,x,y)(轴 Z:(0,0)/(0,180)/(180,180)/(180,0);轴 X:y∈{90,270}×x∈{0,180}),与 Direction.getClockWise 同向;KineticGaugeStatesTest.eachShaftAxisHasFourDistinctRotations 钉死 / Two states used to share x=0,y=0 (and another pair x=0,y=90), so a wrench roll around the shaft stuttered. Each shaft axis now maps its 4 states to 4 distinct (model,x,y) triples, matching getClockWise; pinned by eachShaftAxisHasFourDistinctRotations. || 🧹 清理 |
wrenchAction 分类纯函数与中版的刚体反查(rigidSideTarget/isDisplayFace/isSteepLook)删除;环表提纯为 KineticGaugeStates 纯函数并补环序钉子 / The classifier and the interim rigid-lookup helpers are gone; the rings are pure functions with order pins. |### 🧭 贴地/贴顶放置 / Floor & Ceiling Placement
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🧭 **放置重排** |
facing **恒为水平**(贴墙=点击面,贴地/贴顶=水平正对玩家,不再因陡视变 up/down——2 态换不出 4 偏航角);横置/竖置由 axis_along_first 承担:平视=横置讲台,**陡视(nearestLooking 轴竖直)=竖直轴平板**;有结构轴时优先对齐(RotatedPillarKineticBlock.getPreferredAxis)。俯仰判定用 nearest-looking 而非 getXRot——Sable 会把 orderedByNearest mixin 到子世界局部系,世界俯仰角在旋转结构上会错(2026-09 实机) / Facing is always horizontal on placement; lectern vs vertical-shaft is the steep-look gate on axis_along_first; structure axis preferred when present; nearest-looking instead of world pitch for Sable-rotated structures. |### 🖥️ 倒置屏幕读数 / Inverted Mount Readout
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| 🙃 倒置/朝下读数翻正 **(bug 修复)** |
facing=DOWN 走 blockstate x:180,蓝屏正确朝下,但动态读数随整机一起颠倒(倒置挂墙/朝下时上下翻转)。渲染入口改为 KineticGaugeStates.displayPanel:x:180 时把字形右/上在面板平面内再转 180°(法线不动、右手系保持),从屏幕外侧看文字恢复正立;12 个状态的世界空间文字上方向 Y>0 由 KineticGaugePlacementTest 钉死 / facing=DOWN applies blockstate x:180, so the blue face correctly points down but the dynamic readout flipped with the whole unit. Rendering now goes through KineticGaugeStates.displayPanel, which spins the glyph right/up another 180° in the panel plane on x:180 (normal untouched, still right-handed) so text reads upright from outside. All 12 states' world-space text-up Y>0 is pinned in KineticGaugePlacementTest. |### 🔌 编码器清零改节点体引脚 / Encoder Reset on the Node Body
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🔌 **行为变更** | ENCODER 的清零从**编辑区参数**改为**节点体输入引脚**(电平触发语义不变:拉高清零、持续拉高保持归零;未接线 = 0)。旧连线 pinId 本就是索引
"0",V5→V6 迁移显式钉到 0 号输入并清掉过期 reset 参数 / The ENCODER reset moves from an edit-area parameter to a **body input pin** (level-triggered semantics unchanged; unwired = 0). Old wires already carry pinId "0"; the V5→V6 migration pins them to input 0 and drops the stale reset param. |### 🎛️ PID / PID_POWER 积分死区 / Integral Deadband
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🎛️ **积分死区 deadband** | 新增可编辑/可连线参数
deadband(默认 **0.001**):|err|≤deadband 时积分**保持**——不增长也不清除;|err|>deadband 时正常积分。取代旧的「|err|≤0.001 清零」语义(近零误差不再冲掉 I 项)。PID 参数表变为 kp,ki,kd,scale,ilimit,deadband,PID_POWER 为 kp,ki,kd,ilimit,deadband。**V5→V6 迁移**(与编码器清零同一步)自动为旧节点补默认 0.001(用户已设值含 0 不覆盖),递归处理封装子图。测试:PidDeadbandTest / New editable/wire-overridable deadband param (default **0.001**): when \|err\| ≤ deadband the integral **holds** (neither grows nor clears); outside it integrates normally — replacing the old "clear when \|err\| ≤ 0.001" so a near-zero error no longer wipes the I term. PID params become kp,ki,kd,scale,ilimit,deadband; PID_POWER kp,ki,kd,ilimit,deadband. The **V5→V6 migration** (same step as the encoder reset pin) fills the default 0.001 on legacy nodes (user-set values incl. 0 survive), recursing into sub-graphs. |### 🎛️ 输出指令正/反转与负行程 / Output-Command Forward-Reverse & Negative Travel
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🐛 负数恒无效 **(bug 修复)** |
MotionQuota.of 用 Math.max(0f, amount) 把负行程打成 0 配额 → 负数 ROTATE/MOVE 当帧完成、形同假值。现行程量取 Math.abs,符号只表示方向 / Negative ROTATE/MOVE quotas were clamped to 0 and completed instantly. Travel is now Math.abs; the sign only encodes direction. || 🔄 负行程 = 反转 | ROTATE/MOVE 入栈快照的负数值 → 执行期间输出面
getRotationSpeedModifier = -1(官方 Gearshift 反转语义),编码器积分/瞬时速度同步取输出符号;WAIT / 空闲 / CLUTCH 常接合不反转 / A snapshotted negative ROTATE/MOVE runs the output face at modifier -1 (official Gearshift reverse) and the encoder books the output sign; WAIT / idle / standing CLUTCH never reverse. || 🔘 正/反转按钮 | 位移 / 旋转 / 目标转速 / 转速控制编辑区新增「正转/反转」独立
rev 开关(**不改数值 EditBox**——数值可被引脚覆盖):MOVE/ROTATE 在入栈时对快照值取反;TX_OUT/SPEED_CTRL 在求值结果上取反(与 SPEED_CTRL 的 dir 引脚 XOR)/ Independent rev toggle on Move/Rotate/Target RPM/Speed Control that does **not** edit the value EditBox (the value is wire-overridable). MOVE/ROTATE negate the snapshotted value at enqueue; TX_OUT/SPEED_CTRL negate the eval result (XOR with SPEED_CTRL's dir pin). |### 🔧 数控齿轮箱扳手回归官方 / CNC Gearbox Wrench Back to Official
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🧹 **行为变更** | 扳手点轴端面「翻转输入端」与 action bar 字幕(
input face: …)已移除——输入/输出面由放置感知 + autoSenseInputFace 自动识别(官方从动件同款)。任意面扳手走 IWrenchable 默认旋转;disengageForFlip / resyncKineticsAfterFlip 一并删除 / Wrench-on-end-face "flip input end" and its action-bar subtitle are gone — input/output faces are auto-sensed (placement + autoSenseInputFace), like a vanilla driven member. Wrenching any face is the official IWrenchable rotate; disengageForFlip / resyncKineticsAfterFlip deleted with it. |### 🎛️ 变速器过载后输出不恢复 / Transmission Output Stays Dead After Overload
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| 🐛 过载拆输出 **(bug 修复)** | 输出端负载超容 → 整网
overStressed,官方 getSpeed() 恒 0。cleanOrphanedKineticState 用 getSpeed() 判源死活,把仍在转的源打成失速,**每 tick detach** 拆掉输出侧子树(「过载后自动断开应力」)。输入端应力恢复后 getSpeed() 变回非 0,预检早退认为健康,**不会接回**已拆下游;只有改转速触发 updateTargetRotation 全量拆建才恢复(「改转速才可以刷新输出」)。现源健康/幻影速判定改用 getTheoreticalSpeed()(= speed 字段,官方 validateKinetics 同款)/ Output load past capacity trips network-wide overStressed, and official getSpeed() is hard-zeroed. The orphaned-state pre-check used getSpeed() for source health, so a live source looked dead and every tick detached, tearing down the output subtree. Once capacity recovered the pre-check saw a spinning source and early-returned — never re-attaching what it tore down; only a target change's full rebuild did. Health/phantom checks now use getTheoreticalSpeed() (the raw field, matching official validateKinetics). |### ⚙️ 数控齿轮箱输出端轴面常在 / CNC Gearbox Output Shaft Face Always Present
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| 🐛 放轴不吸附 **(bug 修复)** | 无指令/空闲自动分离时
hasShaftTowards 把输出端轴面整段否掉——Create 的放置吸附(RotatedPillarKineticBlock.getPreferredAxis)与传动耦合(RotationPropagator 要求双方轴面)都认它,贴上去的传动轴**不吸、不连**。现改为官方 AbstractEncasedShaftBlock 同款:两端轴面恒在(只看轴向);离合隔离改走官方 SplitShaftBlockEntity.getRotationSpeedModifier(输出面分离时 0)+ 既有 detach/attachKinetics。BE 基类升为 SplitShaftBlockEntity / While idle the clutch used to return false from hasShaftTowards on the output face, which Create's placement snap and axis coupling both consult — shafts placed against the block would not attach. Now axis-only like official AbstractEncasedShaftBlock; isolation moves to official SplitShaftBlockEntity.getRotationSpeedModifier (0 on the output face while disengaged) plus the existing detach/attachKinetics. The BE base class is now SplitShaftBlockEntity. |### 🗂️ 节点分类与方块名单 / Node Categories & Per-Block Allowances
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🗂️ 分类 14→21 **(UI 变更)** | 节点菜单分组重划:
input 拆为 input_ctrl/input_view/input_motion/input_pose,sequential 拆为 sequential_acc/sequential_state;新增 transmission/speed/radar。ROUND 归 math_basic,SQRT/LN/LOG/EXP 移出三角,POSE_CONVERT/SPLIT 归 input_pose。 || 📋 名单机制 | 10 处逐节点枚举改为
NodeCategory + NodeAllowance(分类白名单 + 类内黑名单);新增节点落入已允许分类即自动可用。 || ➕ 能力补齐 | 程序计算机 / 数控齿轮箱净增 23 项:基础运算 11(
ADD…ROUND)、比较与 OR 6、FORMULA/INTERP、控制类 4(PID/PID_POWER/CLAMP/MAP)。传感器净增 POSE_CONVERT/SPLIT。 || ➖ 能力收紧 | 蓝图计算机失去
STRESS/RPM(对齐文档「仅动力宿主图」);已有图中节点不删除,仅不能新建。 || 🧪 回归 |
NodeAllowanceMigrationTest:覆盖比对 + 允许集差异必须等于声明变更 + 例外最小化。 |### 🖱️ 图编辑器命中与裁剪 / Graph Editor Hit & Cull
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| 🐛 添加节点菜单命中 **(bug 修复)** | 菜单面板(含压在顶栏上的顶部)内点击归菜单,不再被顶栏改名框/设置钮误吞;菜单改为最后渲染、盖在顶栏上,与命中顺序一致。 |
| 🐛 展开节点视口裁剪 **(bug 修复)** | 节点体滚出屏幕、编辑区仍在画面时不再整节点剔除:体/编辑区分别判交;展开高度取有/无
EditState 的较大值(FORMULA MLE 动态行、ACCUMULATOR 动态字段)。 |### 🖥️ HUD 虚像与视角摇晃 / HUD Virtual Image & View Bobbing
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| 🚶 行走时虚像晃动 **(bug 修复)** | Minecraft 把
bobHurt/bobView 写进一个 PoseStack 后**乘进投影矩阵**(GameRenderer.renderLevel: matrix4f.mul(posestack.last().pose())),它作用于 view space,从不进入 BER 的 poseStack。行走时 HUD 虚像内容随之晃动(关闭视频设置里的「视角摇晃」即完全消失,已实测确认)。数值诊断(ViewBobWobbleDiagTest,16 相位采样整圈步态)定位根因:深度锚定在预 bob 坐标上做,GPU 侧把 bob 乘回顶点时,bob 的视空间平移按**玻璃深度**(近,~3 格)做透视除 → 虚像按近物视差随玻璃晃动(0.038 NDC ≈ 1.3°),与设计文档 §9.1「无限远聚焦」矛盾。修复(用户 2026-09-19 选定方案 C「远处虚像」):锚定改为沿 **bob 后**射线(MonitorClipMath.anchoredEmit,先乘 bob 再锚定,发射时预乘 viewRotInv·B⁻¹ 让 GPU 的 bob 恰好抵消)——屏幕位置保持远处画布投影(平移视差按 D+gz 除,小 30+ 倍),只剩与全世界一致的旋转分量(0.0113 NDC,共形下限 0.0123);玩家屏幕定位遮罩的投影眼改为**视觉眼** B⁻¹·0(bob 后视线束在预 bob 视空间的汇聚点)——裁剪窗口与玻璃的落差精确为 **0.0000**,窗口贴住玻璃;深度仍落玻璃平面,遮挡关系不变。文字字形路径(anchorTextVertex)同步修改,锚定数学迁入 MonitorClipMath 纯函数 / Minecraft folds bob into the PROJECTION matrix, acting in view space; it never reaches the BER poseStack — and the HUD virtual-image content wobbled while walking (disabling "View Bobbing" removes it entirely, confirmed). Numeric diagnosis (ViewBobWobbleDiagTest, 16-phase sampling of a full gait cycle) found the root cause: anchoring in pre-bob coords makes the GPU-side bob translation perspective-divide at the **glass depth** (near, ~3 blocks) → the image swayed with near parallax, glued to the glass (0.038 NDC ≈ 1.3°), contradicting design-doc §9.1 infinite focus. Fix (user-chosen option C, "far virtual image"): anchor along the **post-bob** ray (MonitorClipMath.anchoredEmit — apply bob first, then anchor; emit premultiplied by viewRotInv·B⁻¹ so the GPU's bob lands exactly on the desired view position) — the screen position keeps the far-canvas projection (translation parallax divides at D+gz, 30+× steadier) and only the world-rotation sway remains (0.0113 NDC, conformal floor 0.0123); the player-screen mask now projects from the **visual eye** B⁻¹·0 (where the bobed view rays converge) — the clip window tracks the glass with a gap of exactly **0.0000**; depth still lands on the glass plane, occlusion unchanged. The text-glyph path (anchorTextVertex) is fixed the same way, and the anchoring math moved into MonitorClipMath pure functions. |> **设计决策(用户 2026-09-19 选定,钉在
ViewBobWobbleDiagTest / ViewBobAnchorTest)**> **Design decisions (user-chosen 2026-09-19, pinned in ViewBobWobbleDiagTest / ViewBobAnchorTest)**
> 1. 虚像内容 = 远处物体:行走时只随全世界一起转(bob 的旋转分量,远物参照 0.0123 NDC),
> bob 平移分量必须消失。开发中曾先尝试只把遮罩眼挪到
+B·0,实测否决——遮罩眼与> 锚定方式必须**配对**(沿 bob 后射线锚定 ↔ 视觉眼
B⁻¹·0;预 bob 锚定 ↔ 原点眼),>
+B·0 与任何锚定都不封闭(Y 向窗口滑差 0.046 NDC),且它没触及内容摆动的根因。> The virtual image behaves as a far object: only the world-rotation sway remains; the
> mask eye must be PAIRED with the anchoring (post-bob anchor ↔ visual eye B⁻¹·0;
> pre-bob anchor ↔ the origin eye) — the earlier +B·0 attempt closed with nothing
> (Y window slide 0.046 NDC) and never touched the root cause.
> 2. 「补偿更差 3.7 倍」的旧测量是稻草人对比:拿静态内容对比摇晃玻璃,量到的本就是
> 玻璃自己的晃动,不是虚像的性质。
> The old "compensating drifts 3.7× more" measurement was a strawman: static content
> measured against a bobbing glass captures the glass's own motion, not the image's.
> 3. 站定(amp=0)时 B = I,路径与修复前逐字节一致。
> Standing still (amp=0) keeps bob the identity: the path is unchanged.
> **已知范围外 / Known limitation**: 同一 PoseStack 里的
bobHurt(受伤抖动)依赖> GameRenderer 私有的
hurtTime,无法从外部重建,受伤瞬间那一下抖动不在本次修复范围> (持续不到 1 秒、幅度小)。
>
bobHurt sits in the same PoseStack but depends on GameRenderer's private hurtTime> and cannot be rebuilt from outside; that brief hurt wobble is out of scope.
### 🔤 手动字形与语言切换 / Manual Glyphs & Language Switch
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| 🔤 切语言后 HUD 文字变乱线 **(bug 修复)** | 手动字形路径(不走 MultiBufferSource,直接读
BakedGlyph 几何/UV 生成顶点)曾把取到的 FontSet 与字形 RenderType 各缓存一份,且只判 == null(永不刷新)。主界面切换游戏语言(或任何资源重载)时,旧缓存的字形几何与 UV 仍指向已被替换的 atlas,文字画成一团乱线。修复粒度是 **FontSet 本身**:getFontSet 现在**每次实取**(它只是 this.fonts.apply(id) 一次 map 查找,成本可忽略);字形 RenderType 缓存绑定**取到的 FontSet 实例** / The manual-glyph path cached the fetched FontSet and the glyph RenderType on == null (never refreshed). A language switch / reload replaces the atlas, so the stale glyph geometry and UV drew the text as a tangle of lines. Fixed at **FontSet granularity**: getFontSet is now **fetched every time** (it is just this.fonts.apply(id), a map lookup — negligible), and the glyph RenderType cache is bound to the **fetched FontSet instance**. |> **为什么不能按
Font 实例做缓存守卫(第一版踩的坑,已改正)**> **Why the cache guard must not key on the
Font instance (the first version's mistake)**>
Minecraft.font 只在构造器赋值一次(this.font = this.fontManager.createFont()),> 注册为重载监听器的是
fontManager —— 所以语言切换时 **Font 实例不变**,被重建的是> FontManager 内部的
FontSet(FontManager.reload:fontSets.clear() 后 new FontSet,> 旧对象已
close())。绑 Font 的守卫永远不会再次触发,等于没修。>
Minecraft.font is assigned once in the constructor, and it is fontManager — not font> — that is registered as the reload listener. A language switch therefore leaves the Font
> instance untouched and rebuilds the
FontSet inside FontManager (fontSets.clear() then>
new FontSet; the old one is closed). A Font-bound guard never fires again.> 附注:
hudTextRenderType 旧注释写着"资源重载后自动更新",实现却是 if (== null)> —— 注释与实现不符,已按代码实际行为改正 / The old comment claimed "refreshed after a
> resource reload" while the code was
if (== null); corrected.> **无回归测试 / No regression test**: 该修复依赖 Minecraft 的资源重载(切换语言),
> 沙箱内无法驱动,故未钉单测 —— 需游戏内实测:主菜单切换语言 → 进世界看 HUD 文字。
> This fix depends on Minecraft's resource reload (a language switch), which cannot be
> driven in the sandbox, so it is not pinned by a unit test — verify in game: switch the
> language in the main menu, then enter a world and look at the HUD text.
### ✨ 删节点撤销/重做恢复连线 / Node-Delete Undo-Redo Wire Restore
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| ✨ **删节点撤销/重做恢复连线(含 pinId 占用检测)** | 删节点(X 单删 / Delete 多选,含多选节点间互连)原先只入栈
REMOVE_NODE,removeNode 剪掉的连线一去不返——Ctrl+Z 只回来节点空壳。现删除前把触及被删节点的连线(去重)逐条记为**携带稳定 pinId 的 REMOVE_CONN**(同批 + 同步协作者),批次逆序撤销 = 先 ADD_NODE 恢复节点、再按 **pinId** 接线;ADD_CONN 恢复时走 addConnectionWithPinIds:**pinId 解析不到或输入脚已被占用则静默跳过**(不覆盖现有线)。pinId 编入 op stringValue(协议零扩面);删线/连线创建同步携带 pinId,普通删线撤销同样受益。测试:GraphOpTest(打包/解析)+ NodeGraphTest(解析、占用跳过、删后按 pinId 回接、按 pinId 删线)/ Deleting a node (X / Delete, including wires between multi-selected nodes) used to record only REMOVE_NODE — removeNode pruned the wires and Ctrl+Z brought back a bare node. Wires touching the doomed set are now recorded first (de-duplicated) as **pinId-carrying REMOVE_CONN** ops in the same undo batch and synced to collaborators; the reverse batch restores nodes first, then rewires **by pinId**. ADD_CONN restore goes through addConnectionWithPinIds: **unresolvable pinId or occupied input pin is skipped silently** (never clobbers). PinIds ride in the op's stringValue (no wire-format change); wire create/delete carry pinIds too, so ordinary wire-delete undo benefits as well. |### 🛠️ 图编辑器与多人协作 / Graph Editor & Collaboration
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🐛 **#10 频道名旧草稿回写 (bug 修复)** | 输入框聚焦时面板重建会保留改名前草稿(有意为之,不打断打字),但随后防抖把旧文本当作新改名写回服务端,把权威名顶回去。现引入
busNameUserDirty:**只有用户敲键**才标脏;程序装入(初值 / 保留草稿 / 远端刷新)一律不得提交。非 dirty 的差异在失焦/关屏/编译时丢弃并提示「已丢弃未确认的频道名草稿」。守卫收在 GraphBusEditor.shouldCommitBusName 一处 / Focused busBox drafts preserved across panel rebuilds used to be re-committed by the debounce, overwriting the authoritative name. Now only real keystrokes set busNameUserDirty; programmatic loads never commit. Stale drafts are discarded with a chat hint. || 🐛 **#17 整图保存覆盖 (bug 修复)** | 编译/保存原先是
BlueprintSavePacket 整图 NBT 整体替换服务端图——客户端副本一旧就把服务端回退,静默冲掉并发编辑。现改为 GraphSaveRequestPacket(只带坐标):服务端在**自己的权威图**上执行编译复位(GATE/T_FLIPFLOP/LATCH params[1]=params[0],含子图)+ 环检测 + 落盘 + 全量同步。BlueprintSavePacket 与孤儿 loadGraphFromBytes / loadEditorTag 链一并退役删除 / Save/compile used to replace the server graph with the client snapshot. It is now a position-only request; the server runs compile semantics on its own graph. BlueprintSavePacket and the orphaned loadGraphFromBytes / loadEditorTag chain are retired. || 🐛 **封装子图节点数据同步 (bug 修复)** | 子图内编辑公式时,响应器用
host.getGraph().findNode(主图)找节点——找不到就静默 return,**SET_FORMULA 根本不发送**,本地框却仍显示输入;两端因此各显示各的公式/参数。另:远端 SET_PARAM 刷新用 fieldParamIndices.get(paramIndex) 把字段位次当下标,fi==-1(busBox 槽)时 fields.get(-1) 抛 IOOBE 中断刷新;UI 刷新未校验 ownerNodeId 作用域,子图/主图同 id 互相污染。现改为 ed.getGraph() + indexOf 反查 + 同作用域才刷 UI / Sub-graph formula edits silently dropped (wrong graph lookup), remote SET_PARAM UI refresh crashed on field-slot reverse lookup, and UI refresh ignored scope. || 🐛 **封装子图展开状态跨玩家同步 (bug 修复)** | 远端
EXPAND_NODE/COLLAPSE_NODE 把图数据字段 n.expanded(随 NBT 持久化,也是**进入子图时 init 恢复的唯一依据**)一起门在 sameScope 里——玩家停在主图时收到的子图展开/折叠 op 被整条忽略,随后进入子图就恢复出过期状态(别人展开的显示折叠、已折叠的显示展开)。现拆**数据半边**(n.expanded 恒应用到自己子图副本)与 **UI 半边**(展开集合/编辑状态仍仅同作用域) / Cross-scope remote expand/collapse ops left the local sub-graph copy's n.expanded stale (the flag was gated behind the same-scope UI guard), so entering the sub-graph restored the wrong expansion state. The data half now always applies; the UI half stays scope-gated. || 🐛 **参数输入框实时同步 (bug 修复)** | ① 远端只回显
ff3(float),与正在输入的字符串不一致;② 清空/未完成输入 parseFloat 失败被吞、**不发包**,对端停在默认值;③ ff3 用 Math.round(float)(返回 int),\|v\|>2147483.647 时饱和成 Integer.MAX_VALUE,大数被压成 2147483.x。现:SET_PARAM 携带草稿原文(含空串)驱动对端 EditBox 显示(本端聚焦时不覆盖);空/半截输入保持上次权威值只同步草稿;**参数值不再进编辑状态指纹**(值一变就 createEditState+ff3 会把 000 刷成 0.0、大数刷成科学计数);**失焦才归位**为 ff3 规范格式并同步给对端,不改权威值;ff3 改 double 舍入;OpExecutor 对值相同的 SET_PARAM 跳过 bumpGeneration / Peers showed ff3(float) instead of the in-progress string; empty/partial input never shipped; ff3's Math.round(float) saturated large magnitudes. SET_PARAM now carries the raw draft (incl. clear); empty input keeps the last committed number; param *values* are out of the edit-state fingerprint so drafts survive rebuilds; blur normalizes to ff3 without changing the value; OpExecutor skips bumpGeneration when unchanged. || 🐛 **封装子图顶栏合并 (bug 修复)** | 子图的「封装编辑模式」横条(y=2..22)与每帧都画的顶栏重叠、右上 Back 按钮与设置按钮同槽互盖,且 Back 渲染在 y=4、命中却在
TOP_BAR_H+2(渲染/命中脱节,点画的按钮没反应)。现两作用域合并为**同一根顶栏**(同底色同高度):主图 = 名称 + 设置;子图 = 模式标识「◈ 封装编辑模式 ◈ (n/N)」(超限红色 ⚠ + 提示放得下才画)+ **Back 占用设置按钮的同一槽位**(渲染/命中几何一致);子图隐藏图名框并在进入时交出焦点 / The sub-graph mode strip (y=2..22) overlapped the always-drawn top bar, the Back button collided with Settings, and Back's render (y=4) and hit region (TOP_BAR_H+2) diverged. Both scopes now share **one top bar**: main = name + settings; sub = mode indicator (count / over-limit) + **Back in the settings slot** with matching render/hit geometry; the name box hides in the sub-graph and releases focus on entry. || 🐛 **占用封装禁删 (bug 修复)** | 主图按 X(悬停删除)/ DEL(批量删除)可以直接删除**有玩家正在其子图内编辑**的封装节点——对端的编辑器被连人带图拽出来。现删除前经
GraphPresenceTracker.encapOccupied 判定(只认节点编辑模式 presence):占用则跳过/拒绝并给动作栏提示「无法删除:该封装内有玩家正在编辑」。与节点软锁同为建议性 presence 守卫(服务端对 presence 是纯中继);批量删除时占用封装跳过、其余照删 / Pressing X (hover-delete) or DEL (bulk delete) on the main graph could delete an encapsulation **while players were editing inside its sub-graph**, yanking their editor out. Deletion now consults GraphPresenceTracker.encapOccupied (node-editor-mode presence only): occupied encapsulations are refused/skipped with an action-bar hint. Same advisory presence trust level as the node soft lock (the server merely relays presence); in bulk deletes only the occupied ones are skipped. || 🐛 **显示布局锁跟随选择 (bug 修复)** | 显示布局模式的软锁只有**拖动**才生效、松手即解锁——但本端选择框还在,队友看到的是「无锁可抢」,双方可同时选中/抢占同一元素。现选中元素经 presence
selectedNodeId 上报,锁判定改为拖拽 id 或选中 id 任一命中即锁(与节点模式「选中 = 软锁」语义一致);mode 1 时节点图字段(选择/多选/连线拖拽)一律置空,节点图锁列表叠加层过滤 mode 1——显示元素 id 不再以假锁污染相同 id 的节点图节点;协作叠加层的软锁描边同步改为拖拽**或**选中即常驻显示(此前只画拖拽,选中占锁在队友屏幕上不可见)/ The collaboration overlay's lock outline also renders while merely selected (it previously drew only during a drag, making a selection-held lock invisible to teammates); The display-layout soft lock only applied WHILE dragging and released on mouse-up, yet the local selection box stayed up — teammates saw a grabbable element and both sides could claim the same one. The selected element now rides presence selectedNodeId; the lock hits on dragged OR selected id (matching the node editor's selection-lock semantics). Node-graph fields are zeroed in mode 1 and the node lock overlay filters mode 1, so a display element id can no longer phantom-lock a same-id graph node. || 🧹 **显示布局远端拖拽平滑 (行为变更)** | 节点图远端拖拽有 smoothstep 插值(remote* 字段 + 每帧推进),显示布局的
SET_DISPLAY_LAYOUT 却直接落地坐标——队友拖组件在别人屏幕上一跳一跳。现对齐节点模式:位置变化超阈值(归一化 0.005)时启动插值(GraphNode 新增 layoutLerpT/layoutStart*/layoutTarget*,OpExecutor 在 animateMoves 时置起点/目标),客户端每帧推进 layoutX/Y 并在插值期间强制重建元素缓存(插值不 bump 代际,缓存不强制重建会吞掉动画);缩放/旋转不插值。监视器以 100ms 节流流式发送,多帧插值让远端观感连续 / Remote display-layout drags used to land coordinates instantly and looked jumpy on other clients, while the node graph has smoothstep interpolation. SET_DISPLAY_LAYOUT now starts the interpolation past a normalized 0.005 threshold (new layoutLerpT/layoutStart*/layoutTarget* on GraphNode, armed by OpExecutor under animateMoves), the client advances layoutX/Y per frame and force-rebuilds the element cache while animating (a lerp doesn't bump the generation); scale/rotation don't lerp. With the monitor's 100ms throttled stream, remote motion reads as continuous. || 🧹 **显示布局模式并入合并顶栏 (行为变更)** | 显示器显示布局模式原在顶栏下方自绘一条工具条(
< 编辑 / 设置 / S·R)。现并入合并顶栏(与主图/封装子图同一 chrome):左 = 「◈ 显示布局编辑 ◈」+ 选中元素的 S/R 内联编辑,右 = 设置(面板开关)+ 返回两枚 46 宽按钮;渲染与命中几何一致。旧工具条占位行收回——显示区与图层面板整体上移,可视画布更高 / The monitor display-layout mode used to draw its own strip below the top bar (< Graph / Settings / S·R). It is now part of the merged top bar (same chrome as the main graph / encapsulation sub-graph): left = 「◈ Display Layout Edit ◈」+ the selected element's S/R inline editors, right = Settings (panel toggle) and Back as two 46-wide buttons with matching render/hit geometry. The old strip's reserved row is reclaimed — the display area and the layer panel move up, giving a taller canvas. |### ⌨️ 键位系统 / Key Bindings
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🎛️ **键位系统扩容:删除连线 + 像素编辑器 (行为变更)** | 键位设置系统新增 11 个可绑定动作:① **删除连线**(默认 W,悬停连线按键即删;原 Tab+左键 组合保留);② 像素编辑器的 画笔(B)/橡皮(E)/填充(F)/取色(I)/直线(L)/矩形(R)/抓手(H)/网格(G)/笔刷变小([)/变大(]) 全部改走共享键位系统,出厂键与旧硬编码逐项一致(唯一例外:[ / ] 的默认键取 GLFW 真值 91/93——旧硬编码的 219/221 是 Windows VK 码,经 GLFW keyPressed 永不命中,即 [ / ] 笔刷快捷键借此首次真正可用);1..7 按轨道顺序选工具保持固定。冲突规则(等长全同必拒等)覆盖全部新动作,设置界面即时生效;**键位升级为统一序列模型(键鼠交错)**——每个动作只有一条触发序列,**步骤既可以是按键也可以是鼠标点击**,设置里直接录入任意交错队列:点键帽追加键步、点鼠标键把按钮加入队列、**再次点击移出**(预览行实时显示整条队列,如「Tab → 左键 → A → 右键」),「确定绑定」整条提交;引擎分纯键域/混合域独立推进——键步 keyPressed 推进、鼠标步点击推进,任一事件完成即触发,纯右键=单鼠标步、Ctrl+Z=纯键步、Tab → 左键=出厂删线组合,与框选 Tab 键序跨域并存;**上下文菜单恢复键序触发**(按绑定键在光标处打开,且吞掉开菜单键的字符——搜索输入框不再吃到这部分输入;吞字符标志在下一按键事件先行作废、不滞留误吞;菜单打开时引擎不喂键——模态菜单持有键盘,搜索框打字不再误触动作);**删除连线出厂即恢复老组合 Tab+左键**(W 退役)——组合的键盘半边由混合域缓冲推进(Tab 按键触发框选的同时为组合入混合缓冲,事件被引擎消费),与框选键 Tab 的纯键序分域并存、互不清理;**平移 = 按住抓图组合键**:绑定单键后按住它移动鼠标即拖图、成为唯一触发(绑键后左键拖动停用;出厂未绑默认左键拖动;panByKey 与 mouseMoved 物理键态轮询保证松键即停、切屏/失焦不卡死);纯鼠标与组合可共享同一按钮(出厂 PAN 左键拖动 + 删线 Tab+左键 并存),同钮冲突经前缀歧义校验——等长全同对与修饰 ⊆ 前缀对必拒,修饰可区分的不等长对可共存(如 Ctrl+左键 与 左键→右键 各自只在己方修饰态命中);**旧配置迁移**——旧版保存从不写标记,配置新增
editorKeys.format=2 标记用于新表;加载时无标记不再整表回出厂:seq 键序值原样保留(历史脏数据——早期构建未初始化的鼠标槽默认 0=左键并写盘、设置里一堆「/ 左键」的根源——只在 .mouse 鼠标槽字段,读取时忽略、保存时移除并写回标记);冲突校验:键序前缀歧义拒绝、PAN 抓图键对所有序列的键步独占 / 像素编辑器操作指南的键位文案改为**动态读取当前绑定**(模板 + EditorKeys.seqText,重绑后指南同步;模板必须走 I18n.get(key, args...) 带参重载——无参重载对 %s 模板先零参 format,整行渲染成 "Format error: …"),/ Conflict rules cover every new action and the settings tab applies them live; **the bindings upgrade to the unified sequence model (interleaved key+mouse)** - each action holds ONE trigger sequence whose steps may be KEY presses or MOUSE clicks; the settings record arbitrary interleaved queues: keycap clicks append key steps, a mouse-chip click adds the button and a second click removes it (the preview line shows the whole queue live, "Tab → left-click → A → right-click"), and Bind commits it wholesale; the engine advances two independent domains - key steps via keyPressed, mouse steps via clicks, fired by whichever event completes them (a bare right-click = a single mouse step, Ctrl+Z = a pure key sequence, Tab → left-click = the factory wire chord coexisting cross-domain with the box-select Tab sequence); **the context menu regains its key trigger** (opens at the cursor on the bound key, swallowing the opening key's character so the search box never eats that input - the swallow flag is voided on the next key event so it never lingers; the engine is not fed while the menu is open - the modal menu owns the keyboard, so typing in the search box can no longer mis-fire actions); **delete-wire ships as the legacy Tab+left-click chord again** (W retired) - a combo's keyboard half advances through the mixed-domain buffer (the Tab press fires box-select while arming the chord, the key event consumed by the engine), coexisting with the box-select Tab sequence across independent domains; **pan = the hold-grab combo**: bind one key, hold it and move the mouse to drag the canvas as the only trigger (button-drag panning disabled while bound; unbound by factory with left-drag as the default; panByKey plus a physical-key poll in mouseMoved guarantee release-ends-it and no stuck pan across screen switches or focus loss); a plain and a combo may share one button (factory: PAN left-drag + the wire Tab+left chord coexist), same-button clashes go through the prefix-ambiguity check - equal-length all-equal pairs and mods-contained prefixes are refused, modifier-distinguishable pairs coexist (Ctrl+left-click vs left-click → right-click each fire only in their own modifier state); **legacy config migration** - the old save() never wrote a marker; configs now carry an editorKeys.format=2 marker, and a marker-less table no longer resets wholesale: its seq values carry over verbatim, while the historical dirty data (early builds' uninitialized mouse slots defaulting to 0 = left button leaking into saves - the source of the screenshot's pile of "/ left-click" rows) lived only in the .mouse slot fields, which are ignored on load and removed on save with the marker written back; conflict checks: key-prefix ambiguity refused, PAN's grab key exclusive against the key steps of every sequence; the pixel editor's guide popup now reads its key text **live from the current bindings** (templates + EditorKeys.seqText, staying in sync after rebinds; the templates go through the parameterized I18n.get(key, args...) - the no-arg overload zero-arg-formats a %s template first and renders "Format error: ..."); The binding system gains 11 bindable actions: ① **Delete Wire** (default W, press on a hovered wire; the Tab+click chord stays); ② the pixel editor's Brush(B)/Eraser(E)/Fill(F)/Eyedropper(I)/Line(L)/Rect(R)/Hand(H)/Grid(G)/brush Smaller([)/Bigger()] all move to the shared binding system with factory keys identical to the old hardcodes (one exception: [ / ] default to the true GLFW codes 91/93 - the old hardcode's 219/221 were Windows VK codes that GLFW's keyPressed never delivers, so those shortcuts become functional for the first time); the 1..7 rail-order picks stay fixed. Conflict rules cover every new action and the settings tab applies them live. |### 🎛️ 变速器代理态显示 / Transmission Proxy State
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🎛️ **变速器代理态显示 (行为变更)** | 可编程变速器此前无论目标来自节点图还是滚轮值盒,值盒都显示滚轮值——节点控制时玩家盯着的是一个**不生效的数字**,而滚轮照改(改完立刻被图覆盖,谁说了算看不出来)。现引入**代理态**:图运行且图中存在
TX_OUT(存储序首个;该规则收敛到 NodeGraph.firstNodeIdOfType,**代理态判定与目标取值同处发生**,避免两条手写遍历漂移成「盒里写(代理)、实际听滚轮」的死守卫)。此时 ① 值盒显示「**已应用目标 (代理)**」——取 CscTxApplied(已同步的生效值),不取滚轮值、也不新增"节点意图值"字段;两种态都取**绝对值**(正负号是"以输出面为参考"的另一套语义,不混进这个格子);② 滚轮/右键**拒收输入**,走 Create 自带的双边闸门 acceptsValueSettings(客户端输入 ValueSettingsInputHandler:82、服务端收包 ValueSettingsPacket:60、剪贴板读写 ValueSettingsBehaviour:57-69 三处真检查——第三处顺带堵住"用剪贴板把滚轮值灌回来"的旁路),setValueSettings 另做防御性早退;③ 悬停提示第一行改说「目标转速 · 由节点控制」(Create 硬编码的第二行「按住以编辑」删不掉,故由第一行纠正)。代理态由**服务端判定**并随方块实体包同步(CscTxProxy,仅当代理态或已应用值真的变化时发包,受 4 tick 拆建冷却限频,与官方 setValue → sendData 同量级),客户端只消费、不按本地图推导(本地图会被未 ACK 的编辑带偏)。图停止或图中无 TX_OUT 时完全回到手动态:盒内裸数字、滚轮生效。文案走 lang key 双语(zh (代理) / en (proxy))。代理态下盒内数字受 4 tick 冷却与包延迟影响,可能短暂滞后于节点当前输出;**闸门同样滞后** —— 手动态→代理态翻转后、包到达前,客户端仍按旧值放行片刻,玩家可能看到一瞬「可编辑」的假象(值不会落地:服务端按自己的权威值再查一次闸门,客户端先行的输入被拒)。 / The transmission's value box showed the wheel value no matter who owned the target — while the graph drove it the player stared at a **number that did nothing** and the wheel stayed editable (the graph overwrote it immediately, so ownership was invisible). New **proxied state**: while the graph runs with a TX_OUT node (first in storage order; the rule now lives in NodeGraph.firstNodeIdOfType, and the proxy flag and the target value are decided at the **same site**, so two hand-rolled scans cannot drift into a "box says proxied, wheel still wins" dead guard) — (1) the box reads "**applied target (proxy)**" from CscTxApplied (the synced effective value), never the inert wheel value and with no extra "node intent" field; both modes take the **magnitude**, since the sign is output-face-relative and belongs to another concept; (2) the wheel / right-click **refuses input** through Create's own two-sided gate acceptsValueSettings (really checked in three places: client input, the server packet handler and clipboard read/write — the third also closes the "paste the old wheel value back" bypass), with a defensive early return in setValueSettings; (3) the hover tip's first line becomes "Target speed · Node-controlled" (Create's hardcoded "hold to edit" line cannot be removed, so the first line corrects it). The state is **server-decided** and shipped in the block-entity packet (CscTxProxy, sent only when the flag or the applied value actually changes, cooldown-limited by the 4-tick rebuild — the same order as the official setValue -> sendData), and the client consumes it instead of deriving it from its local graph, which local un-ACKed edits skew. With the graph stopped, or no TX_OUT at all, everything returns to manual mode: bare magnitude in the box, live wheel. Wording rides bilingual lang keys (zh (代理) / en (proxy)). While proxied the number can briefly lag the node's current output because of the 4-tick cooldown and packet latency. **The gate lags the same way**: between the manual→proxied flip and the packet's arrival the client still lets the interaction through, so the box can look briefly editable — no value lands, because the server re-checks the gate against its own authoritative flag and rejects the client's optimistic input. |### 🧪 测试 / Tests
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🧪 测试 |
CompileResetAndBusNameGateTest 钉死 dirty 门闩(含工厂装入/保留/响应器执行路径)与编译复位(含子图递归)+ fieldIndexOf 反查 + ff3 大数不饱和 + 草稿文本随 op;EncapSubGraphExpandSyncTest 钉死展开状态跨作用域数据同步、「进入子图 → init 恢复」全链路(renderBg 恢复块抽为 restoreOrRebuildEditStates 作测试缝隙)+ encapOccupied 占用判定(节点编辑模式才算、显示模式/异作用域/非法 id 不算)/ Pins the dirty gate (including the factory load/preserve/responder path), compile reset (with sub-graph recursion) and field reverse-lookup, ff3 large-magnitude safety and draft text on ops; EncapSubGraphExpandSyncTest pins cross-scope expansion data sync, the full enter-sub-graph → restore chain (the renderBg restore block extracted as restoreOrRebuildEditStates) and the encapOccupied policy (node-editor mode only; display mode / other scopes / invalid ids never count);EditorKeysPixelAndWireTest / EditorKeysSequenceTest 钉死出厂触发(含 [ / ] 的 GLFW 91/93)、键鼠交错队列、能力/同域冲突、PAN 抓图/拖动切换与旧配置迁移(legacy seq 原样保留、.mouse 槽字段弃用并写回标记); EditorKeysPixelAndWireTest / EditorKeysSequenceTest pin the factory triggers (incl. GLFW 91/93 for [ / ]), the interleaved key+mouse queues, the capability/same-domain clashes, the PAN grab/drag switch and the legacy config migration (seq values carry over verbatim; .mouse slots dropped and the marker written back). TransmissionScrollDisplayTest 钉死值盒文本形态(手动态 = 裸绝对值;代理态 = 绝对值 + 空格 + 后缀,含空后缀、Integer 极值与「符号不外泄」),GearboxNodesEvalTest 增补 firstNodeIdOfType(存储序首个 TX_OUT、删掉首个由次个顶上、全无则 -1 = 回落手动)/ TransmissionScrollDisplayTest pins the box-text shape (bare magnitude when manual; magnitude + space + suffix when proxied, incl. the empty suffix, the Integer extremes and the no-sign-leak rule) and GearboxNodesEvalTest now covers firstNodeIdOfType (first TX_OUT in storage order, the next one taking over once the first is removed, -1 when none remain = manual fallback). 游戏内单客户端实测通过(2026-09-27):图 running 且 TX_OUT 在控(节点要 -10、滚轮值停在 256)时,值盒显示 10 (代理)、悬停提示第一行「目标转速 · 由节点控制」、滚轮与右键均无反应;同刻存档 NBT 直读为 CscTxProxy=1 / CscTxApplied=-10 / CscTxScroll=256(region 文件逐块解压核对)。**未覆盖**:停图回落手动态、图 running 但图中无 TX_OUT、TX_OUT 存在但未接线(按实现应为 0 (代理))。 / Verified in-game on a single client (2026-09-27): with the graph running and a TX_OUT in control (node asking -10 while the wheel sat at 256) the box read 10 (proxy), the hover tip's first line read "Target speed · Node-controlled", and both the wheel and right-click did nothing; the save's own NBT at that moment held CscTxProxy=1 / CscTxApplied=-10 / CscTxScroll=256 (read straight out of the decompressed region chunks). **Not covered yet**: stopping the graph (fallback to manual), a running graph with no TX_OUT, and a TX_OUT with nothing wired to it (expected 0 (proxy)). |</details>
<summary><b>v1.2.5.1</b> — 动力传感器(Create 表同款 3 轴放置 · STRESS/RPM 节点 · 蓝屏显示)· 编辑器输入焦点与选中高亮修复 · GUI 巨型文件拆分 / Kinetic Gauge (Create-style 3-axis Placement · STRESS/RPM Nodes · Blue Screen) · Editor Input Focus & Highlight Fixes · GUI Decomposition</summary>
### 🎯 编辑器输入与选中修复 / Editor Input & Selection Fixes
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| ⌨️ 输入中途丢焦点 / Focus lost mid-typing | 重建
EditState 会把整批 EditBox 换成新实例并丢掉焦点;现在重建前记录聚焦字段下标与光标,重建后按下标还原(光标仅多行编辑器且文本仍够长时还原)/ An EditState rebuild replaced every box and dropped focus; the focused field index and caret are now captured and restored || 🔁 显示编辑器吞键 / Display editor swallowed keys |
MonitorDisplayEditor.handleKeyPressed 曾无条件 return true,设置面板打开时(离开显示模式后并不关闭)节点图输入框完全收不到按键;改为「仅面板打开且未消费 → 返回 null」把输入交还屏幕(charTyped 同步修正)/ The display editor consumed every key unconditionally, so node-graph edit boxes got nothing while the settings panel was open || 🖱️ 设置面板点击穿透 / Settings-panel clicks fell through | 拆分丢失了「设置面板点击优先」与模式无关的语义:在显示模式点开设置面板后回到节点图,面板仍渲染但点击穿透到底下图编辑区(关闭/保存按钮、输入框不可点);现恢复面板打开即优先——
handleSettingsClick 提为 public,屏幕在面板打开时直接路由 / The split lost the mode-independent settings-panel click priority: a panel opened in display mode kept rendering in graph mode while clicks fell through to the graph editor (close/save buttons and EditBoxes unreachable). Priority is restored — the screen routes to the now-public handleSettingsClick whenever the panel is open || 🖼️ 选中高亮消失 / 回弹 / Highlight vanished or bounced | 高亮判定原用对象相等,整图同步或重载替换节点实例后旧实例再也匹配不上;改为按 id 判定(
isSelectedById / isPrimaryById)/ Highlight matching is now by id instead of object identity || ⚡ 每秒数次整批重建 / Edit boxes rebuilt several times per second | 图代际是 per-instance 的,跨实例用裸 int 比较永远「看起来变了」(实测 1→2→3→4→1 循环);改为绑定图实例 + 按节点结构指纹增量重建,无结构变化即零重建 / The generation compare is bound to the graph instance and rebuilds are incremental per node |
| 📝 折叠丢未提交输入 / Collapse dropped uncommitted input | 增量重建引入的清理曾把「折叠但仍在图」的节点编辑状态一并删除,整图同步导致的折叠后再展开会丢 busBox 未提交文本;现只清已离开图的节点,折叠节点保留状态与指纹、仅退出展开集合 / The cull added with the incremental rebuild also dropped collapsed-but-present nodes' edit states, so a collapse arriving via a whole-graph sync lost uncommitted busBox text on re-expand; only nodes that left the graph are culled now |
| 🔖 书签命名对话框加确认/取消按钮 / Bookmark name dialog gains Confirm/Cancel buttons | 新建/重命名对话框底部新增 **确认/取消** 按钮,纯鼠标即可完成,不再必须按 Enter/Esc;键盘路径保持不变(确认与 Enter 同路径,取消与 Esc 同路径);对话框内点击改为模态消费,不再穿透到底下画布 / The add/rename dialog gains **Confirm/Cancel** buttons for a mouse-only flow — Enter/Esc are no longer required and keep working (Confirm shares the Enter path, Cancel the Esc path); clicks inside the dialog are consumed modally instead of falling through to the canvas |
| 🏷️ 方块名输入框透明化 + 图名软锁 / Transparent block-name box + graph-name soft lock | 顶栏方块名输入框背景改为透明(聚焦时以细底边提示可编辑区);新增**图名软锁**:一人改名时其余玩家的名字框自动只读并交出焦点,名字框显示金色描边与编辑者名字,防止两人同时改名;焦点翻转立即上报(键盘编辑不触发鼠标移动,锁的广播与释放不等 30s 过期)/ The top-bar block-name box is now transparent (a thin underline marks the editable region while focused); a **graph-name soft lock** makes everyone else's box read-only and unfocused with a golden outline and the editor's name shown, preventing simultaneous renames; focus flips broadcast immediately — keyboard editing never moves the mouse, so the lock no longer waits out the 30 s presence expiry |
| 🗂️ 添加菜单节点分类按方块收敛 / Add-menu node categories scoped per block | 蓝图计算机的黑名单漏掉了齿轮箱分类——运动节点(移动/转动/等待/离合/编码器)与目标转速混进了蓝图菜单;现**变速箱**白名单与**转速代理控制器**同款(输出节点为 TX_OUT)、**CNC 齿轮箱** = **编程计算机**同款 + 五个运动节点、蓝图不再出现齿轮箱分类(与 node-guide 的「仅数控齿轮箱图 / 仅变速器图」声明对齐)。只影响添加菜单,旧存档中已放置的节点不受影响 / The blueprint blacklist missed the gearbox category — motion nodes (move/rotate/wait/clutch/encoder) and TX_OUT leaked into its menu; the **transmission** now mirrors the **Speed Proxy's** set (with TX_OUT as its output), the **CNC gearbox** = the **Program Computer's** set + the five motion nodes, and the blueprint menu no longer shows the gearbox category (matching node-guide's "CNC-graph-only / transmission-graph-only" claims). Menu-only: nodes already placed in old saves are unaffected |
### ⚙️ 图求值修复 / Graph Evaluation Fixes
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| 🎛️ 封装内的齿轮箱节点丢失宿主注入 / Gearbox nodes inside encapsulations lost host access | 子图求值器不继承宿主注入(encoderView / commandSink / radarPos):**封装内的 ENCODER 恒输出 0**、MOVE/ROTATE/WAIT/CLUTCH 的指令入栈被静默丢弃、雷达节点同样退化——这正是「编码器输出 0」的根因(宿主构造器的注入只到顶层求值器)。现子图求值器创建时继承全部宿主注入(
GearboxNodesEvalTest 新增回归用例),并补上 recompileEvaluatorLight 漏掉的定制回调重放 / Sub-graph evaluators did not inherit host injections (encoderView / commandSink / radarPos): an **encapsulated ENCODER read a null view — pinned at 0** — motion-command enqueues inside encapsulations were silently dropped, radar likewise; this is the root cause of the "encoder outputs 0" report (the constructor injection only ever reached the top-level evaluator). Sub-evaluators now inherit every host injection (regression test in GearboxNodesEvalTest), and the missed customizer replay in recompileEvaluatorLight is restored || ⚠️ **语义变更**:编码器只在离合接合时计量 / **Behaviour change**: the encoder measures only while engaged | 编码器的位置积分与转速读数此前**无条件**跟随输入网络转速——没有指令、离合已分离甚至图已停止时仍在计数(「没有指令也在动」)。现积分与转速都门控到接合状态,且**积分与指令配额逐 tick 对齐**(在运动决策的同一位置积分、以本 tick 的接合决策作门控——门控读方块状态会因翻转时序在指令起止边界各丢一个 tick 的行程,256rpm 下即 76.8°);分离/空闲时位置保持、转速读 0;node-guide #88 已同步 / The encoder's position integration and velocity readout followed the input network speed **unconditionally** — counting with no commands, a detached clutch, even a stopped graph. Both are now gated on engagement **and tick-aligned with the quota bookkeeping** (integrated at the motion-decision point with this tick's engagement decision — a blockstate-read gate lags the quota across every ENGAGED flip, losing one tick of travel per command boundary = 76.8° at 256 rpm); held with zero velocity while disengaged; node-guide #88 updated |
| 📉 组合线整图同步收敛到显式全量同步 / Composition-line whole-graph sync scoped to explicit full syncs | 组合线方块实体(数控齿轮箱 / 可编程变速器)此前把**整张图**塞进每个客户端数据包——Create 在每次转速变化/状态翻转都会 sendData,打开编辑器的客户端因此反复整图重建(「断动力/启停时一直在刷新图」)。现仅 join / flagFullSync 挂起时携带整图,常规包只带 running 等轻量字段;图变化走 op 通道,存档走 NBT / The composition-line BEs (CNC gearbox / programmable transmission) shipped the **whole graph** in every client data packet — Create fires sendData on every speed change / state flip, so open editors rebuilt wholesale. The graph now travels only on join / flagFullSync; routine packets carry light fields, graph changes ride the op channel, saves write NBT |
### 🧩 GUI 巨型文件拆分 / GUI Decomposition(步骤 1–3)
| Refactor / 重构 | Result / 结果 |
|-----------------|---------------|
| ✂️ HUD 裁剪数学抽出 / HUD clip math extracted |
MonitorBlockEntityRenderer 1742 → 1465 行,新增 MonitorClipMath(纯几何/裁剪/投影,可单测)/ New MonitorClipMath, behaviour-preserving || 🖥️ 显示器显示编辑 GUI 脱离 / Display-layout editor extracted |
MonitorScreen 1767 → 348 行,新增 MonitorDisplayEditor(显示区/图层面板/设置面板/协作存在包);评审时移除从未接线的 drawToolbarStrip 死缝(工具栏条仍由编辑器内部绘制,与原实现一致)/ Display-mode GUI, layer panel, settings panel and presence moved out; the review pass removed the never-wired drawToolbarStrip seam (the toolbar strip stays drawn inside the editor, as in the original) || ⚙️ 设置界面按 tab 拆分 / Settings screen split by tab |
EditorSettingsScreen 1204 → 893 行;新增 EditorSettingsGuideTab、EditorSettingsColorsTab、EditorSettingsHost;键位 tab 待办(计划见 docs/gui-decomposition-plan.md)/ Guide + colours tabs extracted; the keys tab remains, with its plan documented |- 新增文档 / New docs**
- [
docs/gui-decomposition-plan.md](gui-decomposition-plan.md) — GUI 巨型文件拆分路线图(含实施记录与两条拆分裂缝经验) - [
docs/editor-focus-selection-loss.md](editor-focus-selection-loss.md) — 输入焦点/选中丢失的根因分析与运行取证
### 🚌 总线频段解析改为服务端唯一权威 / Bus Band Resolution Now Server-Authoritative
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| 🎛️ 同一个 BUS_IN 在不同客户端显示不同频段图 / Same BUS_IN showed a different band graph per client | BUS_IN 的频段列表过去**不随操作传递**,而是每一侧各自查自己那份全局频段注册表解析。某个频道名失去发布方时,服务端会清掉自己那份定义却**不通知客户端**,各端缓存因此分叉 —— 实测同一次改名得到「服务端空 / 一个客户端空 / 另一个客户端 6 个频段」三种结果。现在解析只发生在**服务端一处**,结果作为一条权威
SET_BANDS 下发给该图**全部编辑者(含发起者)**,各端只应用同一个值 / The list was resolved independently on each side against a per-side cache; the server pruned a dead channel name without telling clients, so the caches diverged (one rename produced three different answers). Resolution now happens once on the server and ships as an authoritative SET_BANDS to every editor, originator included || 🧹 客户端不再自行解析频段 / Clients no longer resolve bands themselves | 移除客户端**四处**解析:改名提交处、展开 BUS_IN 时的自动同步、收到改名 op 后按注册表同步、渲染循环逐帧按本地频段表刷新(正是它长期遮掩了 #15 的过期列表)/ Four client-side resolution sites removed: the rename commit, the expand-BUS_IN auto-sync, the per-op registry re-sync, and the per-frame render-loop refresh (the one that long masked #15's stale lists) |
| ⚠️ **语义变更**:采用到无发布方的频道名会清除该节点频段上的连线 / **Behaviour change**: adopting a name with no publisher prunes that node's band connections | 统一走
SET_BANDS 的剪线语义后,把一个 BUS_IN 改名到一个**无定义的频道名**会让频段归空,从而**删除该节点频段上的连线,且不可撤销**(撤销只恢复名字与频段列表)。改名到**有定义**的频道名不受影响 / Uniform pruning via SET_BANDS means renaming a BUS_IN to a name with no publisher empties its bands and deletes the connections on them, with no undo (Ctrl+Z restores the name and band list only). Renaming to a defined name is unaffected || 🧪 新增回归测试 / New regression tests |
BusInBandResolutionTest —— 改名不得触碰频段、解析顺序(同图节点 → 注册表 → 空)、解析不读自身、SET_BANDS 值未变时为空操作 / Rename must not touch bands; documented resolution order; no self-adoption; unchanged SET_BANDS is a no-op |### 🚌 总线冲突标志与频段收敛 / Bus Conflict Flags & Band Convergence
| Fix / 修复 | Description / 说明 |
|-----------|-------------------|
| ⚠️ 跨方块频道冲突警告终于显示(#12)/ Cross-block conflict warnings now show | 客户端原判定分支结构上不可达,且本地赋值会**抹掉**随图同步来的服务端权威冲突标志;现客户端只合并本地可证明的部分(同图重名**只增不减**),跨方块冲突以服务端下发的标志呈现 / The client branch was structurally unreachable and its local assignment silently erased the server-synced flag; the client now merges only what it can prove (same-graph duplicates, raise-only) while cross-block conflicts arrive from the server |
| 🚫 冲突的 BUS_OUT 不再充当频道定义来源(#14)/ A conflicted BUS_OUT is no longer a definition source | 服务端唯一解析点的「同图优先」分支未排除冲突节点:输家方块内的 BUS_IN 采纳了输家的频段图,而其它方块拿到赢家的。现定义来源必须是非冲突 BUS_OUT / The same-graph-priority branch didn't exclude conflicted nodes, so the BUS_IN inside the losing block adopted the loser's band graph; only a non-conflicted BUS_OUT may now serve as the source |
| 🔁 BUS_IN 频段列表收敛为每 tick 服务端不变量(#15)/ BUS_IN band lists converged by a per-tick server invariant | 频道定义变化后,其它方块里已有 BUS_IN 的频段列表永不刷新(重开编辑器也无效——服务端副本本身就是旧的)。现挂进 GraphHost 每 tick:把每个 BUS_IN 收敛到频道定义,**变化才经节点数据通道**(BusBandSyncPacket)下发,绝不走整图推送 / After a definition change, other blocks' BUS_IN lists never refreshed (reopening the editor didn't help — the server's own copy was stale). GraphHost now converges every BUS_IN per tick, shipping only real changes over the node-data channel (BusBandSyncPacket), never a whole-graph push |
| 🛡️ 收敛跳过「无已加载发布方」的频道(#15 后续修正)/ Convergence skips channels with no loaded publisher | 缺席不是定义:发布方块区块卸载、服务器重启首 tick 的注册顺序、方块被拆除,都会让频道暂时无主——照常收敛会把 BUS_IN 收敛为空、按索引剪光输入连线并落盘,发布方回归后频段恢复而连线**永久丢失**。现解析为空且 CHANNELS 无该名字条目时整轮跳过、保留原列表;改名到死名仍由改名路径的权威 SET_BANDS 清空(#11 语义不变)/ Absence is not a definition: an unloaded publisher chunk, a restart's registration order or a broken block leaves the channel momentarily ownerless — converging then emptied the BUS_IN, pruned every input wire by index and persisted the loss; the bands returned but the wires never did. The pass now skips channels whose name resolves empty with no CHANNELS entry and keeps the list; renaming onto a dead name is still emptied by the rename path's authoritative SET_BANDS (#11 semantics unchanged) |
| 🧬 接替的 BUS_OUT 不再带着别人的频段图上线(#16)/ A successor BUS_OUT no longer comes online with someone else's bands | 同名对齐路径(GraphBusEditor.syncBusBands)只检查了来源、没检查目标:拥有者的频段图被复制进冲突 BUS_OUT,拥有者被删后接替者带着别人的图上线。现来源与目标都过资格检查 / The same-name alignment path checked the source but not the target: the owner's band graph was copied into the conflicted BUS_OUT, and when the owner was deleted the successor came online carrying it. Source and target are now both eligibility-checked |
| 🧹 改名链路收尾(审查跟进)/ Rename-path cleanups (review follow-up) | ① BUS_IN 改名只在**频段真的变化**时才产生权威
SET_BANDS(相同值不再白付版本号 bump、日志与全员广播);② 改名与新频段经**合并版全量同步**(40 tick 宽限)带给非编辑者客户端——此前该通道仅 Monitor 宿主存在,其余宿主的非编辑者会过期到下次整图同步;③ PRIVATE 名框不再逐键按客户端本地 BAND_REGISTRY 重写频段——各端自行推导模式的最后一处残留,PRIVATE 节点本无频段引脚 / ① the authoritative SET_BANDS is emitted only when a rename actually changes the bands (no version bump / log / broadcast for an identical value); ② the rename and its bands reach non-editor clients through the coalesced full sync on every host (only the Monitor had that channel before, and the convergence had no diff left to push); ③ the PRIVATE name box no longer rewrites bands from the client's local registry per keystroke — the last leftover of per-side derivation, on nodes that have no band pins anyway |### 🎛️ 新方块:动力传感器 / New Block: Kinetic Gauge (
create_schematic_compute:kinetic_gauge)- 3 轴多状态放置**(Create 官方应力表/转速表同款语义):
facing(显示面朝向,恒为水平)+axis_along_first;贴着带轴的面放置时自动对齐轴。**放置朝向对官方表有一处有意偏离**:官方表把facing取成点击面,贴地/贴顶时点击面是竖直的,只剩axis_along_first一个自由度 —— 2 个状态换不出 4 个偏航角,屏幕只能朝西或朝北(2026-09-13 实测报告);故贴地/贴顶改为"显示面水平正对玩家"(四向可选),代价是贴顶安装时斜板朝上翘进天花板。贴墙仍保持官方语义(显示面 = 点击面)。回归测试KineticGaugePlacementTest。扳手:点击**轴端面**或**显示面**时,面板绕轴 90° 循环(轴与连接不动,即机械动力对轴端旋转的标准 90° 循环);点击其余两个侧面则整表刚性旋转一步(轴绕点击轴换向、显示随动,同可编程变速器的换轴);潜行拆除走官方默认;自身沿旋转轴贯通传轴。 - 3-axis multi-state placement** (Create gauge semantics):
facing(display direction, always horizontal) +axis_along_first; auto-aligns against shaft-bearing faces. **One intentional deviation from the official gauge**: it takesfacingfrom the clicked face, and a floor/ceiling click is vertical — leaving onlyaxis_along_first, so two states cannot encode four yaws and the screen could only face west or north (in-game report, 2026-09-13). Floor/ceiling placement therefore points the display horizontally at the player (all four directions selectable); the cost is that a ceiling-mounted gauge tilts its panel up into the ceiling. Wall placement keeps the official semantics (display = clicked face). Regression test:KineticGaugePlacementTest. Wrench rotation: the **shaft end face** and the **display face** cycle the panel 90° around the shaft (the shaft and its connections never move — Create's standard 90° end-face rotation); the two remaining side faces rigidly rotate the whole gauge one step (the shaft pivots onto the clicked axis and the display follows — same as the transmission's axis cycling). Deliberately NOT Create's default for this family ("click the display face = cycleaxis_along_first"), which would flip the rotation axis between horizontal and vertical, jump to the_shaft_yvariant and disconnect the gauge from its shaft. Sneak-dismantle keeps the official default; the block passes rotation through along its axis. - 模型双变体**:基础变体(用户手工建模,讲台式屏幕法线上仰 45°,传动轴沿水平方向)覆盖 8 个水平轴状态;
_shaft_y变体(机架滚转 + 西面竖直平板屏)覆盖 4 个竖直轴状态——数学上单一网格无法同时覆盖(屏幕法线⊥轴是旋转不变量),竖直轴状态的屏幕由 BER 复刻 blockstate 旋转绘制,文字永远直立可读。 - Two model variants**: the base (hand-made lectern screen tilted 45° up) covers the 8 horizontal-shaft states;
_shaft_y(rolled frame + flat west panel) covers the 4 vertical-shaft states — a single mesh provably cannot (screen normal ⊥ shaft is rotation-invariant). The BER replays the blockstate rotation, so text is always upright. - 蓝屏显示**(与全息显示器同机制):图里有 DATA/TEXT 节点 → 逐行显示它们(服务端求值快照权威);否则显示内置读数——转速数字 + 应力比例条(绿→黄→红,超载闪烁,对齐 Create 的 1.125 约定)+ 百分比。全部自发光。
- Blue-screen display** (same mechanism as the holographic monitor): DATA/TEXT nodes when present (server eval snapshot); otherwise the built-in readout — speed digits + stress bar (green→yellow→red, overload blink aligned with Create's 1.125 convention) + percentage. Fully emissive.
- 读数自适应排版**:内置读数只使用面板**未被边框遮挡**的窗口(脚本从模型几何推导),窄竖屏把标签与数值上下堆叠、进度条为百分比预留空间;文字/数字比例对齐全息显示器(
GeometryConstants.FONT_BLOCK_SCALE,约 0.24 模型单位/像素)。转速或应力变化时主动同步读数(Create 默认只在转速变化时同步),无需重开界面即可刷新。 - Adaptive readout layout**: the built-in readout stays inside the panel's bezel-unoccluded window (derived from model geometry by script); on the narrow vertical panel the label stacks above the digits and the bar reserves room for the percentage; glyph scale matches the holographic monitor (
GeometryConstants.FONT_BLOCK_SCALE, ≈0.24 model units/px). The readout is pushed when speed *or* stress changes (Create by default only syncs on speed changes), so it live-updates without reopening the UI. - 传动轴绘制**:BER 用共享的
KineticShaftRenderer按AnimationTickHolder相位绘制前后两段轴,转速/相位与相邻的 Create 轴一致。 - Shaft rendering**: the BER draws the front and rear shaft segments through the shared
KineticShaftRendererusing theAnimationTickHolderphase, matching neighbouring Create shafts in speed and phase.
### 📊 新节点:动力网络读数 / New Nodes: Kinetic Network Readings
- STRESS(应力状态)**:0 入 4 出——占比(0-1,超载 >1)、已用(SU)、未用(0-1)、剩余(SU);无网络/零容量全 0。
- STRESS**: 0-in/4-out — ratio (0-1, >1 overloaded), used (SU), unused (0-1), left (SU); all 0 offline.
- RPM(转速)**:0 入 1 出——网络转速(RPM 带符号,过载/无动力为 0)。
- RPM**: 0-in/1-out — network speed (signed RPM, 0 when unpowered/overloaded).
- 经新宿主注入视图
KineticNetworkView读取(求值器保持纯净),ENCAPSULATION 子图求值器同 propagate;动力传感器/可编程变速器/数控齿轮箱三个动力宿主的图均可使用(新增「动力读数」分类)。
KineticNetworkView (evaluator stays pure), propagated into ENCAPSULATION sub-evaluators; available in all three kinetic hosts (new "Kinetic Readings" category).### 🧪 质量与接入 / Quality & Integration
- 新增
KineticNodesEvalTest(视图注入、无注入零退化、封装传播、超载/零容量守卫,6 用例);全仓 421 测试通过。
KineticNodesEvalTest (6 cases: injection, zero degradation, encapsulation propagation, overload/zero-capacity guards); all 421 tests pass.- 模型流水线入库**:手工 Blockbench 工程放在
assets-src/kinetic_gauge/(基础变体 + 竖直变体及各自贴图),由tools/gen_gauge_assets.py生成并校验方块模型/贴图/方块状态;校验项含命名契约(必须有screen元素、bezel*建议)、元素旋转后的包围盒、贴图覆盖率与屏幕面未遮挡跨度,--check模式可随时复验。 - Model pipeline in-repo**: the hand-made Blockbench projects live in
assets-src/kinetic_gauge/(both variants and their own textures) andtools/gen_gauge_assets.pygenerates and validates the block models, textures and blockstate; checks cover the naming contract (ascreenelement is required,bezel*recommended), rotation-aware element bounds, texture coverage and the screen face's unoccluded span —--checkre-verifies at any time. - 便携终端接入修复**:终端对未登记路由的方块(如刚放置、路由表尚未命中的新设备)执行"编辑"时不再抛空指针崩溃,本方块已在便携终端设备表登记(
TerminalRoutingTest覆盖)。 - Portable terminal routing fix**: "Edit" on a block the terminal has no route for (e.g. a freshly placed device not yet matched by the route table) no longer crashes with a null pointer, and this block is registered in the terminal's device table (
TerminalRoutingTestcovers it). - 右键(非扳手、非轴端面)打开图编辑器;护目镜悬停显示转速/应力读数;创造标签页、战利品表、配方(黄铜外壳+轴+铁)、Create 蓝图 SafeNbt 全套接入。
</details>
### 🧮 公式语法升级 / Formula Syntax Upgrade
| Feature / 功能 | Description / 说明 |
|----------------|-------------------|
| 🔁 Control Flow / 控制流 |
repeat / while / if / else / break / continue — loop-heavy formulas spread across ticks / 循环公式跨 tick 分摊 || 🧊 vec3 + Vector Functions / 向量 |
vec3(x,y,z), swizzle v.x/y/z, length/normalize/dot/cross/dist/yaw/pitch (yaw/pitch aligned with the DIRECTION node, degrees, yaw ∈ [0,360)) || ⚖️ Comparison & Logic / 比较逻辑 |
< > <= >= exact; ==/!= 1e-6 tolerance; && \|\| ! with !=0 truthiness || 📐 Scalar Functions / 标量函数 |
sin cos tan asin acos atan2 sinh cosh sqrt ln log exp sec csc cot (degrees convention) || 🎯 @output vec3 Expansion / 输出展开 |
@output v (vec3) auto-expands into 3 scalar pins v.x/v.y/v.z with stable pinIds || 🔗 Warm Restart Toggle / 温启动开关 | Pinless eval-policy setting in the formula edit panel (segmented toggle like the signal generator's mode switch): warm keeps iterating toward new inputs without resetting progress vs strict freeze (default) / 编辑区无引脚两段式按钮:温启动保留进度继续迭代 vs 严格冻结(默认) |
| 🌐 CJK Input / 中文输入 | Chinese/full-width symbols, letters, digits and spaces convert to half-width ASCII as you type (()→(), ×→*, ≥→>=, full-width x→x …) / 中文/全角符号输入即转半角 |
| ✍️ Editor Support / 编辑器支持 | Syntax highlighting, autocomplete and validation for all new tokens;
-- line comments / 新语法高亮补全校验;-- 行注释 |- 统一求值引擎 / Unified eval engine**:single
Valuestack machine for legacy RPN and new AST scripts — old formulas are byte-identical, no migration, no dual-engine drift. / 单一栈机统一求值,旧脚本逐位不变。 - 详见 [
docs/formula-syntax-manual.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/formula-syntax-manual.md)。
### ⏱️ 公式预算池 / Formula Budget Pool
| Mechanism / 机制 | Behavior / 行为 |
|------------------|----------------|
| 🕒 Per-Node Slice / 节点配额 |
slice = formulaBudgetMs / N_heavy_prev (default 3.0ms, configurable 0.5–20); every node admitted every tick — zero starvation / 保底零饿死 || 🤝 Cooperative Suspend / 协作挂起 | Wall-clock check every 16 iterations at loop boundaries; carrier (loop stack + Env snapshot) saved, resumed next tick via seek execution — no lost iterations / 循环边界挂起续算不丢迭代 |
| 📤 Emit-on-Done / 收敛输出 | Outputs frozen during spread, fresh value only on done — half-converged values never leak / 半收敛解永不流出 |
| 🧊 Freeze / Warm / 冻结与温启动 | Input change mid-spread: strict freeze completes the old snapshot (default); warm keeps iterating toward the new inputs without resetting progress (opt-in) / 温启动保留进度继续迭代 |
| 🛡️ MAX_ITER Backstop / 兜底 | 1M iterations spread-wide → shed to lastGood + one-shot warning, unfrozen on formula edit / 超限冻结直到编辑 |
| ⚡ Dedup / 去重 | Same script + same inputs deduplicated per tick (pure functions, array-isolated) / tick 级去重 |
| 📊 Progress Bar / 进度条 | Thin render-state bar on FORMULA nodes (no values): 0..1 progress, breathing fill for
while (indeterminate) / 渲染态进度条 |- 架构 / Architecture**:inline gating — FORMULA evaluates in place at its topological position; no central queue, no added tick latency. / 内联门控,无中央队列无延迟。
### 🎯 火控弹道解算示例 / Fire-Control Ballistic Solver Example
[
docs/examples/ballistic_solver.formula](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/examples/ballistic_solver.formula) — Newton-iteration aim solver ported to the FORMULA language (CreateBigCannons ballistic model: semi-implicit Euler dt=1/20, linear/quadratic drag). 361-point pitch scan + damped Newton refinement; ~600k interpreter iterations per solve, spread across ticks by the budget pool with a progress bar. 11 input pins (muzzle/target positions, v0, gravity, drag, density) → 6 outputs (yaw/pitch/reachable + velocity vector). Validated against a Python reference implementation across four scenarios./ 牛顿迭代弹道反解:361 点俯仰扫描 + 阻尼牛顿精化,单次约 60 万次解释器迭代、由预算池跨 tick 分摊(带进度条)。11 输入(炮口/目标坐标、初速、重力、阻力、密度)→ 6 输出(射向角/射角/可达 + 初速向量)。四组场景与 Python 参考实现对拍通过。
### 🖥️ GUI 架构迁移 / GUI Architecture Migration
- 7 个编辑界面脱离容器体系 / All 7 editors leave the container system**:全部 7 个编辑界面(蓝图 / 转速代理 / 编程计算机 / 传感器 / 控制座椅 / 显示器 / 雷达)从
AbstractContainerScreen+Menu体系迁移为继承新基类AbstractGraphScreen(纯Screen),由方块在客户端直接setScreen打开——无 Menu 注册、无网络 round-trip、即时打开。/ All 7 editors (blueprint / speed proxy / program computer / sensor / control seat / monitor / radar) now extend the newAbstractGraphScreenbase (plainScreen) and open client-side viasetScreen— no menu registrations, no network round-trip, instant open. - 第三方模组注入规避 / Third-party mod injection avoided**:界面不再被 FTB Quests、Quark 等模组识别为容器界面,节点编辑器画布上不再出现无关按钮、任务覆盖层或装饰边框。/ Screens are no longer recognized as container GUIs, so unrelated buttons, quest overlays and decorative frames no longer appear on the node canvas.
- 容器设施全部删除 / Container plumbing removed**:删除 7 个
XxxMenu类、SchematicCompute.MENUS注册(7 个 MenuType)、ClientSetup.registerScreens、SyncedGraphBlockEntity的MenuProvider以及 7 个 BE 的getDisplayName/createMenu。/ Deleted the 7 menu classes, the MENUS DeferredRegister, registerScreens, MenuProvider on the base BE, and getDisplayName/createMenu on all 7 BEs. - 便携终端路径 / Portable terminal path**:终端打开设备编辑界面改为直接构造
XxxScreen(editingPos),不再构造虚拟 Menu。/ The terminal now constructs editor screens directly from the edit position — no virtual menus. - 守卫保持 / Guards preserved**:
pendingLocalOps回弹保护(5892caa)、BE 失效自动关界面、GraphJoin/LeavePacket协作生命周期全部迁入基类,行为与迁移前一致;雷达设置面板 EditBox 写回经preClose()钩子保留。/ The pendingLocalOps bounce-back guard, BE-invalidation auto-close and join/leave collaboration lifecycle all moved into the base class with unchanged behavior; the radar settings EditBox write-back survives via thepreClose()hook.
### 🖼️ 显示器图像系统修复 / Monitor Image System Fixes
| Fix / 修复 | Description / 说明 |
|------------|-------------------|
| ⚓️ 图像锚点对齐 / Image anchor clamp | 编辑器与世界渲染器统一为左上角锚点语义;修正世界渲染器 clamp 上界缺因子 2(
1-bbHalfW → 1-2*bbHalfW),缩放图像不再在右/下边框伸出半个图像宽度、与编辑器错位 / Editor and world renderer now share the top-left anchor; the world clamp bound missing the factor-2 was fixed, so scaled images no longer overhang the right/bottom border by half their size || 📏 边框与辅助线 / Bezel + placement grid | 死区减半(0.08→0.04 屏宽,编辑器与世界渲染器同源常量);摆放辅助线绑定内容区 16 等分 + 中心十字,整格对齐 / Bezel margin halved (shared constant across editor and world renderer); the placement grid is bound to the content area in 16 exact divisions with a bold center cross |
| 🖱️ 陈旧选择拖拽 / Stale-selection drag | 空白处按下不再抓取图层面板的旧选择——仅当按下点落在已选元素(裁剪后的旋转 AABB)内才开拖;"先点图1、再拖图2"不再误移图1 / Pressing empty canvas no longer grabs the layer-panel selection; the press must fall inside the selected element's clamped rotated AABB, fixing the "select image 1, drag image 2 → image 1 moves" bug |
| 🧩 图像画布尺寸 / IMAGE canvas size | IMAGE/IMAGE_SEQUENCE 支持自定义 W×H(1..32,默认 16×16):EditPanel 宽高输入、像素编辑器/缩略图/世界渲染/命中/拖拽全链路按节点尺寸、改尺寸左上角保留内容且全帧同步、旧档迁移保护;像素撤销计数标记改用并行元数据(1×1 画布不再冲突),并补全帧操作缺失的重做路径 / Custom W×H canvas (1..32, default 16×16) with edit-panel inputs, size-aware pixel editor/thumbnails/renderer/hit-tests, top-left-preserving resize across all frames, and legacy-save migration guard; pixel-undo count markers moved to parallel metadata (no more 1×1 collision) and the missing frame-redo path was completed |
| 🖌️ 像素同步与拖拽稳定性 / Pixel sync + drag stability | 像素编辑器所有关闭路径统一走定向同步(SET_IMAGE_PIXELS op),颜色确认(Enter/OK)不再静默关闭丢画;**不再全量上传整图**(避免冲掉其他玩家并发编辑);显示区拖拽改节流流式同步(100ms,松手终发)并支持触屏(mouseDragged 同样更新);整图同步替换后 selectedDisplayNode 按 id 重映射,消除"首次拖正常、之后本地冻结"的孤儿引用 / Every pixel-editor close path now runs the targeted SET_IMAGE_PIXELS sync — color confirm (Enter/OK) no longer closes silently and loses the painting; no more full-graph upload on close (which clobbered other players' concurrent edits); display drags throttle-stream their layout (100ms, final op on release), work on touch (mouseDragged updates too), and selectedDisplayNode is remapped by id after full-graph syncs, fixing the orphaned-reference freeze after the first drag |
| 🤝 显示布局实时协作 / Display-layout collaboration | 拖拽位置实时同步给队友;显示模式下渲染队友光标+名字+拖拽组件彩色描边(组件软锁:队友拖拽中的组件不可抓取);存在光标严格按模式隔离(节点图模式与显示模式互不串场)/ Drag positions sync live to teammates; the display editor renders teammates' cursors with name tags and colored outlines around components being dragged (soft lock: those components cannot be grabbed); presence cursors are strictly per-mode (node-graph and display modes no longer bleed into each other) |
| 🚪 关屏定向提交 / Close-time targeted commit | 显示器关屏不再全量上传整图(旧行为会用本客户端快照覆盖服务端、冲掉其他玩家并发的编辑);改为只把尚未同步的局部编辑定向提交:EditBox 输入(含 TAB 切焦点遗留文本)、busBox 频道名与频段改名、像素编辑器当前帧、进行中的显示区拖拽终态——全部走定向 op/包,图数据早已由各 op 实时同步,服务端即最新真相;设置面板保持显式 Apply 契约 / Closing the monitor screen no longer uploads the whole graph (which overwrote the server graph with this client's snapshot and clobbered other players' concurrent edits); only unsynced in-progress edits are committed via targeted ops/packets: EditBox text (incl. text left by TAB focus moves), busBox channel names + band renames, the pixel editor's current frame, and the final state of an in-flight display drag — the graph is already kept in sync live by ops, so the server holds the truth; the settings panel keeps its explicit-Apply contract |
- 详见 [
docs/monitor-image-fixes-audit.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/monitor-image-fixes-audit.md)(评审结论、grilling 决策与提交记录)。
### 🎨 像素编辑器 / Pixel Editor
| Feature / 功能 | Description / 说明 |
|----------------|-------------------|
| 🖥️ Standalone Screen / 独立界面 | Double-click an IMAGE/IMAGE_SEQUENCE node opens a dedicated
PixelEditorScreen (painting-app layout) instead of an in-editor overlay; ESC/✕ returns to the graph editor (portable-terminal wrapper preserved) / 双击 IMAGE/IMAGE_SEQUENCE 节点打开独立 PixelEditorScreen(绘画软件布局),替代编辑器内浮层;ESC/✕ 回到图编辑器(便携终端包装保持) || 🧰 Toolbar / 工具栏 | Responsive tile layout that **never overlaps**: left panel (single-column compact tool rail: Brush, Eraser, Paint-bucket fill, Eyedropper, Line, Rectangle — brush size/opacity/current colour now live in the top bar), slim top bar (brush state + Fit + Guide + Undo/Redo + Canvas + Close, right-aligned) — the color palette is an **embedded always-on right panel** (see below), so the canvas fills the whole central column / 响应式瓦片布局,**任何窗口尺寸都不重叠**:左面板(单列窄工具列:画笔、橡皮、油漆桶、取色器、直线、矩形——笔刷大小/透明度/当前色已移入顶栏)、瘦身顶栏(画笔状态 + 适配 + 指南 + 撤销/重做 + 画布 + 关闭,右对齐)——取色器为**内嵌式常驻右面板**(见下),画布占满整条中央列 |
| 📐 Layout / 布局 | Every panel keeps its content inside its own strip (top bar
y<30, left panel x<30, palette in the reserved right band, canvas/frame strip in the central column), so components can never overlap at any window size; internal controls are all positioned relative to their own panel anchor (no hard-coded absolute screen coords) / 每个面板内容都约束在自身条带内(顶栏 y<30、左面板 x<30、取色器在右缘预留带、画布/帧条在中央列),因此任何窗口尺寸都不重叠;内部控件全部相对各自面板锚点定位(不再使用硬编码绝对屏幕坐标) || 🖌️ PS Tool Rail / PS 式工具列 | The left tool rail is now PS-style: it hugs the left edge and the right divider (no empty gap), drops the per-button border outline, and highlights the whole cell rectangle only on hover/selected; the rail is slimmed to ~30px so the canvas gets more room / 左侧工具列改为 PS 式:紧贴左缘与右分隔线(不留空隙),去掉每个按钮的单独边框,仅悬停/选中时高亮整块矩形;工具列收窄到约 30px,把更多空间让给画布 |
| ✨ Beautify / 美化 | PS-style polish: cleaner two-tone tool icons, a context status bar (current tool / brush size / zoom (cell px) / grid state / hovered cell / sequence frame), a Fit zoom button, a grid toggle (
G), and keyboard shortcuts (B/E/F/I/L/R/H tools, 1..7 rail order, [/] brush size, Ctrl+Z/Y undo/redo); the brush size also has a draggable **slider on the right of the top-bar status row** (1–32, same range as [/]) / PS 风格打磨:双色调更清晰的工具图标、上下文状态栏(当前工具/笔刷大小/缩放(单元格 px)/网格状态/光标格/序列帧号)、Fit 缩放按钮、网格开关(G)、键盘快捷键(B/E/F/I/L/R/H 工具、1..7 按顺序、[/] 笔刷大小、Ctrl+Z/Y 撤销重做);笔刷大小另有**顶栏状态行右侧可拖动滑块**(1–32,与 [/] 同范围) || ✋ Hand Tool / 抓手工具 | A Hand tool at the end of the tool rail (shortcut
H): with it selected, left-click-drag pans the canvas — no need for middle-mouse or Space / 工具列末尾新增抓手工具(快捷键 H):选中后左键拖拽即可平移画布,无需中键或空格 || 🎨 Embedded Palette / 内嵌调色板 | The color picker is an **embedded** always-on panel on the right (scaled ~0.8x): the panel fills the right band down to the screen bottom, with a solid background + left divider like the other panels (not a floating popup), no toggle, no outside-click close, and the canvas stops at its left edge. The Favorites/Recent titles are drawn at full size (readable) and each shows more rows; the **OK and Eraser buttons are hidden** (in the embedded palette) and the eraser logic was removed from
ColorPickerWidget entirely / 取色器改为**内嵌式**常驻右侧面板(约 0.8x):面板铺满右缘到屏幕底部,实心底 + 左侧分隔线(非浮空弹窗)、无开关、点外部不关闭,画布止于其左缘;「常用/最近使用」标题字放大、各显示更多行;**不再显示「确定」和「橡皮擦」按钮**,且从 ColorPickerWidget 里**彻底移除了橡皮擦逻辑** || 🖱️ RMB Erase / 右键擦除 | Right-click erases to transparent under any tool / 任何工具下右键直接擦为透明 |
| 🩸 Eyedropper Sync / 取色器同步 | The eyedropper now syncs the embedded palette: picking a colour on the canvas updates the palette's SV plane / hue / alpha bars and hex field in real time / 吸管取色后内嵌调色板实时同步:SV 平面、色相/透明度滑条与 hex 输入框都切到吸取的颜色 |
| 🔍 Zoom & Pan / 缩放平移 | Mouse-wheel zoom (anchored at cursor), middle-drag or Space+LMB to pan / 滚轮缩放(光标锚定),中键或空格+左键平移 |
| ↩️ Undo/Redo Buttons / 撤销重做按钮 | Top-bar Undo/Redo buttons + Ctrl+Z/Y; resize undo restores size and all frames / 顶栏撤销/重做按钮 + Ctrl+Z/Y;尺寸撤销恢复旧尺寸与全部帧 |
| 🎞️ Frame Strip / 帧条 | Bottom thumbnail strip with click-to-switch, ◀/▶ nav, +New (blank / from current), Delete frame, and drag-to-reorder — new
REMOVE_IMAGE_FRAME / MOVE_IMAGE_FRAME ops keep frame edits server-authoritative / 底部缩略图条:点击切换、◀/▶ 导航、+New(空白/复制当前)、删除帧、拖拽重排 — 新增 REMOVE_IMAGE_FRAME / MOVE_IMAGE_FRAME op 保持帧编辑服务端权威 || 🎞️ Sequence Area Layout / 序列区布局 | The sequence area is now stacked: a button row (◀/▶ nav + frame count, +New, Delete) sits directly above the thumbnail strip, and the thumbnail strip is flush against the bottom of the screen — the +/- buttons no longer sit inside the strip, and thumbnails fill it from the left margin / 序列区改为上下两段:±/导航 + 帧号、+New、删除 的按钮行紧挨在缩略图条上方,缩略图条紧贴屏幕底部(按钮不再嵌在条内),缩略图从左边缘起填满 |
| 🖼️ Dynamic Thumbnails / 缩略图动态缩放 | Sequence-frame thumbnails now scale dynamically: the height stays fixed (36px — bigger, compact) while the width follows the image's aspect ratio (a wide frame gets a wide thumb, a tall frame a narrow one), rendered to fill by per-pixel integer rects; the per-thumbnail cell borders are removed, the current frame is highlighted with a coloured backdrop instead, and the strip is tightened so the images sit flush at the bottom with no gap / 序列帧缩略图改为动态缩放:**高度固定(36px,更大更紧凑)、宽度随图像宽高比**(宽图宽缩略图、高图窄缩略图),用逐像素整数矩形缩放填满;去掉了每帧的边框,当前帧改用底色高亮替代,并收紧条高让图像**紧贴底部无间隙** |
| 📐 Canvas Size / 画布尺寸 | A "Canvas" button opens a small W/H popup (1..32) with separate Apply/Cancel — Apply resizes every frame / 「画布」按钮弹出 W/H 小窗(1..32)+ 应用/取消,应用时对所有帧生效 |
### 🪟 全息显示器 HUD 模式(Phase 1)/ Monitor HUD Mode (Phase 1)
- 选项卡切换**:显示器设置面板新增
[3D 模式] [HUD 模式]tab——点击立即切换(服务端权威、MonitorSettingsPacket广播、所见即所得);HUD tab 提供面板宽/高/横纵偏移/距离 5 参数,沿用显式 Apply/Enter 契约。设计文档 [docs/monitor-hud-mode-design.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/monitor-hud-mode-design.md) / Settings panel gains[3D Mode] [HUD Mode]tabs: clicking switches immediately (server-authoritative, broadcast via MonitorSettingsPacket, WYSIWYG); the HUD tab exposes panel width/height/lateral/vertical offsets and standoff distance under the explicit Apply/Enter contract. - 世界内玻璃面板**:中心锚点玻璃 quad 按
FACING对齐、距方块表面可调(≥0.05 防 z-fighting)、尺寸 0.1–10 方块、世界固定尺寸远小近大;内容复用现有TEXT/DATA/IMAGE/IMAGE_SEQUENCE节点,在 BER 主 pass **直接绘制**(纯官方接口:PoseStack+MultiBufferSource+MonitorRenderTypes.SCREEN_PIXEL+Font.drawInBatch,与 3D 模式同一套 Sodium/Iris 已验证管线;弃用离屏 FBO——Sodium/Veil 世界管线在 flush 时重置视口/裁剪,读回实证内容只落进纹理一角),玻璃自发光全亮(0xF000F0),任意视角不消失(裁剪包围盒覆盖玻璃体积) / In-world glass panel: center-anchored quad aligned toFACINGwith adjustable standoff (≥0.05 anti-z-fighting), 0.1–10 blocks, fixed world size (perspective-correct near/far); content reusesTEXT/DATA/IMAGE/IMAGE_SEQUENCEnodes drawn **directly in the BER main pass** (official interfaces only:PoseStack+MultiBufferSource+MonitorRenderTypes.SCREEN_PIXEL+Font.drawInBatch— the same Sodium/Iris-proven pipeline as 3D mode; the offscreen FBO was dropped because the Sodium/Veil world pipeline resets viewport/scissor at flush time, with readback proving content only landed in one corner of the texture); the glass is fully self-lit and never vanishes at odd angles (cull box covers the glass volume). - AR HUD Phase 2(共形俯仰梯 + 地平线,2026-08-19 首批)**:新增
HUD_PITCH_LADDER节点(输入 pitch/roll + **透传输出**,玩家在图中自接ATTITUDE/VIEW_ANGLE/公式/总线等任意源;刻度参数 range/interval,默认 **±90° 全姿态**——Sable 物理引擎四元数旋转、无万向锁)。刻度族贴世界水平面共形投影(§9.1:玩家相机 → 世界方向族 → 玻璃平面求交,t≤0/出界自动裁剪),地平线加粗高亮,pitch/roll 输入驱动绿色姿态标记。**普通组件(TEXT/IMAGE 等)可选「贴玻璃 / 贴世界」锚定模式**(世界绝对方向 yaw/pitch,创建时默认取玩家当前视线,GraphNode独立字段 + NBT v5 迁移);编辑器用固定相机模拟预览。数据 20Hz 随ClientboundGraphEvalPacket刷新。 / AR HUD Phase 2 (conformal pitch ladder + horizon, first batch 2026-08-19): newHUD_PITCH_LADDERnode (inputs pitch/roll + passthrough outputs, wired by the player to any source —ATTITUDE/VIEW_ANGLE/formula/bus; ladder params range/interval, default **±90° full attitude** — Sable's quaternion physics has no gimbal lock). Ladder lines are world-horizontal direction fans projected conformally (§9.1: player camera → world direction fan → glass-plane intersection, t≤0/off-panel auto-clipped), the horizon is bold, and the pitch/roll inputs drive a green attitude marker. **Ordinary components (TEXT/IMAGE etc.) can choose on-glass / on-world anchoring** (world-absolute yaw/pitch, defaulting to the player's current view at creation;GraphNodefields + NBT v5 migration); the editor shows a fixed-camera mock preview. Data refreshes at 20Hz viaClientboundGraphEvalPacket. - Phase 2 后续(航向带/速度矢量/其余
HUD_*组件)随排期,见设计文档 §十三 / Remaining Phase 2 (heading tape, velocity vector, other HUD_* components) stays on the roadmap, see design doc §13. - 近处屏幕 + 远处虚像画布(2026-08-21 定稿:顶点级深度锚定 + 玩家屏幕 4 边形遮罩)**:HUD 按真实原理实现——近处玻璃屏幕只画**边框**,内容画在**沿 -FACING(玩家面前)100 格的虚像画布**上(尺寸 ×100 保持角尺寸,内容恒定大小浮在远处 = 无限远聚焦);画布世界固定(poseStack 局部坐标)→ **天然共形(贴世界)且不依赖玩家相机投影,Sable 结构天然支持**;俯仰梯 = 画布内姿态仪(tan 透视刻度 + pitch 平移地平线 + roll 旋转,
ladderCanvasY纯函数);**深度锚定(顶点级几何实现,2026-08-21)**:顶点构造为V'=(fx·gz/fz, fy·gz/fz, gz)——屏幕位置保持远处画布投影、深度 = 玻璃平面 gz(官方接口 + vanillaposition_colorshader,无自定义 shader——Veil 4.0 拦截自定义 ShaderInstance 绑定)→ **前方物体遮挡虚像、后方物体不遮挡**(真实 HUD 遮挡关系);**玩家屏幕定位遮罩(4 边形)**:玻璃面板 4 角点从玩家眼睛投影到画布平面(projectGlassCornersToCanvas),内容(IMAGE 像素 / 俯仰梯刻度)经 Sutherland-Hodgman 凸裁剪(clipPolyToQuad)**只在玩家透过玻璃看到的 4 边形区域内显示**——「hud 只在玻璃上显示」,视线离开玻璃(画布不在玻璃投影内)内容消失;组件级剔除(逐像素/逐字符画布矩形裁剪、view-ray)已移除(GPU 省不了多少、CPU 开销大);姿态数据 20Hz 客户端指数插值到 60fps。ConformalProjectionTest覆盖 4 边形投影与裁剪纯函数 / Near screen + far virtual-image canvas (2026-08-21 final: vertex-level depth anchor + player-screen 4-gon mask): HUD follows the real principle — a near glass screen drawing only a **border**, with content on a **virtual-image canvas pushed 100 blocks along -FACING (in front of the player)** (size ×100 preserves angular size; content floats at constant size far away = infinite focus); the canvas is world-fixed (poseStack local frame) → **natively conformal (world-anchored) with no player-camera projection, Sable structures work natively**; the pitch ladder is an in-canvas attitude indicator (tan-perspective ticks, pitch-shifted horizon, roll rotation, pureladderCanvasY); **depth anchoring (vertex-level geometric, 2026-08-21)**: vertices are built asV'=(fx·gz/fz, fy·gz/fz, gz)— screen position keeps the far-canvas projection while depth lands on the glass plane gz (official interfaces + the vanillaposition_colorshader; no custom shader — Veil 4.0 skips custom ShaderInstance binding) → **near objects occlude the image, far ones do not** (real-HUD occlusion); **player-screen-positioned 4-gon mask**: the glass panel's 4 corners project from the player's eye onto the canvas plane (projectGlassCornersToCanvas), content (IMAGE pixels / pitch-ladder ticks) is Sutherland-Hodgman-clipped (clipPolyToQuad) **to show only inside the 4-gon region seen through the glass** — "HUD shows only on the glass", looking away (canvas outside the glass projection) hides it; component-level culling (per-pixel/per-glyph canvas-rect clipping, view-ray) was removed (negligible GPU savings, heavy CPU cost); 20Hz attitude data is exponentially interpolated client-side to smooth 60fps.ConformalProjectionTestcovers the 4-gon projection and clipping pure functions.
### 🖱️ 拖拽不再刷新全部节点状态 / Drag No Longer Refreshes All Node States
| Fix / 修复 | Description / 说明 |
|------------|-------------------|
| 🎨 视觉 op 不 bump 代际 / Visual ops no longer bump |
MOVE_NODE / SET_ZORDER / SET_COMMENT_TEXT / SET_COMMENT_COLORS / SET_COMMENT_SIZE 是纯视觉 op(不进求值器、非 Monitor 显示内容),不再 bumpGeneration()——此前拖拽节流(50ms)下每个 op 都触发服务端 recompileEvaluatorFull → runtimeState.clear() 清零全部时序状态,并让客户端 renderBg 重建所有展开节点的编辑区 / These visual-only ops (never read by the evaluator, not monitor display content) no longer bump the generation — previously every throttled drag op (50ms) triggered a server full recompile → runtimeState.clear() wiped all sequential state and rebuilt every expanded EditState on clients. || 🧩 移除 applyOp 无条件父图 bump / No unconditional parent bump |
EditSessionRegistry.applyOp 不再无条件 bump 父图代际——结构 op 由 NodeGraph 内部 bump,子图 op 靠子图代际陈旧检测 + rebuildInputCache() 兜底(仅引脚映射变化才 bump)/ No more unconditional parent-graph bump in applyOp — structural ops bump inside NodeGraph, sub-graph ops rely on per-subgraph staleness + rebuildInputCache() (bumps only when pin indices actually change). || 📡 Monitor 全量同步限流 / Coalesced monitor full sync | 显示拖拽的
flagFullSync 改为 requestFullSync + tick 内 flushPendingFullSync 合并冲刷——20Hz 的显示 op 只向非编辑者推 ~0.5Hz 全图 NBT(FULL_SYNC_GRACE_TICKS 节流字段此前是死代码);编辑者仍经 op 广播实时同步 / Display-drag full syncs now coalesce via requestFullSync + tick flushPendingFullSync — 20Hz display ops push the full graph NBT at ~0.5Hz to non-editors (the FULL_SYNC_GRACE_TICKS throttle was dead code); editors still sync in real time via op broadcast. || 🧪 回归测试 / Regression tests |
OpGenerationTest(10 例):MOVE/视觉 op 不 bump、求值 op 仍 bump、结构变更仍 bump / 10 cases: move/visual ops don't bump, eval ops still bump, structural changes still bump. |- 详见 [
docs/drag-state-churn-fix.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/drag-state-churn-fix.md)。
### 🔄 编辑不再清空时序/积分状态 / Edits No Longer Reset Sequential & Integral State
| Fix / 修复 | Description / 说明 |
|------------|-------------------|
| 🧬 重编译保留主图状态 / Recompiles preserve main-graph state |
recompileEvaluatorFull 改为像子图状态一样**保存→剪除→恢复**主图五类状态(pidState 含 PID/ACCUMULATOR/INTEGRATOR、delayQueues、flipflopStates、pulseTimers、debugTime)——连线、添加节点、公式输入、参数编辑(如时序节点参数引脚动态调参)**不再清空时序与积分**;删除节点仅剪除该节点状态(含辅助槽位 -(id+1)/id+100000/id+200000)/ recompileEvaluatorFull now saves→prunes→restores the five main-graph state maps (like sub-graph state): wiring, adding nodes, formula input and param edits (e.g. dynamic tuning via sequential-node param pins) no longer wipe timing or integrals; removing a node prunes only its own state incl. auxiliary slots. || ⚙️ base/light 重编译同步修复 / base & light recompiles fixed too |
recompileEvaluator / recompileEvaluatorLight(Sensor/ControlSeat/Radar/Monitor/SpeedProxy)不再 pidState.clear()——其他方块编辑时 PID 积分同样保留 / These no longer clear pidState — PID integrals survive edits on the other five block types too. || 🗑️ 语义保持 / Semantics kept | 整图替换(
loadGraphFromBytes/关屏上传)仍显式清空(旧节点 ID 无意义);编译按钮的 Latch/GATE/T_FLIPFLOP 当前状态回归初始(params[1])不变 / Whole-graph replacement still clears explicitly (old IDs meaningless); the compile button's latch-state reset stays unchanged. || 🧪 测试 / Tests |
RuntimeState.pruneToAliveIds + 3 例单测(保留含辅助槽/剪除死节点/空集合),全量测试通过 / prune logic + 3 unit tests; full suite green. |### 🗂️ 添加节点菜单双列切换 / Add-Node Menu Two-Column Toggle
| Feature / 功能 | Description / 说明 |
|----------------|-------------------|
| 🖱️ 手动双列开关 / Manual two-column toggle | 菜单标题行右侧的状态文字按钮(
单列/双列,双语),点击切换,开启时金色文字+金框高亮:开启后**所有展开分类**均按双列渲染;关闭时全部单列(三角函数不再自动双列)/ A state-label button on the menu title row (1 Col/2 Col, localized): click to toggle, gold text+border while active. When on, **every expanded category** renders in two columns; when off, all are single-column (Trig no longer auto-expands to two). || 📏 宽度常驻 / Persistent width | 双列开启时面板宽度**常驻双列**——即使没有任何展开分类也保持,切换不跳动 / While two-column is on, the panel width stays two-column even with nothing expanded — no resizing jump. |
| 🔍 搜索列数同步 / Search columns follow | 搜索模式扁平列表列数跟随开关(开启=2 列,关闭=1 列),不再硬编码 2 / The search flat list follows the toggle (on=2, off=1) instead of a hardcoded 2. |
| 🖱️ 搜索可滚动 / Search scrollable | 搜索模式
totalH 改为扁平列表真实高度——匹配多时出现滚动条,滚轮/拖拽可滚动(此前恒短、无法滚动)/ Search-mode totalH now reflects the flat-list height — the scrollbar appears for many matches and wheel/drag scrolling works (previously the list was always shorter than the panel and could not scroll). || 📐 布局联动 / Layout consistency | 面板宽度 / 高度封顶 / 滚动条 / 点击命中全部按当前生效列数计算,切换瞬间重排无错位 / Panel width, height cap, scrollbar and click hit-testing all follow the effective column count — no misalignment on toggle. |
### 📐 姿态传感器 ATTITUDE 修复 / Attitude Sensor ATTITUDE Fix
- ATTITUDE 节点随方块朝向变换 / ATTITUDE now follows the block facing**:同一 Sable 结构上朝向不同的姿态传感器,ATTITUDE(pitch/roll)输出此前完全相同——旧实现只取**结构级**俯仰/横滚(
cachedSubPitch/cachedSubRoll),与方块朝向无关。该结构级语义自 **v1.0.1 首次 Sable 集成(ca514a1)** 起遗留至今:当时及 1.1.x 只实测了 VELOCITY/FORWARD 等朝向类节点,ATTITUDE 从未对照方块朝向验证。修复后由「方块朝向 × 子世界旋转」的**局部基向量**推导方块自身世界姿态:前向向量决定俯仰(与 FORWARD 节点同公式、同符号约定),上向量绕前向轴的倾斜决定横滚。同一结构上侧向安装的传感器,其结构俯仰表现为自身横滚,输出不再相同。/ ATTITUDE (pitch/roll) outputs were identical across differently-faced sensors on the same Sable structure — the old implementation used structure-level pitch/roll only, ignoring the block facing. That structure-level semantics had been inherited since the first Sable integration at **v1.0.1 (ca514a1)**: only VELOCITY/FORWARD heading-type nodes were verified in 1.0.1–1.1.x, and ATTITUDE was never checked against block facings. Now the block's world-space attitude is derived from its local basis rotated by facing × sub-world pose: the forward vector yields pitch (same formula and sign convention as the FORWARD node) and the up vector's tilt around the forward axis yields roll. A sideways-mounted sensor reports the structure pitch as its own roll. - 输出引脚不变 / Output pins unchanged**:仍为 2 引脚(pitch、roll),无图迁移。/ Still 2 pins (pitch, roll) — no graph migration.
- 纯函数可单测 / Pure-function testable**:新增
SensorAttitudeMath.blockAttitude()(零 Minecraft/Sable 依赖)+SensorAttitudeMathTest(7 例,含实测数值锁定:结构 yaw=6.37°/pitch=19.03°/roll=-0.28° 时,面 WEST→(0.27,-19.03)、面 NORTH→(19.03,0.28)、面 SOUTH→(-19.03,-0.28))。/ NewSensorAttitudeMath.blockAttitude()(zero Minecraft/Sable deps) +SensorAttitudeMathTest(7 cases, locking measured values). - 注意 / Note**:pitch 符号约定由旧的欧拉角约定改为前向仰角约定(与 FORWARD 一致)——面朝与结构相反方向的传感器 pitch/roll 符号可能翻转;依赖旧数值的现有图需复查。/ The pitch sign convention switched from the legacy Euler-angle convention to the forward-elevation convention (matching FORWARD) — sensors facing opposite the structure may flip sign; existing graphs relying on legacy values should be re-checked.
- 文档更正 / Docs correction**:VELOCITY / ACCELERATION 描述由「结构本地 / Structure-local」更正为「方块本地 / Block-local」——代码始终按方块 FACING 将结构运动分解到方块自身坐标轴(与 FORWARD/ATTITUDE 的朝向相关语义一致),文档此前与代码不符。/ VELOCITY / ACCELERATION descriptions corrected from "Structure-local" to "Block-local" — the code always resolves structure motion into the block's own axes via FACING (consistent with the facing-dependent FORWARD/ATTITUDE semantics); the docs previously contradicted the code.
### ⏱️ 保险节点长信号支持 / FUSE Long-Signal Support
- 长信号 = 脉冲发生器 / Held-high input = pulse generator**:FUSE(保险)此前只在输入**上升沿**触发一次(2 tick 脉冲 → 冷却),持续高电平期间冷却结束后不会再次触发,无法当脉冲发生器。现在输入**持续高电平**时,冷却结束后自动再触发(周期 ≈ 2 + cooldown),输入变低即停止;上升沿仍立即触发、冷却期间的新上升沿仍被忽略、输入在脉冲/冷却中途变低时当前一轮完整走完——旧行为完全兼容。/ FUSE previously fired only once on a rising edge (2-tick pulse → cooldown) and never re-fired while the input stayed high, so it could not act as a pulse generator. A held-high input now re-fires after each cooldown (period ≈ 2 + cooldown) and stops when the input drops; rising edges still fire immediately, new rising edges during cooldown are still ignored, and a drop mid-cycle lets the current cycle finish — fully backward compatible.
- 脉冲宽度修正 / Pulse-width fix**:文档与注释均写「2 tick 脉冲」,旧代码因计数器 off-by-one 实际只输出 1 tick——已修正为真正的 2 tick(触发 tick + 1)。/ The docs and comments claimed a "2-tick pulse" but an off-by-one in the pulse counter emitted only 1 tick — now a true 2-tick pulse (fire tick + 1).
- 回归测试 / Regression tests**:新增
FuseLongSignalTest(4 例):上升沿 2 tick 脉冲+冷却、持续高电平循环脉冲(t0/t6/t12 触发)、中途变低当前轮走完+重武装、冷却期上升沿忽略+长信号再触发。/ NewFuseLongSignalTest(4 cases): rising-edge 2-tick pulse + cooldown, held-high repeating pulses (fires at t0/t6/t12), mid-cycle drop completes then re-arms, cooldown-period rising edge ignored + held-high re-fire.
### 🔌 时序节点参数引脚修复 / Sequential-Node Param-Pin Fix
- 可连线编辑区参数引脚生效 / Wireable edit-area (param) pins now work**:DELAY/PULSE_EXTEND/LOOP/FUSE 等时序节点的参数引脚(可连线编辑区)此前连上信号**没有任何效果**——通用参数覆盖机制(连线值临时覆盖
node.params)只应用在eval()默认路径,时序节点走evalExt()直接读node.params,从未应用覆盖。修复后evalExt顶部统一应用、尾部恢复(连线值只在该 tick 生效,不污染 EditBox/NBT,断开连线恢复默认)。/ The wireable edit-area (param) pins of sequential nodes (DELAY/PULSE_EXTEND/LOOP/FUSE) previously had **no effect** when wired — the generic override mechanism (wired values temporarily replacenode.params) only ran in theeval()default path, while sequential nodes go throughevalExt()and readnode.paramsdirectly.evalExtnow applies the override up front and restores afterwards (wired values last one tick only — the EditBox/NBT stay clean and un-wiring restores the default). - DELAY 入队移入求值器 / DELAY enqueue moved into the evaluator**:DELAY 的入队此前在方块实体(求值器外)读取
params[0]——参数恢复后读不到连线值。现入队并入 DELAY 求值分支(与子图一致),连线的 duration 即刻生效;BE 侧入队代码移除。/ The DELAY enqueue previously lived in the block entities (outside the evaluator), readingparams[0]after the override was restored — so a wired duration never applied. The enqueue now lives inside the DELAY evaluation branch (matching sub-graphs); the BE-side enqueue was removed. - 边界行为(维持现状)/ Edge behavior (unchanged)**:
<0/0一律钳制为 1(最小时长),非整数向零截断(2.9→2);INTEGRATOR limit<0 输出恒 0、负 step 反向计数由玩家自行负责。/ Values<0/0clamp to 1 (minimum duration); non-integers truncate toward zero (2.9→2); INTEGRATOR limit<0 forces output 0 and negative step counts backwards — left to the player. - 回归测试 / Regression tests**:新增
SequentialParamPinTest(3 例):FUSE cooldown 连线(cd=5→周期 6)、PULSE_EXTEND duration 连线(3 tick)、LOOP count+interval 连线(count=2/interval=3)。/ NewSequentialParamPinTest(3 cases): FUSE cooldown wired (cd=5 → period 6), PULSE_EXTEND duration wired (3 ticks), LOOP count+interval wired (count=2/interval=3).
### 🖥️ 显示器设置面板合并 + 统一细边框 / Monitor Settings-Panel Merge + Unified Thin Border
| Feature / 功能 | Description / 说明 |
|----------------|-------------------|
| 🔀 设置面板合并 / Merged settings panel | 3D 与 HUD 两组设置不再用 tab 切换——面板顶部一个 **HUD 模式复选框**(
hudMode 布尔开关),下方 3D 8 项 + HUD 6 项字段**常显**,非激活组置灰禁用(保存时两组都写入,切回模式数值不丢)/ 3D and HUD settings no longer switch via tabs — a single **HUD-mode checkbox** (hudMode boolean) sits at the top with both field groups (3D 8 + HUD 6) always visible; the inactive group is greyed out (both groups are still saved, so values survive mode switches) || 📏 统一细边框 / Unified thin border | 3D 模式丢弃 0.04 方块粗边框(
drawBorderFace 已删除),改用与 HUD 一致的 4 条 addThickLine 细线(≈1 像素)——两模式视觉一致 / 3D mode drops the 0.04-block border (drawBorderFace removed) for the same 4 addThickLine fine lines as HUD (≈1 px) — both modes now look identical || 🔍 虚像屏幕大小 / Virtual-image scale | 新增设置
virtualImageScale(虚像缩放系数,默认 1.0,范围 0.25–4.0):只缩放 HUD 虚像**内容画布**,与物理玻璃面板(panelSizeX/Y)解耦——调大虚像时玻璃不变,超出玻璃视口的内容被 4 边形遮罩裁剪(透过玻璃看 HUD,物理正确)/ New setting virtualImageScale (default 1.0, range 0.25–4.0): scales only the HUD virtual-image **content canvas**, decoupled from the physical glass (panelSizeX/Y) — enlarging the image leaves the glass unchanged and content beyond the viewport is clipped by the 4-gon mask (physically correct through-glass view) || 💾 数据契约扩展 / Data-contract extension |
MonitorSettingsPacket 增至 15 字段(virtualImageScale 追加在 HUD 组末尾);BE 新增 NBT key vis——旧档缺省回落 1.0,无迁移 / MonitorSettingsPacket grows to 15 fields (virtualImageScale appended after the HUD group); new BE NBT key vis — legacy saves default to 1.0, no migration || 🧪 编解码回归测试 / Codec regression test | 新增
MonitorSettingsPacketCodecTest:15 字段编解码往返逐字段一致 + 字段流顺序断言(vis 位于 HUD 组之后)/ New MonitorSettingsPacketCodecTest: 15-field codec round-trip + byte-stream order assertion (vis sits after the HUD group) |- 详见 [
docs/monitor-mode-settings-merge-plan.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/monitor-mode-settings-merge-plan.md)。
### 🎯 可编程变速箱 + 数控齿轮箱 / Programmable Transmission + CNC Gearbox
| Feature / 功能 | Description / 说明 |
|----------------|-------------------|
| ⚙️ 可编程变速器 / Programmable Transmission | 新方块
programmable_transmission:由节点图编程目标转速(TX_OUT 节点),经 RotationPropagatorMixin 以**绝对速度**传导到机械网络 / New block: programs an absolute target RPM from the node graph (TX_OUT node), conveyed to the kinetic network via RotationPropagatorMixin || 🎛️ 数控齿轮箱 / CNC Gearbox | 新方块
cnc_gearbox:离合 + 运动配额(quota)——速度由上游变速器决定,运动方块只做接合/脱开 / New block: clutch + motion quota — speed comes from the upstream transmission; the motion block only clutches || 📜 指令栈节点 / Command-stack nodes |
MOVE(米)/ ROTATE(度)/ WAIT(tick)——触点上升沿入队;CLUTCH 保持常接合意图;ENCODER 报告位置/速度,带电平触发复位引脚 / Rising edge enqueues; CLUTCH keeps standing engagement; ENCODER reports position/velocity with a level-triggered reset pin || 🧩 参数引脚 / Param pins | 运动类节点输入成为可编辑参数(可选连线覆盖),与 CLAMP min/max 同机制 / Motion-category node inputs become editable params with optional wire override |
| 🧠 触发级内存 / Trigger-level memory |
nodeEdge 状态跨重编译、BE 重建与存档重载存活 / survives recompiles, BE recreation and reloads || 🐛 修复 / Fixes | 负方向网络不再卡死运动配额(quota 永续楔死)/ negative-direction networks no longer wedge the motion quota forever |
| 📚 文档 / Docs | [
docs/programmable-gearbox-plan.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/programmable-gearbox-plan.md) · [docs/programmable-gearbox-eval.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/programmable-gearbox-eval.md) · [docs/programmable-gearbox-handoff.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/programmable-gearbox-handoff.md) · [docs/graph-host-convergence-plan.md](https://github.com/y15173334444/create-schematic-compute/blob/main/docs/graph-host-convergence-plan.md) |### 💾 运行时状态跨存档重载存活 / Runtime State Survives World Reloads
| Fix / 修复 | Description / 说明 |
|------------|-------------------|
| 🗃️ 全量恢复 / Full restore | 存档写入的始终是完整运行时状态,但恢复侧长期只读回
pidState 一项——delayQueues、flipflopStates、pulseTimers、debugTime、nodeEdge、subStates 六类在每次重载后静默归零。现由 RuntimeState.putAllFrom() 单点全量恢复,继承线与 Kinetic 线共用同一入口 / Saves always wrote the full runtime state, but the restore side read back only pidState — six more categories silently reset on every world reload. RuntimeState.putAllFrom() now restores all seven in one place, shared by the inheritance and the kinetic line. || ⚠️ 触发误重触发 / Spurious re-trigger | 触发电平(
nodeEdge)丢失会把"常高"信号误判为新的上升沿 → 存档重载或区块重载后 MOVE/ROTATE/WAIT 指令被反复重新入队("输入一次指令后一直转")。已修复并由回归测试守着 / Losing the trigger level re-fired held-high signals as fresh rising edges, re-enqueuing motion commands after every reload ("one command, spins forever"). Fixed and covered by regression tests. || 🧩 分叉抹平 / Divergence removed | Blueprint / ProgramComputer / Radar 原先各自在子类里补**互不相同**的恢复子集,其余四种 BE 只有 pid;现统一上提到基类,子类不再打补丁 / those three used to patch in **different** subsets while four other BEs got pid only; it now happens once in the base class. |
| ⚙️ Kinetic 线子图状态 / Kinetic-line sub-graph state **(行为变更)** | **可编程变速器 / 数控齿轮箱此前不恢复
subStates**——封装(ENCAPSULATION)内的 DELAY / LATCH / T_FLIPFLOP / PID 在存档重载或离合翻转导致的 BE 重建后归零。现与原生线一致恢复。**注意三线的性质不同**:原生线 Blueprint / ProgramComputer / Radar 原本就在恢复(保持行为),ControlSeat / Sensor / Monitor / SpeedProxy 为新增恢复,Kinetic 线为新增恢复(行为变更)/ The transmission and CNC gearbox used to skip subStates, so every timing node inside an encapsulation reset on world reload or on the BE recreation caused by a clutch flip. Now restored like the native line. **The three groups differ in kind**: Blueprint / ProgramComputer / Radar already restored it (behaviour kept), ControlSeat / Sensor / Monitor / SpeedProxy gain it, and the kinetic line gains it (a behaviour change). || ⏱️ 信号发生器相位 / Generator phase **(行为变更)** | ControlSeat / Radar / Sensor 改用
recompileEvaluatorFull(),debugTime(信号发生器相位)跨重编译保留,与 Monitor / SpeedProxy 的 light 路径对齐;老路径 recompileEvaluator() 已删除 / these three now keep the generator phase across recompiles, matching the light path used by Monitor / SpeedProxy; the legacy recompileEvaluator() path is gone. || 🧪 测试 / Tests |
RuntimeStateRestoreTest 新增 7 例,含"只恢复 pid 必然重触发"的负例对照;全量 332 例通过 / 7 new cases including a negative guard that proves the old behaviour re-fires; full suite of 332 green. |### 🔀 图宿主收敛 · 阶段 1(合并逻辑与回弹保护)/ Graph Host Convergence · Phase 1
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🧩 合并逻辑上提 / Merge hoisted | 7 个 BE 各自覆写的
IMergeableBE.accept() 上提到 SyncedGraphBlockEntity,类型特定字段改由新增的 acceptTypeSpecific() 钩子承载(与 loadTypeSpecific 同构)。七个近乎逐字相同的实现删去六份半,**纯去重**(唯一例外见下条)/ Six and a half near-verbatim copies removed; pure de-duplication except for the item below. || 📡 SpeedProxy 补发方块更新 **(行为变更)** | SpeedProxy 合并时原本**不**发送
sendBlockUpdated,客户端拿不到新的 getUpdateTag;现与其余六个 BE 对齐 / SpeedProxy used to skip it, so tracking clients never received a fresh update tag after a merge. || 🛡️ Radar 回弹保护恢复 **(行为变更,bug 修复)** | Radar 的
loadAdditional 原先**重复**执行图加载,且**不检查** pendingLocalOps / 像素绘制 / 显示拖拽 —— 等于关掉基类三道回弹保护:编辑器打开、正在绘画或拖拽元素时,服务端同步包会砸掉本地图(孤儿化 pixelEdit.node / draggedDisplayNode,表现为"图像变透明""拖拽不跟手")。现已恢复三道护栏 / Radar used to re-load the graph with none of the three guards, so a server sync could clobber in-progress edits (wiped pixels, drags that stop following the cursor). || 🧭 回弹判定收敛 / Guard converged | 三道护栏的判定收敛到
GraphHostOwner.isGraphReplaceBlocked(pendingLocalOps) 一处,继承线与组合线(GraphHost)共用,不再各写一份导致判定漂移 / One shared implementation instead of two copies that could drift apart. || 🤝 跨变体合并保持 / Cross-variant merge kept | 上提后的类型判定允许基类 ↔ Sable 兼容变体(
compat/*BlockEntitySable 四个子类不覆写 accept)双向合并,与旧 instanceof 语义一致 —— 整合包中途加装/移除 Sable 时两种 BE 会在同一世界共存 / Base ↔ Sable variant merges still work, matching the old instanceof semantics; both kinds coexist when Sable is installed or removed mid-game. |### 🔀 图宿主收敛 · 阶段 3(薄壳化清理与归档)/ Graph Host Convergence · Phase 3
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🧹 编辑器保存路径统一 / Editor-save path unified **(行为变更,bug 修复)** | Blueprint / Radar / Monitor 三个各自为政的
loadGraphFromBytes 覆写删除/收缩,统一走引擎 loadGraphFromBytes → loadEditorTag。顺带修复三处分叉缺陷:**Radar** 缺 BUS 注销——编辑保存后旧图通道在 SignalBus 泄漏;**Blueprint / Radar** 缺子图/触发器状态清理——封装内时序跨编辑保存残留;**Monitor** 缺全量同步推送——保存后其他客户端的显示器图保持陈旧 / The three divergent loadGraphFromBytes overrides are gone in favor of the engine path (loadEditorTag). Three latent divergences fixed: Radar skipped BUS unregistration (SignalBus leak across editor saves), Blueprint/Radar skipped the sub-graph/flipflop clear (stale encapsulation timing), Monitor skipped the full-sync push (tracking clients kept a stale monitor graph). || 📻 flipflop 差分广播上提 / Flipflop diff hoisted | Blueprint / ProgramComputer 逐字一致的 30 行触发器差分广播块上提为引擎
broadcastFlipflopDiff()(基线随引擎),两个子类各删 30 行与两个基线字段 / The byte-identical 30-line flipflop diff-sync twins moved into GraphHost.broadcastFlipflopDiff() with the baselines; 30 lines and two fields gone from each subclass. || 🏛️ 契约单点 / One contract |
GraphHostOwner 并入 GraphBlockEntity(唯一契约,引擎构造参数随之统一),GraphHost 沿用现名;17 个过渡委托桥已标 @Deprecated 并附迁移指南,按 BE 逐个直连后再删(日常维护,不再以计划文档跟踪)/ GraphHostOwner merged into GraphBlockEntity (the single contract, engine takes it as constructor parameter); GraphHost keeps its name; the 17 transitional bridges carry @Deprecated plus a migration guide. |### 🐛 联测修复:配额换算与雷达同步 / Fixes from playtesting: quota conversion & radar sync
| Fix / 修复 | Description / 说明 |
|------------|-------------------|
| ⏱️ MOVE 配额换算 **(行为变更,bug 修复)** |
MotionQuota 的米制换算多乘了 dt(0.05):官方换算是 speed/512 **每 tick**(Create 字节码核实:机械活塞以 convertToLinear 为每 tick 位移)。多出的因子让 MOVE 慢 20 倍——90 米 @64RPM 记账 0.00625 米/tick 要 12 分钟,体感即"触发指令后一直旋转"。现 90 米 @64RPM = 720 tick = 36 秒;编码器积分与配额共用同一常量,换算修复后两者保持一致 / The meters conversion carried an extra dt(0.05): the official rate is speed/512 per tick (verified against Create bytecode). MOVE was 20x slower - 90 m at 64 RPM took 12 minutes, reading as "spins forever". Now 36 s. Encoder and quota share the constant, so they stay consistent. || 📡 雷达目标推送门控 **(行为变更,性能修复)** | 雷达 tick 末尾**无条件**推送完整 BE NBT(含整张图)——自雷达诞生起如此。所有追踪客户端每 tick 重载图:编辑雷达时编辑器"图每次重建"的根因。现仅目标列表有变化时推送;blip 的实时数值本就走 EvalSnapshot 广播,空闲时零推送 / The radar's tick ended with an unconditional full-BE-NBT push (whole graph included) every tick since the radar was born - every tracking client reloaded the graph per tick, which read as "the radar graph rebuilds all the time" in the editor. Now gated on an actual target-list change; live blip values already flow via EvalSnapshot. |
| 🏗️ 字段委托引擎 / Fields delegated to the engine | 阶段 1 改写完成:基类只剩
private final GraphHost host + 同名访问器桥(graph() 等)+ 契约委托,7 个子类与全部外部类(屏幕 / 渲染器 / 包类)改走访问器与契约;引擎补 recompileEvaluatorLight() / invalidateEvaluator() / adoptFrom() / getFlipflopStates(),**GraphHost 成为两线唯一引擎实现**(净 −370 行)。三处次可见对齐已披露(服务端 NBT 加载立即强制重编译组合拳、快照广播补求值器空守卫、屏幕侧 be.running = start 改走 setRunning()),均可观察行为不变 / Phase-1 rewrite done: the base class keeps only a private final GraphHost host plus same-name accessor bridges and contract delegation; all external pokes moved onto the contract. The engine gains recompileEvaluatorLight() / invalidateEvaluator() / adoptFrom() / getFlipflopStates(), making **GraphHost the single engine implementation for both lines** (−370 lines net). Three sub-visible alignments disclosed, none observable. || 🏷️ 总线/频段命名实时同步 **(行为变更)** | 总线名与频段名的输入框此前既无 responder 也不走 enterActions —— 只在点**编译**或**关屏**时才批量上传,协作者看不到正在改的名字;而 PRIVATE / TEXT 等同类命名框一直是逐字符同步的,行为不一致。现停止输入约 0.5 秒(10 tick)即自动提交,仍走原本的定向 op 与 BusBandUploadPacket(不做整图上传)。**用防抖而非逐字符**:总线名提交要清旧频道全局数据、重评估冲突、按 BUS_IN/BUS_OUT 分别处理频段,逐字符会把 "abc" 打成 a→ab→abc 三个频道,对端 BUS_IN 还会反复跟着换频段定义;防抖一次只发最终值。编译/关屏的兜底提交保留 / Bus and band name boxes had neither responder nor enterActions — they were only uploaded on **compile** or **screen close**, so collaborators never saw a rename in progress, unlike the PRIVATE/TEXT name boxes which synced per keystroke. Now auto-committed ~0.5 s (10 ticks) after typing stops, still via targeted op / BusBandUploadPacket (no whole-graph upload). **Debounced, not per-keystroke**: committing a bus name clears the old channel's global data, re-evaluates conflicts and handles bands per direction, so per-keystroke would create a→ab→abc as three channels and keep swapping the peer's BUS_IN band definition; debouncing sends only the final value. The compile/close fallback stays. |
| 👻 AR HUD 鬼影溢出 **(bug 修复)** | 画布与字形顶点跑到相机后方(fz>0)时,锚定比例
s=zAnchor/fz 变负 → 顶点被**镜像**到屏幕对侧,quad 的一条边横扫整个屏幕。实测 **θ=60°**(普通斜视,远未到掠射)即触发:fz=+34、s=−0.08,而 s 钳制阈值是 ±1e4 —— 量级差五个数量级,完全拦不住(历史测试也注明"s 钳制不覆盖镜像剔除")。现渲染前把几何裁到相机平面,**留 1 格边距**:裁到 fz=0 会让边界顶点正好落在相机平面上 → s=zAnchor/0=−Infinity → 又被镜像。全部顶点在相机前方时短路,逐像素零额外开销 / When canvas or glyph vertices fall behind the camera (fz>0), the anchor ratio s=zAnchor/fz goes negative and the vertex is **mirrored** across the screen, stretching one quad edge over the whole view. Measured at **θ=60°** — an ordinary oblique view, nowhere near grazing: fz=+34, s=−0.08, while the s clamp sits at ±1e4, five orders of magnitude away (the older test even noted "s clamp does not cover mirror rejection"). Geometry is now clipped to the camera plane before emission, **with a 1-block margin**: clipping to fz=0 puts the boundary vertex exactly on the camera plane → s=zAnchor/0=−Infinity → mirrored again. Short-circuits when everything is in front, so per-pixel cost stays zero. |### 🖥️ 编辑器顶栏与设置 / Editor Top Bar & Settings
| Change / 变更 | Description / 说明 |
|---------------|-------------------|
| 🏷️ 图名称与编辑器顶栏 **(新增)** | 编辑器顶部新增固定顶栏:左侧是**图名称**输入框(逐字符同步,走新图级 op
SET_BLOCK_NAME——名称挂在 NodeGraph 上随图序列化与同步,纯视觉 op 不触发重编译),右侧是设置按钮。此前同类方块在终端里无法区分 / A fixed top bar: the graph **name** box on the left (synced per keystroke via the new graph-level op SET_BLOCK_NAME — the name lives on the NodeGraph, serialized and synced with it, visual-only so no recompile) and a settings button on the right. || 🔎 便携终端搜索与自定义名 **(行为变更)** | 便携终端设备名**自定义名优先、类型名回退**,两条取名路径(本地区块扫描与 Sable 无线回包)均已对齐;并新增**搜索框**(按名称/坐标过滤,不区分大小写)——渲染、点击命中、滚动条几何共用同一过滤列表,否则行号错位会打开错误的设备 / Custom names win over type names in BOTH scan paths (local chunk scan and the Sable packet — the two name sources had to be aligned), plus a search box filtering by name/coordinates. Rendering, click hit-testing and scrollbar geometry all consume the same filtered list. |
| ⚙️ 独立全屏设置界面 **(重构)** | 顶栏设置按钮打开**独立全屏设置界面**(左侧竖排 tab 列:界面颜色 / 键位绑定 / 节点指南 + 返回项):切走时编辑会话保持、返回幂等重新加入;**界面颜色内嵌调整**——16 项色板 + 默认/应用 + 停靠取色器,点「调整」滑出全宽形态 / The top-bar settings button opens a **standalone full-screen settings screen** (vertical tab column: colors / key bindings / node guide + back): switching away keeps the edit session alive and returning re-joins idempotently; colors are adjusted **in place** — 16 swatch entries + defaults/apply + a docked palette, expanding to a full-width form via the adjust button. |
| 🗑️ 工具栏样式按钮移除 **(行为变更)** | 编辑器工具栏的「样式」按钮与 16 色配置面板已删除——独立设置界面内嵌了同样的颜色调整(默认/应用/取色器齐备),界面颜色只保留设置界面一处入口;蓝图计算机的导入/导出按钮左移补位;注释节点的颜色编辑弹窗与显示器/像素编辑器的取色器不受影响 / The editor toolbar's Style button and the 16-color config panel are removed — the standalone settings screen embeds the same color adjustment (defaults/apply/picker included), making settings the single entry for UI colors; the Blueprint import/export button shifts left to fill the gap; the comment-node color popup and the Monitor/pixel-editor pickers are unaffected. |
| 🖱️ 颜色列表滚动条 **(新增)** | 设置界面「界面颜色」tab 的颜色列表新增**可拖动滚动条**:thumb 按住拖拽、轨道点击上下翻 3 行(书签面板同款交互),样式与节点指南 tab 的滚动条一致;行区右移出 10px 条带给滚动条,调整按钮随之左移;滚轮滚动行为不变 / The colors list in the settings screen's colors tab gains a **draggable scrollbar**: press-drag the thumb or click the track to page by 3 rows (bookmark-panel interaction), styled like the guide tab's scrollbar; the row strip moves 10px left to make room (adjust buttons follow); wheel scrolling is unchanged. |
| ⌨️ 屏幕虚拟键盘绑键 **(行为变更)** | 键位绑定 tab 点击动作行后整个界面左滑,右侧展开**无 F 行紧凑配列的屏幕虚拟键盘**(Esc+数字行+三行字母+底部修饰行+Home/方向键)与鼠标左/右/中三键;选中动作的现值键帽描边显示;**旧的「监听下一个物理按键」流程退役**——键位绑定改为纯屏幕操作,物理键盘不再参与 / Clicking an action row in the key-bindings tab slides the UI left into an **on-screen virtual keyboard** (no-F-row compact layout) with the three mouse buttons; the action's current binding is outlined on the caps; **the old "listen for the next physical key" flow is retired** — rebinding is purely on-screen. |
| ⌨️ 删除选中/框选可绑定 **(行为变更)** | 「删除选中节点」与「框选多选」纳入绑定表(现共 10 个动作):删除选中默认 **Delete**——原为 Backspace/Delete 双硬编码,现 Backspace 不再删除选中节点(可自行把 Backspace 绑上去),框选默认 **Tab**(补全弹层优先消费的行为保留:弹层可见时框选键先接受补全;改绑后按键与释放都跟随绑定键);虚拟键盘新增
Del 键帽(Home 旁);键位列表改为滚动窗口并附**可拖动滚动条**(thumb 拖拽 / 轨道 ±3 行翻页 / 滚轮,与颜色列表同款),「收起」按钮固定在列表下方不再被顶出屏幕 / "Delete selected" and "Box-select" join the binding table (10 actions now): delete-selected defaults to **Delete** — previously hardcoded to both Backspace and Delete, Backspace no longer deletes the selection (bind it yourself if wanted); box-select defaults to **Tab** with the suggestion-popup-first behaviour preserved (a visible popup consumes the box-select key; both press and release follow the bound key); the virtual keyboard gains a Del cap next to Home; the key-list becomes a scrolling window with a draggable scrollbar (thumb drag / ±3-row track paging / wheel, colors-list style) so the Collapse button always stays visible below the list. || ⌨️ 键序连招绑定 **(行为变更)** | 键位绑定升级为**序列模式**:每个键盘动作是一条 1~4 步的有序序列(每步 = 主键+修饰位),虚拟键盘上**点键帽即追加步骤**(修饰键帽挂起、随步骤入列自动复位),操作条 = 删一步 / 默认 / 清除 / 确定绑定,预览行实时显示「绑定: Ctrl+K → D」;确定时替换该动作整条序列。匹配引擎逐键推进:完整命中触发、前缀缓冲等待(1.5s 超时作废)、无匹配清缓冲并以当前键为新首步重开(vim 式);输入框聚焦不推进。**冲突规则**:等长键序全同必拒;不等长时短者键前缀且短者修饰 ⊆ 长者才拒——
Ctrl+D 单步与 D→K 连招可共存。单步序列与旧单键行为逐项一致,旧配置(key/mods)读取时无损迁移为单步序列(新格式 seq);鼠标动作(平移/菜单)不参与序列保持单键 / Key bindings are now **sequence-based**: each keyboard action holds one ordered 1–4 step sequence (each step = key + modifier mask). On the virtual keyboard a cap click **appends a step** (modifier caps latch and clear with the step); the bar is Del-step / Default / Clear / Bind; the preview line shows "Bind: Ctrl+K → D" live; Bind replaces the action's whole sequence. The matcher advances per keystroke: full match fires, a prefix buffers (1.5 s timeout), a miss clears and re-evaluates the key as a new first step (vim-style restart); focused inputs never advance it. **Conflicts**: equal-length identical key sequences are always refused; for different lengths only a key-prefix with the shorter's mods contained in the longer's is refused — a Ctrl+D single step and a D→K combo can coexist. Single-step sequences replicate the old single-key behaviour exactly, and legacy configs (key/mods) migrate losslessly into single-step sequences on load (new seq format); mouse actions (pan/menu) stay single-button. || ⌨️ 画布交互可重绑 **(行为变更,默认不变)** | 平移画布、上下文菜单、删除/撤销/重做/复制/重置视角/保存书签的按键此前全部硬编码(左键拖图、右键菜单、X 删除、Ctrl+Z…)。现由
EditorKeys 绑定表统一管理,持久化到客户端配置;**默认值与旧行为逐项一致**。设置弹窗内点击动作行即可重绑(Esc 取消),同类冲突拒绝;每行附"默认"恢复按钮 / Pan, context menu, delete, undo, redo, duplicate, reset-view and bookmark keys were all hardcoded. They now live in an EditorKeys binding table persisted into the client config; **defaults replicate the old behaviour exactly**. Click an action row in settings to rebind (Esc cancels); clashes are refused; each row has a reset button. || 📖 节点指南 **(新增)** | 设置弹窗的指南 tab 从
NodeType 元数据自动生成全部 92 个节点类型(名称走既有 lang 键、引脚数与参数名来自枚举字段)——**零手写文案,新增节点自动跟上**;说明文案可随后按需补 lang 键 / The guide tab is generated from NodeType metadata (names from existing lang keys, pins and params from the enum fields) — all 92 types with zero hand-written copy, and new nodes appear automatically. Descriptions can be added later as lang keys. || 📖 节点指南详情面板 **(新增)** | 指南 tab 点击任意节点行 → 界面左滑展开(与颜色/键位 tab 同款形态):左侧节点栏带**可拖拽滚动条**,右侧详情面板显示该节点元信息(入/出/参数)与逐行换行的详细说明;ESC 或列表下方「收起」按钮退回全宽列表;收起态悬停行仍在底部预览一行截断说明 / Clicking any row in the guide tab slides the UI left (same expansion as the Colors/Keys tabs): the node bar on the left gains a draggable scrollbar, and a detail pane on the right shows the node's metadata (in/out/params) plus its wrapped description. ESC or the Collapse button below the list returns to the full-width list; hovering a row in the collapsed list still previews a truncated line at the bottom. |
| 📖 全量双语节点文案 **(新增)** | 93 个节点类型全部补齐中英双语详细说明,写入
gui…guide.<TYPE> lang 键(设置 → 节点指南即读);审阅稿见 docs/node-guide.md(由流水线从 lang 键生成,符号已清洗,统一约定:布尔判定 >0.5(BOOL 例外 >0)、三角按度等)。说明覆盖功能定位、引脚语义、参数含义与常见陷阱 / All 93 node types now ship full bilingual (zh/en) descriptions in the gui…guide.<TYPE> lang keys consumed by Settings → Node Guide. The review copy lives in docs/node-guide.md (generated from the lang keys; symbol-sanitised; shared conventions such as boolean truth >0.5 — BOOL is >0 — and degrees). Copy covers purpose, pin semantics, parameters and common pitfalls. |### 🦾 数控齿轮箱两端轴动画与输入端跟随 / CNC Gearbox Two-Shaft Animation & Input-Face Following
| Feature / 功能 | Description / 说明 |
|----------------|-------------------|
| 🌀 两端独立轴动画 / Independent two-shaft animation | 两端各一根**独立旋转**的轴端帽(官方 SplitShaft 语义 + 官方角度公式与棋盘相位):输入端恒随网络转速旋转;输出端受离合控制——接合随网络、分离静止。vanilla 回退渲染器与 Flywheel 双实例双路径同语义(Sable 等模组把 Flywheel 后端压到 off 时自动走回退渲染器)/ Each end carries an **independently rotating** shaft cap (official SplitShaft semantics + the official angle formula and checkerboard phase): the input end always spins at network speed; the output end is clutch-controlled — network speed while engaged, static while disengaged. The vanilla fallback renderer and the Flywheel dual-instance path share the semantics (the fallback takes over when mods like Sable push Flywheel's backend to off). |
| 📐 端帽对齐与机壳朝向 / Cap alignment + housing rotation | axis=x 时端帽此前缺少 +Z→+X 对齐(绕轴心扫圈如风扇叶)、机壳 y=90 与输入面语义镜像;现按官方 rotateToFace(SOUTH, dir) 组合对齐、机壳改 y=270,端帽与机壳在两轴向上完全一致 / On axis=x the end caps previously missed the +Z→+X alignment (sweeping the axis like fan blades) and the housing y=90 mirrored the input-face semantics; now aligned via the official rotateToFace(SOUTH, dir) composition with the housing at y=270 — caps and housing agree on both axes. |
| 🔁 扳手翻面重排动力源 / Wrench flip re-sources | 扳手翻面此前只切换状态不重排动力——旧 source 仍指向(翻面后已无轴面的)输出侧,方块保持被倒挂驱动,两端动画语义与实际链条脱节。翻面后现走官方拆建序列(network.remove → detachKinetics → removeSource → attachKinetics)从**新输入面**重新认源 / The wrench flip only cycled the state without re-sourcing — the old source kept pointing at the (now shaft-less) output side, leaving the block driven backwards with its input/output animation disconnected from the real chain. Flipping now runs the official teardown sequence (network.remove → detachKinetics → removeSource → attachKinetics) and re-sources from the **NEW input face**. |
| 🧲 放置双侧感知 / Placement senses both sides | 放进完整链条缺口(两侧都是动力方块)时旧逻辑恒定输入=西,与电机在哪侧无关。现比较两侧邻居的实时转速,**强转侧为输入面**(打平仍默认西,扳手可调)/ Placing into a running chain gap (kinetic neighbours on both sides) always bound input=west regardless of where the motor was. The two neighbours' live speeds are now compared and the **stronger-spinning side becomes the input face** (a tie still defaults west — the wrench overrides). |
| 🧭 输入面自动跟随 **(行为变更)** / Input-face auto-follow | 把动力换到另一侧(挪电机/重接链条)后台块不再死锁旧端:空闲(分离 + 无源 + 停转)时若对侧邻轴在转而输入侧邻轴不动,输入面自动翻向驱动侧并主动重探连接。有驱动、在转、接合中或两侧都在转时不翻(歧义交给扳手)——运行中的方块永不自动换向 / Moving the power to the other end (relocating the motor / re-routing the chain) no longer dead-ends the block on its old side: while idle (disengaged + sourceless + stopped), if the neighbour on the OPPOSITE side spins while the input-side neighbour doesn't, the input face flips toward the drive and re-probes the connection. Never flips while sourced, spinning, or engaged, nor when both sides spin (genuine ambiguity — the wrench decides). |
### 💥 变速器拆建不再炸方块 / Transmission Teardown No Longer Destroys the Block
- 炸方块链条 / The destroy chain**:官方
validateKinetics的清理顺序是先removeSource(自身速度清 0)再detachKinetics,而handleRemoved在速度为 0 时短路早退——**以变速器为源的下游树不会被清洗**(残留旧源+旧转速)。之后任何一次 attach 传播里,下游轴经无源自驱引导把变速器反向收编(source 指到输出侧),TX→上游边再把绝对目标推向异号的上游速度 → 命中官方incompatible守卫destroyBlock;堵住收编后同网的残留树又会命中 epsilon-cycle 守卫。官方 SpeedController 靠「驱动轮恒在 UP 方向、邻居迭代序靠前」避开,直通串联的变速器没有这层保护 / OfficialvalidateKineticsremoves the source (zeroing speed) BEFORE detaching, sohandleRemovedearly-returns on speed==0 and the downstream tree stays sourced to the transmission and spinning. On the next attach pass the downstream shaft claims the transmission backwards through the sourceless bootstrap; the TX→upstream edge then pushes the absolute target into an opposite-sign upstream speed, hitting the officialincompatibleguard (destroyBlock); once the claim is blocked, the same stale tree trips the same-network epsilon-cycle guard instead. The official SpeedController dodges this only because its drive cog is always UP, early in the neighbour iteration order — an inline transmission has no such luck. - 三层修复 / Three-layer fix**:① 依赖方边完美 no-op——source 指向本体的邻居在
getDesiredOutputSpeed返回本体自身转速(newSpeed==邻速走官方|差|≤1e-4 → continue;返回 0 会被官方兜底重挂载块反向改爹);② 孤儿动力态预检——源失速/幻影带速时趁自身速度非 0 先 detach,让官方清洗正常运行;③forceCleanDependentTree——无源停转的终态下自走子树逐节点官方removeSource/ ① dependent-edge perfect no-op ingetDesiredOutputSpeed: a neighbour whose source points at us gets our own current speed back (official|diff|<=1e-4 → continue; returning 0 lets the official fall-through re-parent block flip us under the dependent); ② orphaned-kinetic-state pre-tick hook: with a dead source or phantom speed, detach while our own speed is still non-zero so the official cleanup can run; ③forceCleanDependentTree: in the terminal sourceless-and-stopped state, walk the subtree and give each node the officialremoveSource(). - 验证 / Verified**:RCON 台架实测——0→64→128→64→±64 跨号全部安全、60 轮高频改目标 0 销毁(修复前第 3 轮必炸)、完整拓扑(电机→轴→变速器→轴→CNC→轴)同时改目标+发指令 20/20 全活;单元测试全绿 / RCON bench: the full transition matrix incl. sign crosses holds, 60 rounds of high-frequency target flips with zero destruction (deterministic destroy at round 3 before), and 20/20 rounds of the full topology with simultaneous target flips and CNC commands; unit tests green.
### 🔧 ENCODER 注入与迁移清理 / Encoder Wiring & Migration Cleanup
- ENCODER 实机恒 0 修复**:数控齿轮箱构造器此前只注入指令栈 sink、漏注编码器视图——
GraphEvaluator.encoderView恒为 null,游戏内 ENCODER 三输出恒 0、复位无效(单元测试手动注入视图故全绿)。现setEvaluatorCustomizer同时注入setCommandSink+setEncoderView;GraphHost 每次重建求值器都会重放该回调 / The CNC gearbox constructor injected only the command sink, never the encoder view —GraphEvaluator.encoderViewstayed null, so ENCODER always read 0 in game (unit tests injected the view manually and stayed green). The customizer now wires bothsetCommandSinkandsetEncoderView; GraphHost replays it on every evaluator rebuild. - V4→V5 迁移移除死锚定盖章 / Dead per-node anchor stamping removed**:早期草稿给每个节点盖章
am/ay/ap(逐节点贴玻璃/贴世界锚定),该功能从未落地——GraphNode从不读写这些键、渲染只做显示器级锚定,迁移注释承诺的GraphNode.load默认处理也不存在。现移除盖章(保留子图递归与版本号),注释留档原因与「不要无实现地重新加回」的警示 / An earlier draft stamped per-node AR-HUD anchor tags (am/ay/ap) for a feature that never landed —GraphNodenever reads or writes them and rendering anchors at the monitor level. The stamping is removed (sub-graph recursion and the version stamp remain), with a comment recording why and warning not to re-add it without implementing the fields and renderer consumption. - 封装时序清单更正 / Encapsulation timing checklist corrected**:
docs/encapsulation-timing-state-reset.md第 14 项「BUS 信号快照SignalBus.snapshot()」从未实现,标记为「未采用」并注明现状(BUS/PRIVATE 频道为即时读写共享表) / Checklist item 14 referenced aSignalBus.snapshot()that never existed in the codebase — marked "not adopted", noting the current immediate read/write shared-table behaviour.
### 🎨 界面颜色主题扩容 16→23 并收编各屏 / Theme Extended to 23 Colors Across Screens
- 新键 7 个 / 7 new theme keys**:
panel_bg / panel_header / panel_border / inset_bg / accent / error / hover(默认 = 各屏现值,首屏零视觉变化),设置 → 界面颜色现共 **23 项**色板(旧配置缺失项自动回落默认,向后兼容) / Seven keys added with defaults matching current visuals; the Settings → Colors list now holds 23 swatches (legacy configs fall back per-key to defaults — backward compatible). - 编辑器漏网色接入 / Editor stragglers wired**:强调金(主选/次选、框选、焦点/开关开态、★激活)、悬停行高亮、警示红(公式错误徽章/报告框/警示条)、滚动条 thumb 与部分边框改走
ACC()/HOV()/ERR()/CB()/CSB()——换主题不再失配 / Selection gold, hover highlights, error reds and scrollbar thumbs now read from the theme — no more mismatch when switching themes. - 其它屏收编 / Peripheral screens absorbed**:显示器 / 便携终端 / 像素编辑器 / 取色器 的暖深棕面板 chrome(面板底/标题带/边框/内凹井底/金边)与强调色统一走主题访问器(
PBG/PHT/PBR/PINS/ACC/CSB,跨包 public);各屏画布/内容层、文字灰阶、success/danger 动作色与半透明变体保持本地 / The Monitor / Portable Terminal / Pixel editor / Color Picker warm-brown panel chrome now follows the theme via cross-package public accessors; canvas content layers, text greys, success/danger action colours and alpha variants stay local. - MLE 聚焦错误 / MultiLineEditBox error state**:聚焦+错误边框与 UNKNOWN 下划线改走
ERR()/ Focused-error border and the unknown-token underline useERR().
</details>
- 回归审计 / Regression audit**:对
1915202起的改动做全量业务逻辑审计(6 路并行 + 对抗验证),修复雷达红石输出失效、传感器子关卡姿态误用、flipflop 同步风暴、子图状态泄漏、Sable 专用服务器反射错误等。/ Full business-logic audit of changes since1915202(6 parallel + adversarial verification): fixed radar redstone output, sensor sub-level pose misuse, flipflop sync storm, sub-graph state leak, and Sable dedicated-server reflection errors. - 总线跨方块编辑修复 / BUS cross-block editing fixes**:创建同名 BUS_OUT 不再自动同步覆盖原频道 owner 的 band 定义;改名保留自身 band 与连线(BUS_IN 采用新频道 band);点击空白处提交频道名;修复反复编译+运行导致 BUS_IN 读 0(
loadGraphFromBytes的 generation 冲突);自身 BUS_OUT 不再误报冲突。/ Creating a same-name BUS_OUT no longer overwrites the original owner's band definitions; rename preserves the node's bands and connections (BUS_IN adopts the new channel's bands); clicking empty space commits the channel name; fixed BUS_IN reading 0 after repeated compile+run (generation conflict inloadGraphFromBytes); a node's own BUS_OUT no longer reports a false conflict. - 编译 BUS 断线修复 / Compile-time BUS disconnection fix**:移除
loadGraphFromBytes中cleanupBusChannels(),防止编译时向客户端广播空频段导致连线永久丢失。/ RemovedcleanupBusChannels()fromloadGraphFromBytesto stop empty band syncs from permanently deleting connections. - 编辑器冲突检测 / Editor conflict detection**:修复
crossConflict死代码(客户端从不显示跨方块冲突),改名/删除时localBusNames保持同步。/ Fixed thecrossConflictdead code (cross-block conflicts were never shown client-side);localBusNamesstays in sync on rename/delete.
### 📦 封装节点 / Encapsulation Nodes
- 封装节点输出假数值 / Fake outputs from encapsulated nodes**:修复
recompileEvaluatorFull()的runtimeState.clear()清除子图时序组件状态(DELAY/LATCH/flipflop 等),导致封装内部计算偏差。1.2.3 的子评估器缓存掩盖了此问题,修复缓存失效后暴露。现在重编译前保存并恢复subStates。/runtimeState.clear()no longer wipes sub-graph sequential state (DELAY/LATCH/flipflop etc.) —subStatesare saved and restored before a full recompile; previously masked by the v1.2.3 sub-evaluator cache. - 封装内时序节点编辑区状态 / In-encapsulation sequential node state**:扩展
RuntimeStateSyncPacket携带子图 flipflop 状态,编辑器在子图内显示正确的时序节点实时状态。/RuntimeStateSyncPacketnow carries sub-graph flipflop state so the editor shows correct live sequential state inside encapsulation. - 子图展开状态初始化 / Sub-graph expansion state init**:修复进出封装节点后
expandedInitDone未重置,导致子图展开节点不恢复。/ FixedexpandedInitDonenot resetting when entering/leaving encapsulation, so expanded sub-graph nodes fail to restore.
### 📝 公式编辑器 / Formula Editor
- 公式节点双缓存统一 / Unified formula cache**:移除
GraphEvaluator.scriptCache,改为node.cachedScript单一真相源,消除引脚解析与求值的缓存漂移。/ RemovedGraphEvaluator.scriptCache;node.cachedScriptis now the single source of truth, eliminating pin-resolution vs. evaluation cache drift. - 公式节点清空回弹 A+B / Formula empty-value bounce-back A+B**:
createEditState不再强制默认值。/createEditStateno longer forces default values. - 公式编辑器光标与选区 / Formula editor caret & selection**:MLE 图空间坐标转换 + 方向键折叠选区。/ MLE graph-space coordinate conversion + arrow-key selection folding.
- V3→V4 迁移 / V3→V4 migration**:
GraphMigration复用GraphNode.inputPinId/outputPinId,支持旧版动态引脚连线保留。/ Migration reusesGraphNode.inputPinId/outputPinIdso legacy dynamic-pin connections are preserved.
### 🔄 Sable 兼容 / Sable Compat
- Sable 兼容层加固 / Compat layer hardening**:反射访问改编译期桥,专用服务器不再触发 ClientLevel 加载错误;雷达 Sable 结构扫描在专用服务器正常;无 Sable 环境安全回退。/ Reflection access replaced with a compile-time bridge — dedicated servers no longer trigger ClientLevel load errors; radar Sable structure scanning works on dedicated servers; safe fallback without Sable.
- Sable 重连 / Sable reconnection**:
sable$getLoadingDependencies通过getPlot(chunkPos)安全返回子世界引用,修复重进存档后 Sable 节点失效。/ Safe sub-level reference viagetPlot(chunkPos)— Sable nodes survive world reload.
### 🛠️ 其他修复 / Other Fixes
- 雷达锁定 / Radar lock**:空中 blip 锁定不再被方块 UI 拦截;移除编辑会话成员校验(锁定是使用操作)。/ Air-blip lock is no longer intercepted by the block-UI; removed the edit-session membership check (locking is a use operation).
- 数值输入回弹 / Numeric input bounce-back**:编辑器打开时跳过 NBT 全量图替换,防止服务端同步覆盖本地编辑值。/ Skipped full-graph NBT replacement on editor open so server sync cannot overwrite local edits.
- 临时视角跨方块污染 / Temp camera-view contamination**:改为按
BlockPos存储。/ Temp camera view is now stored perBlockPos. - 中途加入玩家获取完整图 / Mid-game joiners get the full graph**:
loadAdditional守卫由graphReady锁存改为本地待 ACK 编辑计数(pendingLocalOps)—— 加入者无本地编辑时总是应用服务端权威图;活跃编辑者仍受回弹保护(仅在发送 op 且未 ACK 期间跳过替换)。/ TheloadAdditionalguard now uses a pending-local-op counter instead of thegraphReadylatch — joiners with no local edits always apply the authoritative graph, while active editors keep bounce-back protection (replacement skipped only while ops are un-ACKed).
All 7 blocks now support real-time collaborative graph editing — multiple players can edit the same node graph simultaneously. / 全部 7 种方块支持多人实时协作编辑同一节点图。
| Feature / 功能 | Description / 说明 |
|----------------|-------------------|
| 🖱️ Live Cursors / 实时光标 | Colored crosshairs with player names / 彩色十字准星 + 玩家名 |
| 📦 Remote Node Drag / 远程拖拽节点 | Smooth lerp animation on remote moves / 远程移动平滑插值动画 |
| 🔗 Wire Preview / 连线预览 | Live bezier curve while dragging wires / 拖拽连线时实时贝塞尔曲线 |
| 👤 Player List / 玩家列表 | Right-side vertical list, host highlighted / 右侧竖向列表,房主高亮 |
| 🔒 Node Lock / 节点锁定 | IMAGE nodes protected during pixel editing / 像素编辑时自动锁定 |
| ⚡ Join/Leave / 加入离开 | Appear immediately on open, disappear on close / 打开即现,关闭即消 |
| ✏️ Op-Based Editing / 操作同步 |
GraphOp + OpExecutor model, server-authoritative ID allocation / 服务器权威 ID 分配 |### ⚡ Architecture Refactoring / 架构重构
| Change / 改动 | Description / 说明 |
|---------------|-------------------|
| 🖥️ Server-Authoritative Eval / 服务端评估 | Client-side
GraphEvaluator removed. All evaluation runs server-side; results synced via ClientboundGraphEvalPacket + EvalSnapshot. Fixes PRIVATE_IN/BUS_IN always returning 0 on client. || 🏗️ Unified BE Base / 统一 BE 基类 |
SyncedGraphBlockEntity consolidates ~200 lines duplicated across 7 BEs (BUS lifecycle, RedstoneLink, NBT, sync, EvalSnapshot). || 📦 Blob Data Channel / Blob 通道 |
BlobDataPacket + BlobRegistry for chunked large data. SET_IMAGE_PIXELS from Base64 to direct int[]. |### 🔧 Debug Toolchain / 调试工具链
| Tool / 工具 | Description / 说明 |
|-------------|-------------------|
| 📶 Signal Generator / 信号发生器 | Test signal source. Manual curve mode (draggable control points, X-clamped, server-sorted) or custom f(x) formula (all math functions, auto full-width paren conversion). Frequency-generate (auto-cycling X) or input-driven (drag sky-blue marker). Auto-scale Y axis with ±5 outlier clipping. |
| 📊 Signal Probe / 信号探针 | Real-time monitor with 100-tick trend chart. Auto-scale Y axis with outlier clipping. Right-click freeze/unfreeze/clear. |
### 📌 View Bookmarks / 视角书签
- ★ button (bottom-right, above ▼) toggles bookmark panel / ★按钮开关书签面板
[+]/Ctrl+Msave current view,[↺]/Homereset to origin[✎]rename,[✕]delete,[→]or click name to jump with 200ms ease-in-out transition- Drag name area to reorder, synced via
MOVE_BOOKMARKop - Click outside naming dialog to cancel; Esc handled by unified popup stack
- Multiplayer-synced via
ADD_BOOKMARK/REMOVE_BOOKMARK/RENAME_BOOKMARK/MOVE_BOOKMARKops
### 🐛 Fixes & Polish / 修复与打磨
- 🔧 **Graph Init** —
onLoad()bumps generation to force full recompile on first tick. - 🚌 **BUS Channel** —
registerChannels()no longer requiresbandCount()>0; empty-band channels register so BUS_IN reads immediately. - 🎨 **Color Picker UX** — ESC closes picker + panels together. Duplicated nodes get
sortB = original+1. - 📝 **Bilingual Comments** — All
graph/,blocks/,network/source comments now Chinese+English. - 🐛 **Encapsulation DEBUG Visibility** —
EvalSnapshotnow captures sub-evaluator outputs + debugTimes. Signal Generator (blue X marker) and Signal Probe work correctly inside encapsulation sub-graphs. / 封装内信号发生器(蓝色X标记线)和探针现在正确显示。 - ⌨️ **Esc Key Delegation** — Esc now closes sub-UI (bookmark rename, export/import dialog, color picker) before closing the entire editor screen. / Esc 先关闭子 UI 再关整个编辑界面。
- 🔒 **Soft-Lock Scope** — Node locking now scoped by
ownerNodeId. Selecting a node inside encapsulation no longer falsely locks main-graph nodes with the same ID. / 封装内选中节点不再误锁主图同 ID 节点。 - 🖱️ **Cursor Scope Isolation** — Remote player cursors are now filtered by scope; cursors inside encapsulation are hidden from main-graph view and vice versa. / 远端光标按作用域隔离。
- 🟡 **ENCAPSULATION Occupant Highlight** — Golden border + player name label on ENCAPSULATION nodes in the main graph when other players are editing inside. / 主图中被占用的封装节点显示金色边框+玩家名。
- 📝 **ENCAP I/O Rename Sync** — Renaming
ENCAP_INPUT/ENCAP_OUTPUTnow sendsSET_DISPLAY_TEXTop for server sync + undo support. / 封装I/O改名现在同步到服务端并支持撤销。 - 📋 **Ctrl+D Copy Fix** — Copy now uses server-authoritative ID allocation (
ADD_NODE_REQUEST→ ACK); data ops are deferred until all real IDs assigned. Sub-graph content recursively synced for ENCAPSULATION nodes. Fixes "empty node on other clients". / 复制走服务端权威ID分配,封装子图递归同步。 - 📐 **Manual Curve Fixed Y-Axis** — Signal Generator manual curve mode now uses fixed Y range
[-1.1, 1.1]; auto-scaling retained for formula mode. Control points clamped to visible range and rendered above border. / 手动曲线Y轴固定,控制点钳制+边框上方渲染。
### 🔗 Stable PinId Refactoring / 稳定引脚ID重构
Connections now bind to **stable string pin identifiers** instead of positional integer indices. Pin insertion, deletion, or reordering no longer breaks existing connections — they follow the pin by name.
| System / 系统 | pinId Source / pinId 来源 | Before / 修复前 | After / 修复后 |
|---------------|--------------------------|----------------|---------------|
| FORMULA inputs | Variable name (e.g.
A, B, x) | Adding/removing variables shifted pin indices — connections broke or pointed to wrong pins | Connections follow variable names; ensureScriptParsed() eliminates lazy-parse race conditions || FORMULA outputs |
@output label (e.g. result, angle) | Output reordering broke downstream connections | Connections track output labels; "out0" default handled correctly || ENCAPSULATION I/O | Sub-node ID (sorted by Y, then ID) | Dragging ENCAP_INPUT/OUTPUT nodes changed pin order — external connections silently shifted | pinId = sub-node ID, invariant under drag; parent cache rebuilt after sub-graph structural edits |
| BUS bands | Band name (e.g.
band_0, band_1) | Inserting/removing/reordering bands cleared all connections or caused index drift | Only connections on actually-deleted bands are removed; reordered bands preserved |- Key changes:**
NodeConnectiongainsfromPinId/toPinIdfields;save()/load()backward-compatibleGraphNodeaddsinputPinIndex(id)/outputPinIndex(id)/inputPinId(i)/outputPinId(i)— pinId↔index resolution per node typeNodeGraph.rebuildInputCache()resolves all pinIds to current indices, prunes stale connectionsGraphMigrationV3→V4: one-time NBT upgrade converting integer pins to stable pinIds for FORMULA, ENCAP, BUS, and generic nodes (recursive into sub-graphs)GraphEvaluatorBUS evaluation and ENCAP pin injection now match by pinId rather than cache positionBusChannelHelper.syncBandsFromServeronly disconnects actually-removed bands (by name), preserving reordered bandsNbtVersions.DATA_VERSIONbumped 3→4- Eliminates ~200 lines of REWIRE/reconnect complexity from the v1.2.5 roadmap — pin reordering is now free
Related docs: [
docs/v1.2.4-pin-id-stability-plan.md](docs/v1.2.4-pin-id-stability-plan.md)### 🧠 Relay Nodes / 继电器节点
Two new logic nodes for conditional signal routing — available in both Blueprint and Program Computers.
| Node / 节点 | Description / 说明 |
|-------------|-------------------|
| Relay A / 继电器A | SPDT (双掷) — 3 inputs (A, B, Contact), 2 outputs. Contact ≤0.5 → A输出=A, B输出=0; Contact >0.5 → A输出=0, B输出=B. Mutually exclusive throws like a physical relay. |
| Relay B / 继电器B | SPST (单掷) — 3 inputs (A, B, Contact), 1 output. Contact >0.5 → out=B; else → out=A. Merged single-throw variant. |
Both use the standard
>0.5 threshold consistent with BOOL/GATE/OR. No parameters, pure combinatorial logic — compatible with multiplayer collaboration and encapsulation out of the box.### 🪑 Sable Sub-Level Control Seat Camera / Sable 子关卡控制座椅相机
Two camera modes for Control Seat riders inside Sable rotating structures. Camera orientation computed client-side from block FACING + Sable render-pose quaternion — bypasses entity yaw sync (unreliable for
retain_in_sub_level entities).Sable 旋转结构上控制座椅的两种相机模式。座椅世界朝向由客户端根据方块 FACING + Sable 渲染姿态四元数实时计算,不依赖 entity yaw 同步。
| Mode / 模式 | Camera / 相机 | Output / 输出 |
|-------------|--------------|---------------|
| **FIXED** (default) | Locked to seat world orientation (yaw + pitch).
ControlSeatCameraMixin disables Sable camera rotation to prevent double-rotation. / 锁定到座椅世界朝向(偏航+俯仰) | Joystick mx/my from raw mouse delta / 摇杆来自鼠标增量 || **VIEW_DIFFERENCE** | Free camera, mouse-controlled. Sable does not rotate the view. / 自由相机,鼠标控制 |
vy = playerYaw - seatWorldYaw, vp = playerPitch - seatWorldPitch |ControlSeatBlockEntitySable: fixed missingsetYRot()— entity yaw now properly updates bothyRotandyRotO. / 修复缺失的 setYRot()。ControlSeatEntity: manualsetPosskipped inside sub-levels (Sable handles positioning). / 子关卡内跳过手动 setPos。ControlSeatCameraMixin: registered inrequired:falsesable mixin config — silently skipped without Sable. / 无 Sable 时静默跳过。
### 🎮 MOUSE_JOYSTICK Absolute Mode / 鼠标摇杆绝对值模式
Per-node toggle in the edit panel switches between **incremental** (direct mouse delta, default) and **absolute** (accumulated stick position with memory, clamped to
[-1,1]).编辑区提供每节点独立开关,在增量(默认,鼠标位移即输出)和绝对值(累积摇杆位置,停手保持)之间切换。
- Uses
TOGGLE_BOOLop pipeline — server-authoritative, undo-supported, multiplayer-synced. / 复用 BOOL 开关流水线。 - Absolute accumulation uses
ABS_SCALE=1/6per tick for smooth control. / 绝对值每 tick 累积系数 1/6。 - Stick position persists across GUI open/close. / 开菜单再关闭位置保持。
- Both x and y axes accumulate independently. / X/Y 轴独立累积。
### 🔧 Signal Generator Auto-Scale Fix / 信号发生器自动缩放修复
- Root cause**:
computeVisibleRange()used fixed ±5 clipping, squashing large-range formulas (e.g.x*360) into a ~6-unit Y window while rendering used raw values → curve painted to chart corners looking like an inverse-proportional function. - Fix**: Replaced ±5 hard clipping with **percentile-based robust range** (p1–p99). Only extreme outliers (|v| ≥ 1e6) and NaN/Inf are filtered. Both
DEBUG_SIGNAL_GENandDEBUG_PROBEcharts use the same logic. - Y-axis range label**: Chart top-right now shows
min … max(e.g.0.0 … 360.0) so the scale is immediately visible. - Cache**: Formula compilation cache (
debugFormulaRpn) properly invalidated on formula edits — chart refreshes instantly.
### 🎨 Formula Editor UX / 公式编辑器体验
- Syntax Highlighting / 语法高亮** — Real-time token-based colouring with 9 categories: functions (yellow), constants (pink), identifiers (cyan), numbers (orange), operators/parens (grey), comments (green), @output/assignment (purple), unknown (red underline). Token cache avoids per-frame re-parsing. / 实时词法彩色标注,9 种分类:函数(黄)、常量(粉)、标识符(青)、数字(橙)、运算符/括号(灰)、注释(绿)、@output/赋值(紫)、未知(红色下划线)。Token 缓存避免每帧重复解析。
- Autocomplete Popup / 自动补全候选框** — Type identifier characters to trigger filtered dropdown (functions, named constants, current variables); type
@for immediate@output. Keyboard:↑↓navigate,Tab/Enteraccept,Escdismiss. Mouse: click any candidate to accept. Popup renders **above all pins** (z-layer C=5.5) with **zoom-aware scaling** — text and layout scale proportionally with graph zoom. Deleted variables immediately disappear from suggestions. / 输入标识符触发过滤候选框;输入@立即建议@output。键盘导航/接受/关闭,点击候选项接受。候选框渲染在**所有引脚上方**(C=5.5 层),支持**缩放感知**。删除变量立即从候选消失。
- Real-Time Validation / 实时校验** — Red
⚠badge on FORMULA node title bar; hover for tooltip list. Checks: bracket matching, unknown function, wrong arity, invalid assignment (errors), duplicate outputs, @output without identifier (warnings). Red border on the edit box when errors present. Validation cached after NBT reload to avoid per-frame re-parse. / 红色 ⚠ 徽章 + 悬停工具提示。校验:括号匹配、未知函数、参数数错误、无效赋值(错误),重复输出名、@output 缺变量(警告)。输入框红色边框。NBT 重载后缓存避免每帧重解析。
- Named Constants / 命名常量** —
(PI)and(E)in grouping parentheses are literal constants (π / e). BarePI/Eor inside function calls likesin(PI)are variable references (create input pins). Consistent acrossextractVariables(),compile(), andtokenize(). /(PI)/(E)在分组括号内为字面常量。裸PI/E或函数调用内sin(PI)视为变量。三种解析入口行为一致。
- Robustness / 健壮性** — Mouse drag selection restored (hlPos sync scoped). SET_FORMULA self-skip prevents EditState recreation → no focus loss during typing. Formula responder re-fetches graph node each keystroke (handles NBT sync between keystrokes). Connection cleanup corrected to use
inputs()/outputs()clamps. Screen-width hardcoded 1920 replaced withgetGuiScaledWidth(). Null safety in suggestion filtering. / 拖拽选区修复、SET_FORMULA 自跳、按键间图引用重获取、连线清理用 clamp 值、屏幕宽度动态获取、候选过滤 null 防护。
- Tests / 测试** — 27 new unit tests covering tokenize, extractVariables, compile/evaluate, validate, parseScript, countFunctionArgs, and edge cases. / 27 个新单元测试。
> **English:**
> This major update overhauls the graph editor's rendering and hit-testing architecture with a professional **A.B.C Layered Occlusion System**. It fixes long-standing Z-order bugs where nodes would render under expanded panels or have their clicks stolen by background UI. Additionally, introduces fully-fledged **Comment Nodes** for documentation and resolves several critical desync and crash issues.
>
> **中文:**
> 此重大更新为图形编辑器引入了专业的 **A.B.C 分层遮挡系统**,彻底重构了渲染与命中检测架构。修复了节点在展开面板下渲染错误、点击被底层 UI 拦截等长期存在的 Z 轴排序问题。此外,新增了功能完整的**注释节点**,并修复了多处严重的同步错误与崩溃问题。
### ✨ Features & Enhancements | 新特性与优化
- 🎨 A.B.C Occlusion System:**
- EN:** Implements a strict 3-layer sorting hierarchy (A: Layer → B: Depth → C: Internal Element). Layers include Grid, Comments, Connections, Nodes, Overlays, and Tooltips. This ensures UI elements never visually clash or incorrectly overlap.
- CN:** 实现严格的三层排序逻辑(A: 图层 → B: 深度 → C: 内部元素)。图层涵盖网格、注释、连线、节点本体、叠加层及悬浮提示,彻底杜绝 UI 元素视觉冲突。
- 📝 Comment Nodes (Sticky Notes):**
- EN:** Adds a new visual-only node (0 inputs/outputs) available in all 7 programmable blocks. Features resizable dimensions (up to 8000x6000), scrollable markdown text, independent color customization (BG/Border/Text), and nested parenting (dragging a parent moves children).
- CN:** 在全息蓝图等 7 种可编程方块中新增纯视觉注释节点(无输入输出)。支持超大尺寸调节(最大 8000x6000)、文本滚动、Markdown 换行、三色独立定制(背景/边框/文字)及嵌套父子移动逻辑。
- ⚡ Performance & Spatial Logic:**
- EN:** Introduces
SpatialIndex(uniform grid hashing) for O(k) spatial queries, replacing expensive linear searches. ManualEditBoxrendering prevents text bleeding through opaque node bodies. - CN:** 引入基于均匀网格哈希的
SpatialIndex,将空间查询复杂度降至 O(k),取代昂贵的线性扫描。手动渲染编辑框,解决文字穿透节点背景的问题。 - 🖱️ Interaction Polish:**
- EN:** Comment headers are now draggable while the body remains clickable. Ctrl+Scroll scrolls comment text while normal scroll zooms the canvas. Nested comments maintain correct Z-depth (inner stays on top of outer).
- CN:** 注释节点头部支持拖拽,主体保留点击交互。Ctrl+滚轮滚动注释内容,普通滚轮缩放画布。嵌套注释保持正确的 Z 轴深度(内层高于外层)。
### 🐛 Bug Fixes | 问题修复
- 🔧 Editor Z-Order & Hit-Detection:**
- EN:** Fixed nodes rendering under expanded edit panels. Fixed inability to click/drag nodes overlapping expanded areas. Fixed inline edit controls (buttons, fields) ignoring Z-order. Fixed viewport culling ignoring expanded heights.
- CN:** 修复节点在展开面板下渲染的错误;修复重叠在展开区域上的节点无法点击/拖拽的问题;修复内置控件(按钮、输入框)无视 Z 轴排序的问题;修复视口裁剪忽略展开区域高度的问题。
- ☁️ Server & Networking:**
- EN:** **Critical Fix:** Removed client-side class imports (
Screen,Minecraft) from common code to prevent Dedicated Server crashes (Fixes #4). Fixed Monitor block graph overwriting. Fixed BUS band name synchronization. Fixed Image node copy causing false cycles. Fixed Terminal pixel editor Esc behavior. - CN:** **关键修复:** 移除通用代码中对客户端类(
Screen,Minecraft)的引用,防止专用服务端崩溃(修复 #4)。修复 Monitor 方块图像覆盖问题;修复 BUS 频段名称同步问题;修复复制图像节点导致的伪循环;修复终端像素编辑器 Esc 行为。 - 📦 Data Integrity:**
- EN:** Added NBT v3 migration for SortB values. Fixed BUS node collapse logic when connections exist. Fixed pin hitboxes on BUS_OUT nodes.
- CN:** 新增 NBT v3 迁移以支持 SortB 数值。修复 BUS 节点存在连接时的折叠逻辑;修复 BUS_OUT 节点引脚碰撞箱偏移问题。
### 🔧 Technical Changes | 技术变更
- EN:** Refactored package naming to
io.github.y15173334444.create_schematic_compute. Centralizedg.flush()calls around node rendering to isolate Minecraft's vertex buffer submissions. Removed legacysuppressControlsworkarounds in favor of the new occlusion system. - CN:** 重构包名为
io.github.y15173334444.create_schematic_compute。在节点渲染前后集中调用g.flush()以隔离 Minecraft 顶点缓冲提交。废弃旧的suppressControls补丁,全面启用新遮挡系统。
### 📥 Installation
- Requires: NeoForge 1.21.1, Create 6.x
- 📱 **Portable Terminal** — new handheld item to remotely discover and edit programmable blocks. Scans overworld and Sable sub-level devices within configurable range (1–256 blocks). One-click opens the block's native GUI.
- 🇨🇳 便携终端** — 新增手持物品,远程发现和编辑可编程方块。扫描 overworld 和 Sable 子世界设备,范围可配置(1-256 格)。一键打开方块原生 GUI。
- 🔍 **Sable sub-level scanning** — server-side scan via
LevelPlot.getLoadedChunks()with rotation-corrected world position calculation. Classloader-safe interface detection handles Sable's jarjar isolation. - 🇨🇳 Sable 子世界扫描** — 服务端通过
LevelPlot.getLoadedChunks()扫描,带旋转修正的世界坐标计算。类加载器安全的接口检测处理 Sable 的 jarjar 隔离。 - 🖼️ **Photoshop-style layer panel** — redesigned Holographic Monitor display editor with 108px-wide layer panel, 30px rows, and 24×24 component thumbnails. Drag-and-drop layer reordering with ghost row and auto-scroll.
- 🇨🇳 Photoshop 风格图层面板** — 重新设计全息显示器编辑器,108px 宽图层面板,30px 行高,24×24 组件缩略图。支持拖拽排序、幽灵行和自动滚动。
- ↩️ **Undo/Redo system** — Ctrl+Z / Ctrl+Y support for graph editor (add/delete nodes, connections, duplicate) and pixel editor (paint operations, new frames). Graph-level undo uses NBT snapshots with 50-step history.
- 🇨🇳 撤销/重做系统** — 图形编辑器(添加/删除节点、连线、复制)和像素编辑器(绘制、新建帧)支持 Ctrl+Z/Y。图形级撤销使用 NBT 快照,50 步历史记录。
- 🖥️ **Display editor fixes** — selection highlight now renders on top of all elements. Clicking empty display area starts dragging the already-selected component.
- 🇨🇳 显示编辑器修复** — 选中高亮现在渲染在所有元素之上。点击空白区域开始拖拽已选中组件。
- 🛠️ **Radar fixes** — removed aggressive
validateSableCache()that cleared Sable pose every tick. Bootstrap now usesboundingBox()for precise sub-level matching. - 🇨🇳 雷达修复** — 移除每帧清除 Sable 姿态的
validateSableCache()。Bootstrap 现使用boundingBox()精确匹配子世界。 - 🧹 **Code cleanup** — portable terminal streamlined (7 dead packet files removed, screen code -52%). All screens unified
toggleRunning()pattern. - 🇨🇳 代码清理** — 便携终端精简(移除 7 个废弃包文件,屏幕代码减少 52%)。所有屏幕统一
toggleRunning()模式。 - 🎨 **3D terminal model** — custom Blockbench handheld model with GUI display angles.
- 🇨🇳 3D 终端模型** — 自定义 Blockbench 手持模型,已调整 GUI 显示角度。
- ⚡ **GUI 性能优化** — 消除每帧分配:池化 Vector3f/Quaternionf、缓存红石输入列表、用快速格式化替代 String.format(ff0/ff1/ff2/ff3/hex8)、修复 MultiLineEditBox 的 O(n²) 子串分配
- EN GUI perf** — eliminated per-frame allocations: pooled JOML objects, cached redstone inputs, fast formatters, O(n²) substring fix
- 🎨 **原子颜色调色板** — 16 个可配置颜色存入 volatile int[] 数组,原子交换消除跨线程颜色撕裂
- EN Atomic colors** — single volatile array prevents cross-thread color tearing
- 🏗️ **脏标记框架** — NodeGraph.graphGeneration 计数器用于缓存失效;markDirty() 接入所有变更路径(拖拽、参数编辑、展开/折叠、编译、像素编辑)
- EN Dirty flags** — graphGeneration counter with markDirty() on all mutation paths
- 📐 **精度加固** — 新建 GeometryConstants 统一 22 个布局常量、去重 clampImageNorm/elemRotAABB/调色板、统一 FONT_BLOCK_SCALE、修复 PALETTE_CELL 不一致(24→16)、修复网格线子像素抖动(截断→Math.round)、MultiLineEditBox LINE_HEIGHT 从硬编码改为 font.lineHeight
- EN Precision** — shared GeometryConstants, deduplicated geometry, fixed PALETTE_CELL, grid line rounding
- 🛠️ **雷达 Sable 修复** — 移除 tryBootstrapSableCache() 中 100 万坐标守卫(蓝图放置的雷达无法初始化)、修复 RadarBlockEntitySable 中 savedLevel 回退竞争(蓝图放置时双 null 导致 physicsTick 返回)
- EN Radar fixes** — removed 1M coordinate guard, fixed savedLevel race condition
- 🧩 **DIRECTION 节点解锁** — 在 BlueprintScreen 和 ProgramComputerScreen 中可见(定义已久但被所有过滤器隐藏)
- EN DIRECTION node** — now visible in BlueprintScreen and ProgramComputerScreen
- 📦 **雷达战利品表** — 雷达方块破坏时掉落自身
- EN Radar loot** — radar block drops itself on break
- ✨ **Formula → multi-line script editor** — MultiLineEditBox with word wrap, drag-select, Ctrl+A, Enter/arrows, paste \r\n normalization
- 🇨🇳 Formula → 多行脚本编辑器** — 自动换行、拖选、Ctrl+A 全选、Enter/方向键导航、粘贴 \r\n 规范化
- ✨ **Formula script syntax** — assignments (
var = expr),@outputnamed pins,--comments,\line continuation, dynamic I/O pins - 🇨🇳 公式脚本语法** — 赋值语句、@output 命名输出、-- 注释、\\ 续行、动态输入/输出引脚
- ✨ **8 new nodes** — SQRT, LN, LOG, EXP, SEC, CSC, COT, ANGLE_UNWRAP (78 total)
- 🇨🇳 8 个新节点** — 平方根、自然对数、常用对数、指数、正割、余割、余切、角度解绕(共 78 种)
- ✨ **3D Holographic Radar** — real-time scanner, target locking, Classic/Holographic styles, Blockbench model, TARGET_OUT node
- 🇨🇳 3D 全息雷达** — 实时扫描器、目标锁定、经典/全息风格、Blockbench 模型、TARGET_OUT 节点
- ✨ **BUS_IN / BUS_OUT nodes** — multi-band bus channels with global BAND_REGISTRY, zero-copy cross-computer signals
- 🇨🇳 BUS_IN/BUS_OUT 节点** — 多频段总线通道,全局注册表,零拷贝跨计算机信号传递
- ✨ **Encapsulation I/O** — import/export via toolbar, file browser, sub-graph state persistence
- 🇨🇳 封装导入/导出** — 工具栏按钮、文件浏览器、子图状态持久化
- ✨ **World coordinate nodes** — VELOCITY, ACCELERATION, DIRECTION, POSITION for sensors and radar
- 🇨🇳 世界坐标节点** — VELOCITY、ACCELERATION、DIRECTION、POSITION
- ✨ **Identifier scanning** — variable names support
[a-zA-Z_][a-zA-Z0-9_]*(X1/X0 style vars) - 🇨🇳 标识符扫描** — 变量名支持字母数字下划线(X1/X0 风格)
- ✨ **Wide FORMULA node + multi-column Trig menu** — 240px node width, 17-item Trig split into 2 columns
- 🇨🇳 宽体公式节点 + 双列三角菜单** — 240px 节点宽度,17 项三角分类双列显示
- 🐛 **E key fix** — printable keys no longer close GUI
- 🇨🇳 E 键修复** — 可打印字符不再关闭 GUI
- ⚡ **Performance** — dead code removed, ScriptParseResult cached, buildVisualLines dirty flag
- 🇨🇳 性能优化** — 死代码移除、ScriptParseResult 缓存、visualLines dirty 标志
- 🐛 **Various fixes** — expand button hit test, output pin connection offset, pin auto-cleanup, \r\n normalization
- 🇨🇳 多项修复** — 展开按钮命中检测、输出引脚连线偏移、引脚自动清理、\r\n 规范化
- ✨ **Add: LATCH edit panel** — Configurable default set/reset state toggle with real-time current state display
- 🇨🇳 新增:锁存器编辑面板** — 可配置初始置位/复位切换,实时显示当前状态
- ✨ **Add: PRIVATE_IN/PRIVATE_OUT on Program Computer** — Private signal channels now available for cross-block communication
- 🇨🇳 新增:编程计算机支持私有信号** — PRIVATE_IN/PRIVATE_OUT 节点可用于跨方块通信
- ✨ **Add: RuntimeState sync packet** — flipflopStates synced server→client on change for real-time UI display in multiplayer
- 🇨🇳 新增:运行时状态同步包** — 翻转状态变化时服务端→客户端同步,多人游戏编辑区实时显示
- 🐛 **Fix: Recompile state reset** — GATE, T_FLIPFLOP, and LATCH current state now resets to configured default on recompile
- 🇨🇳 修复:重新编译状态重置** — 闸门、T触发器、锁存器重新编译后当前状态回归初始默认值
- 🐛 **Fix: Edit panel live state display** — GATE/T_FLIPFLOP/LATCH current state now updates in real-time during execution (shared object single-player + network sync multiplayer)
- 🇨🇳 修复:编辑区实时状态显示** — 闸门/T触发器/锁存器当前状态运行时实时更新(单机共享对象+多人网络同步)
- 🐛 **Fix: World reload state persistence** — Program Computer and Blueprint Computer now correctly restore flipflopStates and pulseTimers across world reloads
- 🇨🇳 修复:世界重载状态持久化** — 编程计算机和蓝图计算机世界重载后正确恢复时序节点运行状态
- 🐛 **Fix: RuntimeState load consistency** — All 6 block entities audited; Blueprint now loads full runtime state; SpeedProxy clears pidState on graph change
- 🇨🇳 修复:运行时状态加载一致性** — 全部6个方块实体审查;蓝图计算机现在加载完整运行时状态;SpeedProxy 图变化时清理 pidState
- 🔧 **NBT compatibility: v1→v2 migration** — Old LATCH saves (params.length=0) auto-upgraded to new format
- 🇨🇳 NBT 兼容层:v1→v2 迁移** — 旧版锁存器存档(params.length=0)自动升级为新格式
- ✨ **Add: VELOCITY node (56→57)** — Structure-local X/Y/Z velocity from sable physics, ×2 m/s (Control Seat + Attitude Sensor)
- 🇨🇳 新增:速度节点(56→57)** — sable 物理结构本地 X/Y/Z 速度,×2 m/s(控制座椅 + 姿态传感器)
- ✨ **Add: Universal param input pins** — All numeric EditBox params now expose input pins inside the edit panel (PID kp/ki/kd, DELAY ticks, LOOP count/interval, etc.)
- 🇨🇳 新增:通用参数输入引脚** — 所有数值编辑框参数在编辑区内部显示输入引脚(PID 的 kp/ki/kd、DELAY 的 ticks 等)
- ✨ **Add: CLAMP/MAP param pins** — min/max and in/out range pins moved to edit panel with EditBox fallback defaults
- 🇨🇳 新增:CLAMP/MAP 参数引脚** — min/max 和映射范围参数移至编辑区,支持编辑框默认值
- ✨ **Add: NBT compatibility layer** — Data format versioning, v0→v1 migration, stable NodeType string IDs for forward compatibility
- 🇨🇳 新增:NBT 兼容层** — 数据格式版本化、v0→v1 迁移、NodeType 稳定字符串 ID,确保向前兼容
- ✨ **Add: Runtime state persistence** — PID integrals, delay queues, flipflop states saved to NBT and restored on reload
- 🇨🇳 新增:运行时状态持久化** — PID 积分项、延时队列、触发器状态等存入 NBT,存档重载后不丢失
- ✨ **Add: Expanded state NBT persistence** — Node expand/collapse state saved and restored
- 🇨🇳 新增:展开状态持久化** — 节点展开/折叠状态存入 NBT,重载后保持
- ✨ **Add: Edit panel pin rendering** — Param pins rendered as circles in the edit panel, connected pins shown dimmed with label retained
- 🇨🇳 新增:编辑区引脚渲染** — 参数引脚以圆点形式显示在编辑区内,连线后变暗但标签保留
- 🐛 **Fix: Encapsulation node copy** — Ctrl+D now deep-copies sub-graph contents
- 🇨🇳 修复:封装节点复制** — Ctrl+D 现在会深拷贝子图内容
- 🐛 **Fix: Wire drag** — Connects to nearest pin instead of all nearby pins simultaneously
- 🇨🇳 修复:连线拖拽** — 只连最近引脚,不再同时连多个
- 🐛 **Fix: TAB+click** — Deletes the nearest connection instead of the first match
- 🇨🇳 修复:TAB+点击** — 删除最近连线,而非列表第一个
- 🐛 **Fix: Connection bezier positions** — Correctly target functional pins on body and param pins in edit panel
- 🇨🇳 修复:连线贝塞尔位置** — 正确指向节点体功能引脚和编辑区参数引脚
- 🐛 **Fix: Velocity/acceleration block-relative rotation** — Properly rotates to block-local frame
- 🇨🇳 修复:速度/加速度方块相对旋转** — 正确旋转到方块本地坐标系
- 🐛 **Fix: CLAMP/MAP not working** — Evaluator now falls back to EditBox params when pins are unconnected
- 🇨🇳 修复:CLAMP/MAP 不工作** — 求值器无连线时回退到编辑框参数值
- 🐛 **Fix: Block filtering** — VELOCITY correctly excluded from Blueprint, included in ControlSeat/Sensor
- 🇨🇳 修复:节点过滤** — VELOCITY 正确排除于蓝图计算机,包含于控制座椅/姿态传感器**
- ✨ **Add: 7 new node types (49→56)** — OR Gate, GE (>=), LE (<=), ROUND (N decimals), Continuous Integrator, Acceleration, Gamepad Trigger
- 🇨🇳 新增:7 种节点(49→56)** — 或门、大于等于、小于等于、保留N位小数、连续积分器、加速度、手柄扳机
- ✨ **Add: IMAGE/IMAGE_SEQUENCE rotation input** — signal-driven rotation with rotation scale param + per-axis moveScale (X/Y) + invertX/invertY toggles
- 🇨🇳 新增:IMAGE/IMAGE_SEQUENCE 旋转输入** — 信号驱动旋转(旋转倍率参数)+ 分轴移动倍率 + X/Y反转切换
- ✨ **Add: T_FLIPFLOP edit panel** — configurable default on/off state toggle
- 🇨🇳 新增:T 触发器编辑区** — 可配置默认开/关切换
- ✨ **Add: i18n support** — ~130 new translation keys for node edit panels, pin labels, toolbar buttons, toggles (zh_cn + en_us)
- 🇨🇳 新增:多语言支持** — 约 130 个新翻译键覆盖节点编辑区、引脚标签、工具栏按钮、切换按钮
- 🐛 **Fix: GAMEPAD_BUTTON binding** — moved capture from event-driven keyPressed() to frame-polling with edge detection; now works with mapping software
- 🇨🇳 修复:手柄按键绑定** — 从事件驱动改为帧轮询+上升沿检测,现在配合映射软件也能正常工作
- 🐛 **Fix: Gamepad trigger clamp** — trigger axes clamped to [0,1] for phone/Bluetooth gamepads reporting [-1,1]
- 🇨🇳 修复:手柄扳机钳制** — 扳机轴钳制到 [0,1],兼容手机蓝牙手柄的 [-1,1] 范围
- 🐛 **Fix: IMAGE_SEQUENCE frame display** — 3D renderer now reads frame input pin and selects correct frame
- 🇨🇳 修复:图像序列帧显示** — 3D 渲染器现在读取帧输入引脚并选择对应帧
- 🐛 **Fix: Monitor display rotation** — center-based rotation with correct direction matching GUI preview
- 🇨🇳 修复:全息显示器旋转** — 中心基轴旋转,方向与 GUI 预览一致
- 🐛 **Fix: Double checkmark on toggle buttons** — removed duplicate ✔ from i18n strings
- 🇨🇳 修复:切换按钮双勾号** — 移除 i18n 字符串中重复的 ✔
- ⚡ **Perf: Acceleration computation** — uses pure float trig instead of JOML object allocations; no GC stutter on sable structures
- 🇨🇳 性能:加速度计算** — 纯浮点三角函数替代 JOML 对象分配,sable 结构无 GC 卡顿
- ✨ **Add: GATE node** — Signal gate with 4 inputs (value/open/close/toggle) and NBT-persistent state; available on Blueprint and Program computers
- 🐛 **Fix: Node connection culling** — Connections on the left/top side of the GUI are no longer incorrectly culled
- 🐛 **Fix: Monitor GUI rotation** — Display element rotation direction now matches between GUI editor and 3D screen
- 🐛 **Fix: Monitor GUI margins** — Component positions in GUI now include the 0.04-block bezel margin matching the 3D screen
- 🐛 **Fix: Monitor IMAGE clamping** — Rotated IMAGE/IMAGE_SEQUENCE elements use AABB-aware edge clamping matching the 3D renderer
- 🐛 **Fix: Monitor IMAGE positioning** — Clamping bounds aligned with content area instead of display area
- 🐛 **Fix: Monitor settings data loss** — Changing screen settings no longer resets display element positions/rotations
- 🐛 **Fix: Monitor live preview** — Display area updates in real-time while editing screen width/length
- 🐛 **Fix: ACCUMULATOR crash** — Placing accumuator node on Program Computer no longer crashes the game
- 🐛 **Fix: MOUSE_BUTTON node** — Now outputs 1 while button held (previously was pulse-on-click)
- ✨ **Add: Encapsulation node** — nest sub-graphs inside a single node, double-click to expand, 48→49 types
- ✨ **Add: Monitor Redstone Input** — Holographic Monitor can now read Redstone Link network signals via REDSTONE_IN node
- ✨ **Add: Toolbar position toggle** — bottom-right button to switch toolbar (X/Compile/Run/Grid/Style) between top-left and bottom-left; position persisted to config file
- 🐛 **Fix: Control Seat view jump** — smooth transition between Joystick and View Angle modes (Mixin-based raw mouse delta capture, zero GLFW cursor manipulation)
- 🐛 **Fix: Monitor 3D renderer redstone** — 3D holographic display now correctly evaluates REDSTONE_IN nodes (was passing empty InputSource list)
- 🐛 **Fix: Monitor redstone registration** — late-registered listeners now receive initial signal state via force-resend; dedicated MonitorRedstoneSyncPacket for lightweight client sync
- ⚡ **Perf: Comprehensive code audit** — NaN guards on all arithmetic nodes (ADD/SUB/MUL/MAP/INTERP), FORMULA compilation cache, volatile thread safety on all static fields, evaluator caching (60+ FPS → graph-change-only), Sensor reflection cache, ControlSeat entity scan radius 50→2 blocks
- ♻️ **Refactor: RedstoneLinkHelper** — ~400 lines of duplicated redstone link code (FreqLink, registerLinks, addLink, unregisterLinks, lifecycle hooks) deduplicated across 4 block entities (Blueprint, ProgramComputer, ControlSeat, Sensor)
- ♻️ **Refactor: GraphBlockEntity interface** — replaces 6-branch instanceof chains in BlueprintSavePacket/BlueprintTogglePacket with single interface check
- ♻️ **Refactor: Star imports eliminated** — all
import java.util.*expanded to explicit imports across 6 files - 🔧 **Mixin infrastructure** — added Mixin AP +
LocalPlayerMixinfor Entity.turn() interception in Control Seat - 🛡️ **Player disconnect cleanup** — PLAYER_INPUTS now cleared per-player on PlayerLoggedOutEvent
- ✨ **Add: Holographic Monitor** — Floating 3D display with pixel editor, display mode, signal-driven movement
- ✨ **Add: Control Seat** — Sit-able controller with keyboard/mouse/gamepad input, 58 assignable keys, dual modes
- ✨ **Add: Attitude Sensor** — Reads sublevel orientation via ATTITUDE/FORWARD/WORLD_VIEW nodes
- ✨ **Add: 11 new node types** — KEYBOARD, MOUSE_JOYSTICK, VIEW_ANGLE, MOUSE_BUTTON, GAMEPAD_JOYSTICK, GAMEPAD_BUTTON, WORLD_VIEW, ATTITUDE, FORWARD, SPLIT, POSE_CONVERT
- ✨ **Add: 4 Display nodes** — TEXT, DATA, IMAGE, IMAGE_SEQUENCE
- ✨ **Add: Accumulator node** — +/- dual-input rising-edge counter
- ✨ **Add: FORMULA node** — Custom math expressions with multi-letter variables
- ✨ **Add: Sable physics integration** — Control Seat and Attitude Sensor on rotating structures
- ✨ **Add: Color customization** — 16-color theming for node graphs
- ✨ **Add: Grid snap, render priority system, inline node editing**
- ✨ **Add: IWrenchable support** — Wrench rotation and shift+wrench NBT pick-up for all 6 blocks
- ✨ **Add: Multilingual support** — Full EN/ZH localization for Monitor UI
- ✨ **Add: Mouse button proxy** — Left/right click blocked while seated, sent to server for graph use
- ✨ **Add: Mod icon** — New Blockbench-made icon
- 🔧 **Change: Create-style warm metallic GUI palette** (brass/copper/steel)
- 🔧 **Change: Redstone output clamped to 0-15**
- 🔧 **Change: Block placement facing — blocks now place with back towards player**
- 🐛 **Fix: World reload bug** — All blocks now work correctly after save/quit/reload
- 🐛 **Fix: SignalBus cross-world pollution** — Static state properly cleared on server stop
- 🐛 **Fix: NaN propagation** — Guarded POW, ROOT, PID, PID_POWER, CLAMP against NaN/Infinity
- 🐛 **Fix: LIT property crash guard** — All 6 block entities protected if block destroyed between ticks
- 🐛 **Fix: Monitor border rendering** — Visible from both sides, survives optimization mods
- 🐛 **Fix: Depth testing, world culling, screen rotation for Monitor**
- 🐛 **Fix: SpeedProxy shared static PID map → per-instance**
- 🐛 **Fix: Various GUI and node editing improvements**
- 🧹 **Cleanup: Dead code removal, i18n key cleanup, debug logging level reduced**