You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
    }
}

关键改进说明

  1. 修复文件路径错误:原代码中new File(plugin.getDataFolder())指向的是插件数据文件夹,不是ips.yml文件,已修正为正确的文件路径。
  2. 双向映射优化:提前构建IP -> 玩家和玩家 -> IP的双向映射,避免每次查询重复解析YAML,大幅提升效率。
  3. BFS遍历实现全链路查询:
    • 使用队列存储待探索的IP,从目标IP出发,逐层探索关联玩家和IP
    • 用visitedIps和visitedPlayers集合避免重复处理,防止死循环
    • 最终收集所有连通的IP,包含直接和间接关联的结果
  4. 代码健壮性:使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 05:15:00