From 3170de2fe9c96e48c2231d4fb639305f5c6b96a0 Mon Sep 17 00:00:00 2001 From: Tristan Date: Sun, 13 Jul 2025 09:09:01 -0400 Subject: [PATCH] add "reach", add aimassist, add autoclicker --- src/client/java/works/alya/AlyaClient.java | 6 +- .../module/impl/combat/AimAssistModule.java | 499 ++++++++++++++++++ .../module/impl/combat/AutoClickerModule.java | 314 +++++++++++ .../alya/module/impl/combat/ReachModule.java | 160 ++++-- 4 files changed, 947 insertions(+), 32 deletions(-) create mode 100644 src/client/java/works/alya/module/impl/combat/AimAssistModule.java create mode 100644 src/client/java/works/alya/module/impl/combat/AutoClickerModule.java diff --git a/src/client/java/works/alya/AlyaClient.java b/src/client/java/works/alya/AlyaClient.java index e664dba..3255155 100644 --- a/src/client/java/works/alya/AlyaClient.java +++ b/src/client/java/works/alya/AlyaClient.java @@ -24,7 +24,9 @@ import works.alya.event.EventBus; import works.alya.module.ModuleBuilder; import works.alya.module.ModuleRepository; +import works.alya.module.impl.combat.AimAssistModule; import works.alya.module.impl.combat.AttackDelayModule; +import works.alya.module.impl.combat.AutoClickerModule; import works.alya.module.impl.combat.killaura.KillauraModule; import works.alya.module.impl.movement.*; import works.alya.module.impl.utility.antivoid.AntiVoidModule; @@ -170,7 +172,9 @@ private static void initializeModules() { new AntiGravityModule(), new AntiVoidModule(), new TargetStrafeModule(), - new SpeedMonitorModule() + new SpeedMonitorModule(), + new AutoClickerModule(), + new AimAssistModule() ); } diff --git a/src/client/java/works/alya/module/impl/combat/AimAssistModule.java b/src/client/java/works/alya/module/impl/combat/AimAssistModule.java new file mode 100644 index 0000000..548233b --- /dev/null +++ b/src/client/java/works/alya/module/impl/combat/AimAssistModule.java @@ -0,0 +1,499 @@ +/* + * Copyright (c) Alya Client 2024-2025. + * + * This file belongs to Alya Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/AlyaClient/alya-beta.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Alya (and subsequently, its files) are all licensed under the MIT License. + * Alya should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package works.alya.module.impl.combat; + +import works.alya.config.setting.impl.BooleanSetting; +import works.alya.config.setting.impl.ModeSetting; +import works.alya.config.setting.impl.NumberSetting; +import works.alya.event.IEventListener; +import works.alya.event.impl.MotionEvent; +import works.alya.event.impl.TickEvent; +import works.alya.module.Module; +import works.alya.module.ModuleCategory; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.passive.PassiveEntity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.RaycastContext; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +@SuppressWarnings("FieldCanBeLocal") +public class AimAssistModule extends Module { + private final ModeSetting targetMode = new ModeSetting("Target", "Target types", "Players", "Players", "Passive", "Hostile", "All"); + private final ModeSetting sortMode = new ModeSetting("Sort", "Target sorting", "Distance", "Distance", "Health", "Angle", "Crosshair"); + private final NumberSetting range = new NumberSetting<>("Range", "Maximum target distance", 6.0, 1.0, 10.0); + private final NumberSetting fov = new NumberSetting<>("FOV", "Field of view", 90.0, 15.0, 360.0); + private final BooleanSetting targetPlayers = new BooleanSetting("TargetPlayers", "Target players", true); + private final BooleanSetting targetHostile = new BooleanSetting("TargetHostile", "Target hostile mobs", false); + private final BooleanSetting targetPassive = new BooleanSetting("TargetPassive", "Target passive mobs", false); + private final BooleanSetting targetInvisible = new BooleanSetting("TargetInvisible", "Target invisible entities", false); + private final BooleanSetting targetTeam = new BooleanSetting("TargetTeam", "Target team members", false); + private final BooleanSetting prioritizeAttacking = new BooleanSetting("PrioritizeAttacking", "Prioritize entities attacking you", true); + private final BooleanSetting aimOnClick = new BooleanSetting("AimOnClick", "Only aim when clicking", true); + private final BooleanSetting aimOnTarget = new BooleanSetting("AimOnTarget", "Only aim when looking near target", true); + private final BooleanSetting smoothAim = new BooleanSetting("SmoothAim", "Smooth aiming", true); + private final NumberSetting horizontalSpeed = new NumberSetting<>("HSpeed", "Horizontal aim speed", 2.0, 0.1, 10.0); + private final NumberSetting verticalSpeed = new NumberSetting<>("VSpeed", "Vertical aim speed", 2.0, 0.1, 10.0); + private final NumberSetting minAimSpeed = new NumberSetting<>("MinSpeed", "Minimum aim speed", 0.5, 0.1, 5.0); + private final NumberSetting maxAimSpeed = new NumberSetting<>("MaxSpeed", "Maximum aim speed", 3.0, 0.5, 10.0); + private final BooleanSetting randomizeSpeed = new BooleanSetting("RandomSpeed", "Randomize aim speed", true); + private final BooleanSetting aimPrediction = new BooleanSetting("Prediction", "Predict target movement", true); + private final NumberSetting predictionStrength = new NumberSetting<>("PredictStrength", "Prediction strength", 1.0, 0.1, 3.0); + private final BooleanSetting rayTrace = new BooleanSetting("RayTrace", "Check line of sight", true); + private final BooleanSetting lockView = new BooleanSetting("LockView", "Lock view on target", false); + private final NumberSetting lockViewStrength = new NumberSetting<>("LockStrength", "Lock view strength", 0.6, 0.1, 1.0); + private final BooleanSetting aimbot = new BooleanSetting("Aimbot", "Full aimbot mode", false); + private final BooleanSetting silentAim = new BooleanSetting("SilentAim", "Silent aim (server-side only)", false); + private final BooleanSetting mouseFilter = new BooleanSetting("MouseFilter", "Filter mouse movements", true); + private final BooleanSetting respectGCD = new BooleanSetting("RespectGCD", "Respect game's aim mechanics", true); + private final BooleanSetting centerAim = new BooleanSetting("CenterAim", "Aim at center of hitbox", false); + private final NumberSetting hitboxOffset = new NumberSetting<>("HitboxOffset", "Vertical hitbox offset", 0.0, -1.0, 1.0); + private final BooleanSetting dynamicFOV = new BooleanSetting("DynamicFOV", "Adjust FOV based on distance", false); + private Entity currentTarget; + private float targetYaw; + private float targetPitch; + private float lastYaw; + private float lastPitch; + private long lastAimTime; + private Vec3d lastTargetPos; + private boolean isAiming; + private final List potentialTargets = new ArrayList<>(); + + public AimAssistModule() { + super("AimAssist", "Assists with aiming at targets", ModuleCategory.COMBAT); + + addSetting(targetMode); + addSetting(sortMode); + addSetting(range); + addSetting(fov); + addSetting(targetPlayers); + addSetting(targetHostile); + addSetting(targetPassive); + addSetting(targetInvisible); + addSetting(targetTeam); + addSetting(prioritizeAttacking); + addSetting(aimOnClick); + addSetting(aimOnTarget); + addSetting(smoothAim); + addSetting(horizontalSpeed); + addSetting(verticalSpeed); + addSetting(randomizeSpeed); + addSetting(minAimSpeed); + addSetting(maxAimSpeed); + addSetting(aimPrediction); + addSetting(predictionStrength); + addSetting(rayTrace); + addSetting(lockView); + addSetting(lockViewStrength); + addSetting(aimbot); + addSetting(silentAim); + addSetting(mouseFilter); + addSetting(respectGCD); + addSetting(centerAim); + addSetting(hitboxOffset); + addSetting(dynamicFOV); + + minAimSpeed.setVisibilityCondition(randomizeSpeed::getValue); + maxAimSpeed.setVisibilityCondition(randomizeSpeed::getValue); + predictionStrength.setVisibilityCondition(aimPrediction::getValue); + lockViewStrength.setVisibilityCondition(lockView::getValue); + silentAim.setVisibilityCondition(aimbot::getValue); + } + + @SuppressWarnings("unused") + private final IEventListener tickEvent = event -> { + if(!isEnabled() || mc.player == null || mc.world == null) return; + + if(randomizeSpeed.getValue() && System.currentTimeMillis() - lastAimTime > 1000) { + updateAimSpeeds(); + } + + findTargets(); + + if(currentTarget != null) { + setPrefix(sortMode.getValue() + " " + String.format("%.1f", mc.player.distanceTo(currentTarget))); + } else { + setPrefix(sortMode.getValue()); + } + }; + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { + if(!isEnabled() || mc.player == null || mc.world == null || !event.isPre()) return; + + selectTarget(); + + if(!shouldAim()) { + isAiming = false; + return; + } + + if(currentTarget != null) { + calculateAimAngles(); + if(aimbot.getValue()) { + if(silentAim.getValue()) { + event.setYaw(targetYaw); + event.setPitch(targetPitch); + } else { + mc.player.setYaw(targetYaw); + mc.player.setPitch(targetPitch); + } + } else { + applyAimAssist(); + } + + isAiming = true; + lastAimTime = System.currentTimeMillis(); + } else { + isAiming = false; + } + }; + + private void findTargets() { + potentialTargets.clear(); + + if(mc.player == null || mc.world == null) return; + + double maxDistance = range.getValue(); + + List entities = mc.world.getEntitiesByClass(Entity.class, + mc.player.getBoundingBox().expand(maxDistance), this::isValidTarget); + + double fovValue = fov.getValue(); + if(dynamicFOV.getValue()) { + fovValue = Math.min(fovValue * 2, 360.0); + } + + for(Entity entity : entities) { + if(entity.squaredDistanceTo(mc.player) > maxDistance * maxDistance) continue; + + if(fovValue < 360.0 && !isInFOV(entity, fovValue)) continue; + + if(rayTrace.getValue() && !canSeeEntity(entity)) continue; + + potentialTargets.add(entity); + } + + sortTargets(); + } + + private void sortTargets() { + if(potentialTargets.isEmpty() || mc.player == null) return; + + switch(sortMode.getValue()) { + case "Distance" -> potentialTargets.sort(Comparator.comparingDouble(entity -> + entity.squaredDistanceTo(mc.player))); + case "Health" -> potentialTargets.sort(Comparator.comparingDouble(entity -> { + if(entity instanceof LivingEntity living) { + return living.getHealth(); + } + return Double.MAX_VALUE; + })); + case "Angle" -> potentialTargets.sort(Comparator.comparingDouble(this::getAngleToEntity)); + case "Crosshair" -> potentialTargets.sort(Comparator.comparingDouble(entity -> { + float[] rotations = calculateRotationsToEntity(entity); + float yawDiff = Math.abs(MathHelper.wrapDegrees(rotations[0] - mc.player.getYaw())); + float pitchDiff = Math.abs(rotations[1] - mc.player.getPitch()); + return yawDiff + pitchDiff; + })); + } + + if(prioritizeAttacking.getValue()) { + potentialTargets.sort((e1, e2) -> { + boolean e1Attacking = isEntityAttackingPlayer(e1); + boolean e2Attacking = isEntityAttackingPlayer(e2); + + if(e1Attacking && !e2Attacking) return -1; + if(!e1Attacking && e2Attacking) return 1; + return 0; + }); + } + } + + private void selectTarget() { + if(potentialTargets.isEmpty()) { + currentTarget = null; + return; + } + + currentTarget = potentialTargets.getFirst(); + + if(currentTarget != null) { + if(lastTargetPos == null) { + lastTargetPos = currentTarget.getPos(); + } + } else { + lastTargetPos = null; + } + } + + private boolean shouldAim() { + if(currentTarget == null || mc.player == null) return false; + + if(aimOnClick.getValue() && !mc.options.attackKey.isPressed()) return false; + + if(aimOnTarget.getValue()) { + float[] rotations = calculateRotationsToEntity(currentTarget); + float yawDiff = Math.abs(MathHelper.wrapDegrees(rotations[0] - mc.player.getYaw())); + float pitchDiff = Math.abs(rotations[1] - mc.player.getPitch()); + + double aimThreshold = Math.min(60.0, fov.getValue() / 2); + return !(yawDiff > aimThreshold) && !(pitchDiff > aimThreshold / 2); + } + + return true; + } + + private void calculateAimAngles() { + if(currentTarget == null || mc.player == null) return; + + Vec3d targetPos = getTargetPosition(currentTarget); + + if(aimPrediction.getValue() && lastTargetPos != null) { + Vec3d velocity = currentTarget.getPos().subtract(lastTargetPos); + double predictionMultiplier = predictionStrength.getValue(); + + double distance = mc.player.distanceTo(currentTarget); + predictionMultiplier *= Math.min(distance / 5.0, 2.0); + + targetPos = targetPos.add(velocity.multiply(predictionMultiplier)); + } + + lastTargetPos = currentTarget.getPos(); + + Vec3d playerPos = mc.player.getEyePos(); + double deltaX = targetPos.x - playerPos.x; + double deltaY = targetPos.y - playerPos.y; + double deltaZ = targetPos.z - playerPos.z; + + double horizontalDistance = Math.sqrt(deltaX * deltaX + deltaZ * deltaZ); + + targetYaw = (float) Math.toDegrees(Math.atan2(deltaZ, deltaX)) - 90.0F; + targetPitch = (float) -Math.toDegrees(Math.atan2(deltaY, horizontalDistance)); + + targetPitch = MathHelper.clamp(targetPitch, -90.0F, 90.0F); + + if(respectGCD.getValue()) { + float[] corrected = applyGCDCorrection(targetYaw, targetPitch); + targetYaw = corrected[0]; + targetPitch = corrected[1]; + } + } + + private void applyAimAssist() { + if(mc.player == null) return; + + if(lastYaw == 0 && lastPitch == 0) { + lastYaw = mc.player.getYaw(); + lastPitch = mc.player.getPitch(); + } + + float yawDifference = MathHelper.wrapDegrees(targetYaw - mc.player.getYaw()); + float pitchDifference = targetPitch - mc.player.getPitch(); + + float smoothFactor = smoothAim.getValue() ? + horizontalSpeed.getValue().floatValue() : 1.0f; + float verticalSmoothFactor = smoothAim.getValue() ? + verticalSpeed.getValue().floatValue() : 1.0f; + + float yawStep = yawDifference / smoothFactor; + float pitchStep = pitchDifference / verticalSmoothFactor; + + if(lockView.getValue() && isAiming) { + double lockStrength = lockViewStrength.getValue(); + yawStep *= (float) lockStrength; + pitchStep *= (float) lockStrength; + } + + if(mouseFilter.getValue()) { + double aimProgress = 1.0 - (Math.abs(yawDifference) / (fov.getValue() / 2)); + aimProgress = MathHelper.clamp(aimProgress, 0.0, 1.0); + + double filterStrength = 0.3 + (0.7 * aimProgress); + yawStep *= (float) filterStrength; + pitchStep *= (float) filterStrength; + } + + float newYaw = mc.player.getYaw() + yawStep; + float newPitch = MathHelper.clamp(mc.player.getPitch() + pitchStep, -90.0F, 90.0F); + + mc.player.setYaw(newYaw); + mc.player.setPitch(newPitch); + + lastYaw = newYaw; + lastPitch = newPitch; + } + + private float[] calculateRotationsToEntity(Entity entity) { + if(mc.player == null) return new float[]{0, 0}; + + Vec3d playerPos = mc.player.getEyePos(); + Vec3d targetPos = getTargetPosition(entity); + + double deltaX = targetPos.x - playerPos.x; + double deltaY = targetPos.y - playerPos.y; + double deltaZ = targetPos.z - playerPos.z; + + double horizontalDistance = Math.sqrt(deltaX * deltaX + deltaZ * deltaZ); + + float yaw = (float) Math.toDegrees(Math.atan2(deltaZ, deltaX)) - 90.0F; + float pitch = (float) -Math.toDegrees(Math.atan2(deltaY, horizontalDistance)); + + return new float[]{yaw, MathHelper.clamp(pitch, -90.0F, 90.0F)}; + } + + private Vec3d getTargetPosition(Entity entity) { + Box box = entity.getBoundingBox(); + double x = box.minX + (box.maxX - box.minX) * 0.5; + double z = box.minZ + (box.maxZ - box.minZ) * 0.5; + + double y; + if(centerAim.getValue()) { + y = box.minY + (box.maxY - box.minY) * 0.5; + } else { + y = box.minY + (box.maxY - box.minY) * 0.85; + } + + y += hitboxOffset.getValue(); + + return new Vec3d(x, y, z); + } + + private boolean isValidTarget(Entity entity) { + if(entity == mc.player) return false; + if(!(entity instanceof LivingEntity living)) return false; + if(!living.isAlive()) return false; + if(entity instanceof ArmorStandEntity) return false; + + if(entity.isInvisible() && !targetInvisible.getValue()) return false; + + return switch(entity) { + case PlayerEntity ignored -> + targetPlayers.getValue() || targetMode.getValue().equals("Players") || targetMode.getValue().equals("All"); + case HostileEntity ignored -> + targetHostile.getValue() || targetMode.getValue().equals("Hostile") || targetMode.getValue().equals("All"); + case PassiveEntity ignored -> + targetPassive.getValue() || targetMode.getValue().equals("Passive") || targetMode.getValue().equals("All"); + default -> false; + }; + + } + + private boolean isInFOV(Entity entity, double fovValue) { + if(mc.player == null) return false; + + float[] rotations = calculateRotationsToEntity(entity); + float yawDiff = Math.abs(MathHelper.wrapDegrees(rotations[0] - mc.player.getYaw())); + float pitchDiff = Math.abs(rotations[1] - mc.player.getPitch()); + + return yawDiff <= fovValue && pitchDiff <= fovValue / 2; + } + + private double getAngleToEntity(Entity entity) { + if(mc.player == null) return Double.MAX_VALUE; + + float[] rotations = calculateRotationsToEntity(entity); + float yawDiff = Math.abs(MathHelper.wrapDegrees(rotations[0] - mc.player.getYaw())); + float pitchDiff = Math.abs(rotations[1] - mc.player.getPitch()); + + return Math.sqrt(yawDiff * yawDiff + pitchDiff * pitchDiff); + } + + private boolean canSeeEntity(Entity entity) { + if(mc.player == null || mc.world == null) return false; + + if(mc.crosshairTarget instanceof EntityHitResult entityHit && entityHit.getEntity() == entity) { + return true; + } + + Vec3d playerEyes = mc.player.getEyePos(); + Vec3d targetPos = getTargetPosition(entity); + + RaycastContext context = new RaycastContext( + playerEyes, + targetPos, + RaycastContext.ShapeType.COLLIDER, + RaycastContext.FluidHandling.NONE, + mc.player + ); + + BlockHitResult result = mc.world.raycast(context); + return result.getType() == HitResult.Type.MISS; + } + + private boolean isEntityAttackingPlayer(Entity entity) { + if(!(entity instanceof LivingEntity living) || mc.player == null) return false; + + if(living instanceof PlayerEntity) { + Vec3d lookVec = living.getRotationVec(1.0f); + Vec3d toPlayer = mc.player.getPos().subtract(living.getPos()).normalize(); + double dot = lookVec.dotProduct(toPlayer); + + return dot > 0.8; + } + + return living.getAttacking() == mc.player; + } + + private float[] applyGCDCorrection(float yaw, float pitch) { + float gcdValue = getGCD(); + float correctedYaw = Math.round(yaw / gcdValue) * gcdValue; + float correctedPitch = Math.round(pitch / gcdValue) * gcdValue; + correctedPitch = MathHelper.clamp(correctedPitch, -90.0F, 90.0F); + + return new float[]{correctedYaw, correctedPitch}; + } + + private float getGCD() { + float sensitivity = mc.options.getMouseSensitivity().getValue().floatValue(); + return sensitivity * 0.6F + 0.2F; + } + + private void updateAimSpeeds() { + + } + + @Override + protected void onEnable() { + lastYaw = 0; + lastPitch = 0; + lastAimTime = 0; + lastTargetPos = null; + currentTarget = null; + isAiming = false; + + updateAimSpeeds(); + } + + @Override + protected void onDisable() { + currentTarget = null; + lastTargetPos = null; + isAiming = false; + } +} diff --git a/src/client/java/works/alya/module/impl/combat/AutoClickerModule.java b/src/client/java/works/alya/module/impl/combat/AutoClickerModule.java new file mode 100644 index 0000000..9b600ca --- /dev/null +++ b/src/client/java/works/alya/module/impl/combat/AutoClickerModule.java @@ -0,0 +1,314 @@ +/* + * Copyright (c) Alya Client 2024-2025. + * + * This file belongs to Alya Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/AlyaClient/alya-beta.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Alya (and subsequently, its files) are all licensed under the MIT License. + * Alya should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package works.alya.module.impl.combat; + + +import works.alya.AlyaClient; +import works.alya.config.setting.impl.BooleanSetting; +import works.alya.config.setting.impl.ModeSetting; +import works.alya.config.setting.impl.NumberSetting; +import works.alya.event.IEventListener; +import works.alya.event.impl.TickEvent; +import works.alya.module.Module; +import works.alya.module.ModuleCategory; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import org.lwjgl.glfw.GLFW; + +import java.util.Random; + +@SuppressWarnings("FieldCanBeLocal") +public class AutoClickerModule extends Module { + private final ModeSetting clickMode = new ModeSetting("ClickMode", "Type of clicking", "Left", "Left", "Right", "Both"); + private final BooleanSetting randomizeCps = new BooleanSetting("RandomCPS", "Randomize clicks per second", true); + private final NumberSetting cps = new NumberSetting<>("CPS", "Clicks per second", 12, 1, 30); + private final NumberSetting minCps = new NumberSetting<>("MinCPS", "Minimum clicks per second", 8, 1, 30); + private final NumberSetting maxCps = new NumberSetting<>("MaxCPS", "Maximum clicks per second", 14, 1, 30); + private final BooleanSetting breakBlocks = new BooleanSetting("BreakBlocks", "Continue breaking blocks", true); + private final BooleanSetting weaponOnly = new BooleanSetting("WeaponOnly", "Only click when holding a weapon", false); + private final BooleanSetting inventoryFill = new BooleanSetting("InventoryFill", "Click in inventory", false); + private final BooleanSetting onlyWhenFocused = new BooleanSetting("OnlyWhenFocused", "Only click when game is focused", true); + private final BooleanSetting smartMode = new BooleanSetting("SmartMode", "Only attack when looking at entities", false); + private final BooleanSetting respectAttackDelay = new BooleanSetting("RespectDelay", "Respect attack delay module", true); + private final BooleanSetting jitterClick = new BooleanSetting("JitterClick", "Add random jitter to clicks", false); + private final NumberSetting jitterStrength = new NumberSetting<>("JitterStrength", "Strength of jitter effect", 1.0, 0.1, 3.0); + private final BooleanSetting blockHitAssist = new BooleanSetting("BlockHitAssist", "Assist with block hitting", false); + private final NumberSetting blockHitChance = new NumberSetting<>("BlockHitChance", "Chance to block hit", 30, 1, 100); + private final BooleanSetting noBlockBreakDelay = new BooleanSetting("NoBlockBreakDelay", "Remove block breaking delay", false); + private final BooleanSetting mouseDownOnly = new BooleanSetting("MouseDownOnly", "Only click when mouse is held down", false); + + private final Random random = new Random(); + private long lastLeftClick = 0; + private long lastRightClick = 0; + private int currentCps = 12; + private boolean isBlocking = false; + private long lastBlockTime = 0; + private long lastUnblockTime = 0; + private float originalYaw = 0; + private float originalPitch = 0; + private boolean leftMouseDown = false; + private boolean rightMouseDown = false; + + public AutoClickerModule() { + super("AutoClicker", "Automatically clicks for you", ModuleCategory.COMBAT); + + addSetting(clickMode); + addSetting(randomizeCps); + addSetting(cps); + addSetting(minCps); + addSetting(maxCps); + addSetting(breakBlocks); + addSetting(weaponOnly); + addSetting(inventoryFill); + addSetting(onlyWhenFocused); + addSetting(smartMode); + addSetting(respectAttackDelay); + addSetting(jitterClick); + addSetting(jitterStrength); + addSetting(blockHitAssist); + addSetting(blockHitChance); + addSetting(noBlockBreakDelay); + addSetting(mouseDownOnly); + + minCps.setVisibilityCondition(randomizeCps::getValue); + maxCps.setVisibilityCondition(randomizeCps::getValue); + jitterStrength.setVisibilityCondition(jitterClick::getValue); + blockHitChance.setVisibilityCondition(blockHitAssist::getValue); + } + + @SuppressWarnings("unused") + private final IEventListener tickEvent = event -> { + if(!isEnabled() || mc.player == null || mc.world == null) return; + if(onlyWhenFocused.getValue() && !mc.isWindowFocused()) return; + + updateMouseStates(); + + if(randomizeCps.getValue() && System.currentTimeMillis() - Math.max(lastLeftClick, lastRightClick) > 1000) { + currentCps = random.nextInt(maxCps.getValue() - minCps.getValue() + 1) + minCps.getValue(); + } else { + currentCps = cps.getValue(); + } + + if(jitterClick.getValue() && (shouldLeftClick() || shouldRightClick())) { + applyJitter(); + } + + if(shouldLeftClick()) { + performLeftClick(); + } + + if(shouldRightClick()) { + performRightClick(); + } + + if(blockHitAssist.getValue() && isLeftClicking() && random.nextInt(100) < blockHitChance.getValue()) { + handleBlockHit(); + } + + setPrefix(clickMode.getValue() + " " + currentCps); + }; + + private void updateMouseStates() { + if(mc.getWindow() == null) return; + + leftMouseDown = GLFW.glfwGetMouseButton(mc.getWindow().getHandle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS; + rightMouseDown = GLFW.glfwGetMouseButton(mc.getWindow().getHandle(), GLFW.GLFW_MOUSE_BUTTON_RIGHT) == GLFW.GLFW_PRESS; + } + + private boolean shouldLeftClick() { + if(!isLeftClickMode() || mc.interactionManager == null) return false; + + if(mouseDownOnly.getValue() && !leftMouseDown) return false; + + long currentTime = System.currentTimeMillis(); + long clickDelay = calculateClickDelay(); + if(currentTime - lastLeftClick < clickDelay) return false; + + if(weaponOnly.getValue() && !isHoldingWeapon()) return false; + if(smartMode.getValue() && !isLookingAtEntity()) return false; + + if(respectAttackDelay.getValue()) { + AttackDelayModule attackDelayModule = AlyaClient.INSTANCE.getModuleRepository().getModule(AttackDelayModule.class); + if(attackDelayModule != null && attackDelayModule.isEnabled() && !attackDelayModule.canAttack()) { + return false; + } + } + + if(mc.options.attackKey.isPressed() && mc.interactionManager.isBreakingBlock() && !breakBlocks.getValue()) { + return false; + } + + return mc.currentScreen == null || inventoryFill.getValue(); + } + + private boolean shouldRightClick() { + if(!isRightClickMode()) return false; + + if(mouseDownOnly.getValue() && !rightMouseDown) return false; + + long currentTime = System.currentTimeMillis(); + long clickDelay = calculateClickDelay(); + if(currentTime - lastRightClick < clickDelay) return false; + + return mc.currentScreen == null || inventoryFill.getValue(); + } + + private void performLeftClick() { + if(mc.currentScreen == null) { + mc.options.attackKey.setPressed(true); + if(mc.player != null) { + mc.player.swingHand(Hand.MAIN_HAND); + if(mc.interactionManager != null && mc.crosshairTarget != null) { + if(mc.crosshairTarget instanceof EntityHitResult entityHitResult) { + mc.interactionManager.attackEntity(mc.player, entityHitResult.getEntity()); + } + } + } + + mc.options.attackKey.setPressed(false); + } else if(inventoryFill.getValue()) { + int mouseX = (int) (mc.mouse.getX() * mc.getWindow().getScaledWidth() / mc.getWindow().getWidth()); + int mouseY = (int) (mc.mouse.getY() * mc.getWindow().getScaledHeight() / mc.getWindow().getHeight()); + mc.currentScreen.mouseClicked(mouseX, mouseY, 0); + } + + lastLeftClick = System.currentTimeMillis(); + } + + private void performRightClick() { + if(mc.currentScreen == null) { + mc.options.useKey.setPressed(true); + if(mc.player != null && mc.interactionManager != null) { + mc.player.swingHand(Hand.MAIN_HAND); + mc.interactionManager.interactItem(mc.player, Hand.MAIN_HAND); + } + mc.options.useKey.setPressed(false); + } else if(inventoryFill.getValue()) { + int mouseX = (int) (mc.mouse.getX() * mc.getWindow().getScaledWidth() / mc.getWindow().getWidth()); + int mouseY = (int) (mc.mouse.getY() * mc.getWindow().getScaledHeight() / mc.getWindow().getHeight()); + mc.currentScreen.mouseClicked(mouseX, mouseY, 1); + } + + lastRightClick = System.currentTimeMillis(); + } + + private void handleBlockHit() { + if(mc.interactionManager == null) return; + long currentTime = System.currentTimeMillis(); + + if(!isBlocking && currentTime - lastUnblockTime > 200) { + mc.options.useKey.setPressed(true); + mc.interactionManager.interactItem(mc.player, Hand.MAIN_HAND); + isBlocking = true; + lastBlockTime = currentTime; + } else if(isBlocking && currentTime - lastBlockTime > 100) { + mc.options.useKey.setPressed(false); + isBlocking = false; + lastUnblockTime = currentTime; + } + } + + private void applyJitter() { + if(mc.player == null) return; + + if(originalYaw == 0) { + originalYaw = mc.player.getYaw(); + originalPitch = mc.player.getPitch(); + } + + float jitterAmount = (float) (jitterStrength.getValue() * (random.nextFloat() - 0.5f)); + float yawJitter = jitterAmount * 2.0f; + + mc.player.setYaw(mc.player.getYaw() + yawJitter); + mc.player.setPitch(Math.max(-90, Math.min(90, mc.player.getPitch() + jitterAmount))); + } + + private long calculateClickDelay() { + long baseDelay = 1000 / currentCps; + + double randomFactor = 0.8 + (random.nextDouble() * 0.4); + long actualDelay = Math.round(baseDelay * randomFactor); + + return Math.max(actualDelay, 25); + } + + private boolean isLeftClickMode() { + return clickMode.getValue().equals("Left") || clickMode.getValue().equals("Both"); + } + + private boolean isRightClickMode() { + return clickMode.getValue().equals("Right") || clickMode.getValue().equals("Both"); + } + + private boolean isHoldingWeapon() { + if(mc.player == null) return false; + + String itemName = mc.player.getMainHandStack().getItem().getName().getString().toLowerCase(); + return itemName.contains("sword") || itemName.contains("axe"); + } + + private boolean isLookingAtEntity() { + if(mc.crosshairTarget != null && mc.crosshairTarget.getType() == HitResult.Type.ENTITY) { + return ((EntityHitResult) mc.crosshairTarget).getEntity() != null; + } + return false; + } + + private boolean isLeftClicking() { + return System.currentTimeMillis() - lastLeftClick < 200; + } + + @Override + protected void onEnable() { + lastLeftClick = 0; + lastRightClick = 0; + isBlocking = false; + lastBlockTime = 0; + lastUnblockTime = 0; + originalYaw = 0; + originalPitch = 0; + leftMouseDown = false; + rightMouseDown = false; + + if(randomizeCps.getValue()) { + currentCps = random.nextInt(maxCps.getValue() - minCps.getValue() + 1) + minCps.getValue(); + } else { + currentCps = cps.getValue(); + } + } + + @Override + protected void onDisable() { + if(mc.options.attackKey.isPressed()) { + mc.options.attackKey.setPressed(false); + } + + if(mc.options.useKey.isPressed()) { + mc.options.useKey.setPressed(false); + } + + if(mc.player != null && originalYaw != 0) { + mc.player.setYaw(originalYaw); + mc.player.setPitch(originalPitch); + } + + isBlocking = false; + leftMouseDown = false; + rightMouseDown = false; + } +} \ No newline at end of file diff --git a/src/client/java/works/alya/module/impl/combat/ReachModule.java b/src/client/java/works/alya/module/impl/combat/ReachModule.java index a48db5f..7f64fdc 100644 --- a/src/client/java/works/alya/module/impl/combat/ReachModule.java +++ b/src/client/java/works/alya/module/impl/combat/ReachModule.java @@ -17,63 +17,161 @@ package works.alya.module.impl.combat; import works.alya.config.setting.impl.BooleanSetting; +import works.alya.config.setting.impl.NumberSetting; import works.alya.event.IEventListener; -import works.alya.event.impl.MotionEvent; +import works.alya.event.impl.ReachEvent; +import works.alya.event.impl.TickEvent; import works.alya.module.Module; import works.alya.module.ModuleCategory; import works.alya.utilities.misc.RaycastUtility; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; @SuppressWarnings("SameParameterValue") public class ReachModule extends Module { - private static double lastReach = 0d; /** * @credit: NezhaAnticheat - for funny name */ private static final BooleanSetting remoteSpleefHacks = new BooleanSetting("RemoteSpleefHacks", "Allows you to hit blocks from very far away", false); + /** + * Settings for controlling player reach distance + */ + private static final NumberSetting reachDistance = new NumberSetting<>("Reach", "Controls the player's reach distance", 6.0, 3.0, 100.0); + private static final BooleanSetting noLimitReach = new BooleanSetting("NoLimitReach", "Removes the maximum reach limit completely", false); + private static final BooleanSetting attackThroughWalls = new BooleanSetting("AttackThroughWalls", "Attack entities through walls", false); + private static final BooleanSetting autoAttack = new BooleanSetting("AutoAttack", "Automatically attack entities in range", false); + private static final NumberSetting autoAttackRange = new NumberSetting<>("AutoAttackRange", "Range for auto attack", 4.0, 3.0, 6.0); + public ReachModule() { super("Reach", "billy big-arms", ModuleCategory.COMBAT); + addSetting(reachDistance); + addSetting(noLimitReach); + addSetting(attackThroughWalls); + addSetting(autoAttack); + addSetting(autoAttackRange); addSetting(remoteSpleefHacks); + + autoAttackRange.setVisibilityCondition(autoAttack::getValue); } @SuppressWarnings("unused") - private final IEventListener motionEvent = event -> { - if(remoteSpleefHacks.getValue() && mc.player != null && mc.world != null && mc.getNetworkHandler() != null) { - if(mc.options.attackKey.isPressed()) { - BlockHitResult hitResult = RaycastUtility.raycast(mc, 10000.0); - - if(hitResult != null) { - BlockPos blockPos = hitResult.getBlockPos(); - Direction face = hitResult.getSide(); - - PlayerActionC2SPacket startBreaking = new PlayerActionC2SPacket( - PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, - blockPos, - face - ); - - PlayerActionC2SPacket stopBreaking = new PlayerActionC2SPacket( - PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, - blockPos, - face - ); - - mc.getNetworkHandler().sendPacket(startBreaking); - mc.getNetworkHandler().sendPacket(stopBreaking); - - lastReach = hitResult.getPos().distanceTo(mc.player.getEyePos()); - } + private final IEventListener tickEvent = event -> { + if(!isEnabled() || mc.player == null || mc.world == null || mc.getNetworkHandler() == null || !event.isPre()) return; + double lastReach = 0d; + if(remoteSpleefHacks.getValue() && mc.options.attackKey.isPressed()) { + BlockHitResult hitResult = RaycastUtility.raycast(mc, noLimitReach.getValue() ? Double.MAX_VALUE : reachDistance.getValue()); + + if(hitResult != null) { + BlockPos blockPos = hitResult.getBlockPos(); + Direction face = hitResult.getSide(); + + PlayerActionC2SPacket startBreaking = new PlayerActionC2SPacket( + PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, + blockPos, + face + ); + + PlayerActionC2SPacket stopBreaking = new PlayerActionC2SPacket( + PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, + blockPos, + face + ); + + mc.getNetworkHandler().sendPacket(startBreaking); + mc.getNetworkHandler().sendPacket(stopBreaking); + } + } + + if(mc.options.attackKey.isPressed() || autoAttack.getValue()) { + double maxReach = autoAttack.getValue() ? autoAttackRange.getValue() : + (noLimitReach.getValue() ? Double.MAX_VALUE : reachDistance.getValue()); + + Entity target = findTarget(maxReach); + + if(target != null && (mc.options.attackKey.isPressed() || autoAttack.getValue())) { + attackEntity(target); } } }; - public static double getLastReach() { - return lastReach; + /** + * Finds the closest entity to attack based on the player's look vector + */ + private Entity findTarget(double maxDistance) { + if(mc.player == null || mc.world == null) return null; + + Vec3d eyePos = mc.player.getEyePos(); + Vec3d lookVec = mc.player.getRotationVec(1.0f); + + List possibleTargets = new ArrayList<>(); + + for(Entity entity : mc.world.getEntities()) { + if(entity == mc.player) continue; + if(!(entity instanceof LivingEntity)) continue; + + double distance = entity.getPos().distanceTo(mc.player.getPos()); + if(distance > maxDistance) continue; + + if(!attackThroughWalls.getValue()) { + BlockHitResult blockHitResult = RaycastUtility.raycast( + mc, + eyePos.distanceTo(entity.getPos().add(0, entity.getHeight() / 2, 0)) + ); + + if(blockHitResult != null) continue; + } + + Vec3d toEntity = entity.getPos().add(0, entity.getHeight() / 2, 0).subtract(eyePos).normalize(); + double dot = lookVec.dotProduct(toEntity); + + if(dot > 0.5) { + possibleTargets.add(entity); + } + } + + possibleTargets.sort(Comparator.comparingDouble(e -> e.getPos().distanceTo(mc.player.getPos()))); + + return possibleTargets.isEmpty() ? null : possibleTargets.getFirst(); + } + + /** + * Attacks an entity by sending a packet directly to the server + */ + private void attackEntity(Entity entity) { + if(mc.player == null || mc.getNetworkHandler() == null) return; + + PlayerInteractEntityC2SPacket packet = PlayerInteractEntityC2SPacket.attack( + entity, + mc.player.isSneaking() + ); + + mc.getNetworkHandler().sendPacket(packet); + + mc.player.swingHand(Hand.MAIN_HAND); } -} \ No newline at end of file + + @SuppressWarnings("unused") + private final IEventListener reachEvent = event -> { + if(isEnabled()) { + if(noLimitReach.getValue()) { + event.setReachDistance(Double.MAX_VALUE); + } else { + event.setReachDistance(reachDistance.getValue()); + } + } + }; +}