ServerPlaceRecipe.java

net.minecraft.recipebook.ServerPlaceRecipe

信息

  • 全限定名:net.minecraft.recipebook.ServerPlaceRecipe
  • 类型:public class
  • 包:net.minecraft.recipebook
  • 源码路径:src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
  • 起始行号:L18
  • 职责:

    TODO

字段/常量

  • ITEM_NOT_FOUND

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L19
    • 说明:

      TODO

  • inventory

    • 类型: Inventory
    • 修饰符: private final
    • 源码定位: L20
    • 说明:

      TODO

  • menu

    • 类型: ServerPlaceRecipe.CraftingMenuAccess<R>
    • 修饰符: private final
    • 源码定位: L21
    • 说明:

      TODO

  • useMaxItems

    • 类型: boolean
    • 修饰符: private final
    • 源码定位: L22
    • 说明:

      TODO

  • gridWidth

    • 类型: int
    • 修饰符: private final
    • 源码定位: L23
    • 说明:

      TODO

  • gridHeight

    • 类型: int
    • 修饰符: private final
    • 源码定位: L24
    • 说明:

      TODO

  • inputGridSlots

    • 类型: List<Slot>
    • 修饰符: private final
    • 源码定位: L25
    • 说明:

      TODO

  • slotsToClear

    • 类型: List<Slot>
    • 修饰符: private final
    • 源码定位: L26
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.recipebook.ServerPlaceRecipe.CraftingMenuAccess
    • 类型: interface
    • 修饰符: public
    • 源码定位: L240
    • 说明:

      TODO

构造器

private ServerPlaceRecipe(ServerPlaceRecipe.CraftingMenuAccess<R> menu, Inventory inventory, boolean useMaxItems, int gridWidth, int gridHeight, List<Slot> inputGridSlots, List<Slot> slotsToClear) @ L50

  • 构造器名:ServerPlaceRecipe
  • 源码定位:L50
  • 修饰符:private

参数:

  • menu: ServerPlaceRecipe.CraftingMenuAccess
  • inventory: Inventory
  • useMaxItems: boolean
  • gridWidth: int
  • gridHeight: int
  • inputGridSlots: List
  • slotsToClear: List

说明:

TODO

方法

下面的方法块按源码顺序生成。

public static <I extends RecipeInput,R extends Recipe<I>> RecipeBookMenu.PostPlaceAction placeRecipe(ServerPlaceRecipe.CraftingMenuAccess<R> menu, int gridWidth, int gridHeight, List<Slot> inputGridSlots, List<Slot> slotsToClear, Inventory inventory, RecipeHolder<R> recipe, boolean useMaxItems, boolean allowDroppingItemsToClear) @ L28

  • 方法名:placeRecipe
  • 源码定位:L28
  • 返回类型:<I extends RecipeInput,R extends Recipe> RecipeBookMenu.PostPlaceAction
  • 修饰符:public static

参数:

  • menu: ServerPlaceRecipe.CraftingMenuAccess
  • gridWidth: int
  • gridHeight: int
  • inputGridSlots: List
  • slotsToClear: List
  • inventory: Inventory
  • recipe: RecipeHolder
  • useMaxItems: boolean
  • allowDroppingItemsToClear: boolean

说明:

TODO

private RecipeBookMenu.PostPlaceAction tryPlaceRecipe(RecipeHolder<R> recipe, StackedItemContents availableItems) @ L68

  • 方法名:tryPlaceRecipe
  • 源码定位:L68
  • 返回类型:RecipeBookMenu.PostPlaceAction
  • 修饰符:private

参数:

  • recipe: RecipeHolder
  • availableItems: StackedItemContents

说明:

TODO

private void clearGrid() @ L80

  • 方法名:clearGrid
  • 源码定位:L80
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

private void placeRecipe(RecipeHolder<R> recipe, StackedItemContents availableItems) @ L90

  • 方法名:placeRecipe
  • 源码定位:L90
  • 返回类型:void
  • 修饰符:private

参数:

  • recipe: RecipeHolder
  • availableItems: StackedItemContents

说明:

TODO

private static int clampToMaxStackSize(int value, List<Holder<Item>> items) @ L137

  • 方法名:clampToMaxStackSize
  • 源码定位:L137
  • 返回类型:int
  • 修饰符:private static

参数:

  • value: int
  • items: List<Holder>

说明:

TODO

private int calculateAmountToCraft(int biggestCraftableStack, boolean recipeMatchesPlaced) @ L145

  • 方法名:calculateAmountToCraft
  • 源码定位:L145
  • 返回类型:int
  • 修饰符:private

参数:

  • biggestCraftableStack: int
  • recipeMatchesPlaced: boolean

说明:

TODO

