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

216 lines
6.7 KiB
Java

package net.minecraft.world.inventory;
import java.util.Optional;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
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.entity.player.StackedContents;
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.Level;
import net.minecraft.world.level.block.Blocks;
import org.jetbrains.annotations.Nullable;
public class CraftingMenu extends RecipeBookMenu<CraftingInput, CraftingRecipe> {
public static final int RESULT_SLOT = 0;
private static final int CRAFT_SLOT_START = 1;
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 CraftingContainer craftSlots = new TransientCraftingContainer(this, 3, 3);
private final ResultContainer resultSlots = new ResultContainer();
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);
this.access = access;
this.player = playerInventory.player;
this.addSlot(new ResultSlot(playerInventory.player, this.craftSlots, this.resultSlots, 0, 124, 35));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
this.addSlot(new Slot(this.craftSlots, j + i * 3, 30 + j * 18, 17 + i * 18));
}
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 9; j++) {
this.addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18));
}
}
for (int i = 0; i < 9; i++) {
this.addSlot(new Slot(playerInventory, i, 8 + i * 18, 142));
}
}
protected static void slotChangedCraftingGrid(
AbstractContainerMenu menu,
Level level,
Player player,
CraftingContainer craftSlots,
ResultContainer resultSlots,
@Nullable RecipeHolder<CraftingRecipe> recipe
) {
if (!level.isClientSide) {
CraftingInput craftingInput = craftSlots.asCraftInput();
ServerPlayer serverPlayer = (ServerPlayer)player;
ItemStack itemStack = ItemStack.EMPTY;
Optional<RecipeHolder<CraftingRecipe>> optional = level.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftingInput, level, recipe);
if (optional.isPresent()) {
RecipeHolder<CraftingRecipe> recipeHolder = (RecipeHolder<CraftingRecipe>)optional.get();
CraftingRecipe craftingRecipe = recipeHolder.value();
if (resultSlots.setRecipeUsed(level, 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) -> slotChangedCraftingGrid(this, level, this.player, this.craftSlots, this.resultSlots, null));
}
}
@Override
public void beginPlacingRecipe() {
this.placingRecipe = true;
}
@Override
public void finishPlacingRecipe(RecipeHolder<CraftingRecipe> recipe) {
this.placingRecipe = false;
this.access.execute((level, blockPos) -> slotChangedCraftingGrid(this, level, this.player, this.craftSlots, this.resultSlots, recipe));
}
@Override
public void fillCraftSlotsStackedContents(StackedContents itemHelper) {
this.craftSlots.fillStackedContents(itemHelper);
}
@Override
public void clearCraftingContent() {
this.craftSlots.clearContent();
this.resultSlots.clearContent();
}
@Override
public boolean recipeMatches(RecipeHolder<CraftingRecipe> recipe) {
return recipe.value().matches(this.craftSlots.asCraftInput(), this.player.level());
}
@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) {
this.access.execute((level, blockPos) -> itemStack2.getItem().onCraftedBy(itemStack2, level, 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 int getResultSlotIndex() {
return 0;
}
@Override
public int getGridWidth() {
return this.craftSlots.getWidth();
}
@Override
public int getGridHeight() {
return this.craftSlots.getHeight();
}
@Override
public int getSize() {
return 10;
}
@Override
public RecipeBookType getRecipeBookType() {
return RecipeBookType.CRAFTING;
}
@Override
public boolean shouldMoveToInventory(int slotIndex) {
return slotIndex != this.getResultSlotIndex();
}
}