在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);
}
}
}