package de.skate702.craftingkeys.manager; import de.skate702.craftingkeys.CraftingKeys; import de.skate702.craftingkeys.config.Config; import de.skate702.craftingkeys.util.InputUtil; import de.skate702.craftingkeys.util.Logger; import de.skate702.craftingkeys.util.Util; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.gui.inventory.GuiInventory; import net.minecraft.client.settings.KeyBinding; import net.minecraft.init.Blocks; import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import org.lwjgl.input.Keyboard; /** * Provides all needed methods to handle and manage a gui inventory. Does also provide frames for own implementations. */ public abstract class ContainerManager { /** * The Container to work with. */ Container container; /** * Creates a new ContainerManager with the given container. * * @param container The container to work with */ ContainerManager(Container container) { this.container = container; } /** * Checks the current keyDown-Value and does the work! * Use the implementation in ContainerManager if possible. Or define your own. */ public void acceptKey() { // Get hovered slot and goal slotIndex of pressed key (if pressed) Slot currentHoveredSlot = InputUtil.getSlotAtMousePosition((GuiContainer) Util.client.currentScreen); int slotIndex = specificKeyToSlotIndex(); // Handle accepted key if (!InputUtil.isSameKey(slotIndex)) { if (Config.isKeyDropPressed()) { // DROP Logger.info("acceptKey()", "Drop Key pressed."); onDropKeyPressed(); } else if (Config.isKeyInteractPressed()) { // INTERACT Logger.info("acceptKey()", "Interaction Key pressed."); onInteractionKeyPressed(); } else if (slotIndex >= 0 && currentHoveredSlot != null && !Util.isHoldingStack()) { // MOVE FROM SLOT Logger.info("acceptKey()", "Key for index " + slotIndex + " pressed."); onSpecificKeyPressed(currentHoveredSlot.slotNumber, slotIndex); } else if (Util.isHoldingStack()) { // MOVE FROM HAND onHolding(slotIndex); handleNumKey(currentHoveredSlot); } else { // HANDLE NUM KEY MOVING (also with empty hand now -> speed-up) handleNumKey(currentHoveredSlot); } } } /** * Handles what to do when the DropKey is pressed in acceptKey(). */ @SuppressWarnings("WeakerAccess") void onDropKeyPressed() { // Drop every defined dropSlot-Item for (int i : getDropSlots()) { moveStackToInventory(i); } } /** * Handles what to do when the InteractionKey is pressed in acceptKey(). */ void onInteractionKeyPressed() { // Handles Interaction with items held // Stack up on hand if equal or small enough, else throw held stack away if (Util.isHoldingStack() && getItemStack(getInteractionSlotIndex()) != null && ( !Util.getHeldStack().isItemEqual(getItemStack(getInteractionSlotIndex())) || Util.getHeldStack().getCount() + getItemStack(getInteractionSlotIndex()).getCount() > getItemStack(getInteractionSlotIndex()).getMaxStackSize())) { moveStackToInventory(-1); } // Handle Interaction if (Config.isKeyStackPressed()) { int oldStackSize = -1; interact(); while (Util.isHoldingStack() && oldStackSize != Util.getHeldStack().getCount()) { oldStackSize = Util.getHeldStack().getCount(); interact(); } } else { interact(); } } /** * Handles what to do if a specific key is pressed in acceptKey(). * * @param currentHoveredSlot the slot number of the currently hovered Slot (mouse hover) * @param slotIndex the slot index returned from the key input calculation */ void onSpecificKeyPressed(int currentHoveredSlot, int slotIndex) { if (Config.isKeyStackPressed()) { moveAll(currentHoveredSlot, slotIndex); moveStackToInventory(-1); } else { move(currentHoveredSlot, slotIndex, 1); } } /** * Handles what to do with held items in acceptKey(). * * @param slotIndex the slot index returned from the key input calculation */ void onHolding(int slotIndex) { onSpecificKeyPressed(-1, slotIndex); } /** * Handles what to do with NumKey-Inputs while holding a item. * * @param currentHoveredSlot slot where the mouse is right now */ void handleNumKey(Slot currentHoveredSlot) { // hotbar-slots are always the last 9 slots of the currently opened inventory int hotbarStartIndex = Util.client.player.openContainer.getInventory().size() - 9 - 1; if (Util.client.currentScreen instanceof GuiInventory) { hotbarStartIndex -= 1; } int inputdelta; KeyBinding[] hotbar = Util.client.gameSettings.keyBindsHotbar; if (Keyboard.isKeyDown(hotbar[0].getKeyCode())) { inputdelta = 1; } else if (Keyboard.isKeyDown(hotbar[1].getKeyCode())) { inputdelta = 2; } else if (Keyboard.isKeyDown(hotbar[2].getKeyCode())) { inputdelta = 3; } else if (Keyboard.isKeyDown(hotbar[3].getKeyCode())) { inputdelta = 4; } else if (Keyboard.isKeyDown(hotbar[4].getKeyCode())) { inputdelta = 5; } else if (Keyboard.isKeyDown(hotbar[5].getKeyCode())) { inputdelta = 6; } else if (Keyboard.isKeyDown(hotbar[6].getKeyCode())) { inputdelta = 7; } else if (Keyboard.isKeyDown(hotbar[7].getKeyCode())) { inputdelta = 8; } else if (Keyboard.isKeyDown(hotbar[8].getKeyCode())) { inputdelta = 9; } else { return; } // If no stack is held and a num-key is pressed, get the output by interaction, but only // if there could not be meant another stack at mouse position. cool logic! if (!Util.isHoldingStack()) { if (currentHoveredSlot == null || !currentHoveredSlot.getHasStack()) { Logger.info("handleNumKey()", "Trying output to hotbar speedup."); onInteractionKeyPressed(); } } // If held, move! if (Util.isHoldingStack()) { leftClick(hotbarStartIndex + inputdelta); Logger.info("handleNumKey()", "Moved to hotbar slot " + inputdelta + "."); moveStackToInventory(-1); // Handle Minecraft handling. Ah... while (Keyboard.next()) { Logger.info("handleNumKey()", "The cake is a lie!"); } } } /** * Converts the first specific pressed Key to the slot in a given Inventory. * Does also accept Interaction (mapped to -101) and drop key (mapped to -102). * * @return The slot index in the currently managed inventory gui */ protected abstract int specificKeyToSlotIndex(); /** * Maps all specific keys to given indices. Can be used in specificKeyToSlotIndex() * * @param topLeft top-left slot index * @param topCenter top-center slot index * @param topRight top-right slot index * @param centerLeft center-left slot index * @param centerCenter center-center slot index * @param centerRight center-right slot index * @param lowerLeft lower-left slot index * @param lowerCenter lower-center slot index * @param lowerRight lower-right slot index * @return a slot index. wow! */ int mapKeyToSlot(int topLeft, int topCenter, int topRight, int centerLeft, int centerCenter, int centerRight, int lowerLeft, int lowerCenter, int lowerRight) { if (Config.isKeyTopLeftPressed()) { return topLeft; } else if (Config.isKeyTopCenterPressed()) { return topCenter; } else if (Config.isKeyTopRightPressed()) { return topRight; } else if (Config.isKeyCenterLeftPressed()) { return centerLeft; } else if (Config.isKeyCenterCenterPressed()) { return centerCenter; } else if (Config.isKeyCenterRightPressed()) { return centerRight; } else if (Config.isKeyLowerLeftPressed()) { return lowerLeft; } else if (Config.isKeyLowerCenterPressed()) { return lowerCenter; } else if (Config.isKeyLowerRightPressed()) { return lowerRight; } else if (Config.isKeyInteractPressed()) { return -101; } else if (Config.isKeyDropPressed()) { return -102; } else { return -1; } } /** * Moves a full Stack from a slot to another. * * @param srcIndex The Source Slot Index of the Container * @param destIndex The Destination Slot Index of the Container */ void moveAll(int srcIndex, int destIndex) { ItemStack source = getItemStack(srcIndex); if (source == null) { Logger.debug("moveAll(i,i)", "Source ItemStack from Index == null"); } else { move(srcIndex, destIndex, source.getCount()); } } /** * Moves a specified amount of Items from a slot to another. [Based on * INVTW] * * @param srcIndex The Source Slot Index of the Container * @param destIndex The Destination Slot Index of the Container * @param amount The amount of items to move (can be bigger then Stack Size) */ void move(int srcIndex, int destIndex, int amount) { // Stacks ItemStack source = getItemStack(srcIndex); ItemStack destination = getItemStack(destIndex); // Same Location? if (source == null) { return; } else if (srcIndex == destIndex) { return; } // Test for max. moving Amount int sourceSize = source.getCount(); int movedAmount = Math.min(amount, sourceSize); // Clear goal slot (May fail on full inventory!); only available if not holdling if (destination != null && !source.isItemEqual(destination) && srcIndex >= 0) { moveStackToInventory(destIndex); destination = getItemStack(destIndex); } // Move some if (destination == null || source.isItemEqual(destination)) { if (srcIndex >= 0) { leftClick(srcIndex); } for (int i = 0; i < movedAmount; i++) { rightClick(destIndex); } // Move back if (movedAmount < sourceSize && srcIndex > 0) { leftClick(srcIndex); } Logger.info("move(i,i,i)", "Moved " + movedAmount + " from " + srcIndex + " to " + destIndex + "!"); } else { Logger.info("move(i,i,i)", "Unable to move!"); } } /** * Returns the ItemStack in a slot [Based on INVTW] * * @param index The index of the slot in the container * @return Returns the ItemStack */ ItemStack getItemStack(int index) { if (index >= 0 && index < container.inventorySlots.size()) { Slot slot = (Slot) (container.inventorySlots.get(index)); // NEW_1_11 No Null-Stacks anymore. Empty Stacks with air... ItemStack returnStack = (slot == null) ? null : slot.getStack(); if(returnStack.getCount() == 0 && returnStack.getItem() == Item.getItemFromBlock(Blocks.AIR)) { returnStack = null; } return returnStack; } else if (index == -1 && Util.isHoldingStack()) { return Util.getHeldStack(); } else { Logger.debug("getItemStack(i)", "Invalid index"); return null; } } /** * Moves a stack (held or not) to the next fitting inventory slot. * * @param sourceIndex A slot index of the source items */ void moveStackToInventory(int sourceIndex) { // Moving Stack ItemStack stackToMove = null; // Get the stack, index or held, cleanup held stack if (sourceIndex == -1) { if (Util.isHoldingStack()) { stackToMove = Util.getHeldStack(); } } else { stackToMove = getItemStack(sourceIndex); // Is there a currently held stack? if (Util.isHoldingStack()) { moveStackToInventory(-1); } } // Test stack if (stackToMove == null) { Logger.debug("moveStackToInvetory(i)", "Stack at sourceIndex not found."); return; } // Get destination index int destIndex = calcInventoryDestination(stackToMove); // Additional click on source index, if not held if (sourceIndex != -1) { leftClick(sourceIndex); } // Move the item if (destIndex == -1) { // -1 means: Found none, drop item leftClick(-999); Logger.info("moveStackToInventory(i)", "Dropped item from index " + sourceIndex + "."); } else { leftClick(destIndex); Logger.info("moveStackToInventory(i)", "Moved item from index " + sourceIndex + " to " + destIndex + "."); } } /** * Calculates the next fitting or free inventory slot. * * @param stackToMove The ItemType and sized Stack to move * @return A super cool inventory slot index! Or -1, if you are to dumb * to keep your bloody inventory sorted! WHY U NO USE INV TWEAKS?! */ private int calcInventoryDestination(ItemStack stackToMove) { // First run: Try to find a nice stack to put items on additionally for (int i = getInventoryStartIndex(); i < container.inventorySlots.size(); i++) { ItemStack potentialGoalStack = getItemStack(i); if (potentialGoalStack != null && stackToMove != null) { if (potentialGoalStack.isItemEqual(stackToMove)) { if (potentialGoalStack.getCount() + stackToMove.getCount() <= stackToMove.getMaxStackSize()) { return i; } } } } // Second run: Find a free slot for (int i = getInventoryStartIndex(); i < container.inventorySlots.size(); i++) { if (getItemStack(i) == null) { return i; } } // Third run: No slot found. Drop this shit! return -1; } /** * Returns the start index of the user inventory in the current Gui. * * @return A slot index */ protected abstract int getInventoryStartIndex(); protected abstract int getInteractionSlotIndex(); protected abstract int[] getDropSlots(); protected abstract void interact(); /** * Executes a left mouse click on a slot. [Based on INVTW] * * @param index The index of the slot in the container */ void leftClick(int index) { slotClick(index, false); } /** * Executes a right mouse click on a slot. [Based on INVTW] * * @param index The index of the slot in the container */ void rightClick(int index) { slotClick(index, true); } /** * Executes a mouse click on a slot. [Based on INVTW] * * @param index The index of the slot in the container * @param rightClick True, if the click is with the right mouse button */ private void slotClick(int index, boolean rightClick) { Logger.info("slotClick(i,b)", "Clicked @ Slot " + index + " with data " + rightClick + "."); int rightClickData = (rightClick) ? 1 : 0; CraftingKeys.proxy.sendSlotClick(Util.client.playerController, container.windowId, index, rightClickData, 0, Util.client.player); } }