方块搜索服务

基本信息

属性 值
服务端基类 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):

  1. 通过 SearchCooldownService.checkSearchCooldown 限速;
  2. 调用 WorldUtils.getTileEntitiesAround(player, FindItConfig.SEARCH_RADIUS) 取得 TileEntity 列表(见 util/WorldUtils);
  3. 对每个 TileEntity:
    • if (!request.getBlockToFind().equals(tileEntity.getBlockType())) continue; —— 精确匹配方块类;
    • 若 FindIt.isGregTechLoaded() && tileEntity instanceof IGregTechTileEntity,则 tileMeta = gregTech.getMetaTileID(),否则 tileEntity.getBlockMetadata();
    • request.getMetaToFind() == tileMeta 时把坐标加入 positions;
  4. 列表达到 FindItConfig.MAX_RESPONSE_SIZE 时 break;
  5. 通过 FindItNetwork.CHANNEL.sendTo(new BlockFoundResponse(positions), player) 把响应发回客户端。

客户端 ClientBlockFindService.handleResponse(player, response):

  1. 若 positions 非空:
    • player.closeScreen() 关闭当前 NEI GUI;
    • 当 FindItConfig.ENABLE_ROTATE_VIEW 为 true 时调用 ClientFinderHelperUtils.lookAtTarget(player, response);
  2. 高亮渲染分支:
    • 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 中心。

算法:

  1. 取玩家 getPosition(1.0F) 眼睛坐标 eyesPos;
  2. 遍历 positions 用 getDistanceToCenter(欧氏距离)找最小距离点 nearestPos;
  3. center(nearestPos) 取方块中心坐标(+0.5, +0.5, +0.5);
  4. 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,新一次搜索会立即覆盖旧列表。

相关条目