合成网格(Crafting Grid)

基本信息

属性 值
注册名 Translocator:craftingGrid(GameRegistry.registerBlock(blockCraftingGrid, "craftingGrid"))
方块类 codechicken.translocator.BlockCraftingGrid
TileEntity codechicken.translocator.TileCraftingGrid(hasTileEntity 仅 meta == 0)
本地化键 tile.craftingGrid.name=Crafting Grid
纹理根名 planks_oak(setBlockTextureName)
网格贴图 translocator:craftingGrid(registerBlockIcons 单独注册为 gridIcon)
材质 Material.wood
硬度 / 爆炸抗性 未显式设置,沿用 Block 默认(源码中没有 setHardness / setResistance / setLightLevel 调用)
碰撞箱 无(getCollisionBoundingBoxFromPool 返回 null)
不透明 / 常规渲染 isOpaqueCube() 与 renderAsNormalBlock() 均 false;getRenderType() 返回 -1
创造标签 无(未调用 setCreativeTab),且被 NEI 隐藏(API.hideItem)
摆放方式 只能用 C 键 放置

功能

一个贴地、3×3 的临时合成台:把物品放进 9 个格子,按 C 键合成,拿走成品。 与工作台的区别是它支持旋转配方——合成时会把 8 个外圈格子顺时针转 90°,最多试 4 个朝向, 所以对称摆放要求不存在的配方(如 2×2 的配方)也能合成出来。 用完后网格自动消失。

摆放要求

BlockCraftingGrid.placeBlock 的完整判定链:

  1. disableCraftingGridKey 为 true 时直接失败(配置项,见 模组配置)
  2. 必须 side == 1(顶面)或目标是 Blocks.snow_layer
  3. 若目标不是 vine / tallgrass / deadbush 且 !isReplaceable,则 y++(往上顶一格)
  4. 下方 y-1 必须 world.isSideSolid(..., ForgeDirection.UP)——必须有实心支撑面
  5. world.canPlaceEntityOnSide(...) 通过
  6. onBlockPlacedBy → TileCraftingGrid.onPlaced(entity):按放置者朝向设 rotation = (int)(yaw * 4 / 360 + 0.5) & 3(4 个朝向)

没有支撑就掉落:onNeighborBlockChange 发现下方不是实心顶面时 dropBlockAsItem 并置空气, 所以它是"贴地一次性"装置,不是可以挂半空的方块。

数值

数值名 值 来源
槽位数 9(3×3) ItemStack[] items = new ItemStack[9]
每格最多物品 1 个 activate 中 copyStack(held, 1)
合成超时(放置后未操作) 400 tick = 20 秒 字段初始值 public int timeout = 400;
合成超时(每次交互后重置) 2400 tick = 120 秒 activate 末尾 timeout = 2400;
合成朝向尝试次数 4(原向 + 3 次 90° 旋转) for (int i = 0; i < 4; i++)
旋转序列 {0,1,2,5,8,7,6,3},中心格 4 固定不动 rotateItems
旋转步长 arrangement[slots[(i + 2) % 8]] = ...(每次 = 2 步 = 90°) rotateItems
朝向数 4(rotation & 3) onPlaced
物品悬浮动画 0.1 + 0.01 * sin(i * 1.7 + time / 5) TileCraftingGridRenderer
成品悬浮高度 0.6 + 0.02 * sin(time / 10),缩放 0.8,带旋转 TileCraftingGridRenderer
格子缩放 0.5 TileCraftingGridRenderer

⚠️ 400 与 2400 是两个不同的值:字段初始值是 20 秒,但玩家每点一次格子就重置成 2 分钟。 也就是说放下去不动它 20 秒就消失,动过之后可以闲置 2 分钟。

交互

触发 行为
右键格子·空手 取回该格物品(背包满则掉在网格上)
右键格子·持物 放入 1 个;若与该格已有物品完全相同则拒绝(InventoryUtils.areStacksIdentical),换别的物品则替换并把旧的还给玩家
C 键·看向地面/顶面 放置新网格
C 键·看向已有网格 立即合成(服务端 TranslocatorSPH 包 type 2 → TileCraftingGrid.craft)
左键 破坏;getDrops 掉落 9 个格子里的全部物品(不是掉方块物品)
下方支撑被移除 dropBlockAsItem 掉落方块物品并置空气

合成流程

craft(player):

  1. 用 9 个格子构造 InventoryCrafting(3, 3)
  2. 最多 4 轮:CraftingManager.findMatchingRecipe(matrix, worldObj);不匹配就 rotateItems 再试
  3. 匹配成功 → doCraft:成品先给玩家(背包满则掉落),触发 FMLCommonHandler.firePlayerCraftingEvent, mresult.onCrafting(...),然后 9 个格子每格 -1;若该物品有容器则替换为容器(奶桶→桶)
  4. 无论是否合成成功,最后都 dropItems()(把剩余物品,如桶,掉在原地)并 setBlockToAir 移除网格

因此一次 C 键消耗网格本身,是"用完即焚"设计。

掉落

BlockCraftingGrid.getDrops 只掉 tcraft.items 里的物品,不掉方块物品本身 (quantityDropped 未覆盖,方块物品的掉落走 dropBlockAsItem)。 所以拆掉一个放了材料的网格能完整拿回材料。

获取方式

没有合成配方。只能靠 C 键放置;放置失败掉落会给出方块物品, 再右键地面放置——但 placeBlock 走的是 C 键路径,普通右键物品放置走 ItemBlock 默认逻辑, BlockCraftingGrid 未覆写 onBlockActivated 之外的放置逻辑,因此实际上生存里只能靠反复 C 键放置。 它在 NEI 里被 API.hideItem 隐藏,也不属于任何创造标签。

客户端渲染

TileCraftingGridRenderer:先把 gridIcon 贴图以 y + 0.001 的高度、normal (0,1,0) 画成一张贴地四边形; 再按 rotation 旋转矩阵,9 个物品按 (col-1)*5/16, 0.1+波动, (row-1)*5/16 摆放、缩放 0.5; 成品悬在中心上方 0.6、缩放 0.8 并持续旋转(RenderUtils.renderItemUniform(result, time))。 开启 GL12.GL_RESCALE_NORMAL 以正确显示法线。

网络

包 方向 作用
TranslocatorSPH type 1 C→S 放置网格(坐标 + sideHit)
TranslocatorSPH type 2 C→S 合成指定坐标的网格
TranslocatorCPH type 3 S→C 网格描述包(rotation + 9 个 ItemStack),客户端收到后 updateResult()

相关条目