private int moveItemToGrid(Slot targetSlot, Holder<Item> itemInInventory, int count) @ L168

  • 方法名:moveItemToGrid
  • 源码定位:L168
  • 返回类型:int
  • 修饰符:private

参数:

  • targetSlot: Slot
  • itemInInventory: Holder
  • count: int

说明:

TODO

private boolean testClearGrid() @ L193

  • 方法名:testClearGrid
  • 源码定位:L193
  • 返回类型:boolean
  • 修饰符:private

参数:

说明:

TODO

private int getAmountOfFreeSlotsInInventory() @ L228

  • 方法名:getAmountOfFreeSlotsInInventory
  • 源码定位:L228
  • 返回类型:int
  • 修饰符:private

参数:

说明:

TODO

代码

public class ServerPlaceRecipe<R extends Recipe<?>> {
    private static final int ITEM_NOT_FOUND = -1;
    private final Inventory inventory;
    private final ServerPlaceRecipe.CraftingMenuAccess<R> menu;
    private final boolean useMaxItems;
    private final int gridWidth;
    private final int gridHeight;
    private final List<Slot> inputGridSlots;
    private final List<Slot> slotsToClear;
 
    public static <I extends RecipeInput, R extends Recipe<I>> RecipeBookMenu.PostPlaceAction placeRecipe(
        ServerPlaceRecipe.CraftingMenuAccess<R> menu,
        int gridWidth,
        int gridHeight,
        List<Slot> inputGridSlots,
        List<Slot> slotsToClear,
        Inventory inventory,
        RecipeHolder<R> recipe,
        boolean useMaxItems,
        boolean allowDroppingItemsToClear
    ) {
        ServerPlaceRecipe<R> placer = new ServerPlaceRecipe<>(menu, inventory, useMaxItems, gridWidth, gridHeight, inputGridSlots, slotsToClear);
        if (!allowDroppingItemsToClear && !placer.testClearGrid()) {
            return RecipeBookMenu.PostPlaceAction.NOTHING;
        } else {
            StackedItemContents availableItems = new StackedItemContents();
            inventory.fillStackedContents(availableItems);
            menu.fillCraftSlotsStackedContents(availableItems);
            return placer.tryPlaceRecipe(recipe, availableItems);
        }
    }
 
    private ServerPlaceRecipe(
        ServerPlaceRecipe.CraftingMenuAccess<R> menu,
        Inventory inventory,
        boolean useMaxItems,
        int gridWidth,
        int gridHeight,
        List<Slot> inputGridSlots,
        List<Slot> slotsToClear
    ) {
        this.menu = menu;
        this.inventory = inventory;
        this.useMaxItems = useMaxItems;
        this.gridWidth = gridWidth;
        this.gridHeight = gridHeight;
        this.inputGridSlots = inputGridSlots;
        this.slotsToClear = slotsToClear;
    }
 
    private RecipeBookMenu.PostPlaceAction tryPlaceRecipe(RecipeHolder<R> recipe, StackedItemContents availableItems) {
        if (availableItems.canCraft(recipe.value(), null)) {
            this.placeRecipe(recipe, availableItems);
            this.inventory.setChanged();
            return RecipeBookMenu.PostPlaceAction.NOTHING;
        } else {
            this.clearGrid();
            this.inventory.setChanged();
            return RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE;
        }
    }
 
    private void clearGrid() {
        for (Slot slot : this.slotsToClear) {
            ItemStack itemStackCopy = slot.getItem().copy();
            this.inventory.placeItemBackInInventory(itemStackCopy, false);
            slot.set(itemStackCopy);
        }
 
        this.menu.clearCraftingContent();
    }
 
    private void placeRecipe(RecipeHolder<R> recipe, StackedItemContents availableItems) {
        boolean recipeMatchesPlaced = this.menu.recipeMatches(recipe);
        int biggestCraftableStack = availableItems.getBiggestCraftableStack(recipe.value(), null);
        if (recipeMatchesPlaced) {
            for (Slot inputSlot : this.inputGridSlots) {
                ItemStack itemStack = inputSlot.getItem();
                if (!itemStack.isEmpty() && Math.min(biggestCraftableStack, itemStack.getMaxStackSize()) < itemStack.getCount() + 1) {
                    return;
                }
            }
        }
 
        int amountToCraft = this.calculateAmountToCraft(biggestCraftableStack, recipeMatchesPlaced);
        List<Holder<Item>> itemsUsedPerIngredient = new ArrayList<>();
        if (availableItems.canCraft(recipe.value(), amountToCraft, itemsUsedPerIngredient::add)) {
            int adjustedAmountToCraft = clampToMaxStackSize(amountToCraft, itemsUsedPerIngredient);
            if (adjustedAmountToCraft != amountToCraft) {
                itemsUsedPerIngredient.clear();
                if (!availableItems.canCraft(recipe.value(), adjustedAmountToCraft, itemsUsedPerIngredient::add)) {
                    return;
                }
            }
 
            this.clearGrid();
            PlaceRecipeHelper.placeRecipe(
                this.gridWidth,
                this.gridHeight,
                recipe.value(),
                recipe.value().placementInfo().slotsToIngredientIndex(),
                (ingredientIndex, gridIndex, gridXPos, gridYPos) -> {
                    if (ingredientIndex != -1) {
                        Slot targetGridSlot = this.inputGridSlots.get(gridIndex);
                        Holder<Item> itemUsed = itemsUsedPerIngredient.get(ingredientIndex);
                        int remainingCount = adjustedAmountToCraft;
 
                        while (remainingCount > 0) {
                            remainingCount = this.moveItemToGrid(targetGridSlot, itemUsed, remainingCount);
                            if (remainingCount == -1) {
                                return;
                            }
                        }
                    }
                }
            );
        }
    }
 
