Bukkit 1.17.1通过飞行寻路计算玩家非固体路径距离实现聊天隔墙屏蔽
Bukkit 1.17.1 近场聊天遮挡判定解决方案
方案1:原生视线检测(推荐,性能更高)
你的需求本质是判断两名玩家之间是否存在固体方块遮挡,直接使用Bukkit原生提供的视线检测方法即可实现,无需调用复杂的NMS寻路接口,性能损耗极低,兼容性更好。
实现代码如下:
@EventHandler public void onAsyncPlayerChat(AsyncPlayerChatEvent e) { Player sender = e.getPlayer(); Location senderLoc = sender.getLocation(); World world = senderLoc.getWorld(); if (world == null) return; // 最大可接收聊天的距离阈值,单位为方块 final double MAX_CHAT_DISTANCE = 100D; // 使用迭代器安全移除接收者 Iterator<Player> receiverIter = e.getRecipients().iterator(); while (receiverIter.hasNext()) { Player receiver = receiverIter.next(); // 不同世界直接移除 if (!receiver.getWorld().equals(world)) { receiverIter.remove(); continue; } // 距离超过阈值直接移除 double distance = senderLoc.distance(receiver.getLocation()); if (distance > MAX_CHAT_DISTANCE) { receiverIter.remove(); continue; } // 无视线通路直接移除 if (!sender.hasLineOfSight(receiver)) { receiverIter.remove(); } } }
方案2:PathfinderFlying 正确获取路径长度方法
如果你确实需要计算非直线的可通行空气路径长度(比如允许玩家绕开小障碍物接收消息的场景),可以使用NMS寻路接口,你之前的调用方式存在两处问题:
- ChunkCache的Y轴范围设置错误,固定为0会导致高度不同的路径完全无法计算
- 你调用的
a(PathPoint[] var0, PathPoint var1)是A*寻路内部的启发式估值方法,并非实际路径长度计算接口,所以会返回固定值
正确实现代码如下:
@EventHandler public void onAsyncPlayerChat(AsyncPlayerChatEvent e) { Player sender = e.getPlayer(); Location start = sender.getLocation(); World bukkitWorld = start.getWorld(); if (bukkitWorld == null) return; net.minecraft.world.level.World nmsWorld = ((CraftPlayer) sender).getHandle().getWorld(); // 最大路径长度阈值、寻路范围阈值 final int MAX_PATH_LENGTH = 100; final int SEARCH_RANGE = 128; PathfinderFlying pathfinder = new PathfinderFlying(256); EntityInsentientImplementation pathEntity = new EntityInsentientImplementation(EntityTypes.am, nmsWorld); // 配置寻路实体属性,忽略水、熔岩等非固体障碍,根据需求调整 pathEntity.a(PathType.WATER, -1.0F); pathEntity.a(PathType.LAVA, -1.0F); Iterator<Player> receiverIter = e.getRecipients().iterator(); while (receiverIter.hasNext()) { Player receiver = receiverIter.next(); if (!receiver.getWorld().equals(bukkitWorld)) { receiverIter.remove(); continue; } Location dest = receiver.getLocation(); BlockPosition startPos = new BlockPosition(start.getX(), start.getY(), start.getZ()); BlockPosition destPos = new BlockPosition(dest.getX(), dest.getY(), dest.getZ()); // 生成完整路径 Path path = pathfinder.a(nmsWorld, pathEntity, startPos, destPos, SEARCH_RANGE); // 路径不存在、未到达终点、长度超过阈值均移除 if (path == null || !path.e() || path.getPathLength() > MAX_PATH_LENGTH) { receiverIter.remove(); } } }
注意:寻路操作CPU消耗极高,大量玩家同时聊天时容易触发服务器卡顿,非必要场景优先使用方案1。
内容的提问来源于stack exchange,提问作者Marvin Klar
相关产品推荐
相关产品推荐

