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


package skwix.mellstroyclient.core;

import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;

import java.util.Random;

public class RotationManager {

    private static final RotationManager INSTANCE = new RotationManager();

    private float serverYaw;
    private float serverPitch;
    private float prevServerYaw;
    private float prevServerPitch;
    private float visualYaw;
    private float visualPitch;
    private boolean active;

    private Vec3d lockedAimPoint;
    private Vec3d lockedAimOffset;
    private Vec3d lockedAimTargetPos;
    private int lockedAimTargetId = -1;
    private int aimPointTicksRemaining;
    private int aimPointDriftTicks;
    private float lastFtNewYawDiff;
    private float lastFtNewPitchDiff;

    private final Random random = new Random();

    private float lazyOffsetYaw;
    private float lazyOffsetPitch;
    private int lazyCooldown;
    private int ftNewTickCounter;
    private long ftNewSettleStartMs = -1L;
    private long ftNewLastAttackMs = 0L;

    public static RotationManager instance() {
        return INSTANCE;
    }

    public boolean isActive() { return active; }
    public float getServerYaw() { return serverYaw; }
    public float getServerPitch() { return serverPitch; }
    public float getPrevServerYaw() { return prevServerYaw; }
    public float getPrevServerPitch() { return prevServerPitch; }
    public float getVisualYaw() { return visualYaw; }
    public float getVisualPitch() { return visualPitch; }

    public void updateMouseLook(double cursorDeltaX, double cursorDeltaY) {
        MinecraftClient client = MinecraftClient.getInstance();
        double sensitivity = client.options.getMouseSensitivity().getValue() * 0.6D + 0.2D;
        double multiplier = sensitivity * sensitivity * sensitivity * 8.0D;
        boolean invertY = client.options.getInvertYMouse().getValue();

        visualYaw += (float) (cursorDeltaX * multiplier * 0.15D);
        visualPitch += (float) ((invertY ? -cursorDeltaY : cursorDeltaY) * multiplier * 0.15D);
        visualPitch = MathHelper.clamp(visualPitch, -90.0F, 90.0F);
    }

    public void startRotation(float currentYaw, float currentPitch) {
        if (active) {
            return;
        }

        visualYaw = currentYaw;
        visualPitch = currentPitch;
        serverYaw = currentYaw;
        serverPitch = currentPitch;
        prevServerYaw = currentYaw;
        prevServerPitch = currentPitch;
        lockedAimPoint = null;
        lockedAimOffset = null;
        lockedAimTargetPos = null;
        lockedAimTargetId = -1;
        aimPointTicksRemaining = 0;
        aimPointDriftTicks = 0;
        lastFtNewYawDiff = 0.0f;
        lastFtNewPitchDiff = 0.0f;
        lazyCooldown = 0;
        ftNewTickCounter = 0;
        ftNewSettleStartMs = -1L;
        ftNewLastAttackMs = 0L;
        active = true;
    }

    public void stopRotation(Entity player) {
        if (!active) {
            return;
        }

        active = false;
        lockedAimPoint = null;
        lockedAimOffset = null;
        lockedAimTargetPos = null;
        lockedAimTargetId = -1;
        aimPointTicksRemaining = 0;
        aimPointDriftTicks = 0;
        lastFtNewYawDiff = 0.0f;
        lastFtNewPitchDiff = 0.0f;
        ftNewTickCounter = 0;
        ftNewSettleStartMs = -1L;
        ftNewLastAttackMs = 0L;

        if (player != null) {
            player.setYaw(visualYaw);
            player.setPitch(visualPitch);
        }
    }

    public void tickFtNew() {
        ftNewTickCounter++;
    }

    public void markFtNewAttack() {
        ftNewLastAttackMs = System.currentTimeMillis();
        ftNewSettleStartMs = -1L;
        ftNewTickCounter = 0;
    }

