Загрузка данных


package skwix.mellstroyclient.core;

import client.mellstory.client.social.FriendManager;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ShieldItem;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;

import java.util.Random;

public final class KillAura {
    private static final KillAura INSTANCE = new KillAura();

    private static final float REQUIRED_COOLDOWN = 0.86f;
    private static final double ATTACK_RANGE = 3.0d;
    private static final double ATTACK_RANGE_SQUARED = ATTACK_RANGE * ATTACK_RANGE;
    private static final double TARGET_EXTRA_RANGE = 1.0d;
    private static final double TARGET_RANGE = ATTACK_RANGE + TARGET_EXTRA_RANGE;
    private static final double TARGET_RANGE_SQUARED = TARGET_RANGE * TARGET_RANGE;
    private static final float SEARCH_FOV = 360.0f;
    private static final float ATTACK_FOV_STILL = 14.0f;
    private static final float ATTACK_FOV_MOVING = 28.0f;
    private static final double CLOSE_RANGE = 2.35d;
    private static final int SPRINT_RESET_DELAY = 2;
    private static final int SPRINT_SUPPRESS_TICKS = 2;
    private final Random random = new Random();

    private boolean enabled;
    private PlayerEntity lockedTarget;
    private int sprintResetTicks;
    private boolean sprintResetPrimed;
    private int lastHeadTick = Integer.MIN_VALUE;
    private int lastReturnTick = Integer.MIN_VALUE;
    private float smartCritFallDistance;
    private long smartCritRefreshAt;

    private KillAura() {
    }

