package net.minecraft.world.inventory; import java.util.List; import java.util.Optional; import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Container; 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.CraftingInput; import net.minecraft.world.item.crafting.CraftingRecipe; import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.block.Blocks; import org.jetbrains.annotations.Nullable; public class CraftingMenu extends AbstractCraftingMenu { private static final int CRAFTING_GRID_WIDTH = 3; private static final int CRAFTING_GRID_HEIGHT = 3; public static final int RESULT_SLOT = 0; private static final int CRAFT_SLOT_START = 1; private static final int CRAFT_SLOT_COUNT = 9; private static final int CRAFT_SLOT_END = 10; private static final int INV_SLOT_START = 10; private static final int INV_SLOT_END = 37; private static final int USE_ROW_SLOT_START = 37; private static final int USE_ROW_SLOT_END = 46; private final ContainerLevelAccess access; private final Player player; private boolean placingRecipe; public CraftingMenu(int containerId, Inventory playerInventory) { this(containerId, playerInventory, ContainerLevelAccess.NULL); } public CraftingMenu(int containerId, Inventory playerInventory, ContainerLevelAccess access) { super(MenuType.CRAFTING, containerId, 3, 3); this.access = access; this.player = playerInventory.player; this.addResultSlot(this.player, 124, 35); this.addCraftingGridSlots(30, 17); this.addStandardInventorySlots(playerInventory, 8, 84); } protected static void slotChangedCraftingGrid( AbstractContainerMenu menu, ServerLevel level, Player player, CraftingContainer craftSlots, ResultContainer resultSlots, @Nullable RecipeHolder recipe ) { CraftingInput craftingInput = craftSlots.asCraftInput(); ServerPlayer serverPlayer = (ServerPlayer)player; ItemStack itemStack = ItemStack.EMPTY; Optional> optional = level.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftingInput, level, recipe); if (optional.isPresent()) { RecipeHolder recipeHolder = (RecipeHolder)optional.get(); CraftingRecipe craftingRecipe = recipeHolder.value(); if (resultSlots.setRecipeUsed(serverPlayer, recipeHolder)) { ItemStack itemStack2 = craftingRecipe.assemble(craftingInput, level.registryAccess()); if (itemStack2.isItemEnabled(level.enabledFeatures())) { itemStack = itemStack2; } } } resultSlots.setItem(0, itemStack); menu.setRemoteSlot(0, itemStack); serverPlayer.connection.send(new ClientboundContainerSetSlotPacket(menu.containerId, menu.incrementStateId(), 0, itemStack)); } @Override public void slotsChanged(Container container) { if (!this.placingRecipe) { this.access.execute((level, blockPos) -> { if (level instanceof ServerLevel serverLevel) { slotChangedCraftingGrid(this, serverLevel, this.player, this.craftSlots, this.resultSlots, null); } }); } } @Override public void beginPlacingRecipe() { this.placingRecipe = true; } @Override public void finishPlacingRecipe(ServerLevel level, RecipeHolder recipe) { this.placingRecipe = false; slotChangedCraftingGrid(this, level, this.player, this.craftSlots, this.resultSlots, recipe); } @Override public void removed(Player player) { super.removed(player); this.access.execute((level, blockPos) -> this.clearContainer(player, this.craftSlots)); } @Override public boolean stillValid(Player player) { return stillValid(this.access, player, Blocks.CRAFTING_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) { itemStack2.getItem().onCraftedBy(itemStack2, player); if (!this.moveItemStackTo(itemStack2, 10, 46, true)) { return ItemStack.EMPTY; } slot.onQuickCraft(itemStack2, itemStack); } else if (index >= 10 && index < 46) { if (!this.moveItemStackTo(itemStack2, 1, 10, false)) { if (index < 37) { if (!this.moveItemStackTo(itemStack2, 37, 46, false)) { return ItemStack.EMPTY; } } else if (!this.moveItemStackTo(itemStack2, 10, 37, false)) { return ItemStack.EMPTY; } } } else if (!this.moveItemStackTo(itemStack2, 10, 46, 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); if (index == 0) { player.drop(itemStack2, false); } } return itemStack; } @Override public boolean canTakeItemForPickAll(ItemStack stack, Slot slot) { return slot.container != this.resultSlots && super.canTakeItemForPickAll(stack, slot); } @Override public Slot getResultSlot() { return this.slots.get(0); } @Override public List getInputGridSlots() { return this.slots.subList(1, 10); } @Override public RecipeBookType getRecipeBookType() { return RecipeBookType.CRAFTING; } @Override protected Player owner() { return this.player; } }