306 lines
9.6 KiB
Java
306 lines
9.6 KiB
Java
package net.minecraft.world.inventory;
|
|
|
|
import com.mojang.logging.LogUtils;
|
|
import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.component.DataComponents;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.StringUtil;
|
|
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.ItemEnchantments;
|
|
import net.minecraft.world.level.block.AnvilBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.slf4j.Logger;
|
|
|
|
public class AnvilMenu extends ItemCombinerMenu {
|
|
public static final int INPUT_SLOT = 0;
|
|
public static final int ADDITIONAL_SLOT = 1;
|
|
public static final int RESULT_SLOT = 2;
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private static final boolean DEBUG_COST = false;
|
|
public static final int MAX_NAME_LENGTH = 50;
|
|
private int repairItemCountCost;
|
|
@Nullable
|
|
private String itemName;
|
|
private final DataSlot cost = DataSlot.standalone();
|
|
private boolean onlyRenaming = false;
|
|
private static final int COST_FAIL = 0;
|
|
private static final int COST_BASE = 1;
|
|
private static final int COST_ADDED_BASE = 1;
|
|
private static final int COST_REPAIR_MATERIAL = 1;
|
|
private static final int COST_REPAIR_SACRIFICE = 2;
|
|
private static final int COST_INCOMPATIBLE_PENALTY = 1;
|
|
private static final int COST_RENAME = 1;
|
|
private static final int INPUT_SLOT_X_PLACEMENT = 27;
|
|
private static final int ADDITIONAL_SLOT_X_PLACEMENT = 76;
|
|
private static final int RESULT_SLOT_X_PLACEMENT = 134;
|
|
private static final int SLOT_Y_PLACEMENT = 47;
|
|
|
|
public AnvilMenu(int containerId, Inventory playerInventory) {
|
|
this(containerId, playerInventory, ContainerLevelAccess.NULL);
|
|
}
|
|
|
|
public AnvilMenu(int containerId, Inventory playerInventory, ContainerLevelAccess access) {
|
|
super(MenuType.ANVIL, containerId, playerInventory, access, createInputSlotDefinitions());
|
|
this.addDataSlot(this.cost);
|
|
}
|
|
|
|
private static ItemCombinerMenuSlotDefinition createInputSlotDefinitions() {
|
|
return ItemCombinerMenuSlotDefinition.create()
|
|
.withSlot(0, 27, 47, itemStack -> true)
|
|
.withSlot(1, 76, 47, itemStack -> true)
|
|
.withResultSlot(2, 134, 47)
|
|
.build();
|
|
}
|
|
|
|
@Override
|
|
protected boolean isValidBlock(BlockState state) {
|
|
return state.is(BlockTags.ANVIL);
|
|
}
|
|
|
|
@Override
|
|
protected boolean mayPickup(Player player, boolean hasStack) {
|
|
return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > 0;
|
|
}
|
|
|
|
@Override
|
|
protected void onTake(Player player, ItemStack stack) {
|
|
if (!player.hasInfiniteMaterials()) {
|
|
player.giveExperienceLevels(-this.cost.get());
|
|
}
|
|
|
|
if (this.repairItemCountCost > 0) {
|
|
ItemStack itemStack = this.inputSlots.getItem(1);
|
|
if (!itemStack.isEmpty() && itemStack.getCount() > this.repairItemCountCost) {
|
|
itemStack.shrink(this.repairItemCountCost);
|
|
this.inputSlots.setItem(1, itemStack);
|
|
} else {
|
|
this.inputSlots.setItem(1, ItemStack.EMPTY);
|
|
}
|
|
} else if (!this.onlyRenaming) {
|
|
this.inputSlots.setItem(1, ItemStack.EMPTY);
|
|
}
|
|
|
|
this.cost.set(0);
|
|
this.inputSlots.setItem(0, ItemStack.EMPTY);
|
|
this.access.execute((level, blockPos) -> {
|
|
BlockState blockState = level.getBlockState(blockPos);
|
|
if (!player.hasInfiniteMaterials() && blockState.is(BlockTags.ANVIL) && player.getRandom().nextFloat() < 0.12F) {
|
|
BlockState blockState2 = AnvilBlock.damage(blockState);
|
|
if (blockState2 == null) {
|
|
level.removeBlock(blockPos, false);
|
|
level.levelEvent(1029, blockPos, 0);
|
|
} else {
|
|
level.setBlock(blockPos, blockState2, 2);
|
|
level.levelEvent(1030, blockPos, 0);
|
|
}
|
|
} else {
|
|
level.levelEvent(1030, blockPos, 0);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void createResult() {
|
|
ItemStack itemStack = this.inputSlots.getItem(0);
|
|
this.onlyRenaming = false;
|
|
this.cost.set(1);
|
|
int i = 0;
|
|
long l = 0L;
|
|
int j = 0;
|
|
if (!itemStack.isEmpty() && EnchantmentHelper.canStoreEnchantments(itemStack)) {
|
|
ItemStack itemStack2 = itemStack.copy();
|
|
ItemStack itemStack3 = this.inputSlots.getItem(1);
|
|
ItemEnchantments.Mutable mutable = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(itemStack2));
|
|
l += (long)itemStack.getOrDefault(DataComponents.REPAIR_COST, 0).intValue() + itemStack3.getOrDefault(DataComponents.REPAIR_COST, 0).intValue();
|
|
this.repairItemCountCost = 0;
|
|
if (!itemStack3.isEmpty()) {
|
|
boolean bl = itemStack3.has(DataComponents.STORED_ENCHANTMENTS);
|
|
if (itemStack2.isDamageableItem() && itemStack.isValidRepairItem(itemStack3)) {
|
|
int k = Math.min(itemStack2.getDamageValue(), itemStack2.getMaxDamage() / 4);
|
|
if (k <= 0) {
|
|
this.resultSlots.setItem(0, ItemStack.EMPTY);
|
|
this.cost.set(0);
|
|
return;
|
|
}
|
|
|
|
int m;
|
|
for (m = 0; k > 0 && m < itemStack3.getCount(); m++) {
|
|
int n = itemStack2.getDamageValue() - k;
|
|
itemStack2.setDamageValue(n);
|
|
i++;
|
|
k = Math.min(itemStack2.getDamageValue(), itemStack2.getMaxDamage() / 4);
|
|
}
|
|
|
|
this.repairItemCountCost = m;
|
|
} else {
|
|
if (!bl && (!itemStack2.is(itemStack3.getItem()) || !itemStack2.isDamageableItem())) {
|
|
this.resultSlots.setItem(0, ItemStack.EMPTY);
|
|
this.cost.set(0);
|
|
return;
|
|
}
|
|
|
|
if (itemStack2.isDamageableItem() && !bl) {
|
|
int kx = itemStack.getMaxDamage() - itemStack.getDamageValue();
|
|
int m = itemStack3.getMaxDamage() - itemStack3.getDamageValue();
|
|
int n = m + itemStack2.getMaxDamage() * 12 / 100;
|
|
int o = kx + n;
|
|
int p = itemStack2.getMaxDamage() - o;
|
|
if (p < 0) {
|
|
p = 0;
|
|
}
|
|
|
|
if (p < itemStack2.getDamageValue()) {
|
|
itemStack2.setDamageValue(p);
|
|
i += 2;
|
|
}
|
|
}
|
|
|
|
ItemEnchantments itemEnchantments = EnchantmentHelper.getEnchantmentsForCrafting(itemStack3);
|
|
boolean bl2 = false;
|
|
boolean bl3 = false;
|
|
|
|
for (Entry<Holder<Enchantment>> entry : itemEnchantments.entrySet()) {
|
|
Holder<Enchantment> holder = (Holder<Enchantment>)entry.getKey();
|
|
int q = mutable.getLevel(holder);
|
|
int r = entry.getIntValue();
|
|
r = q == r ? r + 1 : Math.max(r, q);
|
|
Enchantment enchantment = holder.value();
|
|
boolean bl4 = enchantment.canEnchant(itemStack);
|
|
if (this.player.hasInfiniteMaterials() || itemStack.is(Items.ENCHANTED_BOOK)) {
|
|
bl4 = true;
|
|
}
|
|
|
|
for (Holder<Enchantment> holder2 : mutable.keySet()) {
|
|
if (!holder2.equals(holder) && !Enchantment.areCompatible(holder, holder2)) {
|
|
bl4 = false;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (!bl4) {
|
|
bl3 = true;
|
|
} else {
|
|
bl2 = true;
|
|
if (r > enchantment.getMaxLevel()) {
|
|
r = enchantment.getMaxLevel();
|
|
}
|
|
|
|
mutable.set(holder, r);
|
|
int s = enchantment.getAnvilCost();
|
|
if (bl) {
|
|
s = Math.max(1, s / 2);
|
|
}
|
|
|
|
i += s * r;
|
|
if (itemStack.getCount() > 1) {
|
|
i = 40;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bl3 && !bl2) {
|
|
this.resultSlots.setItem(0, ItemStack.EMPTY);
|
|
this.cost.set(0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this.itemName != null && !StringUtil.isBlank(this.itemName)) {
|
|
if (!this.itemName.equals(itemStack.getHoverName().getString())) {
|
|
j = 1;
|
|
i += j;
|
|
itemStack2.set(DataComponents.CUSTOM_NAME, Component.literal(this.itemName));
|
|
}
|
|
} else if (itemStack.has(DataComponents.CUSTOM_NAME)) {
|
|
j = 1;
|
|
i += j;
|
|
itemStack2.remove(DataComponents.CUSTOM_NAME);
|
|
}
|
|
|
|
int t = i <= 0 ? 0 : (int)Mth.clamp(l + i, 0L, 2147483647L);
|
|
this.cost.set(t);
|
|
if (i <= 0) {
|
|
itemStack2 = ItemStack.EMPTY;
|
|
}
|
|
|
|
if (j == i && j > 0) {
|
|
if (this.cost.get() >= 40) {
|
|
this.cost.set(39);
|
|
}
|
|
|
|
this.onlyRenaming = true;
|
|
}
|
|
|
|
if (this.cost.get() >= 40 && !this.player.hasInfiniteMaterials()) {
|
|
itemStack2 = ItemStack.EMPTY;
|
|
}
|
|
|
|
if (!itemStack2.isEmpty()) {
|
|
int kxx = itemStack2.getOrDefault(DataComponents.REPAIR_COST, 0);
|
|
if (kxx < itemStack3.getOrDefault(DataComponents.REPAIR_COST, 0)) {
|
|
kxx = itemStack3.getOrDefault(DataComponents.REPAIR_COST, 0);
|
|
}
|
|
|
|
if (j != i || j == 0) {
|
|
kxx = calculateIncreasedRepairCost(kxx);
|
|
}
|
|
|
|
itemStack2.set(DataComponents.REPAIR_COST, kxx);
|
|
EnchantmentHelper.setEnchantments(itemStack2, mutable.toImmutable());
|
|
}
|
|
|
|
this.resultSlots.setItem(0, itemStack2);
|
|
this.broadcastChanges();
|
|
} else {
|
|
this.resultSlots.setItem(0, ItemStack.EMPTY);
|
|
this.cost.set(0);
|
|
}
|
|
}
|
|
|
|
public static int calculateIncreasedRepairCost(int oldRepairCost) {
|
|
return (int)Math.min(oldRepairCost * 2L + 1L, 2147483647L);
|
|
}
|
|
|
|
public boolean setItemName(String itemName) {
|
|
String string = validateName(itemName);
|
|
if (string != null && !string.equals(this.itemName)) {
|
|
this.itemName = string;
|
|
if (this.getSlot(2).hasItem()) {
|
|
ItemStack itemStack = this.getSlot(2).getItem();
|
|
if (StringUtil.isBlank(string)) {
|
|
itemStack.remove(DataComponents.CUSTOM_NAME);
|
|
} else {
|
|
itemStack.set(DataComponents.CUSTOM_NAME, Component.literal(string));
|
|
}
|
|
}
|
|
|
|
this.createResult();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
private static String validateName(String itemName) {
|
|
String string = StringUtil.filterText(itemName);
|
|
return string.length() <= 50 ? string : null;
|
|
}
|
|
|
|
/**
|
|
* Gets the maximum xp cost
|
|
*/
|
|
public int getCost() {
|
|
return this.cost.get();
|
|
}
|
|
}
|