MC Fabric 1.20.1 学习笔记 —— 制作一个独立配方的工作台 06 Slot

54 阅读2分钟

在WorkBlockScreenHandler的构造方法中有很多Slot对象,其中WorkBlockOutputSlot需要我们自己编码,这个类会同时联动输入和输出,做到在输出取走物品后,输入相应减少物品。MC很多逻辑都和我们想的不太一样,也许这也是MC代码被称为屎山的原因吧。

/**
 * 模仿net.minecraft.screen.slot.CraftingResultSlot写的 todo 渲染逻辑还不完全理解,目前当做固定写法即可
 * 产物槽位需要联动控制输出槽位和输出槽位,从输出槽位取走东西后,相应的要减少输入槽位对应物品
 */
public class WorkBlockOutputSlot extends Slot {
    // 输入内容
    private final WorkBlockInputInventory input;
    private final PlayerEntity player;
    // 神秘变量,没看懂,似乎是玩家想要取走的数量,比如单击一次和shift单击一次这种
    private int amount;

    public WorkBlockOutputSlot(Inventory inventory, int index, int x, int y, PlayerEntity player, WorkBlockInputInventory input) {
        // 输出格子的物品栈作为此类的物品栈,包括物品格子的索引,相对左上角的坐标(这里和前端耦合起来了)
        super(inventory, index, x, y);
        this.player = player;
        this.input = input;
    }

    @Override
    public boolean canInsert(ItemStack stack) {
        return false;
    }

    // 从槽位取走产物时
    @Override
    public ItemStack takeStack(int amount) {
        if (this.hasStack()) {
            // 取走的数量应当小于现有数量,比如熔炉烧肉,要小于已经烧出来的肉数量,同时这里使用了累加,似乎是玩家可以连续点击?
            this.amount += Math.min(amount, this.getStack().getCount());
        }
        return super.takeStack(amount);
    }

    @Override
    protected void onCrafted(ItemStack stack, int amount) {
        // 当合成完成时,累加产物数量?
        this.amount += amount;
        this.onCrafted(stack);
    }

    @Override
    protected void onCrafted(ItemStack stack) {
        // 下面可看做固定写法,太乱了,我看不明白
        Inventory inventory;
        // 当产物数量大于0
        if(this.amount > 0) {
            stack.onCraft(this.player.getWorld(), this.player, this.amount);
        }
        // 当自己的物品栈是配方解锁这个类的实例时
        if((inventory = this.inventory) instanceof RecipeUnlocker) {
            // 对合成表进行解锁,属实没看明白
            RecipeUnlocker recipeUnlocker = (RecipeUnlocker) inventory;
            recipeUnlocker.unlockLastRecipe(this.player, this.input.getInputStacks());
        }
        // 又把产物数量设为0
        this.amount = 0;
    }

    @Override
    public void onTakeItem(PlayerEntity player, ItemStack stack) {
        this.onCrafted(stack);
        // 似乎是去获取格子中剩余的物品栈
        DefaultedList<ItemStack> defaultedList = player.getWorld().getRecipeManager().getRemainingStacks(RecipeManager.WORK_BLOCK_RECIPE_TYPE, this.input, player.getWorld());
        for (int i = 0; i < defaultedList.size(); i++) {
            // 这么做不怕溢出吗
            ItemStack itemStack = this.input.getStack(i);
            ItemStack itemStack2 = defaultedList.get(i);
            if(!itemStack.isEmpty()) {
                // 一次合成只消耗1个物品
                this.input.removeStack(i, 1);
                // 变成消耗一个后剩余的,讲道理不是指针已经指好了吗,莫非removeStack会改这个位置的指针
                itemStack = this.input.getStack(i);
            }
            // 产物是空气则跳过
            if(itemStack2.isEmpty()) continue;
            if(itemStack.isEmpty()) {
                // 耗材是空则将输入设置为产物?
                this.input.setStack(i, itemStack2);
                continue;
            }
            if(ItemStack.canCombine(itemStack, itemStack2)){
                // 当产物和耗材可以合并时?
                itemStack2.increment(itemStack.getCount());
                this.input.setStack(i, itemStack2);
                continue;
            }
            // 向玩家身上放物品,移除了就掉地上
            player.getInventory().offerOrDrop(itemStack2);
        }
    }
}