控制面板交互动作
[!INFO] 源码:
src/main/scala/gcewing/projectblue/ControlPanelPart.java
控制面板部件的每一次点击都走 activateCell(int i, EntityPlayer, ItemStack)。手持物决定动作;空手(或不匹配的手持物)则触发控件本身。
动作分发表
activateCell 按顺序判定,命中即 return:
| 顺序 | 条件 | 动作 | 消耗 |
|---|---|---|---|
| 1 | 手持 SprayCanItem |
设置该格通道色;颜色 16 时改为「按格号自动」 | 喷漆罐转 durability |
| 2 | 手持 Items.dye |
设置该格通道色 = 15 - meta |
扣 1 个(非创造) |
| 3 | 手持 Project Red ItemScrewdriver 且潜行 |
切换 flush / surface 安装方式 | 不消耗 |
| 4 | 手持 ItemScrewdriver(不潜行)且该格有控件 |
移除控件并掉落 | 不消耗 |
| 5 | 手持 ItemScrewdriver(不潜行)且该格为空 |
旋转面板(rot = (rot+1)&0x3) |
不消耗 |
| 6 | 手持木炭(Items.coal meta 1) |
打开文字编辑 GUI | 不消耗 |
| 7 | 该格为空 + 手持 miniatureLever |
放入 LEVER | 扣 1 个 |
| 8 | 该格为空 + 手持 miniatureButton |
放入 BUTTON | 扣 1 个 |
| 9 | 该格为空 + 手持 miniatureLamp |
放入 LAMP | 扣 1 个 |
| 10 | 该格为空 + 手持 miniatureCover 且其 NBT mat == 面板基材名 |
放入 BLANK | 扣 1 个 |
| 11 | 以上都不满足 | activateControl(i) — 拨动拉杆 / 按下按钮 |
不消耗 |
LEVER / BUTTON 放入时把手持物的 meta 存为该格的通道色(setControlMeta(i, meta))。
控件行为
| 控件 | 行为 | 细节 |
|---|---|---|
| LEVER | 状态异或 1(开关) | 播放 random.click 音,pitch 0.6(开)/ 0.5(关) |
| BUTTON | 置 1 并计时 20 tick(1 秒)后自动回 0 | buttonDownTime = 20;scheduleTick 自我重排 |
| LAMP | 无输出,仅作为显示 | 状态由外部输入决定,见下 |
| BLANK | 无功能,纯装饰/填充 | 拆下时掉落带 mat NBT 的 miniatureCover |
LAMP 格子在 getInputs() 中被外部信号驱动:setControlState(i, sig[ch] != 0 ? 1 : 0),其中 ch = getChannelColor(i)。
特殊交互
- 潜行 + 螺丝刀点击(
click()而非activate())→ 破坏并掉落整个面板(harvest)。与普通破坏不同,这条路径直接调tile().dropItems(getDrops())+remPart,绕过工具。 - 同一 tick 只处理一次:
activate用静态lastActivateTime去重(源码注释说明手持物非空时会被调用两次)。 - 改通道色后会
FaceUtils.notifyAllNeighbors(this, side)并播放step.snow音效。
坐标 → 格子映射
activate 用命中点反算格子:
i = floor((p.z + 0.5) * gridSize) // 行(局部 Z 轴)
j = floor((-p.x + 0.5) * gridSize) // 列(局部 X 轴取反)
cell = i * gridSize + j
p 是命中点经 localToGlobalTransformation 变换到部件局部坐标后的结果。
信号方向
面板是 IBundledEmitter:getBundledSignal(side) 遍历活跃格子,把状态 > 0 的 LEVER/BUTTON 按其通道色置 signal[channel] = 255。