Drawbridge
基本信息
| 属性 | 值 |
|---|---|
| 注册名 | TMechworks:redstoneMachine |
| metadata | 0 |
| 方块类 | RedstoneMachine(InventoryBlock) |
| TileEntity | DrawbridgeLogic(InventoryLogic 2 槽,实现 IFacingLogic / IActiveLogic / IDrawbridgeLogicBase) |
| 材质 | Material.iron |
| 硬度 | 12(setHardness(12)) |
| 步声 | soundTypeMetal |
| 爆炸抗性 | 未调用 setter —— Block 默认 10.0 |
| 亮度 | 动态:getLightValue 读取槽 1 中的方块亮度(见下) |
| 最大伸展 | 15 格(maxExtension = 15,byte) |
| GUI ID | 0(CommonProxy.drawbridgeID) |
| 假玩家 | FakePlayerLogic(GameProfile 名 Player.Drawbridge) |
| 放置音效 | tile.piston.out,音量 0.25F |
| TE 槽数 | 2(槽 0 = 待放置方块,槽 1 = 「伪装」方块,只影响渲染与光照) |
功能
BuildCraft 式伸缩桥。红石激活时沿面朝方向逐格放置 inventory[0] 中的方块;取消激活时逐格收回。放置由 FakePlayerLogic 执行,因此方块的 onBlockPlaced 看到的是一个合法玩家。
updateEntity 逻辑(blocks/logic/DrawbridgeLogic.java:239+):
working && !isInvalid() && !worldObj.isRemote
ticks++; if (ticks == 5) { ticks = 0;
if (active) { // 伸出
if (inventory[0] != null && stackSize > 0 && extension < maxExtension) {
extension++;
按 direction 偏移得到 (xPos,yPos,zPos)
越界检查 → extension-- 并 working=false
目标格必须 为空气 或 canPlaceBlockAt
placeBlockAt(bufferStack, fakePlayer, world, ..., bufferStack.getItemDamage(), placeBlock)
playSoundEffect("tile.piston.out", 0.25F, ...)
}
} else { ... } // 收回
}
朝向(direction,6 值)
放置时由 setDirection(yaw, pitch, player) 决定:俯视(pitch > 45)→ 1(下);仰视(pitch < -45)→ 0(上);否则按 yaw 映射为 2(北)/ 5(东)/ 3(南)/ 4(西)。
动态亮度(RedstoneMachine.getLightValue)
metadata == 0 或 2 时,读取槽 1 的方块并返回其 getLightValue();槽 1 为空则回落到 super。这是唯一让 Drawbridge 变成光源的途径。
实际放置规则
updateEntity 的判定链(blocks/logic/DrawbridgeLogic.java:396-400):
if (bufferStack != null && validBlock(block) && validMetadata(block, meta) // 恒 true
&& validDrawbridge(xPos, yPos, zPos) && !hasInventory(xPos, yPos, zPos))
validMetadata 是恒 return true 的桩(:476-483,真实逻辑被注释在 javadoc 块里),因此 TMechworksRegistry 的 137 条 drawbridgeState 白名单运行时从未被读取。详见 Drawbridge 放置规则。
生效的过滤只有 isItemValidForSlot(:580-596):必须是 ItemBlock、不在配置黑名单中;槽 1 额外要求 isOpaqueCube() && renderAsNormalBlock() 且堆叠为 1。
伪装渲染
getIcon(IBlockAccess, x, y, z, side):若槽 1 中的方块 renderAsNormalBlock(),直接返回该方块的贴图 —— 即可把 Drawbridge 伪装成任意普通方块。colorMultiplier 同样透传槽 1 的染色值。
数值
| 数值 | 值 |
|---|---|
| metadata | 0 |
| 最大伸展 | 15 格 |
| 伸/缩频率 | 每 5 tick 1 格(0.25 s/格) |
| TE 槽数 | 2 |
| 槽 0 | 待放置方块(消耗源) |
| 槽 1 | 伪装方块(只影响 getIcon / getLightValue / colorMultiplier) |
| 越界上界 | yPos >= 256 或 |x/z| >= 30000000 → 回退 |
| 放置音效 | tile.piston.out 0.25F |
| GUI ID | 0 |
| 硬度 | 12 |
| 假玩家名 | Player.Drawbridge |
| 贴图数 | getTextureNames() 共 17 张(meta 0-3 各自取用) |
| 贴图域声明 | getTextureDomain() 返回 "tinker",但 registerBlockIcons 实际用 "tmechworks:machines/"(见缺陷) |
交互
| 触发 | 行为 |
|---|---|
| 红石脉冲 | setActive(true) → working = true → 每 5 tick 伸 1 格直到槽 0 空或达 15 |
| 红石撤除 | setActive(false) → 每 5 tick 缩 1 格直到 extension = 0 |
| 右键 | 打开 GUI(ID 0),4 个方向按钮设置 placementDirection |
| 槽 1 变化 | setInventorySlotContents / decrStackSize 对 slot 1 调 markBlockForUpdate |
| 断电/区块卸载 | invalidate() 置 fakePlayer = null(下次用时惰性重建) |
配方
common/MechRecipes.java:17-48,2 条(有/无 pattern 变体),图案相同:
a c a
# d #
# r #
| 符号 | 材料 |
|---|---|
# |
ingotBronze × 4 |
a |
ingotAluminumBrass × 2 |
c |
blankPattern meta 1 或 meta 2(两条配方各一) |
r |
minecraft:redstone × 1 |
d |
minecraft:dispenser × 1 |
TCon 手册另有 1 条 MantleClientRegistry.registerManualLargeRecipe("drawbridge", ...)(common/MechContent.java:158-169),图案为 3×3 大合成:redstoneMachine + 4×ingotAluminumBrass + blankPattern meta 1 + 4×ingotBronze + dispenser + redstone。
源码缺陷
getTextureDomain()与registerBlockIcons()不一致(blocks/RedstoneMachine.java:145-156):前者返回"tinker",后者硬编码"tmechworks:machines/"。前者是 MantleInventoryBlock抽象方法的遗留实现,实际无效但会误导读者以为贴图来自 TCon。setDirection(int side)是空方法(:100)—— MantleIFacingLogic的接口方法未实现,只有setDirection(yaw, pitch, player)生效。placeBlockAt前的if (Block.getBlockFromItem(inventory[0].getItem()) == null) return;会卡死(:290):extension++已在前面执行,若此时返回则不回退extension,导致 extension 虚增一格且不放置任何方块。interchangableBlockMapping的反向放置存在缺陷:redstone_ore/redstone_torch/unpowered_repeater/powered_repeater/unpowered_comparator/powered_comparator都只注册了单向映射(registry.put(Blocks.redstone_ore, Blocks.lit_redstone_ore)而无反向),而dirt/grass反而是双向(:222-223)。放置时只查blockToItemMapping,缺失方向的块无法通过 Drawbridge 放置。drawbridgeState中Blocks.tripwire_hook被 put 了两次(lib/TMechworksRegistry.java:191-192),第二次覆盖第一次,HashMap 无害但属冗余。canDropInventorySlot(int)恒false(:102-104),Mantle 销毁流程因此不返还槽内容物。bufferStack是字段而非局部变量(:52),跨 tick 残留,加载旧 NBT 时不会被清空。FakePlayerLogic用new GameProfile(null, "Player.Drawbridge"):UUID 为 null,靠initFakePlayer()惰性重建规避了区块加载时序问题(源码注释明确说明validate()里创建会造成 TileEntity 重复)。getLightValue每次调用最多读 3 次槽 1(getStackInSlot(1)被调用两次),无缓存。
相关条目
- Long Drawbridge - 同一 TE,
maxExtension改为 64 - Igniter - 同一方块 ID 的 meta 1
- Advanced Drawbridge - 同一方块 ID 的 meta 2
- Drawbridge 放置规则 - 110 项方块放置白名单
- Drawbridge GUI - 4 个方向按钮与槽位
- 网络管线 -
PacketDrawbridge同步 placementDirection