    public Vec3d getLockedAimPoint(MinecraftClient client, Entity target) {
        if (client.player == null || target == null) {
            return null;
        }

        Vec3d targetPos = target.getPos();
        Box box = target.getBoundingBox();
        if (lockedAimPoint == null || lockedAimTargetId != target.getId()) {
            Vec3d center = box.getCenter();
            lockedAimOffset = center.subtract(targetPos);
            lockedAimOffset = clampLockedAimOffset(lockedAimOffset);
            lockedAimPoint = targetPos.add(lockedAimOffset);
            lockedAimTargetPos = targetPos;
            lockedAimTargetId = target.getId();
            aimPointTicksRemaining = 2 + random.nextInt(2);
            aimPointDriftTicks = 0;
            return lockedAimPoint;
        }

        if (aimPointTicksRemaining <= 0) {
            aimPointTicksRemaining = 2 + random.nextInt(2);
            aimPointDriftTicks = 0;
        }

        aimPointTicksRemaining--;
        aimPointDriftTicks++;

        lockedAimOffset = lockedAimOffset.add(
                random.nextGaussian() * 0.003d,
                random.nextGaussian() * 0.002d,
                random.nextGaussian() * 0.003d
        );
        lockedAimOffset = clampLockedAimOffset(lockedAimOffset);

        Vec3d baseCenter = box.getCenter();
        lockedAimPoint = clampToBox(baseCenter.add(lockedAimOffset), box);
        lockedAimOffset = clampLockedAimOffset(lockedAimPoint.subtract(baseCenter));
        return lockedAimPoint;
    }

