Skip to content

make bookshelf power configurable and refresh enchantment hint of menu after editing bookshelf power #12345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
);
}

Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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 @NotNull [] rollEnchantmentOffers(
final @NotNull ItemStack targetStack,
final int seed,
final int bookshelfCount,
final int offerAmount
) {
return InternalAPIBridge.get().rollEnchantmentOffers(targetStack, seed, bookshelfCount, offerAmount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,32 @@
this.access.execute((level, blockPos) -> {
IdMap<Holder<Enchantment>> 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<EnchantmentInstance> 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];
Expand Down Expand Up @@ -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<EnchantmentInstance> 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 {
Expand Down Expand Up @@ -171,6 +236,29 @@
item1.consume(i, player);
if (item1.isEmpty()) {
this.enchantSlots.setItem(1, ItemStack.EMPTY);
@@ -183,14 +_,19 @@
}

private List<EnchantmentInstance> 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<EnchantmentInstance> 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<HolderSet.Named<Enchantment>> optional = registryAccess.lookupOrThrow(Registries.ENCHANTMENT).get(EnchantmentTags.IN_ENCHANTING_TABLE);
if (optional.isEmpty()) {
return List.of();
} else {
- List<EnchantmentInstance> list = EnchantmentHelper.selectEnchantment(this.random, stack, cost, optional.get().stream());
+ List<EnchantmentInstance> 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<Holder<Enchantment>> 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;
}
}
Loading