Files
KauriV3-mirror/src/main/java/dev/brighten/ac/utils/MathUtils.java
T
Dawson a04577b194 lots of changes
- Added inventory check type in API
- Added Inventory (A) detection
- Added Inventory (B) detection
- Improved the flag rate and accuracy of Aim check
- Added other bot check that flies around player to Killaura (Bot) to account for clients not doing a proper RayCast and opting to just turn on attack invisibles and mobs.
- Added comments to Killaura (Trace)
- Optimized Fly (A) detection and added comments
- Fixed false positive caused by incorrect acceleration prediction in Fly (A). I used the current onGround when that is actually never a factor in vertical acceleration, only the product of what the client moves to.
- Removed "optimization" in Fly (A) that basically just stopped prediction when client sends onGround and sets motionY to 0. Changed this behavior to it still do the acceleration subtraction 0.08 times 0.98 but run a collision check that will set the y to 0 if necessary; more closely replicates vanilla mechanics.
- Optimized Horizontal check and fixing field name motionX to more appropriate motion name.
- Optimized Velocity (B) by using current Horizontal optimizations and applying them to this check.
- Moved logs command in AnticheatCommand class to its own LogsCommand class. Added other kinds of logs commands like /kauri logs paste to send it to pastebin and /kauri logs web to view logs on the website.
- Fixed error on plugin shutdown caused by NPE. This was due to an order of operations issue with PlayerRegistry and PacketHandler
- Added wrapper for PacketPlayInWindowClick, PacketPlayInClientCommand.
- Added KLocation#getDirection() method as a shorthand to doing MathUtils.getDirection(KLocation field);
- Moved Helper#angularDistance to MathUtils#angularDistance
- Added CollisionBox#downcast() method as a shorthand method to not have to create a new List field every time I want to get the downcasted SimpleCollisionBox of any wrapped CollisionBox.
2022-11-29 10:00:44 -05:00

884 lines
28 KiB
Java

