传送器侧面模式系统(Attachment Modes)

基本信息

属性 值
实现类 codechicken.translocator.TileTranslocator.Attachment(内部类)
归属方块 Translocator:translocator(metadata 0 / 1 共用)
侧面数量 6(Attachment[] attachments = new Attachment[6],下/上/北/南/西/东,side ^ 1 即对面)
生效范围 物品传送器与液体传送器共用同一套模式,见下方变体对比
持久化 每个侧面一个 NBT 复合标签 atmt0 … atmt5

这是整个 mod 的核心机制:传送器本体只是一个"壳",真正干活的是它 6 个侧面上的 Attachment。 TileTranslocator 本身是抽象类,只负责侧面的增删、NBT/网络包同步、射线检测用的碰撞盒和红石供电判定; 具体"搬什么"由两个子类实现——物品走 物品传送器,液体走 液体传送器。

侧面的创建与销毁

创建:用 物品传送器方块物品右键贴在一个容器/罐体表面时, ItemTranslocator.placeBlockAt 调用 createAttachment(side ^ 1),在朝向目标那一面新建一个侧面。 已存在侧面的那一面不能重复添加(if (ttrans.attachments[side ^ 1] != null) return false)。

合法性:BlockTranslocator.canExistOnSide 按 metadata 判定 —— metadata 0 要求 world.getTileEntity(...) instanceof IInventory; metadata 1 要求 instanceof IFluidHandler。不满足则不能附着。

自动销毁:邻接方块变化时 onNeighborBlockChange 遍历 6 面,只要有一面不再满足上面的条件 就调用 harvestPart(i, true) 回收该侧。harvestPart 掉落该侧的物品后把 attachments[i] 置 null, 并检查是否所有侧面都没了——是则把整个方块变成空气。

拆除单个侧面:准星对准某个面左键,removedByPlayer 用射线命中结果里的 subHit % 6 决定拆哪一面, 只掉这一面及其附加物(升级件),方块本体保留;最后一面被拆掉时方块才消失。 quantityDropped 返回 0、掉落完全由 getDrops 逐面收集 —— 这就是为什么拆一个装满升级件的 六面传送器能拿回整套零件。

侧面状态字段

字段 含义 默认值 持久化键
side 所属面(0~5) 构造入参 不保存(由下标决定)
a_eject 抽出面(true=从这一面往外抽) true 不保存(由红石算出)
b_eject 上一 tick 的 a_eject,用于插值 true 不保存
redstone 是否受红石控制 false redstone
invert_redstone 红石逻辑是否取反 true invert_redstone
fast 高速模式(Glowstone 粉) false fast
a_insertpos / b_insertpos 中间插针的伸出进度(1=伸出,0=缩回) 1 不保存
a_insertpos 同上(当前) 1 —

a_eject 的计算式(Attachment.update):

a_eject = (redstone && gettingPowered()) != invert_redstone;

即 红石关闭时永远抽出;红石打开后,是否抽出 = !gettingPowered() XOR invert_redstone, 默认 invert_redstone = true,所以给红石信号 = 停止抽出(可改成给信号才抽出)。 gettingPowered() 用 worldObj.isBlockIndirectlyGettingPowered,是间接供电判定,所以放在红石粉旁边即可。

交互方式

对某一个面右键时,BlockTranslocator.onBlockActivated 先做射线检测: 命中外圈底座(subHit < 6 且局部 x、z 都在 ±2/16 格内)则改判为中心插针(subHit += 6)。 所以一个面有 2 个可点击的子部位:外圈和中心按钮。

触发 条件 行为
右键·外圈·空手 held == null 且 subPart == 0 打开该面的 GUI(物品传送器弹出过滤器界面;液体传送器不弹出任何界面)
右键·中心按钮·空手 held == null 且 subPart == 1 翻转 invert_redstone(切换红石取反逻辑)
右键·空手·潜行 held == null 且 isSneaking() 调用 stripModifiers(),拆掉这一面所有升级件并原样掉回
右键·持红石粉 Items.redstone 且该面未装过 装上红石模式,扣 1 个;并把 invert_redstone 翻转让当前状态保持不变
右键·持萤石粉 Items.glowstone_dust 且该面未装过 装上高速模式,扣 1 个
其他持物 任意 落到 openGui / 子类逻辑
左键·任意面 — 拆掉这一面(见上)

拆除掉的升级件(stripModifiers):红石粉(1 个)、Glowstone 粉(1 个); 物品传送器额外掉 钻石粒 或铁锭; 液体传送器额外掉 GregTech 泵盖。

stripModifiers 里有一行细节:拆掉红石粉时会检查 invert_redstone != a_eject, 如果不一致就把它翻回来,所以拆完后当前的红石表现不变。

渲染图标位

Attachment.getIconIndex() 把状态压成一个贴图列索引,渲染器用它取 translocator:textures/tex.png 上的状态图元(field / 64.0 取横坐标,metadata / 2 取纵坐标):

位 含义
1 / 2 装了红石粉,且当前未通电 / 通电(redstone ? (gettingPowered() ? 2 : 1) : 0)
4 高速模式
8 物品变体独有:调节(regulate)模式
16 / 32 物品变体独有:已装铁锭信号器,当前未充能 / 充能

变体对比:基础 / 物品 / 液体三层

TileTranslocator 是抽象基类,两个子类的差异全部来自 createAttachment 造出的侧面类型。

属性 基础(TileTranslocator) 物品(TileItemTranslocator) 液体(TileLiquidTranslocator)
metadata 0 与 1 共用壳 0 1
侧面类 Attachment Attachment + ItemAttachment Attachment + LiquidAttachment
目标方块要求 由 canExistOnSide 判定 IInventory IFluidHandler
每 tick 抽出上限 抽象,未实现 1 个(fast 时整叠) 100 mB(fast 时 1000 mB)
过滤器 无 9 格,每格 1 / 64 / 65535 个(见物品页) 完全没有,只按流体类型自动分配
额外升级件 红石粉、Glowstone 粉 钻石粒(调节)、铁锭(信号器) GregTech 泵盖(自定义流量)
每 tick 输出分配 未实现 随机拆分到所有注入面,先非红石面后红石面 随机拆分到所有注入面,先非红石面后红石面
客户端动画 插针伸缩 物品实体沿路径浮动 螺旋流体带 + 粒子连线
实现 IFluidHandler 否 否 是(但自身 fill/drain 全部返回 0/null,只用于 WAILA 显示 6 个 0 容量罐体)
输出优先级 — redstone == false 的注入面优先 redstone == false 的注入面优先

三层的关系是「继承 + 覆盖」,不是并列:TileLiquidTranslocator 的 updateEntity() 先调 super.updateEntity()(即 TileTranslocator 的侧面状态推进),再叠加自己的抽取逻辑; TileItemTranslocator 同理。

相关条目