    public static KillAura instance() {
        return INSTANCE;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public PlayerEntity getLockedTarget() {
        return lockedTarget;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
        if (!enabled) {
            clearTarget(MinecraftClient.getInstance().player);
        }
    }

    public void toggle() {
        setEnabled(!enabled);
    }

    public void clearTarget(ClientPlayerEntity player) {
        lockedTarget = null;
        sprintResetTicks = 0;
        sprintResetPrimed = false;
        lastHeadTick = Integer.MIN_VALUE;
        lastReturnTick = Integer.MIN_VALUE;
        smartCritFallDistance = 0.0f;
        smartCritRefreshAt = 0L;

        if (player != null) {
            RotationManager.instance().stopRotation(player);
        }
    }

    public void onHead(MinecraftClient client) {
        if (!canRun(client)) {
            if (RotationManager.instance().isActive()) {
                clearTarget(client.player);
            }
            return;
        }

        ClientPlayerEntity player = client.player;
        if (player.age == lastHeadTick) {
            return;
        }
        lastHeadTick = player.age;

        AuraCombatHelper.tick();
        RotationManager.instance().tickFtNew();

        if (!isValidTarget(player, lockedTarget)) {
            lockedTarget = findBestTarget(client, player);
            resetAttackState();
        }

        applySmartCrits(player);

        if (lockedTarget == null) {
            if (RotationManager.instance().isActive()) {
                clearTarget(player);
            }
            return;
        }

        Vec3d aimPoint = RotationManager.instance().getLockedAimPoint(client, lockedTarget);
        if (aimPoint == null) {
            return;
        }

        if (!RotationManager.instance().isActive()) {
            RotationManager.instance().startRotation(player.getYaw(), player.getPitch());
        }

        boolean attackReady = isCooldownReady(player) && !shouldBlockAttack(player);
        RotationManager.instance().rotateTowardsFtNew(client, aimPoint, attackReady);

        if (shouldPrepareSprintReset(player)) {
            performSprintReset(player);
            sprintResetTicks = SPRINT_RESET_DELAY;
        }

        if (sprintResetTicks > 0) {
            sprintResetTicks--;
            return;
        }

        if (canAttackNow(player, lockedTarget)) {
            attack(client, player, lockedTarget);
        }
    }

    public void onReturn(MinecraftClient client) {
        if (!enabled || lockedTarget == null) {
            return;
        }
        if (client.player == null || client.interactionManager == null) {
            return;
        }
        if (client.player.age == lastReturnTick) {
            return;
        }
        lastReturnTick = client.player.age;

        ClientPlayerEntity player = client.player;
        if (!isValidTarget(player, lockedTarget)) {
            lockedTarget = null;
            resetAttackState();
        }
    }

    private boolean shouldPrepareSprintReset(ClientPlayerEntity player) {
        return player.isSprinting()
                && isCooldownReady(player)
                && lockedTarget != null
                && getAngleToTarget(MinecraftClient.getInstance(), player, lockedTarget) < 25.0f;
    }

    private void performSprintReset(ClientPlayerEntity player) {
        AutoSprint.instance().suppressForTicks(SPRINT_SUPPRESS_TICKS);
        player.setSprinting(false);
        if (MinecraftClient.getInstance().options != null) {
            MinecraftClient.getInstance().options.sprintKey.setPressed(false);
        }
        sprintResetPrimed = true;
    }

    private boolean canAttackNow(ClientPlayerEntity player, PlayerEntity target) {
        if (shouldBlockAttack(player)) {
            return false;
        }
        if (!isCooldownReady(player)) {
            return false;
        }
        if (player.squaredDistanceTo(target) > ATTACK_RANGE_SQUARED) {
            return false;
        }
        if (player.squaredDistanceTo(target) > CLOSE_RANGE * CLOSE_RANGE
                && getAngleToTarget(MinecraftClient.getInstance(), player, target) > getEffectiveAttackFov(player)) {
            return false;
        }
        if (player.isTouchingWater() || player.isInLava() || player.isClimbing() || player.hasVehicle()) {
            return true;
        }
        if (!player.isOnGround()) {
            return player.getVelocity().y < -0.05d;
        }
        return player.squaredDistanceTo(target) <= CLOSE_RANGE * CLOSE_RANGE
                || AuraCombatHelper.shouldIgnoreCritRequirement();
    }

    private boolean shouldBlockAttack(ClientPlayerEntity player) {
        return player.isUsingItem()
                && !(player.getActiveItem().getItem() instanceof ShieldItem)
                || MinecraftClient.getInstance().currentScreen != null;
    }

    private boolean isCriticalWindow(ClientPlayerEntity player) {
        double velocityY = AuraPacketState.isInitialized() ? AuraPacketState.getVelocityY() : player.getVelocity().y;
        double fallDistance = AuraPacketState.isInitialized() ? AuraPacketState.getFallDistance() : player.fallDistance;

        return velocityY < -0.01d
                && fallDistance > 0.0f
                && !player.isGliding()
                && !player.isUsingRiptide()
                && !player.hasStatusEffect(StatusEffects.BLINDNESS);
    }

    private float getEffectiveAttackFov(ClientPlayerEntity player) {
        double horizontalSpeed = player.getVelocity().horizontalLength();
        return horizontalSpeed > 0.08d ? ATTACK_FOV_MOVING : ATTACK_FOV_STILL;
    }

    private void applySmartCrits(ClientPlayerEntity player) {
        if (player.isOnGround()) {
            smartCritFallDistance = 0.0f;
            smartCritRefreshAt = 0L;
            return;
        }

        if (!canFakeCritFallDistance(player)) {
            smartCritFallDistance = 0.0f;
            smartCritRefreshAt = 0L;
            return;
        }

        long now = System.currentTimeMillis();
        if (now >= smartCritRefreshAt || smartCritFallDistance <= 0.0f) {
            smartCritFallDistance = 0.08f + random.nextFloat() * 0.24f;
            smartCritRefreshAt = now + 55L + random.nextInt(76);
        }

        player.fallDistance = smartCritFallDistance;
    }

    private boolean canFakeCritFallDistance(ClientPlayerEntity player) {
        return player.isOnGround() && hasCollisionBlock(player, -0.05d) && hasCollisionBlock(player, 0.2d);
    }

    private boolean hasCollisionBlock(ClientPlayerEntity player, double yOffset) {
        MinecraftClient client = MinecraftClient.getInstance();
        if (client.world == null) {
            return false;
        }

        BlockPos pos = BlockPos.ofFloored(player.getX(), player.getBoundingBox().minY + yOffset, player.getZ());
        if (yOffset > 0.0d) {
            pos = BlockPos.ofFloored(player.getX(), player.getBoundingBox().maxY + yOffset, player.getZ());
        }

        BlockState state = client.world.getBlockState(pos);
        return !state.getCollisionShape(client.world, pos).isEmpty();
    }

    private void attack(MinecraftClient client, ClientPlayerEntity player, PlayerEntity target) {
        int previousSlot = player.getInventory().getSelectedSlot();
        int axeSlot = AuraCombatHelper.findShieldBreakAxeSlot(target);
        boolean useAxe = axeSlot != -1 && axeSlot != previousSlot;
        Hand activeShieldHand = AuraCombatHelper.getActiveShieldHand();
        boolean restoreShield = activeShieldHand != null;
        boolean restoreSprint = AuraCombatHelper.shouldPacketResetSprint();
        boolean deferSprintRestore = sprintResetPrimed;

        if (restoreSprint) {
            player.setSprinting(false);
        }
        if (restoreShield) {
            AuraCombatHelper.releaseOwnShield();
        }
        if (useAxe) {
            AuraCombatHelper.sendHeldItemChange(axeSlot);
        }
        if (client.interactionManager != null) {
            client.interactionManager.attackEntity(player, target);
        }

        if (useAxe) {
            AuraCombatHelper.sendHeldItemChange(previousSlot);
        }
        if (restoreShield) {
            AuraCombatHelper.restoreOwnShield(activeShieldHand);
        }
        sprintResetPrimed = false;

        // MixinClientPlayerInteractionManager records attack timing for both aura
        // attacks and manual hits, so keep timing updates in one place.
    }

    private void resetAttackState() {
        sprintResetTicks = 0;
        sprintResetPrimed = false;
    }

    private boolean isCooldownReady(ClientPlayerEntity player) {
        return player.getAttackCooldownProgress(0.0f) >= REQUIRED_COOLDOWN
                && AuraCombatHelper.canAttackNow(-90L);
    }

    private PlayerEntity findBestTarget(MinecraftClient client, ClientPlayerEntity player) {
        PlayerEntity best = null;
        double bestScore = Double.MAX_VALUE;

        for (PlayerEntity target : client.world.getPlayers()) {
            if (!isValidTarget(player, target)) {
                continue;
            }

            float angle = getAngleToTarget(client, player, target);
            if (angle > SEARCH_FOV) {
                continue;
            }

            double distance = Math.sqrt(player.squaredDistanceTo(target));
            double score = angle + distance * 0.001d;

            if (score < bestScore) {
                bestScore = score;
                best = target;
            }
        }

        return best;
    }

    private boolean isValidTarget(ClientPlayerEntity player, PlayerEntity target) {
        if (target == null || target == player || !target.isAlive() || target.isSpectator()) {
            return false;
        }
        if (target.isCreative() || FriendManager.isFriend(target)) {
            return false;
        }
        if (target.isInvisible() && !hasArmor(target)) {
            return false;
        }
        return player.squaredDistanceTo(target) <= TARGET_RANGE_SQUARED && player.canSee(target);
    }

    private boolean hasArmor(PlayerEntity target) {
        return !target.getEquippedStack(EquipmentSlot.HEAD).isEmpty()
                || !target.getEquippedStack(EquipmentSlot.CHEST).isEmpty()
                || !target.getEquippedStack(EquipmentSlot.LEGS).isEmpty()
                || !target.getEquippedStack(EquipmentSlot.FEET).isEmpty();
    }

    private float getAngleToTarget(MinecraftClient client, ClientPlayerEntity player, PlayerEntity target) {
        Vec3d eyes = player.getEyePos();
        Vec3d aim = RotationManager.instance().getLockedAimPoint(client, target);
        if (aim == null) {
            aim = target.getPos();
        }

        double dx = aim.x - eyes.x;
        double dy = aim.y - eyes.y;
        double dz = aim.z - eyes.z;
        double distXZ = Math.sqrt(dx * dx + dz * dz);

        float targetYaw = (float) (Math.toDegrees(Math.atan2(dz, dx)) - 90.0d);
        float targetPitch = (float) -Math.toDegrees(Math.atan2(dy, distXZ));

        float currentYaw = AuraPacketState.getTrackedYaw(player.getYaw());
        float currentPitch = AuraPacketState.getTrackedPitch(player.getPitch());
        float yawDiff = Math.abs(MathHelper.wrapDegrees(targetYaw - currentYaw));
        float pitchDiff = Math.abs(targetPitch - currentPitch);

        return (float) Math.sqrt(yawDiff * yawDiff + pitchDiff * pitchDiff);
    }

    private boolean canRun(MinecraftClient client) {
        return enabled
                && client.player != null
                && client.world != null
                && client.currentScreen == null
                && client.player.isAlive()
                && !client.player.isSpectator()
                && client.interactionManager != null;
    }
}