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

Spigot插件开发:按概率从列表随机获取Rarity对象问题

问题分析与解决方案

原代码核心问题

  1. 概率被错误缩放:random方法里将每个Rarity的概率除以4,完全扭曲了配置的概率值,导致实际生效的概率远低于预期。
  2. 随机数生成不规范:每次调用random都新建Random实例,既浪费资源又可能导致随机结果不均匀。
  3. 概率总和超标:示例概率总和为55+35+12+6+3+0.1=111.1%,超过100%,这会导致必然返回某个对象,不符合“允许不出结果”的需求。
  4. 无序遍历导致逻辑混乱:使用HashMap.keySet()遍历,元素顺序不确定,调试和概率判断逻辑易出问题。

修正后的代码实现

private final Map<Integer, Rarity> classes = new HashMap<>();
// 复用同一个Random实例,避免重复创建
private final Random random = new Random();

public MobKillListener() {
    for (Map<Integer, Rarity> rarityMap : SchemePlugin.getInstance().getSchemeConfig().classes) {
        classes.putAll(rarityMap);
    }
}

@EventHandler
public void onMobKill(EntityDeathEvent event) {
    if (!(event.getEntity().getKiller() instanceof Player))
        return;

    // 将Rarity和对应的概率整理成有序列表
    List<Map.Entry<Rarity, Double>> rarityList = new ArrayList<>();
    double totalProbability = 0.0;
    for (Rarity rarity : classes.values()) {
        rarityList.add(new AbstractMap.SimpleEntry<>(rarity, rarity.rarity));
        totalProbability += rarity.rarity;
    }

    // 若总概率超过100%,按比例缩放至100%(可选,也可改为提示配置错误)
    if (totalProbability > 100.0) {
        double scale = 100.0 / totalProbability;
        for (int i = 0; i < rarityList.size(); i++) {
            Map.Entry<Rarity, Double> entry = rarityList.get(i);
            rarityList.set(i, new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue() * scale));
        }
        totalProbability = 100.0;
    }

    Rarity rarity = randomSelect(rarityList, totalProbability);
    if (rarity != null) {
        // 执行你的业务逻辑
    }
}

// 正确的概率随机选择方法
private Rarity randomSelect(List<Map.Entry<Rarity, Double>> rarityList, double totalProbability) {
    // 生成0到100之间的随机数
    double rand = random.nextDouble() * 100.0;
    double currentTotal = 0.0;

    for (Map.Entry<Rarity, Double> entry : rarityList) {
        double chance = entry.getValue();
        currentTotal += chance;

        if (rand <= currentTotal) {
            System.out.printf("命中概率: %.2f%%, 当前累加值: %.2f, 随机数: %.2f%n", chance, currentTotal, rand);
            return entry.getKey();
        }
    }

    // 随机数超过所有概率总和,返回null(无产出)
    System.out.printf("未命中任何对象,总概率: %.2f, 随机数: %.2f%n", totalProbability, rand);
    return null;
}

关键优化点

  • 概率逻辑修正:直接使用配置的原始概率值,不再做无意义的除法;若总概率超标,自动按比例缩放至100%,避免必然出结果的问题。
  • 复用Random实例:使用类初始化的random对象,保证随机结果的均匀性。
  • 有序遍历:用ArrayList存储Rarity和概率的键值对,遍历顺序稳定,便于调试和维护。
  • 明确的空返回逻辑:当随机数大于所有Rarity的概率总和时,返回null,实现“允许不出结果”的需求。

额外说明

如果要严格保留配置的概率值(即使总和超过100%),同时保留“不出结果”的可能,可修改randomSelect方法的随机数生成逻辑:

// 随机数范围设为0到总概率和100的较大值,超过100的部分对应无产出
double maxRange = Math.max(100.0, totalProbability);
double rand = random.nextDouble() * maxRange;

内容的提问来源于stack exchange,提问作者reiizl

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 01:30:25