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


package fun.wonderful.client.modules.impl.combat.components.rotations;

import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec2f;
import net.minecraft.util.math.Vec3d;
import fun.wonderful.api.QClient;
import fun.wonderful.api.storages.implement.RotationStorage;
import fun.wonderful.api.utils.combat.IdealHitUtils;
import fun.wonderful.api.utils.rotate.Rotation;
import fun.wonderful.api.utils.rotate.RotationUtils;
import fun.wonderful.client.modules.impl.combat.Aura;
import fun.wonderful.client.modules.impl.combat.components.RotationsSystem;

public class FuntimeRotation extends RotationsSystem implements QClient {

    private final Aura aura;

    private LivingEntity trackedTarget;
    private Vec3d hitPoint;
    private float pointX;
    private float pointY;
    private float pointZ;
    private float pointTargetX;
    private float pointTargetY;
    private float pointTargetZ;
    private int pointChangeIn;
    private int pointChangeAfterCalls;

    private float smoothYawFactor;
    private float smoothPitchFactor;
    private float smoothYawFactorTarget;
    private float smoothPitchFactorTarget;

    private int overshootTicks;
    private float overshootYaw;
    private float overshootPitch;

    private float noiseTime;
    private float driftYaw;
    private float driftPitch;

    public FuntimeRotation(Aura aura) {
        this.aura = aura;
        reset();
    }

    public void reset() {
        trackedTarget = null;
        hitPoint = null;
        pointX = 0.0F;
        pointY = 0.0F;
        pointZ = 0.0F;
        pointTargetX = 0.0F;
        pointTargetY = 0.0F;
        pointTargetZ = 0.0F;
        pointChangeIn = 0;
        pointChangeAfterCalls = randomCallWindow();
        smoothYawFactor = 0.082F;
        smoothPitchFactor = 0.064F;
        smoothYawFactorTarget = smoothYawFactor;
        smoothPitchFactorTarget = smoothPitchFactor;
        overshootTicks = 0;
        overshootYaw = 0.0F;
        overshootPitch = 0.0F;
        noiseTime = (float) (Math.random() * Math.PI * 2.0);
        driftYaw = 0.0F;
        driftPitch = 0.0F;
    }

    @Override
    public void updateRotations(LivingEntity target) {
        if (mc.player == null || target == null) {
            return;
        }

        boolean attackMoment = isAttackMoment();
        if (trackedTarget != target) {
            trackedTarget = target;
            resetPointState(target);
        }

        if (++pointChangeIn >= pointChangeAfterCalls) {
            selectNewPointTarget(target);
            pointChangeIn = 0;
            pointChangeAfterCalls = randomCallWindow();
        }

        pointX = MathHelper.lerp(0.065F, pointX, pointTargetX);
        pointY = MathHelper.lerp(0.065F, pointY, pointTargetY);
        pointZ = MathHelper.lerp(0.065F, pointZ, pointTargetZ);
        hitPoint = getHitPoint(target);

        smoothYawFactor = MathHelper.lerp(0.07F, smoothYawFactor, smoothYawFactorTarget);
        smoothPitchFactor = MathHelper.lerp(0.07F, smoothPitchFactor, smoothPitchFactorTarget);

        Vec2f current = new Vec2f(mc.player.getYaw(), mc.player.getPitch());
        Vec2f baseRot = RotationUtils.getRotations(getPredictedPoint(target, hitPoint));

        float rawYawDelta = MathHelper.wrapDegrees(baseRot.x - current.x);
        float rawPitchDelta = baseRot.y - current.y;

        updateOvershoot(rawYawDelta, rawPitchDelta, attackMoment);
        updateDriftAndNoise(rawYawDelta, rawPitchDelta, attackMoment);

        float targetYaw = baseRot.x + driftYaw + overshootYaw;
        float targetPitch = MathHelper.clamp(baseRot.y + driftPitch + overshootPitch, -89.5F, 89.5F);

        float yawDelta = MathHelper.wrapDegrees(targetYaw - current.x);
        float pitchDelta = targetPitch - current.y;

        float easedYawStep = buildAxisStep(yawDelta, smoothYawFactor, true, attackMoment);
        float easedPitchStep = buildAxisStep(pitchDelta, smoothPitchFactor, false, attackMoment);

        float snappedYaw = snapAngle(current.x, current.x + easedYawStep);
        float snappedPitch = MathHelper.clamp(snapAngle(current.y, current.y + easedPitchStep), -89.5F, 89.5F);

        Vec2f targetRot = new Vec2f(snappedYaw, snappedPitch);
        aura.setRotationSnapshots(current, targetRot);

        float yawSpeed = MathHelper.clamp(Math.abs(MathHelper.wrapDegrees(snappedYaw - current.x)), getSensitivityGcd(), attackMoment ? 7.5F : 4.25F);
        float pitchSpeed = MathHelper.clamp(Math.abs(snappedPitch - current.y), getSensitivityGcd(), attackMoment ? 4.75F : 2.8F);
        RotationStorage.update(
                new Rotation(snappedYaw, snappedPitch),
                yawSpeed,
                pitchSpeed,
                yawSpeed,
                pitchSpeed,
                1,
                1,
                Aura.clientLook.isState()
        );

        rotate = targetRot;
    }

