diff --git a/src/main/java/me/rigamortis/seppuku/impl/management/ModuleManager.java b/src/main/java/me/rigamortis/seppuku/impl/management/ModuleManager.java index 9489770..fa23db1 100644 --- a/src/main/java/me/rigamortis/seppuku/impl/management/ModuleManager.java +++ b/src/main/java/me/rigamortis/seppuku/impl/management/ModuleManager.java @@ -146,6 +146,7 @@ public final class ModuleManager { add(new LogoutSpotsModule()); add(new ChatSuffixModule()); add(new VisualRangeModule()); + add(new HotBarRefillModule()); //p2w experience if (Seppuku.INSTANCE.getCapeManager().hasCape()) diff --git a/src/main/java/me/rigamortis/seppuku/impl/module/misc/HotBarRefillModule.java b/src/main/java/me/rigamortis/seppuku/impl/module/misc/HotBarRefillModule.java new file mode 100644 index 0000000..79281ff --- /dev/null +++ b/src/main/java/me/rigamortis/seppuku/impl/module/misc/HotBarRefillModule.java @@ -0,0 +1,162 @@ +package me.rigamortis.seppuku.impl.module.misc; + +import me.rigamortis.seppuku.Seppuku; +import me.rigamortis.seppuku.api.event.EventStageable; +import me.rigamortis.seppuku.api.event.player.EventUpdateWalkingPlayer; +import me.rigamortis.seppuku.api.module.Module; +import me.rigamortis.seppuku.api.util.Timer; +import me.rigamortis.seppuku.api.value.Value; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.inventory.GuiInventory; +import net.minecraft.init.Items; +import net.minecraft.inventory.ClickType; +import net.minecraft.item.ItemStack; +import team.stiff.pomelo.impl.annotated.handler.annotation.Listener; + +/** + * Automatically refills the players hotbar. + * + * @author Old Chum + * @since 12/7/19 + */ +public class HotBarRefillModule extends Module { + public final Value delay = new Value<>("Delay", new String[]{"Del"}, "The amount of delay in milliseconds.", 50.0f); + public final Value percentage = new Value<>("RefillPercentage", new String[]{"percent", "p", "percent"}, "The percentage a slot should be filled to get refilled.", 50, 0, 100, 1); + public final Value offHand = new Value<>("OffHand", new String[]{"oh", "off", "hand"}, "If the off hand should be refilled.", true); + + private Timer timer = new Timer(); + + public HotBarRefillModule() { + super("HotBarRefill", new String[]{"Replenish", "Refill", "AutoHotBar", "hbr", "Restock", "HBRestock", "HBRefill", "Hotbar"}, "NONE", -1, ModuleType.MISC); + } + + @Listener + public void onWalkingUpdate (EventUpdateWalkingPlayer event) { + if (this.timer.passed(this.delay.getValue())) { + if (event.getStage() == EventStageable.EventStage.PRE) { + Minecraft mc = Minecraft.getMinecraft(); + + if (mc.currentScreen instanceof GuiInventory) { + return; + } + + int toRefill = getRefillable(mc.player); + if (toRefill != -1) { + refillHotbarSlot(mc, toRefill); + } + } + + timer.reset(); + } + } + + /** + * Checks all items in the hotbar that can be refilled + * If offhand is on, it is checked first + * + * @param player The player + * @return The index of the first item to be refilled, -1 if there are no refillable items + */ + private int getRefillable(EntityPlayerSP player) { + if (offHand.getValue()) { + if (player.getHeldItemOffhand().getItem() != Items.AIR + && player.getHeldItemOffhand().getCount() < player.getHeldItemOffhand().getMaxStackSize() + && (double) player.getHeldItemOffhand().getCount() / player.getHeldItemOffhand().getMaxStackSize() <= (percentage.getValue() / 100.0)) { + return 45; + } + } + + for (int i = 0; i < 9; i++) { + ItemStack stack = player.inventory.mainInventory.get(i); + if (stack.getItem() != Items.AIR && stack.getCount() < stack.getMaxStackSize() + && (double) stack.getCount() / stack.getMaxStackSize() <= (percentage.getValue() / 100.0)) { + return i; + } + } + + return -1; + } + + /** + * Searches the player's inventory for the smallest stack. + * Gets the smallest stack so that there are not a a bunch + * of partially full stacks left in the player's inventory. + * + * @param player The player + * @param itemStack The item type that should be found + * @return The index of the smallest stack of the given item, -1 if the given item does not exist + */ + private int getSmallestStack(EntityPlayerSP player, ItemStack itemStack) { + if (itemStack == null) { + return -1; + } + + int minCount = itemStack.getMaxStackSize() + 1; + int minIndex = -1; + + // i starts at 9 so that the hotbar is not checked + for (int i = 9; i < player.inventory.mainInventory.size(); i++) { + ItemStack stack = player.inventory.mainInventory.get(i); + + if (stack.getItem() != Items.AIR + && stack.getItem() == itemStack.getItem() + && stack.getCount() < minCount) { + + minCount = stack.getCount(); + minIndex = i; + } + } + + return minIndex; + } + + /** + * Refills a given slot in the hotbar from an item in the player's inventory. + * Uses the slot's current ItemStack to decide what it should be refilled with. + * + * @param mc The Mincraft instance + * @param slot The slot that should be refilled + */ + public void refillHotbarSlot(Minecraft mc, int slot) { + ItemStack stack; + if (slot == 45) { // Special case for offhand + stack = mc.player.getHeldItemOffhand(); + } else { + stack = mc.player.inventory.mainInventory.get(slot); + } + + // If the slot is air it cant be refilled + if (stack.getItem() == Items.AIR) { + return; + } + + // The slot can't be refilled if there is nothing to refill it with + int biggestStack = getSmallestStack(mc.player, stack); + if (biggestStack == -1) { + return; + } + + // Special case for offhand (can't use QUICK_CLICK) + if (slot == 45) { + mc.playerController.windowClick(mc.player.inventoryContainer.windowId, biggestStack, 0, ClickType.PICKUP, mc.player); + mc.playerController.windowClick(mc.player.inventoryContainer.windowId, 45, 0, ClickType.PICKUP, mc.player); + mc.playerController.windowClick(mc.player.inventoryContainer.windowId, biggestStack, 0, ClickType.PICKUP, mc.player); + return; + } + + int overflow = -1; // The slot a shift click will overflow to + for (int i = 0; i < 9 && overflow == -1; i++) { + if (mc.player.inventory.mainInventory.get(i).getItem() == Items.AIR) { + overflow = i; + } + } + + mc.playerController.windowClick(mc.player.inventoryContainer.windowId, biggestStack, 0, ClickType.QUICK_MOVE, mc.player); + + // If the two stacks don't overflow when combined we don't have to move overflow + if (overflow != -1 && mc.player.inventory.mainInventory.get(overflow).getItem() != Items.AIR) { + mc.playerController.windowClick(mc.player.inventoryContainer.windowId, biggestStack, overflow, ClickType.SWAP, mc.player); + } + } +}