package dev.brighten.ac.utils;
import lombok.val;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class MathUtils {
public static double GROUND_DIVISOR = 0.015625;
public static double offset(Vector from, Vector to) {
from.setY(0);
to.setY(0);
return to.subtract(from).length();
}
public static int angularDistance(double alpha, double beta) {
while (alpha < 0) alpha += 360;
while (beta < 0) beta += 360;
double phi = Math.abs(beta - alpha) % 360;
return (int) (phi > 180 ? 360 - phi : phi);
}
public static boolean playerMoved(Location from, Location to) {
return playerMoved(from.toVector(), to.toVector());
}
public static float gcdSmall(float current, float previous) {
if(current < previous) return gcdSmall(Math.abs(previous), Math.abs(current));
//The larger number has to be first.
return (Math.abs(previous) <= 0.001f) ? current : gcdSmall(previous,
current - (float)Math.floor(current / previous) * previous);
}
public static double lerp(double lerpAmount, double start, double end) {
return start + lerpAmount * (end - start);
}
public static boolean isScientificNotation(double value) {
return String.valueOf(value).contains("E");
}
public static double getDistanceWithoutRoot(KLocation one, KLocation two) {
double deltaX = one.x - two.x, deltaY = one.y - two.y, deltaZ = one.z - two.z;
return (deltaX * deltaX) + (deltaY * deltaY) + (deltaZ * deltaZ);
}
public static boolean isSameLocation(KLocation one, KLocation two) {
return one.x == two.x && one.y == two.y && one.z == two.z;
}
public static double max(double... values) {
return Arrays.stream(values).max().orElse(Double.MAX_VALUE);
}
public static boolean isInteger(String string) {
try {
Integer.parseInt(string);
return true;
} catch(NumberFormatException e) {
return false;
}
}
public static int length(double value) {
return String.valueOf(value).length();
}
public static double getGrid(final Collection<Float> entry) {
double average = 0.0;
double min = 0.0, max = 0.0;
for (final double number : entry) {
if (number < min) min = number;
if (number > max) max = number;
average += number;
}
average /= entry.size();
return (max - average) - min;
}
//Skidded from Luke.
public static double getAngle(Location loc1, Location loc2) {
if (loc1 == null || loc2 == null) return -1;
Vector playerRotation = new Vector(loc1.getYaw(), loc1.getPitch(), 0.0f);
loc1.setY(0);
loc2.setY(0);
val rot = MathUtils.getRotations(loc1, loc2);
Vector expectedRotation = new Vector(rot[0], rot[1], 0);
return MathUtils.yawTo180D(playerRotation.getX() - expectedRotation.getX());
}
public static double getAngle(KLocation loc1, KLocation loc2) {
return getAngle(loc1.toLocation(null), loc2.toLocation(null));
}
public static float distanceBetweenAngles(float a, float b) {
final float first = a % 360;
final float second = b % 360;
final float delta = Math.abs(first - second);
return (float) Math.abs(Math.min(360.0 - delta, delta));
}
public static float getDistanceBetweenAngles(final float angle1, final float angle2) {
float distance = Math.abs(angle1 - angle2) % 360.0f;
if (distance > 180.0f) {
distance = 360.0f - distance;
}
return distance;
}
//Args: Tuple (a) is low outliers, Tupe (B) is high outliers
public static Tuple<List<Double>, List<Double>> getOutliers(List<Double> values) {
if(values.size() < 4) return new Tuple<>(new ArrayList<>(), new ArrayList<>());
double q1 = getMedian(values.subList(0, values.size() / 2)),
q3 = getMedian(values.subList(values.size() / 2, values.size()));
double iqr = Math.abs(q1 - q3);
double lowThreshold = q1 - 1.5 * iqr, highThreshold = q3 + 1.5 * iqr;
val tuple = new Tuple<List<Double>, List<Double>>(new ArrayList<>(), new ArrayList<>());
for (Double value : values) {
if(value < lowThreshold) tuple.one.add(value);
if(value < lowThreshold) tuple.one.add(value);
else if(value > highThreshold) tuple.two.add(value);
}
return tuple;
}
public static Tuple<List<Float>, List<Float>> getOutliersFloat(List<Float> values) {
if(values.size() < 4) return new Tuple<>(new ArrayList<>(), new ArrayList<>());
double q1 = getMedian(values.subList(0, values.size() / 2)),
q3 = getMedian(values.subList(values.size() / 2, values.size()));
double iqr = Math.abs(q1 - q3);
double lowThreshold = q1 - 1.5 * iqr, highThreshold = q3 + 1.5 * iqr;
val tuple = new Tuple<List<Float>, List<Float>>(new ArrayList<>(), new ArrayList<>());
for (Float value : values) {
if(value < lowThreshold) tuple.one.add(value);
else if(value > highThreshold) tuple.two.add(value);
}
return tuple;
}
public static Tuple<List<Long>, List<Long>> getOutliersLong(List<Long> collection) {
List<Long> values = new ArrayList<>(collection);
if(values.size() < 4) return new Tuple<>(new ArrayList<>(), new ArrayList<>());
double q1 = getMedian(values.subList(0, values.size() / 2)),
q3 = getMedian(values.subList(values.size() / 2, values.size()));
double iqr = Math.abs(q1 - q3);
double lowThreshold = q1 - 1.5 * iqr, highThreshold = q3 + 1.5 * iqr;
val tuple = new Tuple<List<Long>, List<Long>>(new ArrayList<>(), new ArrayList<>());
for (Long value : values) {
if(value < lowThreshold) tuple.one.add(value);
else if(value > highThreshold) tuple.two.add(value);
}
return tuple;
}
public static double getMedian(List<Double> data) {
if(data.size() > 1) {
if (data.size() % 2 == 0)
return (data.get(data.size() / 2) + data.get(data.size() / 2 - 1)) / 2;
else
return data.get(Math.round(data.size() / 2f));
}
return 0;
}
public static double getMedian(Iterable<? extends Number> iterable) {
List<Double> data = new ArrayList<>();
for (Number number : iterable) {
data.add(number.doubleValue());
}
return getMedian(data);
}
//Copied from apache math Kurtosis class.
public static double getKurtosisApache(Iterable<? extends Number> iterable) {
List<Double> values = new ArrayList<>();
double total = 0;
double kurt = Double.NaN;
for (Number number : iterable) {
double v = number.doubleValue();
total+= v;
values.add(v);
}
if(values.size() < 2) return kurt;
double mean = total / values.size();
double stdDev = MathUtils.stdev(values);
double accum3 = 0.0D;
for (Double value : values) {
accum3 += Math.pow(value - mean, 4.0D);
}
accum3 /= Math.pow(stdDev, 4.0D);
double n0 = values.size();
double coefficientOne = n0 * (n0 + 1.0D) / ((n0 - 1.0D) * (n0 - 2.0D) * (n0 - 3.0D));
double termTwo = 3.0D * Math.pow(n0 - 1.0D, 2.0D) / ((n0 - 2.0D) * (n0 - 3.0D));
kurt = coefficientOne * accum3 - termTwo;
return kurt;
}
public static double getKurtosis(final Iterable<? extends Number> iterable) {
double n = 0.0;
double n2 = 0.0;
for (Number number : iterable) {
n += number.doubleValue();
++n2;
}
if (n2 < 3.0) {
return 0.0;
}
final double n3 = n2 * (n2 + 1.0) / ((n2 - 1.0) * (n2 - 2.0) * (n2 - 3.0));
final double n4 = 3.0 * Math.pow(n2 - 1.0, 2.0) / ((n2 - 2.0) * (n2 - 3.0));
final double n5 = n / n2;
double n6 = 0.0;
double n7 = 0.0;
for (final Number n8 : iterable) {
n6 += Math.pow(n5 - n8.doubleValue(), 2.0);
n7 += Math.pow(n5 - n8.doubleValue(), 4.0);
}
return n3 * (n7 / Math.pow(n6 / n2, 2.0)) - n4;
}
public static float pow(float number, int times) {
float answer = number;
if(times <= 0) return 0;
for(int i = 1 ; i < times ; i++) {
answer*= number;
}
return answer;
}
public static double varianceSquared(final Number n, final Iterable<? extends Number> iterable) {
double n2 = 0.0;
int n3 = 0;
for (Number number : iterable) {
n2 += Math.pow((number).doubleValue() - n.doubleValue(), 2.0);
++n3;
}
return (n2 == 0.0) ? 0.0 : (n2 / (n3 - 1));
}
public static List<Double> getModes(final Iterable<? extends Number> iterable) {
List<Double> numbers = new ArrayList<>();
for (Number number : iterable) {
numbers.add(number.doubleValue());
}
final Map<Double, Long> countFrequencies = numbers.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
final double maxFrequency = countFrequencies.values().stream()
.mapToDouble(count -> count)
.max().orElse(-1);
return countFrequencies.entrySet().stream()
.filter(tuple -> tuple.getValue() == maxFrequency)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
//Copied from apache math Skewness class.
public static double getSkewnessApache(Iterable<? extends Number> iterable) {
List<Double> values = new ArrayList<>();
double total = 0;
double skew = Double.NaN;
for (Number number : iterable) {
double v = number.doubleValue();
total+= v;
values.add(v);
}
if(values.size() < 2) return skew;
double m = total / values.size();
double accum = 0.0D;
double accum2 = 0.0D;
for (Double value : values) {
double d = value - m;
accum += d * d;
accum2 += d;
}
double variance = (accum - accum2 * accum2 / values.size()) / (values.size() - 1);
double accum3 = 0.0D;
for (Double value : values) {
double d = value - m;
accum3 += d * d * d;
}
accum3 /= variance * Math.sqrt(variance);
double n0 = values.size();
skew = n0 / ((n0 - 1.0D) * (n0 - 2.0D)) * accum3;
return skew;
}
public static double getSkewness(final Iterable<? extends Number> iterable) {
double sum = 0;
int buffer = 0;
final List<Double> numberList = new ArrayList<>();
for (Number num : iterable) {
sum += num.doubleValue();
buffer++;
numberList.add(num.doubleValue());
}
Collections.sort(numberList);
final double mean = sum / buffer;
final double median = (buffer % 2 != 0) ? numberList.get(buffer / 2) : (numberList.get((buffer - 1) / 2) + numberList.get(buffer / 2)) / 2;
return 3 * (mean - median) / deviationSquared(iterable);
}
public static double stdev(final Iterable<? extends Number> iterable) {
double sum = 0.0f;
double num = 0.0f;
final List<Double> list = new ArrayList<>();
for (Number number : iterable) {
list.add(number.doubleValue());
}
for (Double v : list) {
sum+= v;
}
double mean = sum / (float)list.size();
for (Double v : list) {
num+= Math.pow(v - mean, 2.0D);
}
return MathHelper.sqrt_double(num / (double)list.size());
}
public static double deviationSquared(final Iterable<? extends Number> iterable) {
double n = 0.0;
int n2 = 0;
for (Number anIterable : iterable) {
n += (anIterable).doubleValue();
++n2;
}
final double n3 = n / n2;
double n4 = 0.0;
for (Number anIterable : iterable) {
n4 += Math.pow(anIterable.doubleValue() - n3, 2.0);
}
return (n4 == 0.0) ? 0.0 : (n4 / (n2 - 1));
}
public static int getDecimalCount(float number) {
return String.valueOf(number).split("\\.")[1].length();
}
public static int getDecimalCount(double number) {
return String.valueOf(number).split("\\.")[1].length();
}
public static float clampToVanilla(float s, float angle) {
float f = (s * 0.6f + .2f);
float f2 = f * f * f * 1.2f;
return angle - (angle % f2);
}
public static byte getByte(int num) {
if(num > Byte.MAX_VALUE || num < Byte.MIN_VALUE) {
throw new NumberFormatException("Integer " + num + " too large to cast to data format byte!"
+ " (max=" + Byte.MAX_VALUE + " min=" + Byte.MIN_VALUE + ")");
}
return (byte) num;
}
public static short getShort(int num) {
if(num > Short.MAX_VALUE || num < Short.MIN_VALUE) {
throw new NumberFormatException("Integer " + num + " too large to cast to data format short!"
+ " (max=" + Short.MAX_VALUE + " min=" + Short.MIN_VALUE + ")");
}
return (short) num;
}
/* Stolen from Bukkit */
public static Vector getDirection(KLocation loc) {
Vector vector = new Vector();
double rotX = loc.yaw;
double rotY = loc.pitch;
vector.setY(-Math.sin(Math.toRadians(rotY)));
double xz = Math.cos(Math.toRadians(rotY));
vector.setX(-xz * Math.sin(Math.toRadians(rotX)));
vector.setZ(xz * Math.cos(Math.toRadians(rotX)));
return vector;
}
public static boolean approxEquals(double accuracy, double equalTo, double... equals) {
return Arrays.stream(equals).allMatch(equal -> MathUtils.getDelta(equalTo, equal) < accuracy);
}
public static boolean approxEquals(double accuracy, int equalTo, int... equals) {
return Arrays.stream(equals).allMatch(equal -> MathUtils.getDelta(equalTo, equal) < accuracy);
}
public static boolean approxEquals(double accuracy, long equalTo, long... equals) {
return Arrays.stream(equals).allMatch(equal -> MathUtils.getDelta(equalTo, equal) < accuracy);
}
public static double getDistanceToBox(Vector vec, BoundingBox box) {
return vec.distance(getCenterOfBox(box));
}
public static Vector getCenterOfBox(BoundingBox box) {
return box.getMinimum().midpoint(box.getMaximum());
}
//Returns -1 if fails.
public static <T extends Number> T tryParse(String string) {
try {
return (T)(Number)Double.parseDouble(string);
} catch(NumberFormatException e) {
}
return (T)(Number)(-1);
}
//A lighter version of the Java hypotenuse function.
public static double hypot(double... value) {
double total = 0;
for (double val : value) {
total += (val * val);
}
return Math.sqrt(total);
}
public static float hypot(float... value) {
float total = 0;
for (float val : value) {
total += (val * val);
}
return (float) Math.sqrt(total);
}
public static double get3DDistance(Vector one, Vector two) {
return hypot(one.getX() - two.getX(), one.getY() - two.getY(), one.getZ() - two.getZ());
}
public static boolean playerMoved(Vector from, Vector to) {
return from.distance(to) > 0;
}
public static boolean playerLooked(Location from, Location to) {
return (from.getYaw() - to.getYaw() != 0) || (from.getPitch() - to.getPitch() != 0);
}
public static boolean elapsed(long time, long needed) {
return Math.abs(System.currentTimeMillis() - time) >= needed;
}
//Euclid's algorithim
public static long gcd(long a, long b)
{
while (b > 0)
{
long temp = b;
b = a % b; // % is remainder
a = temp;
}
return a;
}
//Euclid's algorithim
public static long gcd(long... input)
{
long result = input[0];
for(int i = 1; i < input.length; i++) result = gcd(result, input[i]);
return result;
}
// Returns the absolute value of n-mid*mid*mid
static double diff(double n,double mid)
{
if (n > (mid*mid*mid))
return (n-(mid*mid*mid));
else
return ((mid*mid*mid) - n);
}
// Returns cube root of a no n
public static double cbrt(double n)
{
// Set start and end for binary search
double start = 0, end = n;
// Set precision
double e = 0.0000001;
double mid = -1;
double error = 1000;
long ticks = 0;
while (error > e)
{
mid = (start + end)/2;
error = diff(n, mid);
// If error is less than e then mid is
// our answer so return mid
// If mid*mid*mid is greater than n set
// end = mid
if ((mid*mid*mid) > n)
end = mid;
// If mid*mid*mid is less than n set
// start = mid
else
start = mid;
if(error > e && ticks++ > 3E4) {
return -1;
}
}
return mid;
}
//A much lighter but very slightly less accurate Math.sqrt.
@Deprecated
public static double sqrt(double number) {
if(number == 0) return 0;
double t;
double squareRoot = number / 2;
do {
t = squareRoot;
squareRoot = (t + (number / t)) / 2;
} while ((t - squareRoot) != 0);
return squareRoot;
}
public static Vector getDirection(float yaw, float pitch) {
float f = MathHelper.cos(-yaw * 0.017453292F - (float)Math.PI);
float f1 = MathHelper.sin(-yaw * 0.017453292F - (float)Math.PI);
float f2 = -MathHelper.cos(-pitch * 0.017453292F);
float f3 = MathHelper.sin(-pitch * 0.017453292F);
return new Vector(f1 * f2, f3, f * f2);
}
public static float sqrt(float number) {
if(number == 0) return 0;
float t;
float squareRoot = number / 2;
do {
t = squareRoot;
squareRoot = (t + (number / t)) / 2;
} while ((t - squareRoot) != 0);
return squareRoot;
}
public static float normalizeAngle(float yaw) {
return yaw % 360;
}
public static double normalizeAngle(double yaw) {
return yaw % 360;
}
public static float getAngleDelta(float one, float two) {
float delta = getDelta(one, two) % 360f;
if(delta > 180) delta = 360 - delta;
return delta;
}
//Euclid's algorithim
public static long lcm(long a, long b)
{
return a * (b / gcd(a, b));
}
//Euclid's algorithim
public static long lcm(long... input)
{
long result = input[0];
for(int i = 1; i < input.length; i++) result = lcm(result, input[i]);
return result;
}
public static float getDelta(float one, float two) {
return Math.abs(one - two);
}
public static double getDelta(double one, double two) {
return Math.abs(one - two);
}
public static long getDelta(long one, long two) {
return Math.abs(one - two);
}
public static long getDelta(int one, int two) {
return Math.abs(one - two);
}
public static long elapsed(long time) {
return Math.abs(System.currentTimeMillis() - time);
}
public static double getHorizontalDistance(Location from, Location to) {
double deltaX = to.getX() - from.getX(), deltaZ = to.getZ() - from.getZ();
return Math.sqrt(deltaX * deltaX + deltaZ * deltaZ);
}
public static double stdev(Collection<Double> list) {
double sum = 0.0;
double mean;
double num = 0.0;
double numi;
double deno = 0.0;
for (double i : list) {
sum += i;
}
mean = sum / list.size();
for (double i : list) {
numi = Math.pow(i - mean, 2);
num += numi;
}
return Math.sqrt(num / list.size());
}
public static int millisToTicks(long millis) {
return (int) Math.ceil(millis / 50D);
}
public static double getVerticalDistance(Location from, Location to) {
return Math.abs(from.getY() - to.getY());
}
public static int getDistanceToGround(Player p) {
Location loc = p.getLocation().clone();
double y = loc.getBlockY();
int distance = 0;
for (double i = y; i >= 0.0; i -= 1.0) {
loc.setY(i);
if (BlockUtils.getBlock(loc).getType().isSolid() || BlockUtils.getBlock(loc).isLiquid()) break;
++distance;
}
return distance;
}
public static double trim(int degree, double d) {
String format = "#.#";
for (int i = 1; i < degree; ++i) {
format = format + "#";
}
DecimalFormat twoDForm = new DecimalFormat(format);
return Double.parseDouble(twoDForm.format(d).replaceAll(",", "."));
}
public static float trimFloat(int degree, float d) {
String format = "#.#";
for (int i = 1; i < degree; ++i) {
format = format + "#";
}
DecimalFormat twoDForm = new DecimalFormat(format);
return Float.parseFloat(twoDForm.format(d).replaceAll(",", "."));
}
public static double getYawDifference(Location one, Location two) {
return Math.abs(one.getYaw() - two.getYaw());
}
public static double round(double value, int places) {
if (places < 0) {
throw new IllegalArgumentException();
}
if(Double.isNaN(value) || Double.isInfinite(value)) return value;
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
//May not be the best on performance. Let me know if you have a better way to calculate mode.
public static <T extends Number> T getMode(Collection<T> collect) {
Map<T, Integer> repeated = new HashMap<>();
//Sorting each value by how to repeat into a map.
collect.forEach(val -> {
int number = repeated.getOrDefault(val, 0);
repeated.put(val, number + 1);
});
//Calculating the largest value to the key, which would be the mode.
return repeated.keySet().stream()
.map(key -> new Tuple<>(key, repeated.get(key))) //We map it into a Tuple for easier sorting.
.max(Comparator.comparing(tup -> tup.two, Comparator.naturalOrder()))
.orElseThrow(NullPointerException::new).one;
}
public static double round(double value, int places, RoundingMode mode) {
if (places < 0) {
throw new IllegalArgumentException();
}
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, mode);
return bd.doubleValue();
}
public static double round(double value) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(0, RoundingMode.UP);
return bd.doubleValue();
}
public static float round(float value, int places) {
if (places < 0) {
throw new IllegalArgumentException();
}
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.floatValue();
}
public static float round(float value, int places, RoundingMode mode) {
if (places < 0) {
throw new IllegalArgumentException();
}
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, mode);
return bd.floatValue();
}
public static float round(float value) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(0, RoundingMode.UP);
return bd.floatValue();
}
public static int floor(double var0) {
int var2 = (int) var0;
return var0 < var2 ? var2 - 1 : var2;
}
public static float yawTo180F(float flub) {
if ((flub %= 360.0f) >= 180.0f) {
flub -= 360.0f;
}
if (flub < -180.0f) {
flub += 360.0f;
}
return flub;
}
public static double yawTo180D(double dub) {
if ((dub %= 360.0) >= 180.0) {
dub -= 360.0;
}
if (dub < -180.0) {
dub += 360.0;
}
return dub;
}
public static double getDirection(Location from, Location to) {
if (from == null || to == null) {
return 0.0;
}
double difX = to.getX() - from.getX();
double difZ = to.getZ() - from.getZ();
return MathUtils.yawTo180F((float) (FastTrig.fast_atan2(difZ, difX) * 180.0 / 3.141592653589793) - 90.0f);
}
public static float[] getRotations(Location one, Location two) {
double diffX = two.getX() - one.getX();
double diffZ = two.getZ() - one.getZ();
double diffY = two.getY() + 2.0 - 0.4 - (one.getY() + 2.0);
double dist = Math.sqrt(diffX * diffX + diffZ * diffZ);
float yaw = (float) (FastTrig.fast_atan2(diffZ, diffX) * 180.0 / 3.141592653589793) - 90.0f;
float pitch = (float) (-FastTrig.fast_atan2(diffY, dist) * 180.0 / 3.141592653589793);
return new float[]{yaw, pitch};
}
public static float[] getRotations(LivingEntity origin, LivingEntity point) {
Location two = point.getLocation(), one = origin.getLocation();
double diffX = two.getX() - one.getX();
double diffZ = two.getZ() - one.getZ();
double diffY = two.getY() + 2.0 - 0.4 - (one.getY() + 2.0);
double dist = Math.sqrt(diffX * diffX + diffZ * diffZ);
float yaw = (float) (FastTrig.fast_atan2(diffZ, diffX) * 180.0 / 3.141592653589793) - 90.0f;
float pitch = (float) (-FastTrig.fast_atan2(diffY, dist) * 180.0 / 3.141592653589793);
return new float[]{yaw, pitch};
}
public static boolean isLookingTowardsEntity(Location from, Location to, LivingEntity entity) {
float[] rotFrom = getRotations(from, entity.getLocation()), rotTo = getRotations(to, entity.getLocation());
float deltaOne = getDelta(from.getYaw(), rotTo[0]), deltaTwo = getDelta(to.getYaw(), rotTo[1]);
float offsetFrom = getDelta(yawTo180F(from.getYaw()), yawTo180F(rotFrom[0])), offsetTo = getDelta(yawTo180F(to.getYaw()), yawTo180F(rotTo[0]));
return (deltaOne > deltaTwo && offsetTo > 15) || (MathUtils.getDelta(offsetFrom, offsetTo) < 1 && offsetTo < 10);
}
public static double[] getOffsetFromEntity(Player player, LivingEntity entity) {
double yawOffset = Math.abs(MathUtils.yawTo180F(player.getEyeLocation().getYaw()) - MathUtils.yawTo180F(MathUtils.getRotations(player.getLocation(), entity.getLocation())[0]));
double pitchOffset = Math.abs(Math.abs(player.getEyeLocation().getPitch()) - Math.abs(MathUtils.getRotations(player.getLocation(), entity.getLocation())[1]));
return new double[]{yawOffset, pitchOffset};
}
public static double[] getOffsetFromLocation(Location one, Location two) {
double yaw = MathUtils.getRotations(one, two)[0];
double pitch = MathUtils.getRotations(one, two)[1];
double yawOffset = Math.abs(yaw - MathUtils.yawTo180F(one.getYaw()));
double pitchOffset = Math.abs(pitch - one.getPitch());
return new double[]{yawOffset, pitchOffset};
}
}