minecraft-src/net/minecraft/world/inventory/MerchantMenu.java
2025-07-04 03:15:13 +03:00

232 lines
7.2 KiB
Java

package net.minecraft.world.inventory;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.Container;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.npc.ClientSideMerchant;
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.trading.ItemCost;
import net.minecraft.world.item.trading.Merchant;
import net.minecraft.world.item.trading.MerchantOffer;
import net.minecraft.world.item.trading.MerchantOffers;
public class MerchantMenu extends AbstractContainerMenu {
protected static final int PAYMENT1_SLOT = 0;
protected static final int PAYMENT2_SLOT = 1;
protected static final int RESULT_SLOT = 2;
private static final int INV_SLOT_START = 3;
private static final int INV_SLOT_END = 30;
private static final int USE_ROW_SLOT_START = 30;
private static final int USE_ROW_SLOT_END = 39;
private static final int SELLSLOT1_X = 136;
private static final int SELLSLOT2_X = 162;
private static final int BUYSLOT_X = 220;
private static final int ROW_Y = 37;
private final Merchant trader;
private final MerchantContainer tradeContainer;
private int merchantLevel;
private boolean showProgressBar;
private boolean canRestock;
public MerchantMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, new ClientSideMerchant(playerInventory.player));
}
public MerchantMenu(int containerId, Inventory playerInventory, Merchant trader) {
super(MenuType.MERCHANT, containerId);
this.trader = trader;
this.tradeContainer = new MerchantContainer(trader);
this.addSlot(new Slot(this.tradeContainer, 0, 136, 37));
this.addSlot(new Slot(this.tradeContainer, 1, 162, 37));
this.addSlot(new MerchantResultSlot(playerInventory.player, trader, this.tradeContainer, 2, 220, 37));
this.addStandardInventorySlots(playerInventory, 108, 84);
}
public void setShowProgressBar(boolean showProgressBar) {
this.showProgressBar = showProgressBar;
}
@Override
public void slotsChanged(Container container) {
this.tradeContainer.updateSellItem();
super.slotsChanged(container);
}
public void setSelectionHint(int currentRecipeIndex) {
this.tradeContainer.setSelectionHint(currentRecipeIndex);
}
@Override
public boolean stillValid(Player player) {
return this.trader.stillValid(player);
}
public int getTraderXp() {
return this.trader.getVillagerXp();
}
public int getFutureTraderXp() {
return this.tradeContainer.getFutureXp();
}
public void setXp(int xp) {
this.trader.overrideXp(xp);
}
public int getTraderLevel() {
return this.merchantLevel;
}
public void setMerchantLevel(int level) {
this.merchantLevel = level;
}
public void setCanRestock(boolean canRestock) {
this.canRestock = canRestock;
}
public boolean canRestock() {
return this.canRestock;
}
@Override
public boolean canTakeItemForPickAll(ItemStack stack, Slot slot) {
return false;
}
@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 == 2) {
if (!this.moveItemStackTo(itemStack2, 3, 39, true)) {
return ItemStack.EMPTY;
}
slot.onQuickCraft(itemStack2, itemStack);
this.playTradeSound();
} else if (index != 0 && index != 1) {
if (index >= 3 && index < 30) {
if (!this.moveItemStackTo(itemStack2, 30, 39, false)) {
return ItemStack.EMPTY;
}
} else if (index >= 30 && index < 39 && !this.moveItemStackTo(itemStack2, 3, 30, false)) {
return ItemStack.EMPTY;
}
} else if (!this.moveItemStackTo(itemStack2, 3, 39, false)) {
return ItemStack.EMPTY;
}
if (itemStack2.isEmpty()) {
slot.setByPlayer(ItemStack.EMPTY);
} else {
slot.setChanged();
}
if (itemStack2.getCount() == itemStack.getCount()) {
return ItemStack.EMPTY;
}
slot.onTake(player, itemStack2);
}
return itemStack;
}
private void playTradeSound() {
if (!this.trader.isClientSide()) {
Entity entity = (Entity)this.trader;
entity.level().playLocalSound(entity.getX(), entity.getY(), entity.getZ(), this.trader.getNotifyTradeSound(), SoundSource.NEUTRAL, 1.0F, 1.0F, false);
}
}
@Override
public void removed(Player player) {
super.removed(player);
this.trader.setTradingPlayer(null);
if (!this.trader.isClientSide()) {
if (!player.isAlive() || player instanceof ServerPlayer && ((ServerPlayer)player).hasDisconnected()) {
ItemStack itemStack = this.tradeContainer.removeItemNoUpdate(0);
if (!itemStack.isEmpty()) {
player.drop(itemStack, false);
}
itemStack = this.tradeContainer.removeItemNoUpdate(1);
if (!itemStack.isEmpty()) {
player.drop(itemStack, false);
}
} else if (player instanceof ServerPlayer) {
player.getInventory().placeItemBackInInventory(this.tradeContainer.removeItemNoUpdate(0));
player.getInventory().placeItemBackInInventory(this.tradeContainer.removeItemNoUpdate(1));
}
}
}
public void tryMoveItems(int selectedMerchantRecipe) {
if (selectedMerchantRecipe >= 0 && this.getOffers().size() > selectedMerchantRecipe) {
ItemStack itemStack = this.tradeContainer.getItem(0);
if (!itemStack.isEmpty()) {
if (!this.moveItemStackTo(itemStack, 3, 39, true)) {
return;
}
this.tradeContainer.setItem(0, itemStack);
}
ItemStack itemStack2 = this.tradeContainer.getItem(1);
if (!itemStack2.isEmpty()) {
if (!this.moveItemStackTo(itemStack2, 3, 39, true)) {
return;
}
this.tradeContainer.setItem(1, itemStack2);
}
if (this.tradeContainer.getItem(0).isEmpty() && this.tradeContainer.getItem(1).isEmpty()) {
MerchantOffer merchantOffer = (MerchantOffer)this.getOffers().get(selectedMerchantRecipe);
this.moveFromInventoryToPaymentSlot(0, merchantOffer.getItemCostA());
merchantOffer.getItemCostB().ifPresent(itemCost -> this.moveFromInventoryToPaymentSlot(1, itemCost));
}
}
}
private void moveFromInventoryToPaymentSlot(int paymentSlotIndex, ItemCost payment) {
for (int i = 3; i < 39; i++) {
ItemStack itemStack = this.slots.get(i).getItem();
if (!itemStack.isEmpty() && payment.test(itemStack)) {
ItemStack itemStack2 = this.tradeContainer.getItem(paymentSlotIndex);
if (itemStack2.isEmpty() || ItemStack.isSameItemSameComponents(itemStack, itemStack2)) {
int j = itemStack.getMaxStackSize();
int k = Math.min(j - itemStack2.getCount(), itemStack.getCount());
ItemStack itemStack3 = itemStack.copyWithCount(itemStack2.getCount() + k);
itemStack.shrink(k);
this.tradeContainer.setItem(paymentSlotIndex, itemStack3);
if (itemStack3.getCount() >= j) {
break;
}
}
}
}
}
/**
* {@link net.minecraft.client.multiplayer.ClientPacketListener} uses this to set offers for the client side MerchantContainer.
*/
public void setOffers(MerchantOffers offers) {
this.trader.overrideOffers(offers);
}
public MerchantOffers getOffers() {
return this.trader.getOffers();
}
public boolean showProgressBar() {
return this.showProgressBar;
}
}