package crazypants.enderio.machine.invpanel.client; import java.util.ArrayList; import java.util.Collection; import java.util.List; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import com.enderio.core.common.util.ItemUtil; import crazypants.enderio.machine.invpanel.GuiInventoryPanel; import crazypants.enderio.machine.invpanel.InventoryPanelContainer; import crazypants.enderio.machine.invpanel.PacketFetchItem; import crazypants.enderio.machine.invpanel.StoredCraftingRecipe; import crazypants.enderio.network.PacketHandler; public class CraftingHelper { final ItemStack[][] ingredients; protected CraftingHelper(ItemStack[][] ingredients) { this.ingredients = ingredients; } public static CraftingHelper createFromRecipe(StoredCraftingRecipe recipe) { ItemStack[][] ingredients = new ItemStack[9][]; for (int idx = 0; idx < 9; idx++) { ItemStack stack = recipe.get(idx); if(stack != null) { ingredients[idx] = new ItemStack[] { stack }; } } return new CraftingHelperNEI(ingredients); } public static CraftingHelper createFromSlots(List<Slot> slots) { if (slots.size() != 9) { return null; } ItemStack[][] ingredients = new ItemStack[9][]; int count = 0; for (int idx = 0; idx < 9; idx++) { Slot slot = slots.get(idx); ItemStack stack = slot.getStack(); if(stack != null) { stack = stack.copy(); stack.stackSize = 1; ingredients[idx] = new ItemStack[] { stack }; count++; } } if (count > 0) { return new CraftingHelperNEI(ingredients); } return null; } public void install() { } public void remove() { } public void refill(GuiInventoryPanel gui, int amount) { InventoryPanelContainer container = gui.getContainer(); InventoryDatabaseClient db = gui.getDatabase(); List<Slot> craftingGrid = container.getCraftingGridSlots(); int slotsToProcess = (1 << 9) - 1; boolean madeProgress; int maxAmount = 64; do { Candidate[] candidates = new Candidate[9]; for (int idx = 0; idx < 9; idx++) { if ((slotsToProcess & (1 << idx)) != 0) { ItemStack[] pstack = ingredients[idx]; Slot slot = craftingGrid.get(idx); ItemStack stack = slot.getStack(); if (pstack == null) { if (stack != null) { return; } } else { Candidate candidate; if (stack != null) { if (!isStackCompatible(pstack, stack)) { return; } candidate = findCandidates(stack, gui, db, candidates); } else { candidate = findAllCandidates(pstack, gui, db, candidates); } if (candidate == null) { return; } candidate.used++; candidates[idx] = candidate; } } } int targetAmount = maxAmount; int currentAmount = 0; for (int idx = 0; idx < 9; idx++) { Candidate candidate = candidates[idx]; if (candidate != null) { Slot slot = craftingGrid.get(idx); int current = getSlotStackSize(slot); int maxStackSize = candidate.stack.getMaxStackSize(); currentAmount = Math.max(currentAmount, current); if (candidate.stack.isStackable() && maxStackSize > 1) { targetAmount = Math.min(targetAmount, current + Math.min(maxStackSize, candidate.getAvailable())); } } } targetAmount = Math.min(targetAmount, currentAmount + amount); madeProgress = false; for (int idx = 0; idx < 9; idx++) { final int mask = 1 << idx; Candidate candidate = candidates[idx]; if (candidate != null) { Slot slot = craftingGrid.get(idx); for (Slot srcSlot : candidate.sourceSlots) { int current = getSlotStackSize(slot); if (current >= targetAmount) { break; } if (container.moveItems(srcSlot.slotNumber, slot.slotNumber, slot.slotNumber + 1, targetAmount - current)) { slotsToProcess &= ~mask; madeProgress = true; } } int current = getSlotStackSize(slot); if (candidate.entry != null) { if (current < targetAmount) { int toMove = Math.min(candidate.entry.getCount(), targetAmount - current); PacketHandler.INSTANCE.sendToServer(new PacketFetchItem(db.getGeneration(), candidate.entry, slot.slotNumber, toMove)); slotsToProcess &= ~mask; current += toMove; } } if (current > 0) { maxAmount = Math.min(maxAmount, current); } } } } while (madeProgress && slotsToProcess != 0); } private static int getSlotStackSize(Slot slot) { ItemStack stack = slot.getStack(); return (stack != null) ? stack.stackSize : 0; } private static boolean isStackCompatible(ItemStack[] pstack, ItemStack stack) { for (ItemStack istack : pstack) { if (ItemUtil.areStackMergable(stack, istack)) { return true; } } return false; } private Candidate findAllCandidates(ItemStack[] pstack, GuiInventoryPanel gui, InventoryDatabaseClient db, Candidate[] candidates) { Candidate bestInventory = null; Candidate bestNetwork = null; for (ItemStack istack : pstack) { Candidate candidate = findCandidates(istack, gui, db, candidates); if (candidate.available > 0) { if (bestInventory == null || bestInventory.available < candidate.available) { bestInventory = candidate; } } if (candidate.entry != null) { if (bestNetwork == null || bestNetwork.entry.getCount() < candidate.entry.getCount()) { bestNetwork = candidate; } } } if (bestInventory != null) { return bestInventory; } else { return bestNetwork; } } private Candidate findCandidates(ItemStack stack, GuiInventoryPanel gui, InventoryDatabaseClient db, Candidate[] candidates) { for (Candidate candidate : candidates) { if (candidate != null && ItemUtil.areStackMergable(candidate.stack, stack)) { return candidate; } } Candidate candidate = new Candidate(stack); InventoryPanelContainer container = gui.getContainer(); if(container.getInventoryPanel().isExtractionDisabled()) { findCandidates(candidate, stack, container.getReturnAreaSlots()); } findCandidates(candidate, stack, container.getPlayerInventorySlots()); findCandidates(candidate, stack, container.getPlayerHotbarSlots()); if (candidate.available == 0 && db != null) { candidate.entry = db.lookupItem(stack, null, false); if (candidate.entry != null && candidate.entry.getCount() <= 0) { candidate.entry = null; } } return candidate; } private void findCandidates(Candidate candidates, ItemStack stack, Collection<Slot> slots) { for (Slot slot : slots) { ItemStack slotStack = slot.getStack(); if (slotStack != null && ItemUtil.areStackMergable(slotStack, stack)) { candidates.sourceSlots.add(slot); candidates.available += slotStack.stackSize; } } } static class Candidate { final ItemStack stack; final ArrayList<Slot> sourceSlots = new ArrayList<Slot>(); ItemEntry entry; int available; int used; public Candidate(ItemStack stack) { this.stack = stack; } public int getAvailable() { int avail = available; if(entry != null) { avail += entry.getCount(); } if(avail > 0 && used > 1) { avail = Math.max(1, avail / used); } return avail; } } }