From b56273bef901949737986353ea95586f02f06db3 Mon Sep 17 00:00:00 2001 From: I-am-DDang_ Date: Thu, 1 May 2025 16:19:18 +0900 Subject: [PATCH 1/7] make bookshelf power configurable and refresh enchantment hint of menu after editing bookshelf power --- .../enchantment/PrepareItemEnchantEvent.java | 4 +++- .../inventory/EnchantmentMenu.java.patch | 24 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java b/paper-api/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java index 4627f5144d31..116b1f31933f 100644 --- a/paper-api/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java @@ -24,7 +24,7 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab private final Block table; private final ItemStack item; private final EnchantmentOffer[] offers; - private final int bonus; + private int bonus; private boolean cancelled; @@ -111,6 +111,8 @@ public int getEnchantmentBonus() { return this.bonus; } + public void setEnchantmentBonus(int bonus) { this.bonus = bonus; } + @Override public boolean isCancelled() { return this.cancelled; diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch index 80fbd66e2285..a7b236846163 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch @@ -64,7 +64,7 @@ this.access.execute((level, blockPos) -> { IdMap> holderIdMap = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); int i1 = 0; -@@ -119,6 +_,42 @@ +@@ -119,6 +_,64 @@ } } @@ -89,6 +89,28 @@ + return; + } + ++ // Paper Start - refreshing enchantment hint with configuring bookshelf power ++ // refreshing offers with event's bookshelf power if event's bookshelf power value is not equal to previous natural bookshelf power value. ++ if (event.getEnchantmentBonus() != i1) { ++ for (int i = 0; i < 3; i++) { ++ org.bukkit.enchantments.Enchantment enchantment = (this.enchantClue[i] >= 0) ? org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holderIdMap.byId(this.enchantClue[i])) : null; ++ event.getOffers()[i] = (enchantment != null) ? new org.bukkit.enchantments.EnchantmentOffer(enchantment, this.levelClue[i], this.costs[i]) : null; ++ ++ this.costs[i] = EnchantmentHelper.getEnchantmentCost(this.random, i, event.getEnchantmentBonus(), item); ++ this.enchantClue[i] = -1; ++ this.levelClue[i] = -1; ++ if (this.costs[i] < i + 1) continue; ++ ++ List enchantmentList = this.getEnchantmentList(level.registryAccess(), item, i, this.costs[i]); ++ if (!enchantmentList.isEmpty()) { ++ EnchantmentInstance enchantmentInstance = enchantmentList.get(this.random.nextInt(enchantmentList.size())); ++ this.enchantClue[i] = holderIdMap.getId(enchantmentInstance.enchantment()); ++ this.levelClue[i] = enchantmentInstance.level(); ++ } ++ } ++ } ++ // Paper end ++ + for (int j = 0; j < 3; j++) { + org.bukkit.enchantments.EnchantmentOffer offer = event.getOffers()[j]; + if (offer != null) { From 94142092789cf518ca56023ee34994f8295352d5 Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Wed, 7 May 2025 12:40:17 +0200 Subject: [PATCH 2/7] Revert "make bookshelf power configurable and refresh enchantment hint of menu after editing bookshelf power" This reverts commit b56273bef901949737986353ea95586f02f06db3. --- .../enchantment/PrepareItemEnchantEvent.java | 4 +--- .../inventory/EnchantmentMenu.java.patch | 24 +------------------ 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java b/paper-api/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java index 116b1f31933f..4627f5144d31 100644 --- a/paper-api/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/enchantment/PrepareItemEnchantEvent.java @@ -24,7 +24,7 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab private final Block table; private final ItemStack item; private final EnchantmentOffer[] offers; - private int bonus; + private final int bonus; private boolean cancelled; @@ -111,8 +111,6 @@ public int getEnchantmentBonus() { return this.bonus; } - public void setEnchantmentBonus(int bonus) { this.bonus = bonus; } - @Override public boolean isCancelled() { return this.cancelled; diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch index a7b236846163..80fbd66e2285 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch @@ -64,7 +64,7 @@ this.access.execute((level, blockPos) -> { IdMap> holderIdMap = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); int i1 = 0; -@@ -119,6 +_,64 @@ +@@ -119,6 +_,42 @@ } } @@ -89,28 +89,6 @@ + return; + } + -+ // Paper Start - refreshing enchantment hint with configuring bookshelf power -+ // refreshing offers with event's bookshelf power if event's bookshelf power value is not equal to previous natural bookshelf power value. -+ if (event.getEnchantmentBonus() != i1) { -+ for (int i = 0; i < 3; i++) { -+ org.bukkit.enchantments.Enchantment enchantment = (this.enchantClue[i] >= 0) ? org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holderIdMap.byId(this.enchantClue[i])) : null; -+ event.getOffers()[i] = (enchantment != null) ? new org.bukkit.enchantments.EnchantmentOffer(enchantment, this.levelClue[i], this.costs[i]) : null; -+ -+ this.costs[i] = EnchantmentHelper.getEnchantmentCost(this.random, i, event.getEnchantmentBonus(), item); -+ this.enchantClue[i] = -1; -+ this.levelClue[i] = -1; -+ if (this.costs[i] < i + 1) continue; -+ -+ List enchantmentList = this.getEnchantmentList(level.registryAccess(), item, i, this.costs[i]); -+ if (!enchantmentList.isEmpty()) { -+ EnchantmentInstance enchantmentInstance = enchantmentList.get(this.random.nextInt(enchantmentList.size())); -+ this.enchantClue[i] = holderIdMap.getId(enchantmentInstance.enchantment()); -+ this.levelClue[i] = enchantmentInstance.level(); -+ } -+ } -+ } -+ // Paper end -+ + for (int j = 0; j < 3; j++) { + org.bukkit.enchantments.EnchantmentOffer offer = event.getOffers()[j]; + if (offer != null) { From bc11611cda6d2852c4f9ab377a6021a1c88e4b83 Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Thu, 24 Apr 2025 16:47:37 +0200 Subject: [PATCH 3/7] Roll EnchantmentOffer API Introduces a new API method that allows plugins to simulate the rolling process of an enchantment table for enchantment offers. This is specifically useful to "reroll" an enchantment tables offers during the PrepareItemEnchantEvent to e.g. change the bookshelf bonus or seed. Co-authored-by: I-am-DDang_ --- .../io/papermc/paper/InternalAPIBridge.java | 19 ++++ .../bukkit/enchantments/EnchantmentOffer.java | 35 +++++++ .../inventory/EnchantmentMenu.java.patch | 94 ++++++++++++++++++- .../paper/PaperServerInternalAPIBridge.java | 52 ++++++++++ 4 files changed, 197 insertions(+), 3 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java index 422fdd93d142..8075050a5fbd 100644 --- a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java +++ b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java @@ -6,7 +6,9 @@ import org.bukkit.block.Biome; import org.bukkit.damage.DamageEffect; import org.bukkit.damage.DamageSource; +import org.bukkit.enchantments.EnchantmentOffer; import org.bukkit.entity.LivingEntity; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -73,5 +75,22 @@ class Holder { * @return combat entry */ CombatEntry createCombatEntry(DamageSource damageSource, float damage, @Nullable FallLocationType fallLocationType, float fallDistance); + + /** + * Rolls a new set of enchantment offers based on a target item stack, a seed and a bookshelf count. + * + * @param targetStack the itemstack for which the enchantment offers are rolled. + * @param seed the seed used for random selection of enchantments. + * Mirrors {@link org.bukkit.inventory.view.EnchantmentView#getEnchantmentSeed()}. + * @param bookshelfCount the number of virtual bookshelves to consider when rolling the enchantments. + * @param offerAmount the amount of enchantment offers to roll. + * @return an array of enchantment offers with size {@code offerAmount}. + */ + @Nullable EnchantmentOffer[] rollEnchantmentOffers( + final ItemStack targetStack, + final int seed, + final int bookshelfCount, + final int offerAmount + ); } diff --git a/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java b/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java index 8111acaa1af5..ceac2eb3834e 100644 --- a/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java +++ b/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java @@ -1,7 +1,11 @@ package org.bukkit.enchantments; import com.google.common.base.Preconditions; +import io.papermc.paper.InternalAPIBridge; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.Objects; /** * A class for the available enchantment offers in the enchantment table. @@ -80,4 +84,35 @@ public void setCost(int cost) { this.cost = cost; } + + @Override + public boolean equals(final Object o) { + if (o == null || getClass() != o.getClass()) return false; + final EnchantmentOffer that = (EnchantmentOffer) o; + return getEnchantmentLevel() == that.getEnchantmentLevel() && getCost() == that.getCost() && Objects.equals(getEnchantment(), that.getEnchantment()); + } + + @Override + public int hashCode() { + return Objects.hash(getEnchantment(), getEnchantmentLevel(), getCost()); + } + + /** + * Rolls a new set of enchantment offers based on a target item stack, a seed and a bookshelf count. + * + * @param targetStack the itemstack for which the enchantment offers are rolled. + * @param seed the seed used for random selection of enchantments. + * Mirrors {@link org.bukkit.inventory.view.EnchantmentView#getEnchantmentSeed()}. + * @param bookshelfCount the number of virtual bookshelves to consider when rolling the enchantments. + * @param offerAmount the amount of enchantment offers to roll. + * @return an array of enchantment offers with size {@code offerAmount}. + */ + public static @Nullable EnchantmentOffer[] rollEnchantmentOffers( + final ItemStack targetStack, + final int seed, + final int bookshelfCount, + final int offerAmount + ) { + return InternalAPIBridge.get().rollEnchantmentOffers(targetStack, seed, bookshelfCount, offerAmount); + } } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch index 80fbd66e2285..1d706d073672 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch @@ -64,10 +64,32 @@ this.access.execute((level, blockPos) -> { IdMap> holderIdMap = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); int i1 = 0; -@@ -119,6 +_,42 @@ +@@ -97,27 +_,42 @@ } } +- this.random.setSeed(this.enchantmentSeed.get()); +- +- for (int i2 = 0; i2 < 3; i2++) { +- this.costs[i2] = EnchantmentHelper.getEnchantmentCost(this.random, i2, i1, item); +- this.enchantClue[i2] = -1; +- this.levelClue[i2] = -1; +- if (this.costs[i2] < i2 + 1) { +- this.costs[i2] = 0; +- } +- } +- +- for (int i2x = 0; i2x < 3; i2x++) { +- if (this.costs[i2x] > 0) { +- List enchantmentList = this.getEnchantmentList(level.registryAccess(), item, i2x, this.costs[i2x]); +- if (enchantmentList != null && !enchantmentList.isEmpty()) { +- EnchantmentInstance enchantmentInstance = enchantmentList.get(this.random.nextInt(enchantmentList.size())); +- this.enchantClue[i2x] = holderIdMap.getId(enchantmentInstance.enchantment()); +- this.levelClue[i2x] = enchantmentInstance.level(); +- } +- } +- } ++ fillEnchantmentOffers(this.random, this.enchantmentSeed.get(), i1, item, level.registryAccess(), this.costs, this.enchantClue, this.levelClue); // Paper - extracted into net.minecraft.world.inventory.EnchantmentMenu.fillEnchantmentOffers + // CraftBukkit start + org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); + org.bukkit.enchantments.EnchantmentOffer[] offers = new org.bukkit.enchantments.EnchantmentOffer[3]; @@ -103,10 +125,53 @@ + } + } + // CraftBukkit end -+ + this.broadcastChanges(); }); - } else { +@@ -131,6 +_,43 @@ + } + } + ++ // Paper - extract offer generation ++ // Extracted over modifications in place given nearly every line has diff to account for non-instance fields for ++ // cost, enchantment and level clues. ++ public static void fillEnchantmentOffers( ++ final RandomSource random, ++ final int seed, ++ final int i1, ++ final ItemStack item, ++ final RegistryAccess registryAccess, ++ final int[] costs, ++ final int[] enchantClue, ++ final int[] levelClue ++ ) { ++ random.setSeed(seed); ++ ++ for (int i2 = 0; i2 < costs.length; i2++) { ++ costs[i2] = EnchantmentHelper.getEnchantmentCost(random, i2, i1, item); ++ enchantClue[i2] = -1; ++ levelClue[i2] = -1; ++ if (costs[i2] < i2 + 1) { ++ costs[i2] = 0; ++ } ++ } ++ ++ for (int i2x = 0; i2x < costs.length; i2x++) { ++ if (costs[i2x] > 0) { ++ List enchantmentList = getEnchantmentList(registryAccess, item, i2x, costs[i2x], random, seed); ++ if (enchantmentList != null && !enchantmentList.isEmpty()) { ++ EnchantmentInstance enchantmentInstance = enchantmentList.get(random.nextInt(enchantmentList.size())); ++ enchantClue[i2x] = registryAccess.lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap().getId(enchantmentInstance.enchantment()); ++ levelClue[i2x] = enchantmentInstance.level(); ++ } ++ } ++ } ++ } ++ // Paper - extract offer generation ++ + @Override + public boolean clickMenuButton(Player player, int id) { + if (id >= 0 && id < this.costs.length) { @@ -145,19 +_,52 @@ return false; } else { @@ -171,6 +236,29 @@ item1.consume(i, player); if (item1.isEmpty()) { this.enchantSlots.setItem(1, ItemStack.EMPTY); +@@ -183,14 +_,19 @@ + } + + private List getEnchantmentList(RegistryAccess registryAccess, ItemStack stack, int slot, int cost) { +- this.random.setSeed(this.enchantmentSeed.get() + slot); ++ // Paper start - make static and public ++ return getEnchantmentList(registryAccess, stack, slot, cost, this.random, this.enchantmentSeed.get()); ++ } ++ public static List getEnchantmentList(RegistryAccess registryAccess, ItemStack stack, int slot, int cost, RandomSource random, int seed) { ++ // Paper end - make static and public ++ random.setSeed(seed + slot); // Paper - make static and public + Optional> optional = registryAccess.lookupOrThrow(Registries.ENCHANTMENT).get(EnchantmentTags.IN_ENCHANTING_TABLE); + if (optional.isEmpty()) { + return List.of(); + } else { +- List list = EnchantmentHelper.selectEnchantment(this.random, stack, cost, optional.get().stream()); ++ List list = EnchantmentHelper.selectEnchantment(random, stack, cost, optional.get().stream()); // Paper - make static and public + if (stack.is(Items.BOOK) && list.size() > 1) { +- list.remove(this.random.nextInt(list.size())); ++ list.remove(random.nextInt(list.size())); // Paper start - make static and public + } + + return list; @@ -202,6 +_,12 @@ return item.isEmpty() ? 0 : item.getCount(); } diff --git a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java index d6933562690e..d3406f4dea70 100644 --- a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java +++ b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java @@ -5,17 +5,30 @@ import io.papermc.paper.world.damagesource.PaperCombatEntryWrapper; import io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper; import net.minecraft.Optionull; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.registries.Registries; +import net.minecraft.util.RandomSource; import net.minecraft.world.damagesource.FallLocation; +import net.minecraft.world.inventory.EnchantmentMenu; +import net.minecraft.world.item.enchantment.Enchantment; import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.damage.CraftDamageEffect; import org.bukkit.craftbukkit.damage.CraftDamageSource; +import org.bukkit.craftbukkit.enchantments.CraftEnchantment; import org.bukkit.craftbukkit.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.RandomSourceWrapper; import org.bukkit.damage.DamageEffect; import org.bukkit.damage.DamageSource; +import org.bukkit.enchantments.EnchantmentOffer; import org.bukkit.entity.LivingEntity; +import org.bukkit.inventory.ItemStack; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +import java.util.Random; @NullMarked public class PaperServerInternalAPIBridge implements InternalAPIBridge { @@ -71,4 +84,43 @@ private CombatEntry createCombatEntry( damageSource, damage, fallLocation, fallDistance )); } + + @Override + public @Nullable EnchantmentOffer[] rollEnchantmentOffers( + final ItemStack targetStack, + final int seed, + final int bookshelfCount, + final int offerAmount + ) { + final int[] costs = new int[offerAmount]; + final int[] enchantClue = new int[offerAmount]; + final int[] levelClue = new int[offerAmount]; + + final RandomSource randomSource = new RandomSourceWrapper(new Random()); + EnchantmentMenu.fillEnchantmentOffers( + randomSource, + seed, + bookshelfCount, + CraftItemStack.unwrap(targetStack), + CraftRegistry.getMinecraftRegistry(), + costs, + enchantClue, + levelClue + ); + + final IdMap> holderIdMap = CraftRegistry.getMinecraftRegistry() + .lookupOrThrow(Registries.ENCHANTMENT) + .asHolderIdMap(); + final @Nullable EnchantmentOffer[] offers = new EnchantmentOffer[offerAmount]; + for (int i = 0; i < costs.length; i++) { + if (enchantClue[i] < 0) continue; + offers[i] = new EnchantmentOffer( + CraftEnchantment.minecraftHolderToBukkit(holderIdMap.byId(enchantClue[i])), + levelClue[i], + costs[i] + ); + } + + return offers; + } } From ae2d5e5cdf1a3a10259e2fce585c188be76fcb7c Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Wed, 7 May 2025 12:54:57 +0200 Subject: [PATCH 4/7] Missing annotations --- .../main/java/org/bukkit/enchantments/EnchantmentOffer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java b/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java index ceac2eb3834e..b02e8f208860 100644 --- a/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java +++ b/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java @@ -107,8 +107,8 @@ public int hashCode() { * @param offerAmount the amount of enchantment offers to roll. * @return an array of enchantment offers with size {@code offerAmount}. */ - public static @Nullable EnchantmentOffer[] rollEnchantmentOffers( - final ItemStack targetStack, + public static @Nullable EnchantmentOffer @NotNull [] rollEnchantmentOffers( + final @NotNull ItemStack targetStack, final int seed, final int bookshelfCount, final int offerAmount From 630efe6047c08e9c3da8c78f0edc539952c13453 Mon Sep 17 00:00:00 2001 From: Warrior <50800980+Warriorrrr@users.noreply.github.com> Date: Sat, 17 Oct 2026 10:29:55 +0200 Subject: [PATCH 5/7] Save on the newline budget --- .../io/papermc/paper/InternalAPIBridge.java | 7 +---- .../paper/PaperServerInternalAPIBridge.java | 30 +++++-------------- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java index 5382b250a5fd..c1ddb7099c43 100644 --- a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java +++ b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java @@ -139,10 +139,5 @@ default VersionFetcher getVersionFetcher() { * @param offerAmount the amount of enchantment offers to roll. * @return an array of enchantment offers with size {@code offerAmount}. */ - @Nullable EnchantmentOffer[] rollEnchantmentOffers( - final ItemStack targetStack, - final int seed, - final int bookshelfCount, - final int offerAmount - ); + @Nullable EnchantmentOffer[] rollEnchantmentOffers(final ItemStack targetStack, final int seed, final int bookshelfCount, final int offerAmount); } diff --git a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java index ccffd8cd0ed4..1f0ad3f6855a 100644 --- a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java +++ b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java @@ -282,39 +282,25 @@ public PersistentDataKey createPersistentDataKey(final Key key, final Per } @Override - public @Nullable EnchantmentOffer[] rollEnchantmentOffers( - final ItemStack targetStack, - final int seed, - final int bookshelfCount, - final int offerAmount - ) { + public @Nullable EnchantmentOffer[] rollEnchantmentOffers(final ItemStack targetStack, final int seed, final int bookshelfCount, final int offerAmount) { final int[] costs = new int[offerAmount]; final int[] enchantClue = new int[offerAmount]; final int[] levelClue = new int[offerAmount]; final RandomSource randomSource = new RandomSourceWrapper(new Random()); - EnchantmentMenu.fillEnchantmentOffers( - randomSource, - seed, - bookshelfCount, - CraftItemStack.unwrap(targetStack), - CraftRegistry.getMinecraftRegistry(), - costs, - enchantClue, - levelClue - ); + EnchantmentMenu.fillEnchantmentOffers(randomSource, seed, bookshelfCount, CraftItemStack.unwrap(targetStack), CraftRegistry.getMinecraftRegistry(), costs, enchantClue, levelClue); final IdMap> holderIdMap = CraftRegistry.getMinecraftRegistry() .lookupOrThrow(Registries.ENCHANTMENT) .asHolderIdMap(); + final @Nullable EnchantmentOffer[] offers = new EnchantmentOffer[offerAmount]; for (int i = 0; i < costs.length; i++) { - if (enchantClue[i] < 0) continue; - offers[i] = new EnchantmentOffer( - CraftEnchantment.minecraftHolderToBukkit(holderIdMap.byId(enchantClue[i])), - levelClue[i], - costs[i] - ); + if (enchantClue[i] < 0) { + continue; + } + + offers[i] = new EnchantmentOffer(CraftEnchantment.minecraftHolderToBukkit(holderIdMap.byId(enchantClue[i])), levelClue[i], costs[i]); } return offers; From 734a89f0cff0d91d953e104371aca904dce04932 Mon Sep 17 00:00:00 2001 From: Warrior <50800980+Warriorrrr@users.noreply.github.com> Date: Sat, 17 Oct 2026 11:11:15 +0200 Subject: [PATCH 6/7] Appease checkstyle --- .../io/papermc/paper/InternalAPIBridge.java | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java index c1ddb7099c43..01874fd3921c 100644 --- a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java +++ b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java @@ -9,11 +9,11 @@ import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; import io.papermc.paper.world.damagesource.CombatEntry; import io.papermc.paper.world.damagesource.FallLocationType; -import java.util.function.Predicate; import java.io.IOException; import java.util.Set; import java.util.function.BooleanSupplier; import java.util.function.Function; +import java.util.function.Predicate; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.flattener.ComponentFlattener; @@ -26,14 +26,14 @@ import org.bukkit.command.CommandSender; import org.bukkit.damage.DamageEffect; import org.bukkit.damage.DamageSource; -import org.bukkit.enchantments.EnchantmentOffer; -import org.bukkit.entity.LivingEntity; -import org.bukkit.inventory.ItemStack; import org.bukkit.damage.DamageType; +import org.bukkit.enchantments.EnchantmentOffer; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Pose; import org.bukkit.entity.SpawnCategory; +import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; @@ -129,15 +129,5 @@ default VersionFetcher getVersionFetcher() { PersistentDataKey createPersistentDataKey(Key key, PersistentDataType type); - /** - * Rolls a new set of enchantment offers based on a target item stack, a seed and a bookshelf count. - * - * @param targetStack the itemstack for which the enchantment offers are rolled. - * @param seed the seed used for random selection of enchantments. - * Mirrors {@link org.bukkit.inventory.view.EnchantmentView#getEnchantmentSeed()}. - * @param bookshelfCount the number of virtual bookshelves to consider when rolling the enchantments. - * @param offerAmount the amount of enchantment offers to roll. - * @return an array of enchantment offers with size {@code offerAmount}. - */ - @Nullable EnchantmentOffer[] rollEnchantmentOffers(final ItemStack targetStack, final int seed, final int bookshelfCount, final int offerAmount); + @Nullable EnchantmentOffer[] rollEnchantmentOffers(ItemStack targetStack, int seed, int bookshelfCount, int offerAmount); } From 6f8fe0e7990074f102f08c5449eef21061d3f0c7 Mon Sep 17 00:00:00 2001 From: Doc Date: Mon, 19 Oct 2026 11:10:05 -0300 Subject: [PATCH 7/7] Cleanup for EnchantmentOffer --- .../bukkit/enchantments/EnchantmentOffer.java | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java b/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java index b02e8f208860..c49950babeee 100644 --- a/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java +++ b/paper-api/src/main/java/org/bukkit/enchantments/EnchantmentOffer.java @@ -3,20 +3,24 @@ import com.google.common.base.Preconditions; import io.papermc.paper.InternalAPIBridge; import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Objects; +import org.checkerframework.checker.index.qual.Positive; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import static io.papermc.paper.util.BoundChecker.requirePositive; /** * A class for the available enchantment offers in the enchantment table. */ +@NullMarked public class EnchantmentOffer { private Enchantment enchantment; private int enchantmentLevel; private int cost; - public EnchantmentOffer(@NotNull Enchantment enchantment, int enchantmentLevel, int cost) { + public EnchantmentOffer(final Enchantment enchantment, final int enchantmentLevel, final int cost) { this.enchantment = enchantment; this.enchantmentLevel = enchantmentLevel; this.cost = cost; @@ -27,9 +31,8 @@ public EnchantmentOffer(@NotNull Enchantment enchantment, int enchantmentLevel, * * @return type of enchantment */ - @NotNull public Enchantment getEnchantment() { - return enchantment; + return this.enchantment; } /** @@ -37,7 +40,7 @@ public Enchantment getEnchantment() { * * @param enchantment type of the enchantment */ - public void setEnchantment(@NotNull Enchantment enchantment) { + public void setEnchantment(final Enchantment enchantment) { Preconditions.checkArgument(enchantment != null, "The enchantment may not be null!"); this.enchantment = enchantment; @@ -49,7 +52,7 @@ public void setEnchantment(@NotNull Enchantment enchantment) { * @return level of the enchantment */ public int getEnchantmentLevel() { - return enchantmentLevel; + return this.enchantmentLevel; } /** @@ -57,8 +60,8 @@ public int getEnchantmentLevel() { * * @param enchantmentLevel level of the enchantment */ - public void setEnchantmentLevel(int enchantmentLevel) { - Preconditions.checkArgument(enchantmentLevel > 0, "The enchantment level must be greater than 0!"); + public void setEnchantmentLevel(final @Positive int enchantmentLevel) { + requirePositive(enchantmentLevel, "enchantmentLevel"); this.enchantmentLevel = enchantmentLevel; } @@ -70,7 +73,7 @@ public void setEnchantmentLevel(int enchantmentLevel) { * @return cost for this enchantment */ public int getCost() { - return cost; + return this.cost; } /** @@ -79,22 +82,24 @@ public int getCost() { * * @param cost cost for this enchantment */ - public void setCost(int cost) { - Preconditions.checkArgument(cost > 0, "The cost must be greater than 0!"); + public void setCost(final @Positive int cost) { + requirePositive(cost, "cost"); this.cost = cost; } @Override - public boolean equals(final Object o) { - if (o == null || getClass() != o.getClass()) return false; + public boolean equals(final @Nullable Object o) { + if (o == null || this.getClass() != o.getClass()) { + return false; + } final EnchantmentOffer that = (EnchantmentOffer) o; - return getEnchantmentLevel() == that.getEnchantmentLevel() && getCost() == that.getCost() && Objects.equals(getEnchantment(), that.getEnchantment()); + return this.getEnchantmentLevel() == that.getEnchantmentLevel() && this.getCost() == that.getCost() && Objects.equals(this.getEnchantment(), that.getEnchantment()); } @Override public int hashCode() { - return Objects.hash(getEnchantment(), getEnchantmentLevel(), getCost()); + return Objects.hash(this.getEnchantment(), this.getEnchantmentLevel(), this.getCost()); } /** @@ -107,8 +112,8 @@ public int hashCode() { * @param offerAmount the amount of enchantment offers to roll. * @return an array of enchantment offers with size {@code offerAmount}. */ - public static @Nullable EnchantmentOffer @NotNull [] rollEnchantmentOffers( - final @NotNull ItemStack targetStack, + public static @Nullable EnchantmentOffer[] rollEnchantmentOffers( + final ItemStack targetStack, final int seed, final int bookshelfCount, final int offerAmount