Minecraft插件开发:如何实现关联IP的全链路查询功能?
实现全链路IP关联查询(Minecraft插件)
问题分析
你的现有代码仅能获取直接关联的IP(即与目标IP同属一个玩家的IP),无法通过玩家作为桥梁,递归发现间接关联的IP。要实现全链路查询,本质是解决图的连通性遍历问题——把IP和玩家看作节点,玩家与自己的所有IP相连,我们需要找出与目标IP连通的所有IP节点。
解决方案代码
import org.bukkit.plugin.Plugin; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.*; import java.util.stream.Collectors; public class IpLinkageChecker { private static final Plugin plugin = Plugin.getPlugin(); private static final File ipFile = new File(plugin.getDataFolder(), "ips.yml"); // 双向映射:玩家UUID -> 对应IP列表;IP -> 使用过该IP的玩家UUID集合 private static Map<UUID, List<String>> playerToIps; private static Map<String, Set<UUID>> ipToPlayers; // 静态加载配置,避免重复读文件 static { reloadIpData(); } /** * 重新加载IP配置文件 */ public static void reloadIpData() { FileConfiguration ipLog = YamlConfiguration.loadConfiguration(ipFile); playerToIps = ipLog.getKeys(false).stream() .collect(Collectors.toMap(UUID::fromString, ipLog::getStringList)); // 构建IP到玩家的反向映射 ipToPlayers = new HashMap<>(); for (Map.Entry<UUID, List<String>> entry : playerToIps.entrySet()) { UUID playerId = entry.getKey(); for (String ip : entry.getValue()) { ipToPlayers.computeIfAbsent(ip, k -> new HashSet<>()).add(playerId); } } } /** * 获取与目标IP全链路关联的所有IP(直接+间接) * @param targetIp 要查询的目标IP * @return 所有关联IP的列表 */ public static List<String> getAssociatedIPs(String targetIp) { Set<String> visitedIps = new HashSet<>(); Set<UUID> visitedPlayers = new HashSet<>(); Queue<String> exploreQueue = new LinkedList<>(); // 初始化队列,从目标IP开始探索 exploreQueue.add(targetIp); while (!exploreQueue.isEmpty()) { String currentIp = exploreQueue.poll(); // 跳过已处理过的IP if (visitedIps.contains(currentIp)) { continue; } visitedIps.add(currentIp); // 获取使用过当前IP的所有玩家 Set<UUID> relatedPlayers = ipToPlayers.getOrDefault(currentIp, Collections.emptySet()); for (UUID playerId : relatedPlayers) { // 跳过已处理过的玩家 if (visitedPlayers.contains(playerId)) { continue; } visitedPlayers.add(playerId); // 将该玩家的所有IP加入队列,继续探索关联链路 List<String> playerRelatedIps = playerToIps.getOrDefault(playerId, Collections.emptyList()); exploreQueue.addAll(playerRelatedIps); } } return new ArrayList<>(visitedIps); } }
关键改进说明
- 修复文件路径错误:原代码中
new File(plugin.getDataFolder())指向的是插件数据文件夹,不是ips.yml文件,已修正为正确的文件路径。 - 双向映射优化:提前构建
IP -> 玩家和玩家 -> IP的双向映射,避免每次查询重复解析YAML,大幅提升效率。 - BFS遍历实现全链路查询:
- 使用队列存储待探索的IP,从目标IP出发,逐层探索关联玩家和IP
- 用
visitedIps和visitedPlayers集合避免重复处理,防止死循环 - 最终收集所有连通的IP,包含直接和间接关联的结果
- 代码健壮性:使用
getOrDefault处理不存在的IP/玩家,避免空指针异常。
测试验证
以你的示例配置为例,输入127.0.0.1时,函数会返回:["127.0.0.0", "127.0.0.1", "127.0.0.2", "127.0.0.3", "127.0.0.4"],符合全链路关联的需求。
内容的提问来源于stack exchange,提问作者izzzzthewiz
相关产品推荐
相关产品推荐