    public void rotateTowards(MinecraftClient client, Vec3d targetPos, float maxSpeed) {
        if (client.player == null) {
            return;
        }

        prevServerYaw = serverYaw;
        prevServerPitch = serverPitch;

        updateLazyAim();

        Vec3d eyes = client.player.getEyePos();
        double dx = targetPos.x - eyes.x;
        double dy = targetPos.y - eyes.y;
        double dz = targetPos.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));

        targetYaw += lazyOffsetYaw;
        targetPitch = MathHelper.clamp(targetPitch + lazyOffsetPitch, -89.0f, 89.0f);

        float yawDiff = MathHelper.wrapDegrees(targetYaw - serverYaw);
        float pitchDiff = targetPitch - serverPitch;
        float angle = (float) Math.sqrt(yawDiff * yawDiff + pitchDiff * pitchDiff);
        float speed = Math.max(1.5f, Math.min(maxSpeed, angle));

        float finalYaw = serverYaw + MathHelper.clamp(yawDiff, -speed, speed);
        float finalPitch = MathHelper.clamp(serverPitch + MathHelper.clamp(pitchDiff, -speed, speed), -90.0f, 90.0f);
        applyQuantizedRotation(client, finalYaw, finalPitch);
    }

    public void rotateTowardsFtNew(MinecraftClient client, Vec3d targetPos, boolean attackReady) {
        if (client.player == null) {
            return;
        }

        prevServerYaw = serverYaw;
        prevServerPitch = serverPitch;

        Vec3d eyes = client.player.getEyePos();
        Vec3d jitteredTargetPos = targetPos.add(
                random.nextGaussian() * 0.02d,
                random.nextGaussian() * 0.02d,
                random.nextGaussian() * 0.02d
        );
        double dx = jitteredTargetPos.x - eyes.x;
        double dy = jitteredTargetPos.y - eyes.y;
        double dz = jitteredTargetPos.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));
        targetPitch = MathHelper.clamp(targetPitch, -90.0f, 90.0f);

        long now = System.currentTimeMillis();
        if (attackReady) {
            ftNewSettleStartMs = -1L;
            applyFtNewStep(client, targetYaw, targetPitch, 130.0f, 130.0f, 0.85f, 0.0f, 0.0f, 0.0f);
            return;
        }

        if (ftNewSettleStartMs < 0L) {
            ftNewSettleStartMs = now;
        }

        long settleAge = now - ftNewSettleStartMs;
        float fade = 1.0f - MathHelper.clamp(settleAge / 300.0f, 0.0f, 1.0f);
        applyFtNewStep(client, targetYaw, targetPitch, 360.0f, 360.0f, 0.85f, 0.0f, 0.0f, fade);
    }

    private void applyFtNewStep(MinecraftClient client, float desiredYaw, float desiredPitch, float yawLimit, float pitchLimit, float smooth, float yawBias, float pitchBias, float jitterFade) {
        float yawDiff = MathHelper.wrapDegrees(desiredYaw - serverYaw);
        float pitchDiff = desiredPitch - serverPitch;
        float angle = Math.max((float) Math.hypot(Math.abs(yawDiff), Math.abs(pitchDiff)), 1.0e-4f);
        float maxDelta = computeAdaptiveMaxDelta(angle);
        float easing = 1.0f - (float) Math.exp(-angle * (0.12f + MathHelper.clamp(smooth, 0.0f, 0.999f) * 0.18f));
        float smoothing = MathHelper.clamp(0.25f + smooth * 0.55f, 0.25f, 0.80f);

        float smoothedYawDiff = limitAcceleration(yawDiff, lastFtNewYawDiff, maxDelta, smoothing);
        float smoothedPitchDiff = limitAcceleration(pitchDiff, lastFtNewPitchDiff, maxDelta, smoothing);

        float nextYaw = serverYaw + smoothedYawDiff * easing + yawBias;
        float nextPitch = serverPitch + smoothedPitchDiff * easing + pitchBias;
        nextPitch = MathHelper.clamp(nextPitch, -90.0f, 90.0f);

        if (jitterFade > 0.0f) {
            nextPitch += (float) (random.nextGaussian() * 0.02d * jitterFade);
        }

        lastFtNewYawDiff = MathHelper.wrapDegrees(nextYaw - serverYaw);
        lastFtNewPitchDiff = nextPitch - serverPitch;
        applyQuantizedRotation(client, nextYaw, nextPitch);
    }

    private void applyQuantizedRotation(MinecraftClient client, float nextYaw, float nextPitch) {
        float yawDiff = MathHelper.wrapDegrees(nextYaw - serverYaw);
        float pitchDiff = nextPitch - serverPitch;

        double sens = client.options.getMouseSensitivity().getValue();
        double f = sens * 0.6D + 0.2D;
        double gcd = f * f * f * 8.0D * 0.15D;

        double yawStep = yawDiff;
        double pitchStep = pitchDiff;
        if (gcd > 1.0e-7D) {
            yawStep = Math.rint(yawDiff / gcd) * gcd;
            pitchStep = Math.rint(pitchDiff / gcd) * gcd;
        }

        float currentClientYaw = client.player.getYaw();
        float currentClientPitch = client.player.getPitch();

        float appliedYaw = (float) (currentClientYaw + yawStep);
        float appliedPitch = (float) MathHelper.clamp(currentClientPitch + pitchStep, -90.0d, 90.0d);

        if (gcd > 1.0e-7D) {
            appliedYaw = (float) (Math.rint(appliedYaw / gcd) * gcd);
            appliedPitch = (float) MathHelper.clamp(Math.rint(appliedPitch / gcd) * gcd, -90.0d, 90.0d);
        }

        client.player.setYaw(appliedYaw);
        client.player.setPitch(appliedPitch);
        client.player.headYaw = appliedYaw;

        serverYaw = appliedYaw;
        serverPitch = appliedPitch;
    }

    private Vec3d clampToBox(Vec3d point, Box box) {
        double x = MathHelper.clamp(point.x, box.minX, box.maxX);
        double y = MathHelper.clamp(point.y, box.minY, box.maxY);
        double z = MathHelper.clamp(point.z, box.minZ, box.maxZ);
        return new Vec3d(x, y, z);
    }

    private Vec3d clampLockedAimOffset(Vec3d offset) {
        return new Vec3d(
                MathHelper.clamp(offset.x, -0.12d, 0.12d),
                MathHelper.clamp(offset.y, -0.12d, 0.12d),
                MathHelper.clamp(offset.z, -0.12d, 0.12d)
        );
    }

    private float limitAcceleration(float currentDiff, float previousDiff, float maxDelta, float smoothing) {
        float delta = currentDiff - previousDiff;
        float clampedDelta = MathHelper.clamp(delta, -maxDelta, maxDelta);
        float blendedDiff = previousDiff + clampedDelta * smoothing;
        return previousDiff + (blendedDiff - previousDiff) * 0.5f;
    }

    private float computeAdaptiveMaxDelta(float angle) {
        if (angle >= 15.0f) {
            return 45.0f;
        }
        if (angle <= 3.0f) {
            return 5.5f;
        }

        float t = (angle - 3.0f) / 12.0f;
        return 5.5f + t * (45.0f - 5.5f);
    }

    private void updateLazyAim() {
        lazyCooldown--;
        if (lazyCooldown <= 0) {
            lazyOffsetYaw = (random.nextFloat() - 0.5f) * 0.4f;
            lazyOffsetPitch = (random.nextFloat() - 0.5f) * 0.2f;
            lazyCooldown = 9 + random.nextInt(8);
        } else {
            lazyOffsetYaw *= 0.9f;
            lazyOffsetPitch *= 0.9f;
        }
    }
}