diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/Offhand.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/Offhand.java index fe1dd83a50..54851c022f 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/Offhand.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/Offhand.java @@ -7,72 +7,129 @@ import meteordevelopment.meteorclient.events.meteor.MouseButtonEvent; import meteordevelopment.meteorclient.events.world.TickEvent; -import meteordevelopment.meteorclient.settings.BoolSetting; -import meteordevelopment.meteorclient.settings.EnumSetting; -import meteordevelopment.meteorclient.settings.Setting; -import meteordevelopment.meteorclient.settings.SettingGroup; +import meteordevelopment.meteorclient.settings.*; import meteordevelopment.meteorclient.systems.modules.Categories; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.utils.misc.input.KeyAction; import meteordevelopment.meteorclient.utils.player.FindItemResult; import meteordevelopment.meteorclient.utils.player.InvUtils; +import meteordevelopment.meteorclient.utils.player.PlayerUtils; import meteordevelopment.orbit.EventHandler; -import net.minecraft.item.AxeItem; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.item.SwordItem; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.item.*; +import static meteordevelopment.orbit.EventPriority.HIGHEST; import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_RIGHT; public class Offhand extends Module { - private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgCombat = settings.createGroup("Combat"); + private final SettingGroup sgTotem = settings.createGroup("Totem"); - private final Setting item = sgGeneral.add(new EnumSetting.Builder() + //Combat + + private final Setting delayTicks = sgCombat.add(new IntSetting.Builder() + .name("item-switch-delay") + .description("The delay in ticks between slot movements.") + .defaultValue(0) + .min(0) + .sliderMax(20) + .build() + ); + private final Setting preferreditem = sgCombat.add(new EnumSetting.Builder() .name("item") .description("Which item to hold in your offhand.") .defaultValue(Item.Crystal) .build() ); - private final Setting hotbar = sgGeneral.add(new BoolSetting.Builder() + private final Setting hotbar = sgCombat.add(new BoolSetting.Builder() .name("hotbar") .description("Whether to use items from your hotbar.") .defaultValue(false) .build() ); - private final Setting rightClick = sgGeneral.add(new BoolSetting.Builder() - .name("right-click") - .description("Only holds the item in your offhand when you are holding right click.") + private final Setting rightgapple = sgCombat.add(new BoolSetting.Builder() + .name("right-gapple") + .description("Will switch to a gapple when holding right click.(DO NOT USE WITH POTION ON)") + .defaultValue(false) + .build() + ); + + + private final Setting SwordGap = sgCombat.add(new BoolSetting.Builder() + .name("sword-gapple") + .description("Will switch to a gapple when holding a sword and right click.") .defaultValue(false) + .visible(rightgapple::get) .build() ); - private final Setting swordGap = sgGeneral.add(new BoolSetting.Builder() - .name("sword-gap") + private final Setting alwaysSwordGap = sgCombat.add(new BoolSetting.Builder() + .name("always-gap-on-sword") .description("Holds an Enchanted Golden Apple when you are holding a sword.") - .defaultValue(true) + .defaultValue(false) + .visible(() -> !rightgapple.get()) .build() ); - private final Setting crystalCa = sgGeneral.add(new BoolSetting.Builder() - .name("crystal-on-ca") - .description("Holds a crystal when you have Crystal Aura enabled.") - .defaultValue(true) + + private final Setting alwaysPot = sgCombat.add(new BoolSetting.Builder() + .name("always-pot-on-sword") + .description("Will switch to a potion when holding a sword") + .defaultValue(false) + .visible(() -> !rightgapple.get() && !alwaysSwordGap.get()) + .build() + ); + private final Setting potionClick = sgCombat.add(new BoolSetting.Builder() + .name("sword-pot") + .description("Will switch to a potion when holding a sword and right click.") + .defaultValue(false) + .visible(() -> !rightgapple.get() && !alwaysPot.get() && !alwaysSwordGap.get() ) .build() ); - private final Setting crystalMine = sgGeneral.add(new BoolSetting.Builder() - .name("crystal-on-mine") - .description("Holds a crystal when you are mining.") + //Totem + + private final Setting minHealth = sgTotem.add(new DoubleSetting.Builder() + .name("min-health") + .description("Will hold a totem when below this amount of health.") + .defaultValue(10) + .range(0,36) + .sliderRange(0,36) + .build() + ); + + private final Setting elytra = sgTotem.add(new BoolSetting.Builder() + .name("elytra") + .description("Will always hold a totem while flying with an elytra.") .defaultValue(false) .build() ); + private final Setting falling = sgTotem.add(new BoolSetting.Builder() + .name("falling") + .description("Will hold a totem if fall damage could kill you.") + .defaultValue(false) + .build() + ); + + private final Setting explosion = sgTotem.add(new BoolSetting.Builder() + .name("explosion") + .description("Will hold a totem when explosion damage could kill you.") + .defaultValue(true) + .build() + ); + + private boolean isClicking; private boolean sentMessage; + private Item currentItem; + public boolean locked; + + private int totems, ticks; public Offhand() { super(Categories.Combat, "offhand", "Allows you to hold specified items in your offhand."); @@ -80,65 +137,111 @@ public Offhand() { @Override public void onActivate() { + ticks = 0; sentMessage = false; isClicking = false; - currentItem = item.get(); + currentItem = preferreditem.get(); } - @EventHandler - private void onTick(TickEvent.Pre event) { - AutoTotem autoTotem = Modules.get().get(AutoTotem.class); + @EventHandler(priority = HIGHEST + 999) + private void onTick(TickEvent.Pre event) throws InterruptedException { + FindItemResult result = InvUtils.find(Items.TOTEM_OF_UNDYING); + totems = result.count(); - // Sword Gap - if ((mc.player.getMainHandStack().getItem() instanceof SwordItem - || mc.player.getMainHandStack().getItem() instanceof AxeItem) && swordGap.get()) currentItem = Item.EGap; + if (totems <= 0) locked = false; + else if (ticks > delayTicks.get()) { + boolean low = mc.player.getHealth() + mc.player.getAbsorptionAmount() - PlayerUtils.possibleHealthReductions(explosion.get(), falling.get()) <= minHealth.get(); + boolean ely = elytra.get() && mc.player.getEquippedStack(EquipmentSlot.CHEST).getItem() == Items.ELYTRA && mc.player.isFallFlying(); + FindItemResult item = InvUtils.find(itemStack -> itemStack.getItem() == currentItem.item, 0, 35); - // Ca and mining - else if ((Modules.get().isActive(CrystalAura.class) && crystalCa.get()) - || mc.interactionManager.isBreakingBlock() && crystalMine.get()) currentItem = Item.Crystal; + // Calculates Damage from Falling, Explosions + Elyta + locked = (low || ely); - else currentItem = item.get(); + if (locked && mc.player.getOffHandStack().getItem() != Items.TOTEM_OF_UNDYING) { + InvUtils.move().from(result.slot()).toOffhand(); + } - // Checking offhand item - if (mc.player.getOffHandStack().getItem() != currentItem.item) { - FindItemResult item = InvUtils.find(itemStack -> itemStack.getItem() == currentItem.item, hotbar.get() ? 0 : 9, 35); + ticks = 0; + return; + } + ticks++; + + AutoTotem autoTotem = Modules.get().get(AutoTotem.class); + + // Returns to the original Item + currentItem = preferreditem.get(); - // No offhand item - if (!item.found()) { - if (!sentMessage) { - warning("Chosen item not found."); - sentMessage = true; + // Sword Gap & Right Gap + if (rightgapple.get()) { + if (!locked) { + if (SwordGap.get() && mc.player.getMainHandStack().getItem() instanceof SwordItem) { + if (isClicking) { + currentItem = Item.EGap; + } + } + if (!SwordGap.get()) { + if (isClicking) { + currentItem = Item.EGap; + } } } + } - // Swap to offhand - else if ((isClicking || !rightClick.get()) && !autoTotem.isLocked() && !item.isOffhand()) { - InvUtils.move().from(item.slot()).toOffhand(); - sentMessage = false; + // Always Gap + else if ((mc.player.getMainHandStack().getItem() instanceof SwordItem || mc.player.getMainHandStack().getItem() instanceof AxeItem) && alwaysSwordGap.get()) currentItem = Item.EGap; + + // Potion Click + else if (potionClick.get()) { + if (!locked) { + if (mc.player.getMainHandStack().getItem() instanceof SwordItem) { + if (isClicking) { + currentItem = Item.Potion; + } + } } } - // If not clicking, set to totem if auto totem is on - else if (!isClicking && rightClick.get()) { - if (autoTotem.isActive()) { - FindItemResult totem = InvUtils.find(itemStack -> itemStack.getItem() == Items.TOTEM_OF_UNDYING, hotbar.get() ? 0 : 9, 35); + // Always Pot + else if ((mc.player.getMainHandStack().getItem() instanceof SwordItem || mc.player.getMainHandStack().getItem() instanceof AxeItem) && alwaysPot.get()) currentItem = Item.Potion; - if (totem.found() && !totem.isOffhand()) { - InvUtils.move().from(totem.slot()).toOffhand(); + + else currentItem = preferreditem.get(); + + // Checking offhand item + if (mc.player.getOffHandStack().getItem() != currentItem.item) { + if (ticks >= delayTicks.get()) { + if (!locked) { + FindItemResult item = InvUtils.find(itemStack -> itemStack.getItem() == currentItem.item, hotbar.get() ? 0 : 9, 35); + + // No offhand item + if (!item.found()) { + if (!sentMessage) { + warning("Chosen item not found."); + sentMessage = true; + } + } + + // Swap to offhand + else if ((isClicking || !autoTotem.isLocked() && !item.isOffhand())) { + InvUtils.move().from(item.slot()).toOffhand(); + sentMessage = false; + } + ticks = 0; + return; } - } else { - FindItemResult empty = InvUtils.find(ItemStack::isEmpty, hotbar.get() ? 0 : 9, 35); - if (empty.found()) InvUtils.move().fromOffhand().to(empty.slot()); + ticks++; } } } @EventHandler private void onMouseButton(MouseButtonEvent event) { + // Detects if the User is right-clicking isClicking = mc.currentScreen == null && !Modules.get().get(AutoTotem.class).isLocked() && !usableItem() && !mc.player.isUsingItem() && event.action == KeyAction.Press && event.button == GLFW_MOUSE_BUTTON_RIGHT; } private boolean usableItem() { + // What counts as a Usable Item return mc.player.getMainHandStack().getItem() == Items.BOW || mc.player.getMainHandStack().getItem() == Items.TRIDENT || mc.player.getMainHandStack().getItem() == Items.CROSSBOW @@ -147,20 +250,21 @@ private boolean usableItem() { @Override public String getInfoString() { - return item.get().name(); + return preferreditem.get().name(); } public enum Item { + // Items the module could put on your offhand EGap(Items.ENCHANTED_GOLDEN_APPLE), Gap(Items.GOLDEN_APPLE), Crystal(Items.END_CRYSTAL), Totem(Items.TOTEM_OF_UNDYING), - Shield(Items.SHIELD); - + Shield(Items.SHIELD), + Potion(Items.POTION); net.minecraft.item.Item item; - Item(net.minecraft.item.Item item) { this.item = item; } } + }