    private void resetPointState(LivingEntity target) {
        Box box = target.getBoundingBox();
        pointX = randomRange(-0.18F, 0.18F);
        pointY = randomRange(0.34F, 0.76F);
        pointZ = randomRange(-0.18F, 0.18F);
        pointTargetX = pointX;
        pointTargetY = pointY;
        pointTargetZ = pointZ;
        hitPoint = new Vec3d(
                box.getCenter().x + box.getLengthX() * pointX,
                box.minY + box.getLengthY() * pointY,
                box.getCenter().z + box.getLengthZ() * pointZ
        );
        selectNewPointTarget(target);
    }

    private void selectNewPointTarget(LivingEntity target) {
        Box box = target.getBoundingBox();
        pointTargetX = randomRange(-0.42F, 0.42F);
        pointTargetY = randomRange(0.18F, 0.88F);
        pointTargetZ = randomRange(-0.42F, 0.42F);

        if (Math.abs(box.getLengthX() * (pointTargetX - pointX)) < 0.02D) {
            pointTargetX = MathHelper.clamp(pointTargetX + Math.copySign(0.08F, pointTargetX == 0.0F ? 1.0F : pointTargetX), -0.46F, 0.46F);
        }
        if (Math.abs(box.getLengthY() * (pointTargetY - pointY)) < 0.02D) {
            pointTargetY = MathHelper.clamp(pointTargetY + 0.06F, 0.16F, 0.90F);
        }
        if (Math.abs(box.getLengthZ() * (pointTargetZ - pointZ)) < 0.02D) {
            pointTargetZ = MathHelper.clamp(pointTargetZ - Math.copySign(0.08F, pointTargetZ == 0.0F ? 1.0F : pointTargetZ), -0.46F, 0.46F);
        }

        smoothYawFactorTarget = randomRange(0.065F, 0.11F);
        smoothPitchFactorTarget = randomRange(0.05F, 0.09F);
    }

    private Vec3d getHitPoint(LivingEntity target) {
        Box box = target.getBoundingBox();
        return new Vec3d(
                box.getCenter().x + box.getLengthX() * pointX,
                box.minY + box.getLengthY() * pointY,
                box.getCenter().z + box.getLengthZ() * pointZ
        );
    }

