放置范围客户端预览
魔杖瞄准方块时,客户端会用白色线框把即将放置的所有方块画出来。
这是 core/BlockEvents.java 在 DrawBlockHighlightEvent 中实现的。
基本信息
| 属性 | 值 |
|---|---|
| 类 | portablejim.bbw.core.BlockEvents |
| 注册 | ClientProxy.RegisterEvents() → MinecraftForge.EVENT_BUS.register(blockEvents) |
| 事件 | DrawBlockHighlightEvent(仅客户端存在) |
| 渲染 API | 纯 OpenGL 立即模式(LWJGL GL11) |
⚠️ 该类只在客户端加载(由
ClientProxy实例化)。 服务端的ServerProxy继承CommonProxy,RegisterEvents()是空实现, 因此服务端不做任何预览计算,也省掉了 BFS 的开销。
触发条件
三个条件必须同时满足才画预览:
if (event.currentItem != null && event.currentItem.getItem() instanceof IWandItem
&& event.target != null
&& event.target.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
| 条件 | 说明 |
|---|---|
手持物品是 IWandItem |
即本 mod 的四根魔杖之一 |
| 准星命中方块 | 不能命中实体或空气 |
sourceItems instanceof ItemBlock |
目标方块有对应的物品形式 |
第三个条件在源码里检查了两次(外层
IWandItem判断 + 内层重复判断), 属于冗余但无害的代码。
计算流程:与服务端完全一致
预览调用的是与服务端 onItemUse 同一套方法:
| 步骤 | 方法 |
|---|---|
| ① 取材料 | worker.getProperItemStack(worldShim, playerShim, clickedPos) |
| ② 查映射 | mappingManager.getMapping(targetedBlock, meta) |
| ③ 算上限 | Math.min(wand.getMaxBlocks(...), playerShim.countItems(...)) |
| ④ BFS | worker.getBlockPositionList(...) |
唯一差异:预览走 mappingManager.getMapping(block, meta),
而服务端 ItemBasicWand.getCustomMapping() 额外支持 Backhand 副手分支。
装了 Backhand 且副手持方块时,预览和实际放置的目标可能不一致。
countItems 里会走 AE2 的客户端分支(见 网络协议),
所以预览的上限也受 AE2 数量同步的 10 刻延迟影响。
渲染参数
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glDepthMask(true);
GL11.glLineWidth(2.5F);
for (Point3d block : blocks) {
AxisAlignedBB boundingBox = AxisAlignedBB
.getBoundingBox(x, y, z, x + 1, y + 1, z + 1)
.contract(0.005, 0.005, 0.005);
RenderGlobal.drawOutlinedBoundingBox(boundingBox.getOffsetBoundingBox(-interpolatedX, …), 0xC0C0C0);
}
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
| 参数 | 值 | 作用 |
|---|---|---|
| 线宽 | 2.5F |
比默认线更粗,远距离也看得清 |
| 颜色 | 0xC0C0C0 |
银灰 |
| AABB 收缩 | 每轴 0.005 |
避免相邻格线框重叠成实心块 |
| 深度写入 | glDepthMask(true) |
被实体遮挡的方块也能看到线框 |
| 混合 | GL_BLEND 开启/结束时关闭 |
半透明叠加 |
坐标做了插值平滑,避免跟随玩家时抖动:
double interpolatedX = event.player.lastTickPosX + (event.player.posX - event.player.lastTickPosX) * event.partialTicks;
绘制完会把 GL_TEXTURE_2D 和 GL_BLEND 状态还原,不污染其他渲染器。
边界情况
| 情况 | 表现 |
|---|---|
| BFS 结果为空(种子被面锁定拒绝) | 不画任何线框(if (!blocks.isEmpty())) |
| 目标方块在硬黑名单里 | getProperItemStack 返回 null → 不画 |
| 材料数量为 0 | countItems 返回 0 → maxBlocks = 0 → BFS 立刻退出 → 不画 |
| 创造模式 | CreativePlayerShim.countItems 恒 MAX_VALUE → 画出魔杖理论上限 |
⚠️ 创造模式预览会画出满上限范围(如 Unbreakable Wand 的 4096 格), 因为创造模式不扣材料也不扣耐久。
相关条目
- BFS 方块扩展算法 - 被复用的搜索逻辑
- 魔杖等级系统 - 决定线框大小的上限
- 魔杖物品通用行为 -
addInformation的工具提示 - AE2 Integration - 预览上限受数量同步延迟影响