From ec0e59294e46afea7843953166263e1afb467301 Mon Sep 17 00:00:00 2001 From: dudi4 Date: Tue, 9 Jun 2026 01:53:26 +0200 Subject: [PATCH] Fix preview roll chances ignoring permission-locked rewards The crate preview always computed roll chances against the global reward pool. Because the actual roll excludes rewards a player cannot win (gated by permissions/requirements), a player without access saw the locked reward hidden while the remaining rewards still displayed their global percentages, which no longer summed to 100%. Add a player-aware getRollChance(Player) that derives odds from the pool actually available to that player, at both the rarity and reward level, and use it in PreviewMenu. The no-arg getRollChance() now delegates to the global pool, so editor/admin displays are unchanged. A reward the player cannot win reports 0%. --- .../excellentcrates/api/crate/Reward.java | 3 +++ .../excellentcrates/crate/impl/Crate.java | 7 ++++++- .../excellentcrates/crate/impl/Rarity.java | 8 +++++++- .../excellentcrates/crate/menu/PreviewMenu.java | 5 +++++ .../crate/reward/AbstractReward.java | 17 +++++++++++++++-- 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/main/java/su/nightexpress/excellentcrates/api/crate/Reward.java b/src/main/java/su/nightexpress/excellentcrates/api/crate/Reward.java index 8821768a..444fbc18 100644 --- a/src/main/java/su/nightexpress/excellentcrates/api/crate/Reward.java +++ b/src/main/java/su/nightexpress/excellentcrates/api/crate/Reward.java @@ -3,6 +3,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import su.nightexpress.excellentcrates.crate.impl.Crate; import su.nightexpress.excellentcrates.crate.impl.Rarity; import su.nightexpress.excellentcrates.crate.limit.LimitValues; @@ -49,6 +50,8 @@ public interface Reward extends Writeable { double getRollChance(); + double getRollChance(@Nullable Player player); + @NotNull String getId(); @NotNull Crate getCrate(); diff --git a/src/main/java/su/nightexpress/excellentcrates/crate/impl/Crate.java b/src/main/java/su/nightexpress/excellentcrates/crate/impl/Crate.java index 243062e4..9d548679 100644 --- a/src/main/java/su/nightexpress/excellentcrates/crate/impl/Crate.java +++ b/src/main/java/su/nightexpress/excellentcrates/crate/impl/Crate.java @@ -820,7 +820,12 @@ public LinkedHashMap getRewardsMap() { @NotNull public Set getRarities() { - return this.getRewards().stream().map(Reward::getRarity).collect(Collectors.toSet()); + return this.getRarities(null); + } + + @NotNull + public Set getRarities(@Nullable Player player) { + return this.getRewards(player, null).stream().map(Reward::getRarity).collect(Collectors.toSet()); } @NotNull diff --git a/src/main/java/su/nightexpress/excellentcrates/crate/impl/Rarity.java b/src/main/java/su/nightexpress/excellentcrates/crate/impl/Rarity.java index ab052d9e..d2a31375 100644 --- a/src/main/java/su/nightexpress/excellentcrates/crate/impl/Rarity.java +++ b/src/main/java/su/nightexpress/excellentcrates/crate/impl/Rarity.java @@ -1,6 +1,8 @@ package su.nightexpress.excellentcrates.crate.impl; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import su.nightexpress.excellentcrates.CratesPlugin; import su.nightexpress.excellentcrates.Placeholders; import su.nightexpress.nightcore.config.FileConfig; @@ -47,7 +49,11 @@ public double getRollChance() { } public double getRollChance(@NotNull Crate crate) { - return this.getRollChance(crate.getRarities()); + return this.getRollChance(crate, null); + } + + public double getRollChance(@NotNull Crate crate, @Nullable Player player) { + return this.getRollChance(crate.getRarities(player)); } public double getRollChance(@NotNull Collection rarities) { diff --git a/src/main/java/su/nightexpress/excellentcrates/crate/menu/PreviewMenu.java b/src/main/java/su/nightexpress/excellentcrates/crate/menu/PreviewMenu.java index cf492d2b..0605a579 100644 --- a/src/main/java/su/nightexpress/excellentcrates/crate/menu/PreviewMenu.java +++ b/src/main/java/su/nightexpress/excellentcrates/crate/menu/PreviewMenu.java @@ -23,6 +23,7 @@ import su.nightexpress.nightcore.ui.menu.item.MenuItem; import su.nightexpress.nightcore.ui.menu.type.LinkedMenu; import su.nightexpress.nightcore.util.Lists; +import su.nightexpress.nightcore.util.NumberUtil; import su.nightexpress.nightcore.util.bukkit.NightItem; import su.nightexpress.nightcore.util.placeholder.Replacer; @@ -100,6 +101,10 @@ public MenuFiller createFiller(@NotNull MenuViewer viewer) { .setLore(this.rewardLore) .replacement(replacer -> { replacer + // Player-aware odds: reflect the rewards actually rollable for THIS player, + // so permission-locked rewards don't skew the previewed percentages. + .replace(REWARD_ROLL_CHANCE, () -> NumberUtil.format(reward.getRollChance(player))) + .replace(REWARD_RARITY_ROLL_CHANCE, () -> NumberUtil.format(reward.getRarity().getRollChance(crate, player))) .replace(GENERIC_LIMITS, limits) .replace(NO_PERMISSION, restrictions) .replace("%win_limit_amount%", limits) diff --git a/src/main/java/su/nightexpress/excellentcrates/crate/reward/AbstractReward.java b/src/main/java/su/nightexpress/excellentcrates/crate/reward/AbstractReward.java index 0d40feb2..84ff5f39 100644 --- a/src/main/java/su/nightexpress/excellentcrates/crate/reward/AbstractReward.java +++ b/src/main/java/su/nightexpress/excellentcrates/crate/reward/AbstractReward.java @@ -2,6 +2,7 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import su.nightexpress.excellentcrates.CratesPlugin; import su.nightexpress.excellentcrates.Placeholders; import su.nightexpress.excellentcrates.api.crate.Reward; @@ -199,8 +200,20 @@ public void give(@NotNull Player player) { @Override public double getRollChance() { - double sum = this.crate.getRewards(this.rarity).stream().mapToDouble(Reward::getWeight).sum(); - double rarityChance = this.rarity.getRollChance(this.crate); + return this.getRollChance(null); + } + + @Override + public double getRollChance(@Nullable Player player) { + // A player who can't win this reward has a real chance of 0%. + if (player != null && !this.canWin(player)) return 0D; + + // Use the reward pool actually available to the player so previewed odds match real odds + // (rewards locked behind permissions are excluded from the roll, raising everyone else's chance). + double sum = this.crate.getRewards(player, this.rarity).stream().mapToDouble(Reward::getWeight).sum(); + if (sum <= 0D) return 0D; + + double rarityChance = this.rarity.getRollChance(this.crate, player); double chance = (this.weight / sum) * (rarityChance / 100D); return chance * 100D;