minecraft-src/net/minecraft/world/inventory/EnchantmentMenu.java
2025-07-04 03:45:38 +03:00

264 lines
9 KiB
Java

package net.minecraft.world.inventory;
import java.util.List;
import java.util.Optional;
import net.minecraft.Util;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMap;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.HolderSet.Named;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
import net.minecraft.tags.EnchantmentTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EnchantingTableBlock;
public class EnchantmentMenu extends AbstractContainerMenu {
static final ResourceLocation EMPTY_SLOT_LAPIS_LAZULI = ResourceLocation.withDefaultNamespace("container/slot/lapis_lazuli");
private final Container enchantSlots = new SimpleContainer(2) {
@Override
public void setChanged() {
super.setChanged();
EnchantmentMenu.this.slotsChanged(this);
}
};
private final ContainerLevelAccess access;
private final RandomSource random = RandomSource.create();
private final DataSlot enchantmentSeed = DataSlot.standalone();
public final int[] costs = new int[3];
public final int[] enchantClue = new int[]{-1, -1, -1};
public final int[] levelClue = new int[]{-1, -1, -1};
public EnchantmentMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
}
public EnchantmentMenu(int containerId, Inventory playerInventory, ContainerLevelAccess access) {
super(MenuType.ENCHANTMENT, containerId);
this.access = access;
this.addSlot(new Slot(this.enchantSlots, 0, 15, 47) {
@Override
public int getMaxStackSize() {
return 1;
}
});
this.addSlot(new Slot(this.enchantSlots, 1, 35, 47) {
@Override
public boolean mayPlace(ItemStack stack) {
return stack.is(Items.LAPIS_LAZULI);
}
@Override
public ResourceLocation getNoItemIcon() {
return EnchantmentMenu.EMPTY_SLOT_LAPIS_LAZULI;
}
});
this.addStandardInventorySlots(playerInventory, 8, 84);
this.addDataSlot(DataSlot.shared(this.costs, 0));
this.addDataSlot(DataSlot.shared(this.costs, 1));
this.addDataSlot(DataSlot.shared(this.costs, 2));
this.addDataSlot(this.enchantmentSeed).set(playerInventory.player.getEnchantmentSeed());
this.addDataSlot(DataSlot.shared(this.enchantClue, 0));
this.addDataSlot(DataSlot.shared(this.enchantClue, 1));
this.addDataSlot(DataSlot.shared(this.enchantClue, 2));
this.addDataSlot(DataSlot.shared(this.levelClue, 0));
this.addDataSlot(DataSlot.shared(this.levelClue, 1));
this.addDataSlot(DataSlot.shared(this.levelClue, 2));
}
@Override
public void slotsChanged(Container container) {
if (container == this.enchantSlots) {
ItemStack itemStack = container.getItem(0);
if (!itemStack.isEmpty() && itemStack.isEnchantable()) {
this.access.execute((level, blockPos) -> {
IdMap<Holder<Enchantment>> idMap = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap();
int ix = 0;
for (BlockPos blockPos2 : EnchantingTableBlock.BOOKSHELF_OFFSETS) {
if (EnchantingTableBlock.isValidBookShelf(level, blockPos, blockPos2)) {
ix++;
}
}
this.random.setSeed(this.enchantmentSeed.get());
for (int j = 0; j < 3; j++) {
this.costs[j] = EnchantmentHelper.getEnchantmentCost(this.random, j, ix, itemStack);
this.enchantClue[j] = -1;
this.levelClue[j] = -1;
if (this.costs[j] < j + 1) {
this.costs[j] = 0;
}
}
for (int jx = 0; jx < 3; jx++) {
if (this.costs[jx] > 0) {
List<EnchantmentInstance> list = this.getEnchantmentList(level.registryAccess(), itemStack, jx, this.costs[jx]);
if (list != null && !list.isEmpty()) {
EnchantmentInstance enchantmentInstance = (EnchantmentInstance)list.get(this.random.nextInt(list.size()));
this.enchantClue[jx] = idMap.getId(enchantmentInstance.enchantment());
this.levelClue[jx] = enchantmentInstance.level();
}
}
}
this.broadcastChanges();
});
} else {
for (int i = 0; i < 3; i++) {
this.costs[i] = 0;
this.enchantClue[i] = -1;
this.levelClue[i] = -1;
}
}
}
}
@Override
public boolean clickMenuButton(Player player, int id) {
if (id >= 0 && id < this.costs.length) {
ItemStack itemStack = this.enchantSlots.getItem(0);
ItemStack itemStack2 = this.enchantSlots.getItem(1);
int i = id + 1;
if ((itemStack2.isEmpty() || itemStack2.getCount() < i) && !player.hasInfiniteMaterials()) {
return false;
} else if (this.costs[id] <= 0
|| itemStack.isEmpty()
|| (player.experienceLevel < i || player.experienceLevel < this.costs[id]) && !player.hasInfiniteMaterials()) {
return false;
} else {
this.access.execute((level, blockPos) -> {
ItemStack itemStack3 = itemStack;
List<EnchantmentInstance> list = this.getEnchantmentList(level.registryAccess(), itemStack, id, this.costs[id]);
if (!list.isEmpty()) {
player.onEnchantmentPerformed(itemStack, i);
if (itemStack.is(Items.BOOK)) {
itemStack3 = itemStack.transmuteCopy(Items.ENCHANTED_BOOK);
this.enchantSlots.setItem(0, itemStack3);
}
for (EnchantmentInstance enchantmentInstance : list) {
itemStack3.enchant(enchantmentInstance.enchantment(), enchantmentInstance.level());
}
itemStack2.consume(i, player);
if (itemStack2.isEmpty()) {
this.enchantSlots.setItem(1, ItemStack.EMPTY);
}
player.awardStat(Stats.ENCHANT_ITEM);
if (player instanceof ServerPlayer) {
CriteriaTriggers.ENCHANTED_ITEM.trigger((ServerPlayer)player, itemStack3, i);
}
this.enchantSlots.setChanged();
this.enchantmentSeed.set(player.getEnchantmentSeed());
this.slotsChanged(this.enchantSlots);
level.playSound(null, blockPos, SoundEvents.ENCHANTMENT_TABLE_USE, SoundSource.BLOCKS, 1.0F, level.random.nextFloat() * 0.1F + 0.9F);
}
});
return true;
}
} else {
Util.logAndPauseIfInIde(player.getName() + " pressed invalid button id: " + id);
return false;
}
}
private List<EnchantmentInstance> getEnchantmentList(RegistryAccess registryAccess, ItemStack stack, int slot, int cost) {
this.random.setSeed(this.enchantmentSeed.get() + slot);
Optional<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, ((Named)optional.get()).stream());
if (stack.is(Items.BOOK) && list.size() > 1) {
list.remove(this.random.nextInt(list.size()));
}
return list;
}
}
public int getGoldCount() {
ItemStack itemStack = this.enchantSlots.getItem(1);
return itemStack.isEmpty() ? 0 : itemStack.getCount();
}
public int getEnchantmentSeed() {
return this.enchantmentSeed.get();
}
@Override
public void removed(Player player) {
super.removed(player);
this.access.execute((level, blockPos) -> this.clearContainer(player, this.enchantSlots));
}
@Override
public boolean stillValid(Player player) {
return stillValid(this.access, player, Blocks.ENCHANTING_TABLE);
}
@Override
public ItemStack quickMoveStack(Player player, int index) {
ItemStack itemStack = ItemStack.EMPTY;
Slot slot = this.slots.get(index);
if (slot != null && slot.hasItem()) {
ItemStack itemStack2 = slot.getItem();
itemStack = itemStack2.copy();
if (index == 0) {
if (!this.moveItemStackTo(itemStack2, 2, 38, true)) {
return ItemStack.EMPTY;
}
} else if (index == 1) {
if (!this.moveItemStackTo(itemStack2, 2, 38, true)) {
return ItemStack.EMPTY;
}
} else if (itemStack2.is(Items.LAPIS_LAZULI)) {
if (!this.moveItemStackTo(itemStack2, 1, 2, true)) {
return ItemStack.EMPTY;
}
} else {
if (this.slots.get(0).hasItem() || !this.slots.get(0).mayPlace(itemStack2)) {
return ItemStack.EMPTY;
}
ItemStack itemStack3 = itemStack2.copyWithCount(1);
itemStack2.shrink(1);
this.slots.get(0).setByPlayer(itemStack3);
}
if (itemStack2.isEmpty()) {
slot.setByPlayer(ItemStack.EMPTY);
} else {
slot.setChanged();
}
if (itemStack2.getCount() == itemStack.getCount()) {
return ItemStack.EMPTY;
}
slot.onTake(player, itemStack2);
}
return itemStack;
}
}