Загрузка данных
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 maxDelta = computeAdaptiveMaxDelta((float) Math.hypot(Math.abs(yawDiff), Math.abs(pitchDiff)));
// Переводим расчет на фиксированную временную шкалу демпфирования
float easing = MathHelper.clamp(0.15f + smooth * 0.45f, 0.15f, 0.75f);
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 + yawBias;
float nextPitch = serverPitch + smoothedPitchDiff + 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 clampedDiff = MathHelper.clamp(currentDiff, -maxDelta, maxDelta);
// Линейно интерполируем между предыдущим шагом и ограниченным текущим
return previousDiff + (clampedDiff - previousDiff) * smoothing;
}
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;
}
}
}