方块搜索服务
基本信息
| 属性 | 值 |
|---|---|
| 服务端基类 | com.gtnh.findit.service.blockfinder.BlockFindService |
| 客户端类 | com.gtnh.findit.service.blockfinder.ClientBlockFindService(继承 BlockFindService) |
| 主类注册 | FindIt.preInit 中 event.getSide() == Side.CLIENT ? new ClientBlockFindService() : new BlockFindService() |
| 触发入口 | 搜索附近方块 热键 |
| 网络通道 | FindItNetwork.CHANNEL(com.gtnh.findit.FindItNetwork,SimpleNetworkWrapper 实例) |
| 消息流 | FindBlockRequest(C→S)→ BlockFoundResponse(S→C) |
功能
FindIt 的服务端方块搜索实现:在 ±FindItConfig.SEARCH_RADIUS 立方体内扫描所有 TileEntity,对每个 TileEntity 比对 block + meta,命中坐标通过 BlockFoundResponse 回传给客户端。
服务端 BlockFindService.handleRequest(player, request):
- 通过
SearchCooldownService.checkSearchCooldown限速; - 调用
WorldUtils.getTileEntitiesAround(player, FindItConfig.SEARCH_RADIUS)取得 TileEntity 列表(见util/WorldUtils); - 对每个 TileEntity:
if (!request.getBlockToFind().equals(tileEntity.getBlockType())) continue;—— 精确匹配方块类;- 若
FindIt.isGregTechLoaded() && tileEntity instanceof IGregTechTileEntity,则tileMeta = gregTech.getMetaTileID(),否则tileEntity.getBlockMetadata(); request.getMetaToFind() == tileMeta时把坐标加入positions;
- 列表达到
FindItConfig.MAX_RESPONSE_SIZE时break; - 通过
FindItNetwork.CHANNEL.sendTo(new BlockFoundResponse(positions), player)把响应发回客户端。
客户端 ClientBlockFindService.handleResponse(player, response):
- 若
positions非空:player.closeScreen()关闭当前 NEI GUI;- 当
FindItConfig.ENABLE_ROTATE_VIEW为 true 时调用ClientFinderHelperUtils.lookAtTarget(player, response);
- 高亮渲染分支:
FindItConfig.USE_PARTICLE_HIGHLIGHTER == true→ParticlePosition.highlightBlocks(player.worldObj, positions);- 否则 →
BlockHighlighter.highlightBlocks(positions, currentTimeMillis + BLOCK_HIGHLIGHTING_DURATION*1000L),由RenderWorldLastEvent钩子(WorldRenderListener)逐帧渲染。
关键数据结构
FindBlockRequest(C→S)
com.gtnh.findit.service.blockfinder.FindBlockRequest implements IMessage:
| 字段 | 类型 | 序列化 |
|---|---|---|
blockToFind |
Block |
Block.getIdFromBlock(block) → buf.writeShort(...) |
metaToFind |
int |
buf.writeShort(...) |
BlockFindInputHandler.findStack(stack) 调用 Block.getBlockFromItem(stack.getItem()) 取转 Block;当转 Block 是 Blocks.air 时直接返回 false(不可搜索)。metaToFind 取自 stack.getItemDamage()。
Handle.onMessage 守卫 message.blockToFind != null && message.blockToFind != Blocks.air,不满足直接丢弃。
BlockFoundResponse(S→C)
com.gtnh.findit.service.blockfinder.BlockFoundResponse implements IMessage:
| 字段 | 类型 | 序列化 |
|---|---|---|
positions |
List<ChunkPosition> |
长度 int,每个 (x, y, z) 各 1 个 int(ProtoUtils.writePositions/readPositions) |
Handle.onMessage 在 Side.CLIENT 通过 Minecraft.getMinecraft().thePlayer 调 ClientBlockFindService.getInstance().handleResponse(...)。
数值
| 数值 | 默认 | 字段 |
|---|---|---|
| 搜索半径 | 16 |
FindItConfig.SEARCH_RADIUS |
| 服务端冷却 | 10 tick |
FindItConfig.SEARCH_COOLDOWN |
| 最大响应数 | 20 |
FindItConfig.MAX_RESPONSE_SIZE |
| 方块高亮时长 | 8 秒 |
FindItConfig.BLOCK_HIGHLIGHTING_DURATION |
| 视角旋转 | 默认关闭 | FindItConfig.ENABLE_ROTATE_VIEW |
| 线框 vs 粒子 | 默认线框(关闭) | FindItConfig.USE_PARTICLE_HIGHLIGHTER |
渲染与工具类
BlockHighlighter(线框模式)
com.gtnh.findit.fx.BlockHighlighter 在 RenderWorldLastEvent 里逐帧画:
- 闪烁:
((time / 500) & 1) == 0时不画(500ms 翻转一次); - 颜色:
GL11.glColor4f(1.0f, 0.0f, 0.0f, 1.0f)纯红; - 线宽:
GL11.glLineWidth(3); GL11.glDisable(GL11.GL_DEPTH_TEST)与GL11.glDisable(GL11.GL_TEXTURE_2D),所有线框始终可见;- 命中方块是
BlockChest时用getChestHighlightBox适配相邻合并箱子碰撞箱,否则用getBlockHighlightBox; - 到期后
positions.clear()。
ParticlePosition(粒子模式)
com.gtnh.findit.fx.ParticlePosition extends EntityReddustFX:
- 颜色
(255/255f, 165/255f, 255/255f)淡红紫色; noClip=true,motionX/Y/Z *= 0.1、particleScale *= 2.0f、particleMaxAge *= 10;- 每个 ChunkPosition 粒子数:
particleCount = positions.size() <= 10 ? 12 : max(12 - (positions.size() - 10) / 2, 2)
- 每次搜索
validVersion++,旧批次粒子onUpdate()检测到版本不一致时setDead(),避免重叠渲染。
ClientFinderHelperUtils.lookAtTarget
com.gtnh.findit.util.ClientFinderHelperUtils.lookAtTarget(player, response) 把视角旋转到 response.getPositions() 中距离玩家眼睛坐标最近的 ChunkPosition 中心。
算法:
- 取玩家
getPosition(1.0F)眼睛坐标eyesPos; - 遍历
positions用getDistanceToCenter(欧氏距离)找最小距离点nearestPos; center(nearestPos)取方块中心坐标(+0.5, +0.5, +0.5);Rotation.lookAt(eyesPos, nearestPos)计算 yaw/pitch 并apply(player)。
第三方 mod 集成
- NotEnoughItems:注册
GuiContainerManager.addInputHandler与API.addHashBind("gui.findit.find_block", Keyboard.KEY_Y)。 - GregTech:服务端
IGregTechTileEntity使用getMetaTileID()取 meta(而非原方块 meta)以正确匹配 GregTech 元 TileEntity。
限制
- 服务端仅按 Block 类精确匹配 + meta 整数匹配;不支持 NBT / TileEntity 自定义字段过滤。
- 不做异步分块扫描:单次
WorldUtils.getTileEntitiesAround同步遍历所有 TileEntity,超大SEARCH_RADIUS时性能随立方体内 TileEntity 数恶化。 BlockFoundResponse.positions受MAX_RESPONSE_SIZE截断;服务端先到先得,没有按距离排序。BlockHighlighter.highlightBlocks(positions, expire)只保留最后一次的positions,新一次搜索会立即覆盖旧列表。
相关条目
- 搜索附近方块 热键 - 触发本服务的客户端入口
- FindItConfig - 所有可调开关
- 搜索冷却服务 - 服务端每玩家 tick 冷却
- 物品搜索服务 - 配对服务,按 ItemStack/NBT/FluidStack 匹配