This commit is contained in:
Dawson
2023-03-22 15:50:05 -04:00
parent 6a4b779b7c
commit 24a1f83d35
85 changed files with 446 additions and 876 deletions
@@ -0,0 +1,143 @@
/*
* Copyright (c) 2018 NGXDEV.COM. Licensed under MIT.
*/
package dev.brighten.ac.packet;
import dev.brighten.ac.utils.reflections.Reflections;
import dev.brighten.ac.utils.reflections.types.WrappedClass;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.bukkit.Bukkit;
import java.util.logging.Level;
//Protocol Version numbers: https://wiki.vg/Protocol_version_numbers
@Getter
@AllArgsConstructor
public enum ProtocolVersion {
V1_7(4, "v1_7_R3"),
V1_7_10(5, "v1_7_R4"),
V1_8(45, "v1_8_R1"),
V1_8_5(46, "v1_8_R2"),
V1_8_9(47, "v1_8_R3"),
V1_9(107, "v1_9_R1"),
V1_9_1(108, "v1_9_R1"),
V1_9_2(109, "v1_9_R2"),
V1_9_4(110, "v1_9_R2"),
V1_10(210, "v1_10_R1"),
V1_10_2(210, "v1_10_R1"),
V1_11(316, "v1_11_R1"),
V1_12(335, "v1_12_R1"),
V1_12_1(338, null),
V1_12_2(340, "v1_12_R1"),
V1_13(350, "v1_13_R1"),
V1_13_1(351, "v1_13_R2"),
V1_13_2(352, "v1_13_R2"),
V1_14(477, "v1_14_R1"),
V1_14_1(480, "v1_14_R1"),
V1_14_2(485, "v1_14_R1"),
V1_14_3(490, "v1_14_R1"),
V1_14_4(498, "v1_14_R1"),
V1_15(573, "v1_15_R1"),
V1_15_1(575, "v1_15_R1"),
V1_15_2(578, "v1_15_R1"),
V1_16(735, "v1_16_R1"),
V1_16_1(736, "v1_16_R1"),
V1_16_2(751, "v1_16_R2"),
V1_16_3(753, "v1_16_R2"),
V1_16_4(754, "v1_16_R3"),
V1_16_5(754, "v1_16_R3"),
V1_17(755, "v1_17_R1"),
V1_17_1(756, "v1_17_R1"),
V1_18(757, "v1_18_R1"),
V1_18_2(758, "v1_18_R2"),
V1_19(759, "v1_19_R1"),
v1_19_1(760, "v1_19_R1"),
UNKNOWN(-1, "UNKNOWN");
@Getter
private static final ProtocolVersion gameVersion = fetchGameVersion();
private final int version;
@Getter
private static boolean paper;
private final String serverVersion;
private static ProtocolVersion fetchGameVersion() {
ProtocolVersion toReturn = UNKNOWN;
for (ProtocolVersion version : values()) {
if (version.getServerVersion() != null && version.getServerVersion().equals(Reflections.VERSION)) {
toReturn = version;
break;
}
}
if(toReturn.isOrAbove(ProtocolVersion.V1_17)) {
WrappedClass mv = Reflections.getNMSClass("MinecraftVersion");
Object mvObject = mv.getFieldByName("a").get(null);
String version = mv.getFieldByType(String.class, 1).get(mvObject);
switch(version) {
case "1.19": {
toReturn = V1_19;
break;
}
case "1.18.2": {
toReturn = V1_18_2;
break;
}
case "1.18.1":
case "1.18": {
toReturn = V1_18;
Bukkit.getLogger().log(Level.INFO, "Version is 1.18");
break;
}
case "1.17.1": {
toReturn = V1_17_1;
break;
}
default: {
toReturn = V1_17;
break;
}
}
}
return toReturn;
}
public static ProtocolVersion getVersion(int versionId) {
for (ProtocolVersion version : values()) {
if (version.getVersion() == versionId) return version;
}
return UNKNOWN;
}
public boolean isBelow(ProtocolVersion version) {
return this.getVersion() < version.getVersion();
}
public boolean isOrBelow(ProtocolVersion version) {
return this.getVersion() <= version.getVersion();
}
public boolean isAbove(ProtocolVersion version) {
return this.getVersion() > version.getVersion();
}
public boolean isOrAbove(ProtocolVersion version) {
return this.getVersion() >= version.getVersion();
}
static {
try {
Class.forName("org.github.paperspigot.PaperSpigotConfig");
paper = true;
} catch(Exception e) {
paper = false;
}
}
}
@@ -0,0 +1,104 @@
package dev.brighten.ac.utils;
public class FastTrig
{
/** Fast approximation of 1.0 / sqrt(x).
* See <a href="http://www.beyond3d.com/content/articles/8/">http://www.beyond3d.com/content/articles/8/</a>
* @param x Positive value to estimate inverse of square root of
* @return Approximately 1.0 / sqrt(x)
**/
public static double
invSqrt(double x)
{
double xhalf = 0.5 * x;
long i = Double.doubleToRawLongBits(x);
i = 0x5FE6EB50C7B537AAL - (i>>1);
x = Double.longBitsToDouble(i);
x = x * (1.5 - xhalf*x*x);
return x;
}
/** Approximation of arctangent.
* Slightly faster and substantially less accurate than
* {@link Math#atan2(double, double)}.
**/
public static double fast_atan2(double y, double x)
{
double d2 = x*x + y*y;
// Bail out if d2 is NaN, zero or subnormal
if (Double.isNaN(d2) ||
(Double.doubleToRawLongBits(d2) < 0x10000000000000L))
{
return Double.NaN;
}
// Normalise such that 0.0 <= y <= x
boolean negY = y < 0.0;
if (negY) {y = -y;}
boolean negX = x < 0.0;
if (negX) {x = -x;}
boolean steep = y > x;
if (steep)
{
double t = x;
x = y;
y = t;
}
// Scale to unit circle (0.0 <= y <= x <= 1.0)
double rinv = invSqrt(d2); // rinv ≅ 1.0 / hypot(x, y)
x *= rinv; // x ≅ cos θ
y *= rinv; // y ≅ sin θ, hence θ ≅ asin y
// Hack: we want: ind = floor(y * 256)
// We deliberately force truncation by adding floating-point numbers whose
// exponents differ greatly. The FPU will right-shift y to match exponents,
// dropping all but the first 9 significant bits, which become the 9 LSBs
// of the resulting mantissa.
// Inspired by a similar piece of C code at
// http://www.shellandslate.com/computermath101.html
double yp = FRAC_BIAS + y;
int ind = (int) Double.doubleToRawLongBits(yp);
// Find φ (a first approximation of θ) from the LUT
double φ = ASIN_TAB[ind];
double = COS_TAB[ind]; // cos(φ)
// sin(φ) == ind / 256.0
// Note that sφ is truncated, hence not identical to y.
double = yp - FRAC_BIAS;
double sd = y * - x * ; // sin(θ-φ) ≡ sinθ cosφ - cosθ sinφ
// asin(sd) ≅ sd + ⅙sd³ (from first 2 terms of Maclaurin series)
double d = (6.0 + sd * sd) * sd * ONE_SIXTH;
double θ = φ + d;
// Translate back to correct octant
if (steep) { θ = Math.PI * 0.5 - θ; }
if (negX) { θ = Math.PI - θ; }
if (negY) { θ = -θ; }
return θ;
}
private static final double ONE_SIXTH = 1.0 / 6.0;
private static final int FRAC_EXP = 8; // LUT precision == 2 ** -8 == 1/256
private static final int LUT_SIZE = (1 << FRAC_EXP) + 1;
private static final double FRAC_BIAS =
Double.longBitsToDouble((0x433L - FRAC_EXP) << 52);
private static final double[] ASIN_TAB = new double[LUT_SIZE];
private static final double[] COS_TAB = new double[LUT_SIZE];
static
{
/* Populate trig tables */
for (int ind = 0; ind < LUT_SIZE; ++ ind)
{
double v = ind / (double) (1 << FRAC_EXP);
double asinv = Math.asin(v);
COS_TAB[ind] = Math.cos(asinv);
ASIN_TAB[ind] = asinv;
}
}
}
@@ -0,0 +1,132 @@
package dev.brighten.ac.utils;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.util.Vector;
import java.util.Objects;
public class KLocation implements Cloneable {
public double x, y, z;
public float yaw, pitch;
public long timeStamp;
public KLocation(double x, double y, double z, float yaw, float pitch, long timeStamp) {
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
this.timeStamp = timeStamp;
}
public KLocation(double x, double y, double z, float yaw, float pitch) {
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
this.timeStamp = System.currentTimeMillis();
}
public KLocation(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
this.timeStamp = System.currentTimeMillis();
}
public KLocation(Vector vector) {
this.x = vector.getX();
this.y = vector.getY();
this.z = vector.getZ();
this.timeStamp = System.currentTimeMillis();
}
public KLocation(Location location) {
this.x = location.getX();
this.y = location.getY();
this.z = location.getZ();
this.yaw = location.getYaw();
this.pitch = location.getPitch();
this.timeStamp = System.currentTimeMillis();
}
public Vector toVector() {
return new Vector(x, y, z);
}
public Location toLocation(World world) {
return new Location(world, x, y, z, yaw, pitch);
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public KLocation clone() {
return new KLocation(x, y, z, yaw, pitch, timeStamp);
}
public double distanceSquared(KLocation other) {
double dx = (x - other.x), dy = (y - other.y), dz = (z - other.z);
return dx * dx + dy * dy + dz * dz;
}
public double distance(KLocation other) {
return Math.sqrt(distanceSquared(other));
}
public KLocation add(double x, double y, double z) {
this.x+= x;
this.y+= y;
this.z+= z;
return this;
}
public KLocation subtract(double x, double y, double z) {
this.x-= x;
this.y-= y;
this.z-= z;
return this;
}
public KLocation setLocation(KLocation loc) {
this.x = loc.x;
this.y = loc.y;
this.z = loc.z;
this.yaw = loc.yaw;
this.pitch = loc.pitch;
this.timeStamp = loc.timeStamp;
return this;
}
public Vector getDirection() {
return MathUtils.getDirection(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KLocation kLocation = (KLocation) o;
return Double.compare(kLocation.x, x) == 0 && Double.compare(kLocation.y, y) == 0 && Double.compare(kLocation.z, z) == 0 && Float.compare(kLocation.yaw, yaw) == 0 && Float.compare(kLocation.pitch, pitch) == 0 && timeStamp == kLocation.timeStamp;
}
@Override
public int hashCode() {
return Objects.hash(x, y, z, yaw, pitch, timeStamp);
}
@Override
public String toString() {
return "KLocation{" +
"x=" + x +
", y=" + y +
", z=" + z +
", yaw=" + yaw +
", pitch=" + pitch +
", timeStamp=" + timeStamp +
'}';
}
}
@@ -0,0 +1,930 @@
package dev.brighten.ac.utils;
import lombok.val;
import me.hydro.emulator.util.mcp.MathHelper;
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;
//
@SuppressWarnings("unused")
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();
}
/**
* Get Average
*
* @return double
*/
public static double getAverage(List<Double> list) {
double sum = 0;
for (double d : list) {
sum += d;
}
return sum / list.size();
}
public static double getAverage(double[] list) {
double sum = 0;
for (double d : list) {
sum += d;
}
return sum / list.length;
}
public static double getAverage(int[] list) {
double sum = 0;
for (double d : list) {
sum += d;
}
return sum / list.length;
}
public static float getAverage(float[] list) {
float sum = 0;
for (float d : list) {
sum += d;
}
return sum / list.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;
}
public static double getGrid(final 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.length;
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.getRotation(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 = getMedianFloat(values.subList(0, values.size() / 2)),
q3 = getMedianFloat(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 = MathUtils.getMedianFloat(values.subList(0, values.size() / 2)),
q3 = MathUtils.getMedianFloat(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 = getMedianFloat(values.subList(0, values.size() / 2)),
q3 = getMedianFloat(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) {
return calculateDoubleMedian(data);
}
public static float getMedianFloat(List<Float> 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 getMedianFloat(Iterable<? extends Number> iterable) {
List<Double> data = new ArrayList<>();
for (Number number : iterable) {
data.add(number.doubleValue());
}
return calculateDoubleMedian(data);
}
private static double calculateDoubleMedian(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;
}
//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);
}
//Returns -1 if fails.
public static Number tryParse(String string) {
try {
return Double.parseDouble(string);
} catch(NumberFormatException exception) {
return (-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 hypotSqrt(double left, double right) {
return (left * left) + (right * right);
}
public static float hypotSqrt(float left, float right) {
return (left * left) + (right * right);
}
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(MathHelper.FastMathType.VANILLA, -yaw * 0.017453292F - (float)Math.PI);
float f1 = MathHelper.sin(MathHelper.FastMathType.VANILLA, -yaw * 0.017453292F - (float)Math.PI);
float f2 = -MathHelper.cos(MathHelper.FastMathType.VANILLA, -pitch * 0.017453292F);
float f3 = MathHelper.sin(MathHelper.FastMathType.VANILLA, -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 double trim(int degree, double d) {
DecimalFormat twoDForm = new DecimalFormat("#.#" + "#".repeat(Math.max(0, degree - 1)));
return Double.parseDouble(twoDForm.format(d).replaceAll(",", "."));
}
public static float trimFloat(int degree, float d) {
DecimalFormat twoDForm = new DecimalFormat("#.#" + "#".repeat(Math.max(0, degree - 1)));
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[] getRotation(Location one, Location two) {
return getRotation(new KLocation(one), new KLocation(two));
}
public static float[] getRotation(KLocation one, KLocation two) {
double diffX = two.x - one.x;
double diffZ = two.z - one.z;
double diffY = two.y - one.y;
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[] getRotation(LivingEntity origin, LivingEntity point) {
return getRotation(origin.getLocation(), point.getLocation());
}
public static boolean isLookingTowardsEntity(Location from, Location to, LivingEntity entity) {
float[] rotFrom = getRotation(from, entity.getLocation()), rotTo = getRotation(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.getRotation(player.getLocation(), entity.getLocation())[0]));
double pitchOffset = Math.abs(Math.abs(player.getEyeLocation().getPitch()) - Math.abs(MathUtils.getRotation(player.getLocation(), entity.getLocation())[1]));
return new double[]{yawOffset, pitchOffset};
}
public static double[] getOffsetFromLocation(Location one, Location two) {
double yaw = MathUtils.getRotation(one, two)[0];
double pitch = MathUtils.getRotation(one, two)[1];
double yawOffset = Math.abs(yaw - MathUtils.yawTo180F(one.getYaw()));
double pitchOffset = Math.abs(pitch - one.getPitch());
return new double[]{yawOffset, pitchOffset};
}
}
@@ -0,0 +1,36 @@
package dev.brighten.ac.utils;
import lombok.NoArgsConstructor;
import java.util.Objects;
@NoArgsConstructor
public class Tuple<A, B> {
public A one;
public B two;
public Tuple(A one, B two) {
this.one = one;
this.two = two;
}
public boolean equals(Object object) {
if (this.getClass().isInstance(object)) {
var toCompare = (Tuple<?, ?>) object;
return one.equals(toCompare.one) && two.equals(toCompare.two);
} else return false;
}
@Override
public String toString() {
return "Tuple{" +
"one=" + one +
", two=" + two +
'}';
}
@Override
public int hashCode() {
return Objects.hash(one, two);
}
}
@@ -0,0 +1,9 @@
package dev.brighten.ac.utils.objects;
import dev.brighten.ac.utils.Tuple;
@FunctionalInterface
public interface BiSupplier<T, V> {
Tuple<T, V> get();
}
@@ -0,0 +1,71 @@
package dev.brighten.ac.utils.objects;
import dev.brighten.ac.utils.MathUtils;
import java.util.Collections;
import java.util.DoubleSummaryStatistics;
import java.util.LinkedList;
import java.util.stream.DoubleStream;
import java.util.stream.Stream;
public class Interval extends LinkedList<Double> {
private final long max;
public Interval(long max) {
this.max = max;
}
public Interval(Interval in) {
this.max = in.max;
}
public double average() {
return getDoubleStream().summaryStatistics().getAverage();
}
public DoubleSummaryStatistics getSummary() {
return getDoubleStream().summaryStatistics();
}
public double frequency(double freq) {
return Collections.frequency(this, freq);
}
public long distinctCount() {
return getDoubleStream().distinct().count();
}
public Stream<Double> distinct() {
return stream().distinct();
}
public double std() {
return MathUtils.stdev(this);
}
public double max() {
return getDoubleStream().summaryStatistics().getMax();
}
public double min() {
return getDoubleStream().summaryStatistics().getMin();
}
public boolean add(double x) {
if (size() == max) {
removeLast();
}
addFirst(x);
return true;
}
public void clearIfMax() {
if (size() == max) {
this.clear();
}
}
public DoubleStream getDoubleStream() {
return stream().mapToDouble(val -> val);
}
}
@@ -0,0 +1,87 @@
package dev.brighten.ac.utils.objects;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.BiFunction;
import java.util.function.Function;
public class MethodFunction {
private Function function;
private BiFunction biFunc;
private TriFunction triFunc;
private QuadFunction quadFunc;
private final Method method;
public MethodFunction(Method method, Function function) {
this.function = function;
this.method = method;
method.setAccessible(true);
}
public MethodFunction(Method method, BiFunction biFunc) {
this.biFunc = biFunc;
this.method = method;
method.setAccessible(true);
}
public MethodFunction(Method method, TriFunction triFunc) {
this.triFunc = triFunc;
this.method = method;
method.setAccessible(true);
}
public MethodFunction(Method method, QuadFunction quadFunc) {
this.quadFunc = quadFunc;
this.method = method;
method.setAccessible(true);
}
public MethodFunction(Method method) {
this.method = method;
method.setAccessible(true);
}
//Apparently not allowed to convert Function from Object. I guess it's because they're an interface :/.
/*public MethodFunction(Method method, Object objFunc) {
if(objFunc instanceof Function) {
this.function = (Function) objFunc;
} else if(objFunc instanceof BiFunction) {
this.biFunc = (BiFunction) objFunc;
} else if(objFunc instanceof TriFunction) {
this.triFunc = (TriFunction) objFunc;
} else if(objFunc instanceof QuadFunction) {
this.quadFunc = (QuadFunction) objFunc;
}
}*/
/** Maximum arguments of 3 **/
public <T> T invokeMethod(Object instance, Object... args) {
if(args.length <= 3) {
if(function != null) {
return (T) function.apply(instance);
} else if(biFunc != null) {
return (T) biFunc.apply(instance, getArgOrNull(args, 0));
} else if(triFunc != null) {
return (T) triFunc.apply(instance, getArgOrNull(args, 0),
getArgOrNull(args, 1));
} else if(quadFunc != null) {
return (T) quadFunc.apply(instance, getArgOrNull(args, 0),
getArgOrNull(args, 1), getArgOrNull(args, 2));
}
}
try {
return (T) method.invoke(instance, args);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
private static <T> T getArgOrNull(T[] array, int index) {
if(array.length > index) {
return array[index];
}
return null;
}
}
@@ -0,0 +1,6 @@
package dev.brighten.ac.utils.objects;
@FunctionalInterface
public interface MultiFunction<R> {
R apply(Object... o);
}
@@ -0,0 +1,7 @@
package dev.brighten.ac.utils.objects;
@FunctionalInterface
public interface QuadFunction<R, T, U, V, G>{
R apply(T t, U u, V v, G g);
}
@@ -0,0 +1,119 @@
package dev.brighten.ac.utils.objects;
import org.bukkit.Bukkit;
import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class RemoteClassLoader extends ClassLoader {
private final byte[] jarBytes;
public final Set<String> names;
public Map<String, Class> classes = new HashMap<>();
public RemoteClassLoader(byte[] jarBytes, ClassLoader parent) throws IOException {
super(parent);
this.jarBytes = jarBytes;
this.names = RemoteClassLoader.loadNames(jarBytes);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
if(names != null) {
names.forEach(name -> {
try {
String shit = name.replace(".class", "shitnibba123@")
.replace("/", ".")
.replace("shitnibba123@", ".class");
classes.put(shit,
getClass(shit));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
});
} else Bukkit.getLogger().warning("names null.");
}
/**
* This will put all the entries into a thread-safe Set
*/
private static Set<String> loadNames(byte[] jarBytes) throws IOException {
Set<String> set = new HashSet<>();
try (ZipInputStream jis =
new ZipInputStream(new ByteArrayInputStream(jarBytes))) {
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
set.add(entry.getName());
}
}
return set;
}
@Override
public InputStream getResourceAsStream(String name) {
// I moved the JarInputStream declaration outside the
// try-with-resources statement as it must not be closed otherwise
// the returned InputStream won't be readable as already closed
boolean found = false;
ZipInputStream jis = null;
try {
jis = new ZipInputStream(new ByteArrayInputStream(jarBytes));
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
if (entry.getName().equals(name)) {
found = true;
return jis;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// Only close the stream if the entry could not be found
if (jis != null && !found) {
try {
jis.close();
} catch (IOException e) {
// ignore me
}
}
}
return null;
}
@Override
public Class findClass(String name) throws ClassNotFoundException {
if(!classes.containsKey(name)) {
byte[] b = loadClassFromFile(name);
return defineClass(name, b, 0, b.length);
} else return classes.get(name);
}
private Class getClass(String name) throws ClassNotFoundException {
byte[] b = loadClassFromFile(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassFromFile(String fileName) {
String name = fileName.replace(".class", "shitguy123@").replace('.', File.separatorChar).replace("shitguy123@", ".class") + (!fileName.contains(".class") ? ".class" : "");
InputStream inputStream = getResourceAsStream(name);
byte[] buffer;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = 0;
try {
if(inputStream != null) {
while ( (nextValue = inputStream.read()) != -1 ) {
byteStream.write(nextValue);
}
}
} catch (IOException e) {
e.printStackTrace();
}
buffer = byteStream.toByteArray();
return buffer;
}
}
@@ -0,0 +1,7 @@
package dev.brighten.ac.utils.objects;
@FunctionalInterface
public interface TriFunction<R, T, U, V> {
R apply(T t, U u, V v);
}
@@ -0,0 +1,17 @@
package dev.brighten.ac.utils.objects;
import lombok.RequiredArgsConstructor;
import java.util.function.BooleanSupplier;
@RequiredArgsConstructor
public class VariableValue<T> {
private final T isTrue;
private final T isFalse;
private final BooleanSupplier variable;
public T get() {
return variable.getAsBoolean() ? isTrue : isFalse;
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018 NGXDEV.COM. Licensed under MIT.
* Modified by funkemunky.
*/
package dev.brighten.ac.utils.objects.evicting;
import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Stream;
public class ConcurrentEvictingList<T> extends ConcurrentLinkedDeque<T> {
private final int maxSize;
public ConcurrentEvictingList(int maxSize) {
this.maxSize = maxSize;
}
public ConcurrentEvictingList(Collection<? extends T> c, int maxSize) {
super(c);
this.maxSize = maxSize;
}
public int getMaxSize() {
return maxSize;
}
@Override
public boolean add(T t) {
if (size() >= maxSize) remove(0);
return super.add(t);
}
@Override
public boolean addAll(Collection<? extends T> c) {
return c.stream().anyMatch(this::add);
}
@Override
public Stream<T> stream() {
return new CopyOnWriteArrayList<>(this).stream();
}
}
@@ -0,0 +1,50 @@
package dev.brighten.ac.utils.objects.evicting;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
@RequiredArgsConstructor
public class ConcurrentEvictingMap<K, V> extends ConcurrentSkipListMap<K, V> {
@Getter
private final int size;
@Override
public V putIfAbsent(K key, V value) {
if(!value.equals(get(key)))
checkAndRemove();
return super.putIfAbsent(key, value);
}
@Override
public V put(K key, V value) {
checkAndRemove();
return super.put(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
m.forEach(this::put);
}
@Override
public void clear() {
super.clear();
}
@Override
public V remove(Object key) {
return super.remove(key);
}
private boolean checkAndRemove() {
if(size() >= size) {
entrySet().remove(firstEntry());
return true;
}
return false;
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018 NGXDEV.COM. Licensed under MIT.
* Modified by funkemunky.
*/
package dev.brighten.ac.utils.objects.evicting;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Stream;
public class EvictingList<T> extends LinkedList<T> {
private final int maxSize;
public EvictingList(int maxSize) {
this.maxSize = maxSize;
}
public EvictingList(Collection<? extends T> c, int maxSize) {
super(c);
this.maxSize = maxSize;
}
public int getMaxSize() {
return maxSize;
}
@Override
public boolean add(T t) {
if (size() >= maxSize) removeFirst();
return super.add(t);
}
@Override
public boolean addAll(Collection<? extends T> c) {
return c.stream().anyMatch(this::add);
}
@Override
public Stream<T> stream() {
return new CopyOnWriteArrayList<>(this).stream();
}
}
@@ -0,0 +1,19 @@
package dev.brighten.ac.utils.objects.evicting;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.LinkedHashMap;
import java.util.Map;
@RequiredArgsConstructor
public class EvictingMap<K, V> extends LinkedHashMap<K, V> {
@Getter
private final int size;
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() >= size;
}
}
@@ -0,0 +1,53 @@
package dev.brighten.ac.utils.objects.filtered;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class ConcurrentFilteredList<T> extends CopyOnWriteArrayList<T> {
private final Predicate<T> predicate;
public ConcurrentFilteredList(Predicate<T> predicate) {
this.predicate = predicate;
}
@Override
public boolean add(T t) {
if(predicate.test(t)) {
return super.add(t);
}
return false;
}
@Override
public boolean addAll(Collection<? extends T> c) {
List<? extends T> filtered = c.stream().filter(predicate).collect(Collectors.toList());
return super.addAll(filtered);
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
List<? extends T> filtered = c.stream().filter(predicate).collect(Collectors.toList());
return super.addAll(index, filtered);
}
@Override
public void add(int index, T element) {
if(predicate.test(element)) {
super.add(index, element);
}
}
@Override
public T set(int index, T element) {
if(predicate.test(element)) {
return super.set(index, element);
}
return size() > index ? get(index) : null;
}
}
@@ -0,0 +1,32 @@
package dev.brighten.ac.utils.objects.filtered;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class ConcurrentFilteredSet<T> extends ConcurrentSkipListSet<T> {
private final Predicate<T> predicate;
public ConcurrentFilteredSet(Predicate<T> predicate) {
this.predicate = predicate;
}
@Override
public boolean add(T t) {
if(predicate.test(t)) {
return super.add(t);
}
return false;
}
@Override
public boolean addAll(Collection<? extends T> c) {
List<? extends T> filtered = c.stream().filter(predicate).collect(Collectors.toList());
return super.addAll(filtered);
}
}
@@ -0,0 +1,53 @@
package dev.brighten.ac.utils.objects.filtered;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class FilteredList<T> extends ArrayList<T> {
private final Predicate<T> predicate;
public FilteredList(Predicate<T> predicate) {
this.predicate = predicate;
}
@Override
public boolean add(T t) {
if(predicate.test(t)) {
return super.add(t);
}
return false;
}
@Override
public boolean addAll(Collection<? extends T> c) {
List<? extends T> filtered = c.stream().filter(predicate).collect(Collectors.toList());
return super.addAll(filtered);
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
List<? extends T> filtered = c.stream().filter(predicate).collect(Collectors.toList());
return super.addAll(index, filtered);
}
@Override
public void add(int index, T element) {
if(predicate.test(element)) {
super.add(index, element);
}
}
@Override
public T set(int index, T element) {
if(predicate.test(element)) {
return super.set(index, element);
}
return size() > index ? get(index) : null;
}
}
@@ -0,0 +1,32 @@
package dev.brighten.ac.utils.objects.filtered;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class FilteredSet<T> extends HashSet<T> {
private final Predicate<T> predicate;
public FilteredSet(Predicate<T> predicate) {
this.predicate = predicate;
}
@Override
public boolean add(T t) {
if(predicate.test(t)) {
return super.add(t);
}
return false;
}
@Override
public boolean addAll(Collection<? extends T> c) {
List<? extends T> filtered = c.stream().filter(predicate).collect(Collectors.toList());
return super.addAll(filtered);
}
}
@@ -0,0 +1,95 @@
package dev.brighten.ac.utils.objects.listmap;
import lombok.val;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentListMap<K, V> implements ListMap<K, V> {
private final Map<K, List<V>> values = new ConcurrentHashMap<>();
@Override
public List<V> getList(K key) {
createIfNotExists(key);
return values.get(key);
}
@Override
public void createIfNotExists(K key) {
if(!values.containsKey(key))
values.put(key, new ArrayList<>());
}
@Override
public void add(K key, V value) {
val list = getList(key);
list.add(value);
values.put(key, list);
}
@Override
public int remove(V value) {
int removed = 0;
for (K k : values.keySet()) {
List<V> vals = values.get(k);
for (V val : vals) {
if(!val.equals(value)) continue;
vals.remove(val);
values.put(k, vals);
removed++;
}
}
return removed;
}
@Override
public boolean remove(K key, V value) {
val vals = getList(key);
boolean removed = vals.remove(value);
if(removed) {
values.put(key, vals);
return true;
}
return false;
}
@Override
public List<V> removeKey(K key) {
return values.remove(key);
}
@Override
public boolean clear() {
if(values.size() > 0) {
values.clear();
}
return false;
}
@Override
public ContainsResult containsValue(V value) {
for (K key : values.keySet()) {
val list = values.get(key);
for (V v : list) {
if(value.equals(v)) return new ContainsResult(key, true);
}
}
return new ContainsResult(null, false);
}
@Override
public boolean containsKey(K key) {
return values.containsKey(key);
}
}
@@ -0,0 +1,95 @@
package dev.brighten.ac.utils.objects.listmap;
import lombok.val;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HashListMap<K, V> implements ListMap<K, V> {
private final Map<K, List<V>> values = new HashMap<>();
@Override
public List<V> getList(K key) {
createIfNotExists(key);
return values.get(key);
}
@Override
public void createIfNotExists(K key) {
if(!values.containsKey(key))
values.put(key, new ArrayList<>());
}
@Override
public void add(K key, V value) {
val list = getList(key);
list.add(value);
values.put(key, list);
}
@Override
public int remove(V value) {
int removed = 0;
for (K k : values.keySet()) {
List<V> vals = values.get(k);
for (V val : vals) {
if(!val.equals(value)) continue;
vals.remove(val);
values.put(k, vals);
removed++;
}
}
return removed;
}
@Override
public boolean remove(K key, V value) {
val vals = getList(key);
boolean removed = vals.remove(value);
if(removed) {
values.put(key, vals);
return true;
}
return false;
}
@Override
public List<V> removeKey(K key) {
return values.remove(key);
}
@Override
public boolean clear() {
if(values.size() > 0) {
values.clear();
}
return false;
}
@Override
public ContainsResult containsValue(V value) {
for (K key : values.keySet()) {
val list = values.get(key);
for (V v : list) {
if(value.equals(v)) return new ContainsResult(key, true);
}
}
return new ContainsResult(null, false);
}
@Override
public boolean containsKey(K key) {
return values.containsKey(key);
}
}
@@ -0,0 +1,36 @@
package dev.brighten.ac.utils.objects.listmap;
import lombok.Getter;
import java.util.List;
public interface ListMap<K, V> {
List<V> getList(K key);
void createIfNotExists(K key);
void add(K key, V value);
int remove(V value);
boolean remove(K key, V value);
List<V> removeKey(K key);
boolean clear();
ContainsResult containsValue(V value);
boolean containsKey(K key);
@Getter
class ContainsResult {
private final boolean result;
private final Object key;
protected ContainsResult(Object key, boolean result) {
this.key = key;
this.result = result;
}
}
}
@@ -0,0 +1,112 @@
/*
* Created by Justin Heflin on 4/19/18 8:21 PM
* Copyright (c) 2018.
*
* Can be redistributed non commercially as long as credit is given to original copyright owner.
*
* last modified: 4/19/18 7:22 PM
*/
package dev.brighten.ac.utils.reflections;
import dev.brighten.ac.utils.objects.QuadFunction;
import dev.brighten.ac.utils.objects.TriFunction;
import dev.brighten.ac.utils.reflections.types.WrappedClass;
import dev.brighten.ac.packet.ProtocolVersion;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.val;
import org.bukkit.Bukkit;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.function.BiFunction;
import java.util.function.Function;
@Getter
public class Reflections {
private static final String craftBukkitString;
private static final String netMinecraftServerString;
private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
public static String OBC_PREFIX = Bukkit.getServer().getClass().getPackage().getName();
public static String VERSION = OBC_PREFIX.replace("org.bukkit.craftbukkit", "")
.replace(".", "");
static {
String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
craftBukkitString = "org.bukkit.craftbukkit." + version + ".";
netMinecraftServerString = "net.minecraft.server." + version + ".";
}
public static boolean classExists(String name) {
try {
Class.forName(name);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
public static WrappedClass getCBClass(String name) {
return getClass(craftBukkitString + name);
}
@SneakyThrows
public static WrappedClass getNMSClass(String name) {
try {
return getClass(netMinecraftServerString + name);
} catch(Throwable e) {
throw new ClassNotFoundException(name);
}
}
public static WrappedClass getClass(String name) {
try {
return new WrappedClass(Class.forName(name));
} catch (ClassNotFoundException | NoClassDefFoundError e) {
throw new NullPointerException("Class" + name + " could not be found!");
}
}
public static WrappedClass getUtilClass(String name) {
return getClass((ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)
? "net.minecraft.util." : "") + name.replace("dev.brighten.ac.utils.", ""));
}
@SneakyThrows
public static <T> T createMethodLambda(Method method) {
if(!method.isAccessible()) return null;
val handle = lookup.unreflect(method);
Class<?> functionType;
switch(method.getParameterCount()) {
case 0:
functionType = Function.class;
break;
case 1:
functionType = BiFunction.class;
break;
case 2:
functionType = TriFunction.class;
break;
case 3:
functionType = QuadFunction.class;
default:
functionType = null;
break;
}
if(functionType != null) {
return (T) LambdaMetafactory.metafactory(lookup, "apply",
MethodType.methodType(functionType),
MethodType.methodType(method.getReturnType(), handle.type().parameterArray()),
handle, handle.type()).getTarget().invoke();
}
return null;
}
public static WrappedClass getClass(Class clazz) {
return new WrappedClass(clazz);
}
}
@@ -0,0 +1,106 @@
package dev.brighten.ac.utils.reflections.impl;
import dev.brighten.ac.utils.reflections.Reflections;
import dev.brighten.ac.utils.reflections.types.WrappedClass;
import dev.brighten.ac.utils.reflections.types.WrappedMethod;
import dev.brighten.ac.packet.ProtocolVersion;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class CraftReflection {
public static WrappedClass craftHumanEntity = Reflections.getCBClass("entity.CraftHumanEntity"); //1.7-1.14
public static WrappedClass craftEntity = Reflections.getCBClass("entity.CraftEntity"); //1.7-1.14
public static WrappedClass craftItemStack = Reflections.getCBClass("inventory.CraftItemStack"); //1.7-1.14
public static WrappedClass craftBlock = Reflections.getCBClass("block.CraftBlock"); //1.7-1.14
public static WrappedClass craftPlayer = Reflections.getCBClass("entity.CraftPlayer");
public static WrappedClass craftWorld = Reflections.getCBClass("CraftWorld"); //1.7-1.14
public static WrappedClass craftInventoryPlayer = Reflections.getCBClass("inventory.CraftInventoryPlayer"); //1.7-1.14
public static WrappedClass craftServer = Reflections.getCBClass("CraftServer"); //1.7-1.14\
public static WrappedClass craftChunk = Reflections.getCBClass("CraftChunk");
public static WrappedClass craftMagicNumbers = Reflections.getCBClass("util.CraftMagicNumbers");
public static WrappedClass craftChatMessage = Reflections.getCBClass("util.CraftChatMessage");
//Vanilla Instances
private static final WrappedMethod itemStackInstance = craftItemStack.getMethod("asNMSCopy", ItemStack.class); //1.7-1.14
private static final WrappedMethod humanEntityInstance = craftHumanEntity.getMethod("getHandle"); //1.7-1.14
private static final WrappedMethod entityInstance = craftEntity.getMethod("getHandle"); //1.7-1.14
private static final WrappedMethod blockInstance = craftBlock.getMethod(ProtocolVersion.getGameVersion()
.isOrAbove(ProtocolVersion.V1_17_1) ? "getNMS" : "getNMSBlock"); //1.7-1.14
private static final WrappedMethod worldInstance = craftWorld.getMethod("getHandle"); //1.7-1.14
private static final WrappedMethod bukkitEntity = MinecraftReflection.entity.getMethod("getBukkitEntity"); //1.7-1.14
private static final WrappedMethod getInventory = craftInventoryPlayer.getMethod("getInventory"); //1.7-1.14
private static final WrappedMethod mcServerInstance = craftServer.getMethod("getServer"); //1.7-1.14
private static final WrappedMethod entityPlayerInstance = craftPlayer.getMethod("getHandle");
private static final WrappedMethod chunkInstance = craftChunk.getMethod("getHandle");
private static final WrappedMethod methodGetBlockFromMaterial = ProtocolVersion.getGameVersion()
.isOrAbove(ProtocolVersion.V1_13) ? craftMagicNumbers.getMethod("getBlock", Material.class)
: craftMagicNumbers.getMethod("getBlock", int.class);
private static WrappedMethod fromComponent;
public static <T> T getVanillaItemStack(ItemStack stack) {
return itemStackInstance.invoke(null, stack);
}
public static <T> T getEntityHuman(HumanEntity entity) {
return humanEntityInstance.invoke(entity);
}
public static <T> T getEntity(Entity entity) {
return entityInstance.invoke(entity);
}
public static <T> T getEntityPlayer(Player player) {
return entityPlayerInstance.invoke(player);
}
public static <T> T getVanillaBlock(Block block) {
return blockInstance.invoke(block);
}
public static <T> T getVanillaWorld(World world) {
return worldInstance.invoke(world);
}
public static Entity getBukkitEntity(Object vanillaEntity) {
return bukkitEntity.invoke(vanillaEntity);
}
public static <T> T getVanillaInventory(Player player) {
return getInventory.invoke(player.getInventory());
}
public static <T> T getMinecraftServer() {
return mcServerInstance.invoke(Bukkit.getServer());
}
public static <T> T getVanillaChunk(Chunk chunk) {
return chunkInstance.invoke(chunk);
}
public static <T> T getVanillaBlock(Material material) {
if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) {
return methodGetBlockFromMaterial.invoke(null, material);
} else {
return methodGetBlockFromMaterial.invoke(null, material.getId());
}
}
public static String getMessageFromComp(Object ichatcomp, String defaultColor) {
if(fromComponent == null) return "Not a usable version (1.8+ only)";
return fromComponent.invoke(null, ichatcomp);
}
static {
if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) {
fromComponent = craftChatMessage.getMethod("fromComponent",
MinecraftReflection.iChatBaseComponent.getParent());
}
}
}
@@ -0,0 +1,356 @@
package dev.brighten.ac.utils.reflections.impl;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.utils.reflections.Reflections;
import dev.brighten.ac.utils.reflections.types.WrappedClass;
import dev.brighten.ac.utils.reflections.types.WrappedConstructor;
import dev.brighten.ac.utils.reflections.types.WrappedField;
import dev.brighten.ac.utils.reflections.types.WrappedMethod;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class MinecraftReflection {
public static WrappedClass entity = Reflections.getNMSClass("Entity");
public static WrappedClass axisAlignedBB = Reflections.getNMSClass("AxisAlignedBB");
public static WrappedClass entityHuman = Reflections.getNMSClass("EntityHuman");
public static WrappedClass entityLiving = Reflections.getNMSClass("EntityLiving");
public static WrappedClass block = Reflections.getNMSClass("Block");
public static WrappedClass iBlockData, blockBase,
chunkProviderServer = Reflections.getNMSClass("ChunkProviderServer");
public static WrappedClass itemClass = Reflections.getNMSClass("Item"),
enumChatFormat = Reflections.getNMSClass("EnumChatFormat");
public static WrappedClass world = Reflections.getNMSClass("World");
public static WrappedClass worldServer = Reflections.getNMSClass("WorldServer");
public static WrappedClass playerInventory = Reflections.getNMSClass("PlayerInventory");
public static WrappedClass itemStack = Reflections.getNMSClass("ItemStack"),
item = Reflections.getNMSClass("Item");
public static WrappedClass chunk = Reflections.getNMSClass("Chunk");
public static WrappedClass classBlockInfo;
public static WrappedClass minecraftServer = Reflections.getNMSClass("MinecraftServer");
public static WrappedClass entityPlayer = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_17)
? Reflections.getClass("net.minecraft.server.level.EntityPlayer")
: Reflections.getNMSClass("EntityPlayer");
public static WrappedClass playerConnection = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_17)
? Reflections.getClass("net.minecraft.server.network.PlayerConnection")
: Reflections.getNMSClass("PlayerConnection");
public static WrappedClass networkManager = Reflections.getNMSClass("NetworkManager");
public static WrappedClass serverConnection = Reflections.getNMSClass("ServerConnection");
public static WrappedClass gameProfile = Reflections.getUtilClass("com.mojang.authlib.GameProfile");
private static final WrappedClass propertyMap = Reflections.getUtilClass("com.mojang.authlib.properties.PropertyMap");
private static final WrappedClass forwardMultiMap = Reflections.getUtilClass("com.google.common.collect.ForwardingMultimap");
public static WrappedClass iChatBaseComponent = Reflections.getNMSClass("IChatBaseComponent"),
chatComponentText;
public static WrappedClass vec3D = Reflections.getNMSClass("Vec3D");
private static final WrappedMethod getProfile = CraftReflection.craftPlayer.getMethod("getProfile");
private static final WrappedMethod methodGetServerConnection = minecraftServer
.getMethodByType(serverConnection.getParent(), ProtocolVersion.getGameVersion()
.isBelow(ProtocolVersion.V1_13) ? 1 : 0);
private static WrappedConstructor chatComponentTextConst;
private static final WrappedMethod getProperties = gameProfile.getMethod("getProperties");
private static final WrappedMethod removeAll = forwardMultiMap.getMethod("removeAll", Object.class);
private static final WrappedMethod putAll = propertyMap.getMethod("putAll", Object.class, Iterable.class);
private static final WrappedMethod worldGetType;
//SimpleCollisionBoxes
private static final WrappedMethod getCubes;
private static final WrappedField aBB = axisAlignedBB.getFieldByName("a");
private static final WrappedField bBB = axisAlignedBB.getFieldByName("b");
private static final WrappedField cBB = axisAlignedBB.getFieldByName("c");
private static final WrappedField dBB = axisAlignedBB.getFieldByName("d");
private static final WrappedField eBB = axisAlignedBB.getFieldByName("e");
private static final WrappedField fBB = axisAlignedBB.getFieldByName("f");
private static WrappedConstructor aabbConstructor;
private static WrappedMethod idioticOldStaticConstructorAABB, methodBlockCollisionBox;
private static final WrappedField entitySimpleCollisionBox = entity.getFirstFieldByType(axisAlignedBB.getParent());
public static WrappedClass enumAnimation = Reflections.getNMSClass("EnumAnimation");
//ItemStack methods and fields
private static WrappedMethod enumAnimationStack;
private static final WrappedField activeItemField;
private static final WrappedMethod getItemMethod = itemStack.getMethodByType(item.getParent(), 0);
private static final WrappedMethod getAnimationMethod = itemClass.getMethodByType(enumAnimation.getParent(), 0);
private static final WrappedMethod canDestroyMethod;
//1.13+ only
private static WrappedClass voxelShape;
private static WrappedClass worldReader;
private static WrappedMethod getCubesFromVoxelShape;
private static final WrappedMethod itemStackAsBukkitCopy = CraftReflection.craftItemStack
.getMethod("asBukkitCopy", itemStack.getParent());
//Blocks
private static WrappedMethod addCBoxes;
public static WrappedClass blockPos;
private static WrappedConstructor blockPosConstructor;
private static WrappedMethod getBlockData, getBlock;
private static WrappedField blockData;
private static final WrappedField frictionFactor;
private static final WrappedField strength;
private static final WrappedField chunkProvider = MinecraftReflection.worldServer
.getFieldByType(Reflections.getNMSClass(ProtocolVersion.getGameVersion()
.isBelow(ProtocolVersion.V1_16)
&& ProtocolVersion.getGameVersion()
.isOrAbove(ProtocolVersion.V1_9) ? "IChunkProvider" : "ChunkProviderServer")
.getParent(), 0);
//Entity Player fields
private static final WrappedField connectionField = entityPlayer
.getFieldByType(playerConnection.getParent(), 0);
private static final WrappedField connectionNetworkField = playerConnection
.getFieldByType(networkManager.getParent(), 0);
private static final WrappedField networkChannelField = networkManager.getFieldByType(Reflections
.getUtilClass("io.netty.channel.Channel").getParent(), 0);
//General Fields
private static final WrappedField primaryThread = minecraftServer.getFirstFieldByType(Thread.class);
public static <T> T getGameProfile(Player player) {
return getProfile.invoke(player);
}
//1.7 field is boundingBox
//1.8+ method is getBoundingBox.
public static <T> T getEntityBoundingBox(Entity entity) {
Object vanillaEntity = CraftReflection.getEntity(entity);
return entitySimpleCollisionBox.get(vanillaEntity);
}
public static <T> T getItemInUse(HumanEntity entity) {
Object humanEntity = CraftReflection.getEntityHuman(entity);
return activeItemField.get(humanEntity);
}
//Can use either a Bukkit or vanilla object
public static <T> T getItemFromStack(Object object) {
Object vanillaStack;
if(object instanceof ItemStack) {
vanillaStack = CraftReflection.getVanillaItemStack((ItemStack)object);
} else vanillaStack = object;
return getItemMethod.invoke(vanillaStack);
}
//Can use either a Bukkit or vanilla object
public static <T> T getItemAnimation(Object object) {
Object vanillaStack;
if(object instanceof ItemStack) {
vanillaStack = CraftReflection.getVanillaItemStack((ItemStack)object);
} else vanillaStack = object;
Object item = getItemFromStack(vanillaStack);
return getAnimationMethod.invoke(item, vanillaStack);
}
public static Object getChatComponentFromText(String string) {
return chatComponentTextConst.newInstance(string);
}
public static int getPing(Player player) {
return -1;
}
public static <T> T getServerConnection() {
return methodGetServerConnection.invoke(CraftReflection.getMinecraftServer());
}
public static <T> T getServerConnection(Object minecraftServer) {
return methodGetServerConnection.invoke(minecraftServer);
}
public static Thread getMainThread(Object minecraftServer) {
return primaryThread.get(minecraftServer);
}
public static Thread getMainThread() {
return getMainThread(CraftReflection.getMinecraftServer());
}
//Can either use Player or EntityPlayer object.
public static <T> T getPlayerConnection(Object player) {
Object entityPlayer;
if(player instanceof Player) {
entityPlayer = CraftReflection.getEntityPlayer((Player)player);
} else entityPlayer = player;
return connectionField.get(entityPlayer);
}
//Can either use Player or EntityPlayer object.
public static <T> T getNetworkManager(Object player) {
return connectionNetworkField.get(getPlayerConnection(player));
}
//Can either use Player or EntityPlayer object.
public static <T> T getChannel(Object player) {
Object networkManager = getNetworkManager(player);
return networkChannelField.get(networkManager);
}
//Use the netty Channel class.
public static void disconnectChannel(Object channel) {
new WrappedClass(channel.getClass()).getMethod("close").invoke(channel);
}
private static WrappedMethod fluidMethod;
private static final WrappedMethod getFlowMethod;
public static ItemStack toBukkitItemStack(Object vanillaItemStack) {
return itemStackAsBukkitCopy.invoke(null, vanillaItemStack);
}
/**
* Extracts AxisAlignedBB Points.
* @param aabb AxisAlignedBB
* @return double[6] of points.
*/
public static double[] fromAABB(Object aabb) {
double[] boxArray = new double[6];
boxArray[0] = aBB.get(aabb);
boxArray[1] = bBB.get(aabb);
boxArray[2] = cBB.get(aabb);
boxArray[3] = dBB.get(aabb);
boxArray[4] = eBB.get(aabb);
boxArray[5] = fBB.get(aabb);
return boxArray;
}
/**
* Creates a new AxisAlignedBB.
* @return new AxisAlignedBB
*/
public static <T> T toAABB(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) {
return idioticOldStaticConstructorAABB
.invoke(null,
minX, minY, minZ,
maxX, maxY, maxZ);
} else return aabbConstructor
.newInstance(minX, minY, minZ,
maxX, maxY, maxZ);
}
//Either bukkit or vanilla world object can be used.
public static <T> T getChunkProvider(Object world) {
Object vanillaWorld;
if(world instanceof World) {
vanillaWorld = CraftReflection.getVanillaWorld((World)world);
} else vanillaWorld = world;
return chunkProvider.get(vanillaWorld);
}
public static <T> List<T> getVanillaChunks(World world) {
return Arrays.stream(world.getLoadedChunks())
.map(c -> (T) CraftReflection.getVanillaChunk(c))
.collect(Collectors.toList());
}
static {
if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10)) {
iBlockData = Reflections.getNMSClass("IBlockData");
blockPos = Reflections.getNMSClass("BlockPosition");
blockPosConstructor = blockPos.getConstructor(int.class, int.class, int.class);
getBlock = iBlockData.getMethodByType(block.getParent(), 0);
blockData = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_17)
? block.getFieldByType(iBlockData.getParent(), 0) : block.getFieldByName("blockData");
blockPosConstructor = blockPos.getConstructor(int.class, int.class, int.class);
getBlockData = block.getMethodByType(iBlockData.getParent(), 0);
aabbConstructor = axisAlignedBB
.getConstructor(double.class, double.class, double.class, double.class, double.class, double.class);
worldGetType = worldServer.getMethodByType(iBlockData.getParent(), 0, blockPos.getParent());
} else {
idioticOldStaticConstructorAABB = axisAlignedBB.getMethod("a",
double.class, double.class, double.class, double.class, double.class, double.class);
worldGetType = worldServer.getMethod("getType", int.class, int.class, int.class);
}
if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12)) {
getCubes = world.getMethod("a", axisAlignedBB.getParent());
if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) {
//1.7.10 does not have the BlockPosition object yet.
addCBoxes = block.getMethod("a", world.getParent(), int.class, int.class, int.class,
axisAlignedBB.getParent(), List.class, entity.getParent());
methodBlockCollisionBox = block
.getMethod("a", world.getParent(), int.class, int.class, int.class);
} else {
addCBoxes = block.getMethod("a", world.getParent(), blockPos.getParent(), iBlockData.getParent(),
axisAlignedBB.getParent(), List.class, entity.getParent());
if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) {
methodBlockCollisionBox = block
.getMethod("a", iBlockData.getParent(), world.getParent(), blockPos.getParent());
} else methodBlockCollisionBox = block
.getMethod("a", world.getParent(), blockPos.getParent(), iBlockData.getParent());
}
getFlowMethod = Reflections.getNMSClass("BlockFluids")
.getDeclaredMethodByType(vec3D.getParent(), 0);
} else if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) {
getCubes = world.getMethod("getCubes", entity.getParent(), axisAlignedBB.getParent());
addCBoxes = block.getMethod("a", iBlockData.getParent(), world.getParent(), blockPos.getParent(),
axisAlignedBB.getParent(), List.class, entity.getParent(), boolean.class);
methodBlockCollisionBox = block
.getMethod("a", iBlockData.getParent(), world.getParent(), blockPos.getParent());
getFlowMethod = Reflections.getNMSClass("BlockFluids")
.getDeclaredMethodByType(vec3D.getParent(), 0);
} else {
classBlockInfo = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_16)
? Reflections.getNMSClass("BlockBase$Info") : Reflections.getNMSClass("Block$Info");
worldReader = Reflections.getNMSClass("IWorldReader");
//1.13 and 1.13.1 returns just VoxelShape while 1.13.2+ returns a Stream<VoxelShape>
getCubes = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_18)
? worldReader.getMethodByType(List.class, 0, entity.getParent(), axisAlignedBB.getParent())
: (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_16) ?
worldReader.getMethod("a", entity.getParent(), axisAlignedBB.getParent(),
double.class, double.class, double.class)
: world.getMethod("c", entity.getParent(), axisAlignedBB.getParent(), Predicate.class));
voxelShape = Reflections.getNMSClass("VoxelShape");
getCubesFromVoxelShape = voxelShape.getMethodByType(List.class, 0);
fluidMethod = world.getMethodByType(Reflections.getNMSClass("Fluid").getParent(), 0, blockPos.getParent());
getFlowMethod = Reflections.getNMSClass("Fluid").getMethodByType(vec3D.getParent(), 0);
if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_19)) {
chatComponentText = Reflections.getNMSClass("ChatComponentText");
chatComponentTextConst = chatComponentText.getConstructor(String.class);
}
}
if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_16)) {
blockBase = Reflections.getNMSClass("BlockBase");
}
if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) {
activeItemField = entityHuman.getFieldByType(itemStack.getParent(), 0);
} else {
activeItemField = entityLiving.getFieldByType(itemStack.getParent(), 0);
}
canDestroyMethod = ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_16)
? playerInventory.getMethod("b",
ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9)
? iBlockData.getParent() : itemClass.getParent())
: itemStack.getMethodByType(boolean.class, 0, iBlockData.getParent());
if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_17)) {
frictionFactor = (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_16)
? block : blockBase).getFieldByName("frictionFactor");
} else frictionFactor = blockBase.getFieldByType(float.class, 1);
strength = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_17)
? blockBase.getFieldByType(float.class, 0)
: (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_16)
? block.getFieldByName("strength") : blockBase.getFieldByName("durability"));
}
}
@@ -0,0 +1,346 @@
/*
* Created by Justin Heflin on 4/19/18 8:21 PM
* Copyright (c) 2018.
*
* Can be redistributed non commercially as long as credit is given to original copyright owner.
*
* last modified: 4/19/18 7:22 PM
*/
package dev.brighten.ac.utils.reflections.types;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.Getter;
import lombok.val;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@Getter
public class WrappedClass {
private final Class parent;
private final Cache<String, WrappedMethod> methodCache = CacheBuilder.newBuilder()
.expireAfterAccess(2, TimeUnit.MINUTES).maximumSize(200L).build();
private final Cache<String, WrappedField> fieldCache = CacheBuilder.newBuilder()
.expireAfterAccess(2, TimeUnit.MINUTES).maximumSize(200L).build();
public WrappedClass(Class parent) {
this.parent = parent;
}
public WrappedField getFieldByName(String name) {
Optional<WrappedField> cached = Optional.ofNullable(fieldCache.getIfPresent(name));
if(cached.isPresent()) {
return cached.get();
}
Field tempField = null;
Class<?> clazz = this.parent;
do {
for (Field field : this.parent.getDeclaredFields()) {
if (field.getName().equals(name)) {
tempField = field;
break;
}
}
if (tempField != null) {
tempField.setAccessible(true);
WrappedField toReturn = new WrappedField(this, tempField);
fieldCache.put(name, toReturn);
return toReturn;
}
if(clazz.equals(this.parent.getSuperclass())) {
clazz = null;
} else clazz = this.parent.getSuperclass();
} while(clazz != null && !clazz.getName().contains("Object"));
return null;
}
public WrappedConstructor getConstructor(Class<?>... types) {
try {
return new WrappedConstructor(this, this.parent.getDeclaredConstructor(types));
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}
public List<WrappedField> getFields(Predicate<WrappedField>... parameters) {
return getFields()
.stream()
.filter(field -> Arrays.stream(parameters).allMatch(param -> param.test(field)))
.collect(Collectors.toList());
}
public List<WrappedMethod> getMethods(Predicate<WrappedMethod>... parameters) {
return getMethods()
.stream()
.filter(method -> Arrays.stream(parameters).allMatch(param -> param.test(method)))
.collect(Collectors.toList());
}
public List<WrappedConstructor> getConstructors() {
return Arrays.stream(this.parent.getConstructors())
.map(construct -> new WrappedConstructor(this, construct))
.collect(Collectors.toList());
}
public WrappedConstructor getConstructor() {
val optional = Arrays.stream(this.parent.getConstructors())
.filter(cons -> cons.getParameterCount() == 0).findFirst();
return optional.map(constructor -> new WrappedConstructor(this, constructor)).orElse(null);
}
public WrappedConstructor getConstructorAtIndex(int index) {
return new WrappedConstructor(this, this.parent.getConstructors()[index]);
}
public boolean isAnnotationPresent(Class<? extends Annotation> annClass) {
return parent.isAnnotationPresent(annClass);
}
public boolean hasMethod(String name, Class<?>... args) {
for (Method declaredMethod : parent.getDeclaredMethods()) {
if(declaredMethod.getName().equals(name)
&& Arrays.equals(args, declaredMethod.getParameterTypes()))
return true;
}
return false;
}
public <T> T getAnnotation(Class<T> annClass) {
return (T) parent.getDeclaredAnnotation(annClass);
}
public WrappedField getFieldByType(Class<?> type, int index) {
String key = type.getName() + ";;" + index;
Optional<WrappedField> cached = Optional.ofNullable(fieldCache.getIfPresent(key));
if(cached.isPresent()) {
return cached.get();
}
Class<?> clazz = this.parent;
do {
for (Field[] fields : new Field[][]{clazz.getDeclaredFields()}) {
for (Field field : fields) {
if (type.isAssignableFrom(field.getType()) && index-- <= 0) {
WrappedField toReturn = new WrappedField(this, field);
fieldCache.put(key, toReturn);
return toReturn;
}
}
}
if(clazz.equals(this.parent.getSuperclass())) {
clazz = null;
} else clazz = this.parent.getSuperclass();
} while(clazz != null && !clazz.getName().contains("Object"));
throw new NullPointerException("Could not find field with type " + type.getSimpleName() + " at index " + index);
}
public WrappedField getFirstFieldByType(Class<?> type) {
return this.getFieldByType(type, 0);
}
public WrappedMethod[] getDeclaredMethods() {
return Arrays.stream(getParent().getDeclaredMethods())
.map(m -> new WrappedMethod(this, m))
.toArray(WrappedMethod[]::new);
}
public boolean isAssignableFrom(WrappedClass wrapped) {
return wrapped.getParent().isAssignableFrom(getParent());
}
public boolean isAssignableFrom(Class<?> paramClass) {
return getParent().isAssignableFrom(paramClass);
}
public WrappedMethod getMethod(String name, Class... parameters) {
String key = name + ";;" + Arrays.stream(parameters).map(Class::getName)
.collect(Collectors.joining(","));
Optional<WrappedMethod> cached = Optional.ofNullable(methodCache.getIfPresent(key));
if(cached.isPresent()) return cached.get();
else {
for (Method method : this.parent.getDeclaredMethods()) {
if (!method.getName().equals(name) || parameters.length != method.getParameterTypes().length) {
continue;
}
boolean same = true;
for (int x = 0; x < method.getParameterTypes().length; x++) {
if (method.getParameterTypes()[x] != parameters[x]) {
same = false;
break;
}
}
if (same) {
WrappedMethod toReturn = new WrappedMethod(this, method);
methodCache.put(key, toReturn);
return toReturn;
}
}
for (Method method : this.parent.getMethods()) {
if (!method.getName().equals(name) || parameters.length != method.getParameterTypes().length) {
continue;
}
boolean same = true;
for (int x = 0; x < method.getParameterTypes().length; x++) {
if (method.getParameterTypes()[x] != parameters[x]) {
same = false;
break;
}
}
if (same) {
WrappedMethod toReturn = new WrappedMethod(this, method);
methodCache.put(key, toReturn);
return toReturn;
}
}
}
throw new NullPointerException("Could not find method in " + getParent().getSimpleName() + " with name " + name);
}
public WrappedMethod getDeclaredMethodByType(Class<?> type, int index) {
String key = "declared:" + type.getName() + ";;" + index;
Optional<WrappedMethod> cached = Optional.ofNullable(methodCache.getIfPresent(key));
if(cached.isPresent()) {
return cached.get();
}
for (Method method : this.parent.getDeclaredMethods()) {
if(type.isAssignableFrom(method.getReturnType()) && index-- <= 0) {
WrappedMethod toReturn = new WrappedMethod(this, method);
methodCache.put(key, toReturn);
return toReturn;
}
}
throw new NullPointerException("Could not find method with return type " + type.getSimpleName() + " at index " + index);
}
public WrappedMethod getMethodByType(Class<?> type, int index) throws NullPointerException {
String key = "nondeclared:" + type.getName() + ";;" + index;
Optional<WrappedMethod> cached = Optional.ofNullable(methodCache.getIfPresent(key));
if(cached.isPresent()) {
return cached.get();
}
for (Method method : this.parent.getMethods()) {
if(type.isAssignableFrom(method.getReturnType()) && index-- <= 0) {
WrappedMethod toReturn = new WrappedMethod(this, method);
methodCache.put(key, toReturn);
return toReturn;
}
}
throw new NullPointerException("Could not find method with return type " + type.getName()
+ " at index " + index);
}
public WrappedMethod getMethodByType(Class<?> type, int index, Class<?>... parameters) throws NullPointerException {
for (Method method : this.parent.getMethods()) {
if(type.isAssignableFrom(method.getReturnType()) && parameters.length == method.getParameterCount()) {
boolean same = true;
for (int x = 0; x < method.getParameterTypes().length; x++) {
if (method.getParameterTypes()[x] != parameters[x]) {
same = false;
break;
}
}
if(same && index-- <= 0)
return new WrappedMethod(this, method);
}
}
throw new NullPointerException("Could not find method with return type " + type.getName()
+ " at index " + index);
}
public WrappedMethod getDeclaredMethodByType(Class<?> type, int index, Class<?>... parameters) throws NullPointerException {
for (Method method : this.parent.getDeclaredMethods()) {
if(type.isAssignableFrom(method.getReturnType()) && parameters.length == method.getParameterCount()) {
boolean same = true;
for (int x = 0; x < method.getParameterTypes().length; x++) {
if (method.getParameterTypes()[x] != parameters[x]) {
same = false;
break;
}
}
if(same && index-- <= 0)
return new WrappedMethod(this, method);
}
}
throw new NullPointerException("Could not find method with return type " + type.getName()
+ " at index " + index);
}
//We have a separate method instead of just calling WrappedClass#getMethods(boolean, boolean)
//for performance reasons.
public List<WrappedMethod> getMethods() {
return Arrays.stream(parent.getMethods())
.map(method -> new WrappedMethod(this, method))
.collect(Collectors.toList());
}
public List<WrappedMethod> getMethods(boolean noStatic, boolean noFinal) {
return Arrays.stream(parent.getMethods())
.filter(method ->
(!noFinal || !Modifier.isFinal(method.getModifiers())
&& (!noStatic || !Modifier.isStatic(method.getModifiers()))))
.map(method -> new WrappedMethod(this, method))
.collect(Collectors.toList());
}
public List<WrappedMethod> getMethods(boolean noStatic) {
return getMethods(noStatic, false);
}
//We have a separate method instead of just calling WrappedClass#getFields(boolean, boolean)
// or performance reasons.
public List<WrappedField> getFields() {
return Arrays.stream(parent.getDeclaredFields())
.map(field -> new WrappedField(this, field))
.collect(Collectors.toList());
}
public List<WrappedField> getFields(boolean noStatic, boolean noFinal) {
return Arrays.stream(parent.getDeclaredFields())
.filter(field ->
(!noFinal || !Modifier.isFinal(field.getModifiers())
&& (!noStatic || !Modifier.isStatic(field.getModifiers()))))
.map(field -> new WrappedField(this, field))
.collect(Collectors.toList());
}
public List<WrappedField> getFields(boolean noStatic) {
return getFields(noStatic, false);
}
public Enum getEnum(String name) {
return Enum.valueOf(this.parent, name);
}
}
@@ -0,0 +1,44 @@
/*
* Created by Justin Heflin on 4/19/18 8:21 PM
* Copyright (c) 2018.
*
* Can be redistributed non commercially as long as credit is given to original copyright owner.
*
* last modified: 4/19/18 7:22 PM
*/
package dev.brighten.ac.utils.reflections.types;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@RequiredArgsConstructor
@AllArgsConstructor
@Getter
public class WrappedConstructor {
private final WrappedClass parent;
private Constructor constructor;
public <T> T newInstance(Object... args) {
try {
constructor.setAccessible(true);
return (T) constructor.newInstance(args);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
public <T> T newInstance() {
try {
constructor.setAccessible(true);
return (T) constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
}
@@ -0,0 +1,58 @@
/*
* Created by Justin Heflin on 4/19/18 8:21 PM
* Copyright (c) 2018.
*
* Can be redistributed non commercially as long as credit is given to original copyright owner.
*
* last modified: 4/19/18 7:22 PM
*/
package dev.brighten.ac.utils.reflections.types;
import lombok.Getter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
@Getter
public class WrappedField {
private final WrappedClass parent;
private final Field field;
private final Class<?> type;
public WrappedField(WrappedClass parent, Field field) {
this.parent = parent;
this.field = field;
this.type = field.getType();
this.field.setAccessible(true);
}
public <T> T get(Object parent) {
try {
return (T) this.field.get(parent);
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
public void set(Object parent, Object value) {
try {
this.field.setAccessible(true);
this.field.set(parent, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public boolean isAnnotationPresent(Class<? extends Annotation> annClass) {
return field.isAnnotationPresent(annClass);
}
public <T> T getAnnotation(Class<? extends Annotation> annClass) {
return (T) field.getAnnotation(annClass);
}
public int getModifiers() {
return this.field.getModifiers();
}
}
@@ -0,0 +1,89 @@
/*
* Created by Justin Heflin on 4/19/18 8:21 PM
* Copyright (c) 2018.
*
* Can be redistributed non commercially as long as credit is given to original copyright owner.
*
* last modified: 4/19/18 7:22 PM
*/
package dev.brighten.ac.utils.reflections.types;
import dev.brighten.ac.utils.objects.MethodFunction;
import dev.brighten.ac.utils.objects.QuadFunction;
import dev.brighten.ac.utils.objects.TriFunction;
import dev.brighten.ac.utils.reflections.Reflections;
import lombok.Getter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
@Getter
public class WrappedMethod {
private final WrappedClass parent;
private final Method method;
private final String name;
private MethodFunction mfunc;
private final List<Class<?>> parameters;
private final boolean isVoid;
public WrappedMethod(WrappedClass parent, Method method) {
this.name = method.getName();
this.method = method;
this.parent = parent;
this.parameters = Arrays.asList(method.getParameterTypes());
try {
int length = method.getParameterCount();
switch(length) {
case 0:
Function func = Reflections.createMethodLambda(method);
mfunc = new MethodFunction(method, func);
break;
case 1:
BiFunction bifunc = Reflections.createMethodLambda(method);
mfunc = new MethodFunction(method, bifunc);
break;
case 2:
TriFunction trifunc = Reflections.createMethodLambda(method);
mfunc = new MethodFunction(method, trifunc);
break;
case 3:
QuadFunction quadFunc = Reflections.createMethodLambda(method);
mfunc = new MethodFunction(method, quadFunc);
break;
default:
method.setAccessible(true);
mfunc = new MethodFunction(method);
break;
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
isVoid = method.getReturnType().equals(void.class);
}
public <T> T invoke(Object object, Object... args) {
return mfunc.invokeMethod(object, args);
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
return method.isAnnotationPresent(annotation);
}
public Parameter[] getParameters() {
return method.getParameters();
}
public Class<?>[] getParameterTypes() {
return method.getParameterTypes();
}
public int getModifiers() {
return this.method.getModifiers();
}
}