package codechicken.nei; import codechicken.nei.guihook.GuiContainerManager; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import java.util.*; import static codechicken.nei.NEIServerUtils.*; public class FastTransferManager { /** * Based on the general assumption that we want to fill top to bottom, left to right */ public static class SlotPositionComparator implements Comparator<Integer> { Container container; public SlotPositionComparator(Container c) { container = c; } @Override public int compare(Integer arg0, Integer arg1) { Slot slot1 = container.getSlot(arg0); Slot slot2 = container.getSlot(arg1); if (slot2.yDisplayPosition != slot1.yDisplayPosition) { return slot1.yDisplayPosition - slot2.yDisplayPosition; } return slot1.xDisplayPosition - slot2.xDisplayPosition; } } public LinkedList<LinkedList<Integer>> slotZones = new LinkedList<LinkedList<Integer>>(); public HashMap<Integer, Integer> slotZoneMap = new HashMap<Integer, Integer>(); private void generateSlotMap(Container container, ItemStack stack) { stack = stack.copy(); stack.stackSize = 1; for (int slotNo = 0; slotNo < container.inventorySlots.size(); slotNo++) { if (slotZoneMap.containsKey(slotNo) || !container.getSlot(slotNo).isItemValid(stack)) { continue; } HashSet<Integer> connectedSlots = new HashSet<Integer>(); findConnectedSlots(container, slotNo, connectedSlots); LinkedList<Integer> zoneSlots = new LinkedList<Integer>(connectedSlots); Collections.sort(zoneSlots, new SlotPositionComparator(container)); slotZones.add(zoneSlots); for (int i : zoneSlots) { slotZoneMap.put(i, slotZones.size() - 1); } } } private void findConnectedSlots(Container container, int slotNo, HashSet<Integer> connectedSlots) { connectedSlots.add(slotNo); Slot slot = container.getSlot(slotNo); final int threshold = 18; for (int i = 0; i < container.inventorySlots.size(); i++) { if (connectedSlots.contains(i)) { continue; } Slot slot1 = container.getSlot(i); if (Math.abs(slot.xDisplayPosition - slot1.xDisplayPosition) <= threshold && Math.abs(slot.yDisplayPosition - slot1.yDisplayPosition) <= threshold) { findConnectedSlots(container, i, connectedSlots); } } } public static int findSlotWithItem(Container container, ItemStack teststack) { for (int slotNo = 0; slotNo < container.inventorySlots.size(); slotNo++) { ItemStack stack = container.getSlot(slotNo).getStack(); if (stack != null && areStacksSameType(stack, teststack)) { return slotNo; } } return -1; } public static void clearSlots(Container container) { for (int slotNo = 0; slotNo < container.inventorySlots.size(); slotNo++) { ((Slot) container.inventorySlots.get(slotNo)).putStack(null); } } public void performMassTransfer(GuiContainer window, int fromSlot, int toSlot, ItemStack heldStack) { generateSlotMap(window.inventorySlots, heldStack); Integer fromZone = slotZoneMap.get(fromSlot); Integer toZone = slotZoneMap.get(toSlot); if (fromZone == null || toZone == null || fromZone.equals(toZone)) { return; } if (NEIClientUtils.getHeldItem() != null && !areStacksSameType(heldStack, NEIClientUtils.getHeldItem())) { return; } if (!fillZoneWithHeldItem(window, toZone)) { return; } for (int transferFrom : slotZones.get(fromZone)) { ItemStack transferStack = window.inventorySlots.getSlot(transferFrom).getStack(); if (!areStacksSameType(heldStack, transferStack)) { continue; } clickSlot(window, transferFrom); if (!fillZoneWithHeldItem(window, toZone)) { clickSlot(window, transferFrom); return; } } } /** * @return The slot that one item from the source slot will end up in apon shift clicking, -1 if none. */ public int findShiftClickDestinationSlot(Container container, int fromSlot) { LinkedList<ItemStack> save = saveContainer(container); Slot slot = container.getSlot(fromSlot); ItemStack stack = slot.getStack(); if (stack == null) { return -1; } stack.stackSize = 1; slot.putStack(stack.copy()); LinkedList<ItemStack> compareBefore = saveContainer(container); container.slotClick(fromSlot, 0, 1, Minecraft.getMinecraft().thePlayer); LinkedList<ItemStack> compareAfter = saveContainer(container); try { //if(compareAfter.get(fromSlot) != null)//transfer failed //return -1; for (int i = 0; i < compareBefore.size(); i++) { if (i == fromSlot) { continue; } ItemStack before = compareBefore.get(i); ItemStack after = compareAfter.get(i); if (!areStacksIdentical(before, after) && after != null) { if (before == null ? areStacksSameType(stack, after) ://transfered into this empty slot areStacksSameType(stack, after) && after.stackSize - before.stackSize > 0)//it added to this stack { return i; } } } return -1; } finally { restoreContainer(container, save); } } public LinkedList<ItemStack> saveContainer(Container container) { LinkedList<ItemStack> stacks = new LinkedList<ItemStack>(); for (int i = 0; i < container.inventorySlots.size(); i++) { stacks.add(copyStack(container.getSlot(i).getStack())); } return stacks; } public void restoreContainer(Container container, LinkedList<ItemStack> items) { for (int i = 0; i < container.inventorySlots.size(); i++) { container.getSlot(i).putStack(items.get(i)); } container.slotClick(-999, 0, 0, Minecraft.getMinecraft().thePlayer); } public void transferItem(GuiContainer window, int fromSlot) { int toSlot = findShiftClickDestinationSlot(window.inventorySlots, fromSlot); if (toSlot == -1) { return; } Slot from = window.inventorySlots.getSlot(fromSlot); if (from.isItemValid(from.getStack())) { moveOneItem(window, fromSlot, toSlot); } else//slots that you can't put stuff in { moveOutputSet(window, fromSlot, toSlot); } } public void moveOutputSet(GuiContainer window, int fromSlot, int toSlot) { if (NEIClientUtils.getHeldItem() != null) { return; } clickSlot(window, fromSlot);//pickup fromSlot if (NEIClientUtils.getHeldItem() == null)//maybe this container does auto transfers. No need to pick up the final item { return; } clickSlot(window, toSlot);//place one in toSlot } public void moveOneItem(GuiContainer window, int fromSlot, int toSlot) { clickSlot(window, fromSlot);//pickup fromSlot clickSlot(window, toSlot, 1);//place one in toSlot clickSlot(window, fromSlot);//place down in fromSlot } public void retrieveItem(GuiContainer window, int toSlot) { Slot slot = window.inventorySlots.getSlot(toSlot); ItemStack slotStack = slot.getStack(); if (slotStack == null || slotStack.stackSize == slot.getSlotStackLimit() || slotStack.stackSize == slotStack.getMaxStackSize()) { return; } generateSlotMap(window.inventorySlots, slotStack); Integer destZone = slotZoneMap.get(toSlot); if (destZone == null)//slots that don't accept { return; } int firstZoneSlot = findShiftClickDestinationSlot(window.inventorySlots, toSlot); int firstZone = -1; if (firstZoneSlot != -1) { Integer integer = slotZoneMap.get(firstZoneSlot); if (integer != null) { firstZone = integer; if (retrieveItemFromZone(window, firstZone, toSlot)) { return; } } } for (int zone = 0; zone < slotZones.size(); zone++) { if (zone == destZone || zone == firstZone) { continue; } if (retrieveItemFromZone(window, zone, toSlot)) { return; } } retrieveItemFromZone(window, destZone, toSlot); } private boolean retrieveItemFromZone(GuiContainer window, int zone, int toSlot) { ItemStack stack = window.inventorySlots.getSlot(toSlot).getStack(); for (int i : slotZones.get(zone)) { if (i == toSlot) { continue; } Slot slot = window.inventorySlots.getSlot(i); ItemStack stack1 = slot.getStack(); if (areStacksSameType(stack, stack1) && stack1.stackSize != slot.getSlotStackLimit() && //get from full stacks on second pass stack1.stackSize != stack1.getMaxStackSize()) { moveOneItem(window, i, toSlot); return true; } } for (int i : slotZones.get(zone)) { if (i == toSlot) { continue; } Slot slot = window.inventorySlots.getSlot(i); ItemStack stack1 = slot.getStack(); if (areStacksSameType(stack, stack1)) { moveOneItem(window, i, toSlot); return true; } } return false; } public static void clickSlot(GuiContainer window, int slotIndex) { clickSlot(window, slotIndex, 0); } public static void clickSlot(GuiContainer window, int slotIndex, int button) { clickSlot(window, slotIndex, button, 0); } public static void clickSlot(GuiContainer window, int slotIndex, int button, int modifier) { GuiContainerManager.getManager(window).handleSlotClick(slotIndex, button, modifier); } private boolean fillZoneWithHeldItem(GuiContainer window, int zoneIndex) { for (int transferTo : slotZones.get(zoneIndex)) { ItemStack held = NEIClientUtils.getHeldItem(); if (held == null) { break; } ItemStack inToSlot = window.inventorySlots.getSlot(transferTo).getStack(); if (!areStacksSameType(inToSlot, held)) { continue; } clickSlot(window, transferTo); } for (int transferTo : slotZones.get(zoneIndex))//repeat on empty slots { ItemStack held = NEIClientUtils.getHeldItem(); if (held == null) { break; } ItemStack inToSlot = window.inventorySlots.getSlot(transferTo).getStack(); if (inToSlot != null) { continue; } clickSlot(window, transferTo); } return NEIClientUtils.getHeldItem() == null; } public void throwAll(GuiContainer window, int pickedUpFromSlot) { ItemStack held = NEIClientUtils.getHeldItem(); if (held == null) { return; } clickSlot(window, -999); generateSlotMap(window.inventorySlots, held); Integer zone = slotZoneMap.get(pickedUpFromSlot); if (zone == null) //something went wrong and we can't work out where the item was picked up from { return; } for (int slotIndex : slotZones.get(zone)) { Slot slot = window.inventorySlots.getSlot(slotIndex); if (areStacksSameType(held, slot.getStack())) { clickSlot(window, slotIndex); clickSlot(window, -999); } } } }