    private static int clampToMaxStackSize(int value, List<Holder<Item>> items) {
        for (Holder<Item> item : items) {
            value = Math.min(value, item.components().getOrDefault(DataComponents.MAX_STACK_SIZE, 1));
        }
 
        return value;
    }
 
    private int calculateAmountToCraft(int biggestCraftableStack, boolean recipeMatchesPlaced) {
        if (this.useMaxItems) {
            return biggestCraftableStack;
        } else if (recipeMatchesPlaced) {
            int smallestStackSize = Integer.MAX_VALUE;
 
            for (Slot inputSlot : this.inputGridSlots) {
                ItemStack itemStack = inputSlot.getItem();
                if (!itemStack.isEmpty() && smallestStackSize > itemStack.getCount()) {
                    smallestStackSize = itemStack.getCount();
                }
            }
 
            if (smallestStackSize != Integer.MAX_VALUE) {
                smallestStackSize++;
            }
 
            return smallestStackSize;
        } else {
            return 1;
        }
    }
 
    private int moveItemToGrid(Slot targetSlot, Holder<Item> itemInInventory, int count) {
        ItemStack itemInTargetSlot = targetSlot.getItem();
        int inventorySlotId = this.inventory.findSlotMatchingCraftingIngredient(itemInInventory, itemInTargetSlot);
        if (inventorySlotId == -1) {
            return -1;
        } else {
            ItemStack inventoryItem = this.inventory.getItem(inventorySlotId);
            ItemStack takenStack;
            if (count < inventoryItem.getCount()) {
                takenStack = this.inventory.removeItem(inventorySlotId, count);
            } else {
                takenStack = this.inventory.removeItemNoUpdate(inventorySlotId);
            }
 
            int takenCount = takenStack.getCount();
            if (itemInTargetSlot.isEmpty()) {
                targetSlot.set(takenStack);
            } else {
                itemInTargetSlot.grow(takenCount);
            }
 
            return count - takenCount;
        }
    }
 
    private boolean testClearGrid() {
        List<ItemStack> freeSlots = Lists.newArrayList();
        int freeSlotsInInventory = this.getAmountOfFreeSlotsInInventory();
 
        for (Slot inputSlot : this.inputGridSlots) {
            ItemStack itemStack = inputSlot.getItem().copy();
            if (!itemStack.isEmpty()) {
                int slotId = this.inventory.getSlotWithRemainingSpace(itemStack);
                if (slotId == -1 && freeSlots.size() <= freeSlotsInInventory) {
                    for (ItemStack itemStackInList : freeSlots) {
                        if (ItemStack.isSameItem(itemStackInList, itemStack)
                            && itemStackInList.getCount() != itemStackInList.getMaxStackSize()
                            && itemStackInList.getCount() + itemStack.getCount() <= itemStackInList.getMaxStackSize()) {
                            itemStackInList.grow(itemStack.getCount());
                            itemStack.setCount(0);
                            break;
                        }
                    }
 
                    if (!itemStack.isEmpty()) {
                        if (freeSlots.size() >= freeSlotsInInventory) {
                            return false;
                        }
 
                        freeSlots.add(itemStack);
                    }
                } else if (slotId == -1) {
                    return false;
                }
            }
        }
 
        return true;
    }
 
    private int getAmountOfFreeSlotsInInventory() {
        int freeSlots = 0;
 
        for (ItemStack item : this.inventory.getNonEquipmentItems()) {
            if (item.isEmpty()) {
                freeSlots++;
            }
        }
 
        return freeSlots;
    }
 
    public interface CraftingMenuAccess<T extends Recipe<?>> {
        void fillCraftSlotsStackedContents(StackedItemContents stackedContents);
 
        void clearCraftingContent();
 
        boolean recipeMatches(RecipeHolder<T> recipe);
    }
}

引用的其他类