    private void updateOvershoot(float yawDelta, float pitchDelta, boolean attackMoment) {
        if (overshootTicks > 0) {
            overshootYaw *= 0.38F;
            overshootPitch *= 0.38F;
            overshootTicks--;
            return;
        }

        overshootYaw = 0.0F;
        overshootPitch = 0.0F;

        float sharpTurn = Math.abs(yawDelta) + Math.abs(pitchDelta) * 0.45F;
        if (attackMoment && sharpTurn > 46.0F && Math.random() < 0.07D) {
            overshootTicks = 1 + (int) (Math.random() * 2.0D);
            overshootYaw = Math.copySign(randomRange(0.5F, 1.05F), yawDelta == 0.0F ? 1.0F : yawDelta);
            overshootPitch = Math.copySign(randomRange(0.12F, 0.35F), pitchDelta == 0.0F ? 1.0F : pitchDelta);
        }
    }

    private void updateDriftAndNoise(float yawDelta, float pitchDelta, boolean attackMoment) {
        float yawAbs = Math.abs(yawDelta);
        float pitchAbs = Math.abs(pitchDelta);
        boolean stableHold = yawAbs < 1.6F && pitchAbs < 1.2F;

        noiseTime += attackMoment ? 0.12F : 0.075F;
        driftYaw *= attackMoment ? 0.22F : 0.74F;
        driftPitch *= attackMoment ? 0.22F : 0.74F;

        if (stableHold) {
            float yawAmp = randomRange(0.02F, 0.07F);
            float pitchAmp = randomRange(0.02F, 0.06F);
            driftYaw += (float) Math.sin(noiseTime * 0.95F) * yawAmp;
            driftPitch += (float) Math.cos(noiseTime * 1.08F) * pitchAmp;
        }
    }

    private float buildAxisStep(float delta, float smoothingFactor, boolean yawAxis, boolean attackMoment) {
        float absDelta = Math.abs(delta);
        if (absDelta < 1.0E-4F) {
            return 0.0F;
        }

        float axisBias = yawAxis ? randomRange(0.82F, 0.98F) : randomRange(0.74F, 0.92F);
        float attackBoost = attackMoment ? (yawAxis ? 1.10F : 1.04F) : 0.92F;
        float eased = 1.0F - (float) Math.exp(-absDelta * smoothingFactor * axisBias * attackBoost);
        float step = delta * eased;

        float minStep = getSensitivityGcd();
        float maxStep = yawAxis
                ? (attackMoment ? 5.8F : 3.2F)
                : (attackMoment ? 3.6F : 2.1F);
        return MathHelper.clamp(step, -maxStep, maxStep) + Math.copySign(Math.min(minStep, absDelta), delta) * 0.05F;
    }

    private float snapAngle(float current, float target) {
        float gcd = getSensitivityGcd();
        if (gcd <= 0.0F) {
            return target;
        }

        float delta = MathHelper.wrapDegrees(target - current);
        float snappedDelta = Math.round(delta / gcd) * gcd;
        if (snappedDelta == 0.0F && Math.abs(delta) >= gcd * 0.35F) {
            snappedDelta = Math.copySign(gcd, delta);
        }
        return current + snappedDelta;
    }

    private float getSensitivityGcd() {
        float sensitivity = mc.options.getMouseSensitivity().getValue().floatValue();
        float f = sensitivity * 0.6F + 0.2F;
        return f * f * f * 8.0F;
    }

    private boolean isAttackMoment() {
        float attackThreshold = Math.max(0.82F, IdealHitUtils.getAICooldown() - 0.12F);
        boolean readyByCooldown = mc.player.getAttackCooldownProgress(1.5F) >= attackThreshold;
        boolean fallingForCrit = !mc.player.isOnGround()
                && mc.player.getVelocity().y < 0.0D
                && mc.player.fallDistance > 0.0F;
        return readyByCooldown || fallingForCrit;
    }

    private int randomCallWindow() {
        return 3 + (int) (Math.random() * 5.0D);
    }

    private float randomRange(float min, float max) {
        return min + (float) Math.random() * (max - min);
    }
}