diff --git a/src/main/java/com/zenith/command/CommandManager.java b/src/main/java/com/zenith/command/CommandManager.java index a1956df60..a83d1e275 100644 --- a/src/main/java/com/zenith/command/CommandManager.java +++ b/src/main/java/com/zenith/command/CommandManager.java @@ -39,6 +39,7 @@ public class CommandManager { new AutoDisconnectCommand(), new AutoDropCommand(), new AutoEatCommand(), + new AutoGapCommand(), new AutoFishCommand(), new AutoMendCommand(), new AutoOmenCommand(), diff --git a/src/main/java/com/zenith/command/impl/AutoGapCommand.java b/src/main/java/com/zenith/command/impl/AutoGapCommand.java new file mode 100644 index 000000000..6a713cd80 --- /dev/null +++ b/src/main/java/com/zenith/command/impl/AutoGapCommand.java @@ -0,0 +1,65 @@ +package com.zenith.command.impl; + +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.zenith.command.api.Command; +import com.zenith.command.api.CommandCategory; +import com.zenith.command.api.CommandContext; +import com.zenith.command.api.CommandUsage; +import com.zenith.module.impl.AutoGap; + +import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; +import static com.zenith.Globals.CONFIG; +import static com.zenith.Globals.MODULE; +import static com.zenith.command.brigadier.ToggleArgumentType.getToggle; +import static com.zenith.command.brigadier.ToggleArgumentType.toggle; + +public class AutoGapCommand extends Command { + @Override + public CommandUsage commandUsage() { + return CommandUsage.builder() + .name("autoGap") + .category(CommandCategory.MODULE) + .description("Automatically eats golden apples when health is below a set threshold.") + .usageLines( + "on/off", + "health ", + "onFire on/off" + ) + .build(); + } + + @Override + public LiteralArgumentBuilder register() { + return command("autoGap") + .then(argument("toggle", toggle()).executes(c -> { + CONFIG.client.extra.autoGap.enabled = getToggle(c, "toggle"); + MODULE.get(AutoGap.class).syncEnabledFromConfig(); + c.getSource().getEmbed() + .title("AutoGap " + toggleStrCaps(CONFIG.client.extra.autoGap.enabled)); + return OK; + })) + .then(literal("health").then(argument("health", integer(-1)).executes(c -> { + CONFIG.client.extra.autoGap.healthThreshold = IntegerArgumentType.getInteger(c, "health"); + c.getSource().getEmbed() + .title("AutoGap Health Threshold Set"); + return OK; + }))) + .then(literal("onFire").then(argument("toggle", toggle()).executes(c -> { + CONFIG.client.extra.autoGap.onFire = getToggle(c, "toggle"); + c.getSource().getEmbed() + .title("AutoGap On Fire " + toggleStrCaps(CONFIG.client.extra.autoGap.onFire)); + return OK; + }))); + } + + @Override + public void defaultHandler(final CommandContext context) { + if (context.getData().containsKey("noDefaultEmbed")) return; + context.getEmbed() + .addField("AutoGap", toggleStr(CONFIG.client.extra.autoGap.enabled)) + .addField("Health Threshold", CONFIG.client.extra.autoGap.healthThreshold) + .addField("On Fire", toggleStr(CONFIG.client.extra.autoGap.onFire)) + .primaryColor(); + } +} diff --git a/src/main/java/com/zenith/command/impl/ModulePriorityCommand.java b/src/main/java/com/zenith/command/impl/ModulePriorityCommand.java index b61f2821d..dec7208b6 100644 --- a/src/main/java/com/zenith/command/impl/ModulePriorityCommand.java +++ b/src/main/java/com/zenith/command/impl/ModulePriorityCommand.java @@ -39,6 +39,7 @@ public CommandUsage commandUsage() { "autoTotem ", "autoArmor ", "autoEat ", + "autoGap ", "autoOmen ", "click ", "killAura ", @@ -90,6 +91,17 @@ public LiteralArgumentBuilder register() { c.getSource().getEmbed() .title("AutoEat Priority Reset"); }))) + .then(literal("autoGap") + .then(argument("priority", integer()).executes(c -> { + CONFIG.client.extra.autoGap.priority = getInteger(c, "priority"); + c.getSource().getEmbed() + .title("AutoGap Priority Set"); + })) + .then(literal("default").executes(c -> { + CONFIG.client.extra.autoGap.priority = null; + c.getSource().getEmbed() + .title("AutoGap Priority Reset"); + }))) .then(literal("autoOmen") .then(argument("priority", integer()).executes(c -> { CONFIG.client.extra.autoOmen.priority = getInteger(c, "priority"); @@ -219,6 +231,7 @@ String priorityList() { new ModuleInstance("AutoTotem", () -> MODULE.get(AutoTotem.class).getPriority(), () -> CONFIG.client.extra.autoTotem.priority), new ModuleInstance("AutoArmor", () -> MODULE.get(AutoArmor.class).getPriority(), () -> CONFIG.client.extra.autoArmor.priority), new ModuleInstance("AutoEat", () -> MODULE.get(AutoEat.class).getPriority(), () -> CONFIG.client.extra.autoEat.priority), + new ModuleInstance("AutoGap", () -> MODULE.get(AutoGap.class).getPriority(), () -> CONFIG.client.extra.autoGap.priority), new ModuleInstance("AutoOmen", () -> MODULE.get(AutoOmen.class).getPriority(), () -> CONFIG.client.extra.autoOmen.priority), new ModuleInstance("Click", () -> MODULE.get(Click.class).getPriority(), () -> CONFIG.client.extra.click.priority), new ModuleInstance("KillAura", () -> MODULE.get(KillAura.class).getPriority(), () -> CONFIG.client.extra.killAura.actionPriority), diff --git a/src/main/java/com/zenith/module/ModuleManager.java b/src/main/java/com/zenith/module/ModuleManager.java index 270e0844a..9c2262dd5 100644 --- a/src/main/java/com/zenith/module/ModuleManager.java +++ b/src/main/java/com/zenith/module/ModuleManager.java @@ -24,6 +24,7 @@ public void init() { new AutoDisconnect(), new AutoDrop(), new AutoEat(), + new AutoGap(), new AutoFish(), new AutoMend(), new AutoOmen(), diff --git a/src/main/java/com/zenith/module/impl/AutoGap.java b/src/main/java/com/zenith/module/impl/AutoGap.java new file mode 100644 index 000000000..be25da8b2 --- /dev/null +++ b/src/main/java/com/zenith/module/impl/AutoGap.java @@ -0,0 +1,193 @@ +package com.zenith.module.impl; + +import com.github.rfresh2.EventConsumer; +import com.zenith.event.client.ClientBotTick; +import com.zenith.feature.inventory.InventoryActionRequest; +import com.zenith.feature.player.ClickTarget; +import com.zenith.feature.player.Input; +import com.zenith.feature.player.InputRequest; +import com.zenith.mc.food.FoodRegistry; +import com.zenith.util.RequestFuture; +import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataTypes; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; + +import java.util.List; +import java.util.Objects; + +import static com.github.rfresh2.EventConsumer.of; +import static com.zenith.Globals.CACHE; +import static com.zenith.Globals.CONFIG; +import static com.zenith.Globals.INPUTS; +import static com.zenith.Globals.INVENTORY; + +public class AutoGap extends AbstractInventoryModule { + private int delay = 0; + private boolean isEating = false; + private RequestFuture swapFuture = RequestFuture.rejected; + + public AutoGap() { + super(HandRestriction.EITHER, 0); + } + + @Override + public List> registerEvents() { + return List.of( + of(ClientBotTick.class, this::handleClientTick), + of(ClientBotTick.Starting.class, this::handleBotTickStarting), + of(ClientBotTick.Stopped.class, this::handleBotTickStopped) + ); + } + + @Override + public int getPriority() { + return Objects.requireNonNullElse(CONFIG.client.extra.autoGap.priority, 11500); + } + + @Override + public boolean enabledSetting() { + return CONFIG.client.extra.autoGap.enabled; + } + + public boolean isEating() { + return enabledSetting() && isEating; + } + + void handleClientTick(final ClientBotTick e) { + if (CACHE.getPlayerCache().getThePlayer().isAlive() + && CACHE.getPlayerCache().getGameMode() != GameMode.CREATIVE + && CACHE.getPlayerCache().getGameMode() != GameMode.SPECTATOR + ) { + if (delay > 0) { + delay--; + if (isEating) { + INPUTS.submit(InputRequest.noInput(this, getPriority())); + INVENTORY.submit(InventoryActionRequest.noAction(this, getPriority())); + } + return; + } + isEating = false; + if (!swapFuture.isDone()) { + INPUTS.submit(InputRequest.noInput(this, getPriority())); + return; + } + if (!shouldEatGap()) { + return; + } + var invActionResult = doInventoryActionsV2(); + switch (invActionResult.state()) { + case ITEM_IN_HAND -> { + delay = invActionResult.expectedDelay(); + startEating(); + INVENTORY.submit(InventoryActionRequest.noAction(this, getPriority())); + } + case SWAPPING -> swapFuture = invActionResult.inventoryActionFuture(); + case NO_ITEM -> { + } + default -> throw new IllegalStateException("Unexpected action state: " + invActionResult.state()); + } + } else { + isEating = false; + delay = 0; + } + } + + void startEating() { + if (!isItemEquipped()) return; + var hand = getHand(); + INPUTS.submit(InputRequest.builder() + .owner(this) + .input(Input.builder() + .rightClick(true) + .hand(hand) + .clickTarget(ClickTarget.None.INSTANCE) + .clickRequiresRotation(false) + .build()) + .priority(getPriority()) + .build()) + .addInputExecutedListener(future -> { + isEating = true; + delay = 50; + }); + } + + public void onEnable() { + reset(); + } + + public void onDisable() { + reset(); + } + + void handleBotTickStarting(final ClientBotTick.Starting event) { + reset(); + } + + void handleBotTickStopped(final ClientBotTick.Stopped event) { + reset(); + } + + void reset() { + delay = 0; + isEating = false; + swapFuture = RequestFuture.rejected; + } + + boolean shouldEatGap() { + return isLowHealth() || shouldEatFromOnFire(); + } + + boolean isLowHealth() { + return CACHE.getPlayerCache().getThePlayer().getHealth() <= CONFIG.client.extra.autoGap.healthThreshold; + } + + boolean hasFireResistance() { + return CACHE.getPlayerCache().getThePlayer().getPotionEffectMap().containsKey(Effect.FIRE_RESISTANCE); + } + + boolean shouldEatFromOnFire() { + return CONFIG.client.extra.autoGap.onFire && isPlayerOnFire() && !hasFireResistance(); + } + + boolean isPlayerOnFire() { + Byte flagsByte = CACHE.getPlayerCache().getThePlayer().getMetadataValue(0, MetadataTypes.BYTE, Byte.class); + return isOnFireFlags(flagsByte); + } + + static boolean isOnFireFlags(final Byte flagsByte) { + return flagsByte != null && (flagsByte & 0x01) != 0; + } + + @Override + public boolean itemPredicate(final ItemStack itemStack) { + final boolean requireEnchantedGap = shouldEatFromOnFire() && !isLowHealth(); + return shouldUseItem(itemStack, requireEnchantedGap, hasEnchantedGapInInventory()); + } + + boolean shouldUseItem(final ItemStack itemStack, final boolean requireEnchantedGap, final boolean hasEnchantedGapInInventory) { + if (requireEnchantedGap) { + return isEnchantedGap(itemStack); + } + if (isEnchantedGap(itemStack)) return true; + return isRegularGap(itemStack) && !hasEnchantedGapInInventory; + } + + boolean hasEnchantedGapInInventory() { + var inventory = CACHE.getPlayerCache().getPlayerInventory(); + for (int i = 9; i <= 44; i++) { + if (isEnchantedGap(inventory.get(i))) { + return true; + } + } + return false; + } + + boolean isRegularGap(ItemStack itemStack) { + return itemStack != null && itemStack.getId() == FoodRegistry.GOLDEN_APPLE.id(); + } + + boolean isEnchantedGap(ItemStack itemStack) { + return itemStack != null && itemStack.getId() == FoodRegistry.ENCHANTED_GOLDEN_APPLE.id(); + } +} diff --git a/src/main/java/com/zenith/util/config/Config.java b/src/main/java/com/zenith/util/config/Config.java index a36f8104c..b03fd893e 100644 --- a/src/main/java/com/zenith/util/config/Config.java +++ b/src/main/java/com/zenith/util/config/Config.java @@ -163,6 +163,7 @@ public static final class Extra { public final PearlLoader pearlLoader = new PearlLoader(); public final Waypoints waypoints = new Waypoints(); public final AutoDrop autoDrop = new AutoDrop(); + public final AutoGap autoGap = new AutoGap(); public String whisperCommand = "msg"; public int tpsBufferSize = 20; public final Tasks tasks = new Tasks(); @@ -443,6 +444,13 @@ public enum Mode { public HashSet foods = new HashSet<>(); } + public static final class AutoGap { + public @Nullable Integer priority = null; + public boolean enabled = false; + public int healthThreshold = 10; + public boolean onFire = false; + } + public static final class AutoOmen { public @Nullable Integer priority = null; public boolean enabled = false;