合成网格(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 的完整判定链:
disableCraftingGridKey为 true 时直接失败(配置项,见 模组配置)- 必须
side == 1(顶面)或目标是Blocks.snow_layer - 若目标不是
vine/tallgrass/deadbush且!isReplaceable,则y++(往上顶一格) - 下方
y-1必须world.isSideSolid(..., ForgeDirection.UP)——必须有实心支撑面 world.canPlaceEntityOnSide(...)通过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):
- 用 9 个格子构造
InventoryCrafting(3, 3) - 最多 4 轮:
CraftingManager.findMatchingRecipe(matrix, worldObj);不匹配就rotateItems再试 - 匹配成功 →
doCraft:成品先给玩家(背包满则掉落),触发FMLCommonHandler.firePlayerCraftingEvent,mresult.onCrafting(...),然后 9 个格子每格 -1;若该物品有容器则替换为容器(奶桶→桶) - 无论是否合成成功,最后都
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() |