minecraft-src/net/minecraft/world/inventory/SmithingMenu.java
2025-07-04 01:41:11 +03:00

137 lines
5.3 KiB
Java

package net.minecraft.world.inventory;
import java.util.List;
import java.util.OptionalInt;
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.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.crafting.SmithingRecipe;
import net.minecraft.world.item.crafting.SmithingRecipeInput;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public class SmithingMenu extends ItemCombinerMenu {
public static final int TEMPLATE_SLOT = 0;
public static final int BASE_SLOT = 1;
public static final int ADDITIONAL_SLOT = 2;
public static final int RESULT_SLOT = 3;
public static final int TEMPLATE_SLOT_X_PLACEMENT = 8;
public static final int BASE_SLOT_X_PLACEMENT = 26;
public static final int ADDITIONAL_SLOT_X_PLACEMENT = 44;
private static final int RESULT_SLOT_X_PLACEMENT = 98;
public static final int SLOT_Y_PLACEMENT = 48;
private final Level level;
@Nullable
private RecipeHolder<SmithingRecipe> selectedRecipe;
private final List<RecipeHolder<SmithingRecipe>> recipes;
public SmithingMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
}
public SmithingMenu(int containerId, Inventory playerInventory, ContainerLevelAccess access) {
super(MenuType.SMITHING, containerId, playerInventory, access);
this.level = playerInventory.player.level();
this.recipes = this.level.getRecipeManager().getAllRecipesFor(RecipeType.SMITHING);
}
@Override
protected ItemCombinerMenuSlotDefinition createInputSlotDefinitions() {
return ItemCombinerMenuSlotDefinition.create()
.withSlot(0, 8, 48, itemStack -> this.recipes.stream().anyMatch(recipeHolder -> ((SmithingRecipe)recipeHolder.value()).isTemplateIngredient(itemStack)))
.withSlot(1, 26, 48, itemStack -> this.recipes.stream().anyMatch(recipeHolder -> ((SmithingRecipe)recipeHolder.value()).isBaseIngredient(itemStack)))
.withSlot(2, 44, 48, itemStack -> this.recipes.stream().anyMatch(recipeHolder -> ((SmithingRecipe)recipeHolder.value()).isAdditionIngredient(itemStack)))
.withResultSlot(3, 98, 48)
.build();
}
@Override
protected boolean isValidBlock(BlockState state) {
return state.is(Blocks.SMITHING_TABLE);
}
@Override
protected boolean mayPickup(Player player, boolean hasStack) {
return this.selectedRecipe != null && this.selectedRecipe.value().matches(this.createRecipeInput(), this.level);
}
@Override
protected void onTake(Player player, ItemStack stack) {
stack.onCraftedBy(player.level(), player, stack.getCount());
this.resultSlots.awardUsedRecipes(player, this.getRelevantItems());
this.shrinkStackInSlot(0);
this.shrinkStackInSlot(1);
this.shrinkStackInSlot(2);
this.access.execute((level, blockPos) -> level.levelEvent(1044, blockPos, 0));
}
private List<ItemStack> getRelevantItems() {
return List.of(this.inputSlots.getItem(0), this.inputSlots.getItem(1), this.inputSlots.getItem(2));
}
private SmithingRecipeInput createRecipeInput() {
return new SmithingRecipeInput(this.inputSlots.getItem(0), this.inputSlots.getItem(1), this.inputSlots.getItem(2));
}
private void shrinkStackInSlot(int index) {
ItemStack itemStack = this.inputSlots.getItem(index);
if (!itemStack.isEmpty()) {
itemStack.shrink(1);
this.inputSlots.setItem(index, itemStack);
}
}
@Override
public void createResult() {
SmithingRecipeInput smithingRecipeInput = this.createRecipeInput();
List<RecipeHolder<SmithingRecipe>> list = this.level.getRecipeManager().getRecipesFor(RecipeType.SMITHING, smithingRecipeInput, this.level);
if (list.isEmpty()) {
this.resultSlots.setItem(0, ItemStack.EMPTY);
} else {
RecipeHolder<SmithingRecipe> recipeHolder = (RecipeHolder<SmithingRecipe>)list.get(0);
ItemStack itemStack = recipeHolder.value().assemble(smithingRecipeInput, this.level.registryAccess());
if (itemStack.isItemEnabled(this.level.enabledFeatures())) {
this.selectedRecipe = recipeHolder;
this.resultSlots.setRecipeUsed(recipeHolder);
this.resultSlots.setItem(0, itemStack);
}
}
}
@Override
public int getSlotToQuickMoveTo(ItemStack stack) {
return this.findSlotToQuickMoveTo(stack).orElse(0);
}
private static OptionalInt findSlotMatchingIngredient(SmithingRecipe recipe, ItemStack stack) {
if (recipe.isTemplateIngredient(stack)) {
return OptionalInt.of(0);
} else if (recipe.isBaseIngredient(stack)) {
return OptionalInt.of(1);
} else {
return recipe.isAdditionIngredient(stack) ? OptionalInt.of(2) : OptionalInt.empty();
}
}
@Override
public boolean canTakeItemForPickAll(ItemStack stack, Slot slot) {
return slot.container != this.resultSlots && super.canTakeItemForPickAll(stack, slot);
}
@Override
public boolean canMoveIntoInputSlots(ItemStack stack) {
return this.findSlotToQuickMoveTo(stack).isPresent();
}
private OptionalInt findSlotToQuickMoveTo(ItemStack stack) {
return this.recipes
.stream()
.flatMapToInt(recipeHolder -> findSlotMatchingIngredient((SmithingRecipe)recipeHolder.value(), stack).stream())
.filter(i -> !this.getSlot(i).hasItem())
.findFirst();
}
}