操作很短,规则很实在:挖掘只认前景层、放置走服务端、合成要摆对九宫格。
快捷栏 9 格,方块来自资源包 mapper 的 block.* 调色板。
| 按键 | 作用 | 说明 |
|---|---|---|
| WASD / 方向键 / 空格 | 移动、跳跃 | 引擎自带;Shift 之类的组合要看引擎实现 |
| 1 – 9 | 切换快捷栏方块 | 方块名与库存显示在快捷栏上方 |
| 鼠标左键 | 挖方块 | 掉落进背包(下面有规则) |
| 鼠标右键 | 放置选中的方块 | 由内核点击钩子接管,跳过引擎默认的"放泥土" |
| I | 背包 + 3×3 合成台 | 点材料放入 / 点格子取回 / 点产物格合成 |
| ESC | 设置面板 | 缩放、HUD 透明度与大小、诊断行、全屏、创造模式 |
| R | 重载资源包 | 引擎自带(改完贴图不用重启) |
| E / Q | 已被引擎占用 | 引擎的 client.World 用它们做相机缩放 —— 别再拿来做面板 |
钩子跑在“引擎真正移除之前”,所以能读到现在是什么方块。
// mod 侧(服务端):左键点击钩子里先记掉落,再放行让引擎去挖 if (clickType == 0) { if (!hasForegroundBlock(api, cx, cy, lx, ly)) return false; // 背景层挖不掉 → 没有掉落 BlockAPI b = api.blockManager().getBlock(cx, cy, lx, ly); String drop = Items.dropOf(b.getBlockType()); // 矿石→材料,草方块→泥土,草/树叶→不掉 if (drop != null) { addItem(conn, drop, 1); syncInventory(conn); } return false; // 交给引擎去挖 }
Chunk.setBackgroundBlock(),
它只往数组里塞、从不设置 isBackground = true,所以地形背景方块的
isBackground() 全是 false。照它判断的话,对着背景格狂点左键就能无限刷。getBlock() 是“前景没有就返回背景”,光看它分不出层;((server.Chunk) chunkManager.getChunk(cx,cy)).getForegroundBlock(lx,ly) != null;按 I 打开。左边是背包(9 列),中间 3×3,右边产物格。
客户端只发“九宫格里的九个物品”,服务端用同一份配方表
(Items.matchGrid,无序匹配)判配方,再核对背包里确实有这些材料,
才扣料、加产物、把新背包推回客户端。摆错或材料不够,服务端什么都不动。
只走一条路 —— 引擎自己的点击包 + 内核钩子。
PlaceRequest,它跑在
ModLoader.tickAll()(GameWorld.onTick() 之后),会越过引擎同 tick 的
“放/挖到达顺序”,于是“右键放 → 同一 tick 左键挖”变成“挖掉又被放回来”。现在那条通道只注册、不写世界。mods\*.jar 与 plant-mod-agent.jar 只在启动时读一次。改完立刻生效,并存进游戏目录的 hotbar.settings(删掉即恢复默认)。
| 行 | 范围 | 写进配置 |
|---|---|---|
| 相机缩放 | 0.25 – 5.0,步进 0.25 | zoom |
| 快捷栏透明度 | 20% – 100% | hudAlpha |
| 快捷栏大小 | 24 – 72 像素 | cellSize |
| 显示诊断行 | 开 / 关 | showDiag |
| 全屏 | 窗口 ↔ 全屏 | —(不持久化) |
| 无限放置(创造模式) | 开 / 关 | creative |