Загрузка данных
package fun.wonderful.client.modules.impl.combat.components.rotations;
import fun.wonderful.api.QClient;
import fun.wonderful.api.storages.implement.FreeLookStorage;
import fun.wonderful.api.storages.implement.RotationStorage;
import fun.wonderful.api.utils.combat.IdealHitUtils;
import fun.wonderful.api.utils.combat.RayTraceUtil;
import fun.wonderful.api.utils.rotate.MultipointUtils;
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;
import fun.wonderful.client.modules.impl.combat.components.interpolation.BestPoint;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec2f;
import net.minecraft.util.math.Vec3d;
public class FuntimeRotation extends RotationsSystem implements QClient {
private final Aura aura;
private LivingEntity trackedTarget;
private Vec2f attackAimRotation = Vec2f.ZERO;
private Vec3d aimPoint;
private Vec3d aimPointTarget;
private float currentYaw;
private float currentPitch;
private float lastSentYaw;
private float lastSentPitch;
private float driftYaw;
private float driftPitch;
private float driftYawTarget;
private float driftPitchTarget;
private float noisePhase;
private int aimPointTicks;
private int snapTicks;
private int driftTicks;
private boolean attackSnapQueued;
public FuntimeRotation(Aura aura) {
this.aura = aura;
reset();
}
public void reset() {
trackedTarget = null;
aimPoint = null;
aimPointTarget = null;
aimPointTicks = 0;
snapTicks = 0;
driftTicks = 0;
attackSnapQueued = false;
driftYaw = 0.0F;
driftPitch = 0.0F;
driftYawTarget = 0.0F;
driftPitchTarget = 0.0F;
noisePhase = (float) (Math.random() * Math.PI * 2.0D);
if (mc.player != null) {
currentYaw = mc.player.getYaw();
currentPitch = mc.player.getPitch();
} else {
currentYaw = 0.0F;
currentPitch = 0.0F;
}
lastSentYaw = currentYaw;
lastSentPitch = currentPitch;
attackAimRotation = new Vec2f(currentYaw, currentPitch);
}
@Override
public void updateRotations(LivingEntity target) {
if (mc.player == null || target == null) {
return;
}
if (trackedTarget != target) {
trackedTarget = target;
currentYaw = mc.player.getYaw();
currentPitch = mc.player.getPitch();
lastSentYaw = currentYaw;
lastSentPitch = currentPitch;
aimPoint = null;
aimPointTarget = null;
aimPointTicks = 0;
snapTicks = 0;
resetDrift();
}
float attackReadiness = mc.player.getAttackCooldownProgress(1.5F);
float distance = (float) mc.player.getEyePos().distanceTo(target.getBoundingBox().getCenter());
float distanceFactor = getDistanceFactor(distance);
boolean snapToHitbox = attackSnapQueued && shouldSnapToHitbox(attackReadiness, distanceFactor);
if (snapToHitbox) {
snapTicks = Math.max(snapTicks, 3);
} else if (snapTicks > 0) {
snapTicks--;
}
boolean activeSnap = snapToHitbox || snapTicks > 0;
if (!activeSnap) {
holdRealHeadShake();
return;
}
Vec3d point = updateMultipoint(target, true, distanceFactor);
Vec3d predicted = getPredictedPoint(target, point);
Vec2f targetRot = RotationUtils.getRotations(predicted);
attackAimRotation = targetRot;
updateDrift(snapToHitbox, distanceFactor);
float desiredYaw = targetRot.x + driftYaw;
float desiredPitch = MathHelper.clamp(targetRot.y + driftPitch, -89.0F, 89.0F);
float yawDelta = MathHelper.wrapDegrees(desiredYaw - currentYaw);
float pitchDelta = desiredPitch - currentPitch;
boolean hardSnap = true;
float yawStep = hardSnap
? 360.0F
: MathHelper.lerp(distanceFactor, 10.5F, 17.0F);
float pitchStep = hardSnap
? 360.0F
: MathHelper.lerp(distanceFactor, 5.5F, 8.5F);
currentYaw += MathHelper.clamp(yawDelta, -yawStep, yawStep);
currentPitch = MathHelper.clamp(currentPitch + MathHelper.clamp(pitchDelta, -pitchStep, pitchStep), -89.0F, 89.0F);
float follow = hardSnap ? 1.0F : 0.7F;
float outYaw = smoothLerp(lastSentYaw, currentYaw, follow);
float outPitch = MathHelper.clamp(MathHelper.lerp(follow, lastSentPitch, currentPitch), -89.0F, 89.0F);
float[] noise = getMicroNoise(snapToHitbox, distanceFactor);
outYaw += noise[0];
outPitch = MathHelper.clamp(outPitch + noise[1], -89.0F, 89.0F);
lastSentYaw = outYaw;
lastSentPitch = outPitch;
Vec2f currentRot = new Vec2f(mc.player.getYaw(), mc.player.getPitch());
Vec2f outputRot = new Vec2f(outYaw, outPitch);
aura.setRotationSnapshots(currentRot, outputRot);
rotate = outputRot;
RotationStorage.update(
new Rotation(outYaw, outPitch),
360.0F,
hardSnap ? 360.0F : 75.0F,
45.0F,
45.0F,
0,
1,
false
);
syncBodyToSnap(outYaw);
}
public void queueAttackSnap() {
attackSnapQueued = true;
snapTicks = Math.max(snapTicks, 3);
aimPointTicks = 0;
}
public boolean isAttackSnapActive() {
return attackSnapQueued || snapTicks > 0;
}
public void clearAttackSnap() {
attackSnapQueued = false;
snapTicks = 0;
}
private void holdRealHeadShake() {
float realYaw = FreeLookStorage.getFreeYaw();
float realPitch = FreeLookStorage.getFreePitch();
if (driftTicks > 0) {
driftTicks--;
} else {
driftYawTarget = randomRange(-1.8F, 1.8F);
driftPitchTarget = randomRange(-0.45F, 0.45F);
driftTicks = 3 + (int) (Math.random() * 5.0D);
}
noisePhase += 0.18F;
driftYaw = MathHelper.lerp(0.34F, driftYaw, driftYawTarget);
driftPitch = MathHelper.lerp(0.28F, driftPitch, driftPitchTarget);
float shakeYaw = (float) Math.sin(noisePhase * 1.4F) * 0.65F
+ (float) Math.cos(noisePhase * 0.73F) * 0.35F
+ driftYaw;
float shakePitch = (float) Math.sin(noisePhase * 1.17F + 0.45F) * 0.18F
+ driftPitch;
float outYaw = realYaw + shakeYaw;
float outPitch = MathHelper.clamp(realPitch + shakePitch, -89.0F, 89.0F);
currentYaw = outYaw;
currentPitch = outPitch;
lastSentYaw = outYaw;
lastSentPitch = outPitch;
Vec2f realRot = new Vec2f(realYaw, realPitch);
Vec2f outputRot = new Vec2f(outYaw, outPitch);
attackAimRotation = outputRot;
aura.setRotationSnapshots(realRot, outputRot);
rotate = outputRot;
RotationStorage.update(
new Rotation(outYaw, outPitch),
12.0F,
6.0F,
18.0F,
10.0F,
1,
1,
false
);
}
private void syncBodyToSnap(float yaw) {
if (mc.player == null) {
return;
}
float bodyYaw = approachYaw(mc.player.bodyYaw, yaw, 75.0F);
float headYaw = approachYaw(mc.player.headYaw, yaw, 95.0F);
mc.player.prevBodyYaw = mc.player.bodyYaw;
mc.player.prevHeadYaw = mc.player.headYaw;
mc.player.bodyYaw = bodyYaw;
mc.player.headYaw = headYaw;
}
public void smoothReturnToRealHead() {
if (mc.player == null) {
reset();
return;
}
float targetYaw = FreeLookStorage.getFreeYaw();
float targetPitch = FreeLookStorage.getFreePitch();
float yawDelta = Math.abs(MathHelper.wrapDegrees(targetYaw - mc.player.getYaw()));
float pitchDelta = Math.abs(targetPitch - mc.player.getPitch());
float yawSpeed = MathHelper.clamp(yawDelta * 0.22F, 7.0F, 24.0F);
float pitchSpeed = MathHelper.clamp(pitchDelta * 0.26F, 5.0F, 16.0F);
if (RotationStorage.instance != null) {
RotationStorage.instance.stopRotation();
}
RotationStorage.update(
new Rotation(targetYaw, targetPitch),
yawSpeed,
pitchSpeed,
yawSpeed,
pitchSpeed,
0,
1,
false
);
reset();
}
public boolean isAimReadyForAttack(EntityHitResult result) {
if (mc.player == null || trackedTarget == null || attackAimRotation == null) {
return false;
}
float yawDiff = Math.abs(MathHelper.wrapDegrees(attackAimRotation.x - mc.player.getYaw()));
float pitchDiff = Math.abs(attackAimRotation.y - mc.player.getPitch());
double reach = Math.min(6.5D, mc.player.getEyePos().distanceTo(trackedTarget.getBoundingBox().getCenter()) + 1.2D);
boolean onTarget = (result != null && result.getEntity() == trackedTarget)
|| RayTraceUtil.rayTraceSingleEntity(mc.player.getYaw(), mc.player.getPitch(), reach, trackedTarget);
return yawDiff <= 3.2F && pitchDiff <= 2.6F && onTarget;
}
private Vec3d updateMultipoint(LivingEntity target, boolean snapToHitbox, float distanceFactor) {
if (aimPoint == null || aimPointTarget == null || aimPointTicks <= 0 || snapToHitbox) {
aimPointTarget = pickMultipoint(target, snapToHitbox, distanceFactor);
aimPoint = aimPoint == null || snapToHitbox ? aimPointTarget : aimPoint;
aimPointTicks = snapToHitbox ? 2 : 5 + (int) (Math.random() * 5.0D);
} else {
aimPointTicks--;
}
float follow = snapToHitbox ? 0.9F : MathHelper.lerp(distanceFactor, 0.34F, 0.48F);
aimPoint = new Vec3d(
MathHelper.lerp(follow, aimPoint.x, aimPointTarget.x),
MathHelper.lerp(follow, aimPoint.y, aimPointTarget.y),
MathHelper.lerp(follow, aimPoint.z, aimPointTarget.z)
);
return aimPoint;
}
private Vec3d pickMultipoint(LivingEntity target, boolean snapToHitbox, float distanceFactor) {
double reach = mc.player.getEyePos().distanceTo(target.getBoundingBox().getCenter()) + 1.5D;
Vec3d point;
if (snapToHitbox) {
point = lowerBodyPoint(target, distanceFactor, 0.0D);
} else {
int mode = (int) (Math.random() * 5.0D);
if (mode == 0) {
point = BestPoint.getMultipoint(target, reach);
} else if (mode == 1) {
point = lowerBodyPoint(target, distanceFactor, -0.16D);
} else if (mode == 2) {
point = lowerBodyPoint(target, distanceFactor, 0.16D);
} else if (mode == 3) {
point = lowerBodyPoint(target, distanceFactor, Math.random() < 0.5D ? -0.08D : 0.08D);
} else {
point = stableBodyPoint(target);
}
}
if (point == null) {
point = stableBodyPoint(target);
}
Vec3d visible = BestPoint.getNearestVisiblePoint(target, point, reach);
if (visible != null) {
point = visible;
}
return clampInsideBody(target, point, snapToHitbox, distanceFactor);
}
private Vec3d clampInsideBody(LivingEntity target, Vec3d point, boolean snapToHitbox, float distanceFactor) {
Box box = target.getBoundingBox();
double inset = snapToHitbox ? 0.025D : MathHelper.lerp(distanceFactor, 0.045D, 0.075D);
double minX = box.minX + inset;
double maxX = box.maxX - inset;
double minZ = box.minZ + inset;
double maxZ = box.maxZ - inset;
double minY = box.minY + box.getLengthY() * (snapToHitbox ? 0.28D : 0.24D);
double maxY = box.minY + box.getLengthY() * (snapToHitbox ? 0.54D : 0.58D);
return new Vec3d(
MathHelper.clamp(point.x, minX, maxX),
MathHelper.clamp(point.y, minY, maxY),
MathHelper.clamp(point.z, minZ, maxZ)
);
}
private Vec3d stableBodyPoint(LivingEntity target) {
Box box = target.getBoundingBox();
return new Vec3d(
box.getCenter().x,
box.minY + box.getLengthY() * 0.42D,
box.getCenter().z
);
}
private Vec3d lowerBodyPoint(LivingEntity target, float distanceFactor, double sideOffset) {
Box box = target.getBoundingBox();
double halfX = box.getLengthX() * MathHelper.lerp(distanceFactor, 0.18D, 0.28D);
double halfZ = box.getLengthZ() * MathHelper.lerp(distanceFactor, 0.18D, 0.28D);
double xOffset = MathHelper.clamp(sideOffset, -0.22D, 0.22D) * box.getLengthX();
double zOffset = randomRange(-0.08F, 0.08F) * box.getLengthZ();
return new Vec3d(
box.getCenter().x + MathHelper.clamp(xOffset, -halfX, halfX),
box.minY + box.getLengthY() * randomRange(0.31F, 0.5F),
box.getCenter().z + MathHelper.clamp(zOffset, -halfZ, halfZ)
);
}
private void updateDrift(boolean snapToHitbox, float distanceFactor) {
if (snapToHitbox) {
driftYawTarget = 0.0F;
driftPitchTarget = 0.0F;
driftYaw = MathHelper.lerp(0.48F, driftYaw, driftYawTarget);
driftPitch = MathHelper.lerp(0.48F, driftPitch, driftPitchTarget);
return;
}
if (driftTicks > 0) {
driftTicks--;
} else {
driftYawTarget = randomRange(
-MathHelper.lerp(distanceFactor, 2.4F, 4.8F),
MathHelper.lerp(distanceFactor, 2.4F, 4.8F)
);
driftPitchTarget = randomRange(
-MathHelper.lerp(distanceFactor, 0.55F, 1.15F),
MathHelper.lerp(distanceFactor, 0.55F, 1.15F)
);
driftTicks = 5 + (int) (Math.random() * 8.0D);
}
driftYaw = MathHelper.lerp(0.18F, driftYaw, driftYawTarget);
driftPitch = MathHelper.lerp(0.16F, driftPitch, driftPitchTarget);
}
private void resetDrift() {
driftYaw = 0.0F;
driftPitch = 0.0F;
driftYawTarget = 0.0F;
driftPitchTarget = 0.0F;
driftTicks = 0;
}
private float[] getMicroNoise(boolean snapToHitbox, float distanceFactor) {
noisePhase += snapToHitbox ? 0.065F : 0.04F;
float yawScale = snapToHitbox
? MathHelper.lerp(distanceFactor, 0.035F, 0.07F)
: MathHelper.lerp(distanceFactor, 0.08F, 0.16F);
float pitchScale = snapToHitbox
? MathHelper.lerp(distanceFactor, 0.018F, 0.04F)
: MathHelper.lerp(distanceFactor, 0.035F, 0.075F);
float yawNoise = (float) (Math.sin(noisePhase) + Math.cos(noisePhase * 1.7F)) * yawScale;
float pitchNoise = (float) Math.sin(noisePhase * 1.31F + 0.4F) * pitchScale;
return new float[]{yawNoise, pitchNoise};
}
private boolean shouldSnapToHitbox(float attackReadiness, float distanceFactor) {
float threshold = Math.max(0.78F, IdealHitUtils.getAICooldown() - MathHelper.lerp(distanceFactor, 0.035F, 0.16F));
boolean readyByCooldown = attackReadiness >= threshold;
boolean fallingForCrit = !mc.player.isOnGround()
&& mc.player.getVelocity().y < 0.0D
&& mc.player.fallDistance > 0.0F;
return readyByCooldown || fallingForCrit;
}
private float smoothLerp(float from, float to, float alpha) {
float delta = MathHelper.wrapDegrees(to - from);
return from + delta * MathHelper.clamp(alpha, 0.0F, 1.0F);
}
private float approachYaw(float from, float to, float maxStep) {
float delta = MathHelper.wrapDegrees(to - from);
return from + MathHelper.clamp(delta, -maxStep, maxStep);
}
private float randomRange(float min, float max) {
return min + (float) Math.random() * (max - min);
}
private float getDistanceFactor(float distance) {
return MathHelper.clamp((distance - 1.6F) / 3.8F, 0.0F, 1.0F);
}
}