Compare commits

..
Author SHA1 Message Date
Axionize 72b8616ffe Merge remote-tracking branch 'origin/2.0' into optimize-entity-packets
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/latency/CompensatedEntities.java
2024-11-25 16:28:14 -05:00
Axionize 0f3bf60549 Minor Optimization to addEntity() 2024-11-17 11:51:15 -05:00
Axionize deb2628f77 Optimize if else in updateEntityMetaData() 2024-11-17 11:50:47 -05:00
113 changed files with 729 additions and 2657 deletions

No files matched your search

+2 -168
View File
@@ -30,7 +30,7 @@ version = "2.3.68"
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(18))
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
// Set to false for debug builds
@@ -59,18 +59,11 @@ repositories {
// FastUtil, Discord-Webhooks
}
// Add JMH configuration
configurations {
create("jmh")
create("jmhAnnotationProcessor")
}
dependencies {
implementation("com.github.retrooper:packetevents-spigot:2.6.1-SNAPSHOT")
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
implementation("club.minnced:discord-webhooks:0.8.0") // Newer versions include kotlin-stdlib, which leads to incompatibility with plugins that use Kotlin
implementation("it.unimi.dsi:fastutil:8.5.15")
implementation("it.unimi.dsi:fastutil:8.5.13")
implementation("github.scarsz:configuralize:1.4.0")
//implementation("com.github.grimanticheat:grimapi:1193c4fa41")
@@ -83,12 +76,6 @@ dependencies {
compileOnly("com.viaversion:viaversion-api:5.0.4-SNAPSHOT")
//
compileOnly("io.netty:netty-all:4.1.85.Final")
// Replace jmhImplementation with the new configuration
"jmh"("org.openjdk.jmh:jmh-core:1.37")
"jmhAnnotationProcessor"("org.openjdk.jmh:jmh-generator-annprocess:1.37")
implementation(files("./nalim.jar"))
}
bukkit {
@@ -156,16 +143,6 @@ bukkit {
description = "Exempt from all checks"
default = Permission.Default.FALSE
}
register("grim.verbose") {
description = "Receive verbose alerts for violations. Requires grim.alerts"
default = Permission.Default.OP
}
register("grim.verbose.enable-on-join") {
description = "Enable verbose alerts on join. Requires grim.alerts and grim.alerts.enable-on-join"
default = Permission.Default.FALSE
}
}
}
@@ -182,71 +159,6 @@ publishing.publications.create<MavenPublication>("maven") {
artifact(tasks["shadowJar"])
}
java {
sourceSets {
create("java18") {
java {
srcDirs("src/main/java18")
}
compileClasspath += main.get().output
runtimeClasspath += main.get().output
dependencies {
implementation(files("./nalim.jar")) // Add nalim.jar to java18 source set
}
}
create("jmh") {
java {
srcDir("src/jmh/java")
}
compileClasspath += sourceSets.main.get().output +
sourceSets.getByName("java18").output +
configurations["jmh"]
runtimeClasspath += sourceSets.main.get().output +
sourceSets.getByName("java18").output +
configurations["jmh"]
}
}
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
toolchain {
languageVersion.set(JavaLanguageVersion.of(18))
}
}
tasks.withType<JavaCompile> {
if (name == "compileJava") {
options.compilerArgs.addAll(listOf("--add-exports","java.base/jdk.internal=ALL-UNNAMED",
"--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED"))
}
if (name == "compileJava18Java") {
options.compilerArgs.addAll(listOf("--add-modules", "jdk.incubator.vector", "-Xlint:unchecked"))
sourceCompatibility = "18"
targetCompatibility = "18"
}
if (name == "compileJava21Java") {
options.compilerArgs.addAll(listOf("--enable-preview", "--add-modules", "jdk.incubator.vector", "-Xlint:unchecked"))
sourceCompatibility = "21"
targetCompatibility = "21"
}
if (name == "compileJmhJava") {
options.compilerArgs.addAll(listOf("--add-modules", "jdk.incubator.vector"))
sourceCompatibility = "18"
targetCompatibility = "18"
}
}
tasks.withType<Jar> {
manifest {
attributes("Multi-Release" to "true")
}
duplicatesStrategy = DuplicatesStrategy.INCLUDE // Important for multi-release JARs
from(sourceSets.main.get().output)
from(sourceSets.getByName("java18").output) {
into("META-INF/versions/18")
}
}
tasks.shadowJar {
minimize()
archiveFileName.set("${project.name}-${project.version}.jar")
@@ -270,81 +182,3 @@ tasks.shadowJar {
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
}
}
tasks.register<Jar>("jmhJar") {
dependsOn("compileGeneratedJmh")
from(sourceSets["main"].output)
from(sourceSets["java18"].output)
from(sourceSets["jmh"].output)
from("${buildDir}/classes/java/jmh")
from(configurations["jmh"].map { if (it.isDirectory) it else zipTree(it) })
manifest {
attributes(
"Main-Class" to "org.openjdk.jmh.Main",
"Add-Opens" to "java.base/java.lang java.base/java.io java.base/java.util java.base/java.util.concurrent java.base/java.net",
"Add-Modules" to "jdk.incubator.vector"
)
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveClassifier.set("benchmarks")
}
tasks.register<JavaCompile>("compileGeneratedJmh") {
dependsOn("compileJmhJava")
source = fileTree("${buildDir}/generated-sources/jmh")
classpath = sourceSets["jmh"].compileClasspath +
sourceSets["java18"].output +
sourceSets["java18"].compileClasspath +
sourceSets.main.get().output +
sourceSets.main.get().compileClasspath +
files("${buildDir}/classes/java/jmh")
destinationDirectory.set(file("${buildDir}/classes/java/jmh"))
sourceCompatibility = "18"
targetCompatibility = "18"
options.compilerArgs.addAll(listOf("--add-modules", "jdk.incubator.vector"))
}
tasks.register("jmh") {
dependsOn("jmhJar")
doLast {
val includes = System.getProperty("includes", "")
javaexec {
classpath = files(tasks.named("jmhJar").get().outputs.files)
mainClass.set("org.openjdk.jmh.Main")
jvmArgs = listOf("--enable-preview", "--add-modules", "jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions", "-XX:+EnableJVMCI", "-javaagent:nalim.jar")
// Initialize the args list with default settings
args = mutableListOf<String>().apply {
// Add any default arguments here if needed
if (includes.isNotEmpty()) {
addAll(listOf(includes))
}
}
}
}
}
tasks.named<JavaCompile>("compileJmhJava") {
source = fileTree("src/jmh/java")
classpath = sourceSets["jmh"].compileClasspath +
sourceSets.main.get().output +
sourceSets["java18"].output
destinationDirectory.set(file("${buildDir}/classes/java/jmh"))
sourceCompatibility = "18"
targetCompatibility = "18"
options.compilerArgs.addAll(listOf("--add-modules", "jdk.incubator.vector"))
}
tasks.named("jmhJar") {
dependsOn("compileJmhJava")
}
@@ -1,148 +0,0 @@
package ac.grim.grimac.utils.vector;
import jdk.incubator.vector.*;
public final class SIMDVector3D implements Vector3D {
private static final VectorSpecies<Double> SPECIES = DoubleVector.SPECIES_256;
private static final VectorMask<Double> LENGTH_3_ARRAY_MASK = SPECIES.indexInRange(0, 3);
private static final VectorShuffle<Double> CROSS_PRODUCT_SHUFFLE1 = VectorShuffle.fromArray(SPECIES, new int[]{1, 2, 0, 3}, 0);
private static final VectorShuffle<Double> CROSS_PRODUCT_SHUFFLE2 = VectorShuffle.fromArray(SPECIES, new int[]{2, 0, 1, 3}, 0);
private static final DoubleVector FOURTH_COMPONENT_ZERO = DoubleVector.zero(SPECIES).withLane(3, 1.0);
private DoubleVector vector;
public SIMDVector3D(double x, double y, double z) {
this.vector = DoubleVector.fromArray(SPECIES, new double[]{x, y, z, 0}, 0, LENGTH_3_ARRAY_MASK);
}
@Override
public double getX() {
return this.vector.lane(0);
}
@Override
public double getY() {
return this.vector.lane(1);
}
@Override
public double getZ() {
return this.vector.lane(2);
}
@Override
public Vector3D setX(double x) {
this.vector = this.vector.withLane(0, x);
return this;
}
@Override
public Vector3D setY(double y) {
this.vector = this.vector.withLane(1, y);
return this;
}
@Override
public Vector3D setZ(double z) {
this.vector = this.vector.withLane(2, z);
return this;
}
@Override
public double length() {
return Math.sqrt(lengthSquared());
}
@Override
public double lengthSquared() {
return this.vector.mul(this.vector).reduceLanes(VectorOperators.ADD);
}
@Override
public Vector3D multiply(double m) {
this.vector = this.vector.mul(m);
return this;
}
@Override
public Vector3D normalize() {
// DoubleVector squared = this.vector.mul(this.vector);
// double sum = squared.reduceLanes(VectorOperators.ADD);
// double length = Math.sqrt(sum);
// this.vector = this.vector.div(length);
// return this;
this.vector = this.vector.div(length());
return this;
}
@Override
public Vector3D crossProduct(Vector3D other) {
SIMDVector3D o = (SIMDVector3D) other;
DoubleVector tmp0 = this.vector.rearrange(CROSS_PRODUCT_SHUFFLE1);
DoubleVector tmp1 = o.vector.rearrange(CROSS_PRODUCT_SHUFFLE2);
DoubleVector tmp2 = tmp0.mul(o.vector);
DoubleVector tmp3 = tmp0.mul(tmp1);
DoubleVector tmp4 = tmp2.rearrange(CROSS_PRODUCT_SHUFFLE1);
this.vector = tmp3.sub(tmp4).blend(FOURTH_COMPONENT_ZERO, LENGTH_3_ARRAY_MASK.not());
return this;
}
@Override
public Vector3D add(Vector3D o) {
this.vector = this.vector.add(((SIMDVector3D) o).vector);
return this;
}
@Override
public Vector3D subtract(Vector3D o) {
this.vector = this.vector.sub(((SIMDVector3D) o).vector);
return this;
}
@Override
public Vector3D multiply(Vector3D o) {
this.vector = this.vector.mul(((SIMDVector3D) o).vector);
return this;
}
@Override
public double distance(Vector3D o) {
return Math.sqrt(distanceSquared(o));
}
@Override
public double distanceSquared(Vector3D o) {
DoubleVector diff = this.vector.sub(((SIMDVector3D) o).vector);
return diff.mul(diff).reduceLanes(VectorOperators.ADD);
}
@Override
public double dot(Vector3D o) {
return this.vector.mul(((SIMDVector3D) o).vector).reduceLanes(VectorOperators.ADD);
}
@Override
public Vector3D clone() {
// I think this makes a shallow clone if I do it like this?
// try {
// return (Vector3D) super.clone();
// } catch (CloneNotSupportedException e) {
// throw new Error(e);
// }
try {
SIMDVector3D cloned = (SIMDVector3D) super.clone();
// Create a new DoubleVector with the same values
cloned.vector = DoubleVector.fromArray(SPECIES,
new double[]{this.getX(), this.getY(), this.getZ(), 0}, 0);
return cloned;
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
}
@@ -1,10 +0,0 @@
package ac.grim.grimac.utils.vector;
public class VectorOperationsJava18 implements VectorOperations {
@Override
public Vector3D newVector(double x, double y, double z) {
return new SIMDVector3D(x, y, z);
}
}
@@ -1,114 +0,0 @@
//package ac.grim.grimac.benchmark.vector;
//
//import ac.grim.grimac.utils.vector.Java21SIMDVector3D;
//import org.openjdk.jmh.annotations.*;
//
//import java.util.concurrent.TimeUnit;
//
//@BenchmarkMode(Mode.AverageTime)
//@OutputTimeUnit(TimeUnit.NANOSECONDS)
//@State(Scope.Thread)
//@Warmup(iterations = 2, time = 1)
//@Measurement(iterations = 3, time = 1)
//@Fork(1)
//public class Java21SIMDVector3DBenchmark {
//
// private Java21SIMDVector3D vector1;
// private Java21SIMDVector3D vector2;
//
// @Setup
// public void setup() {
// vector1 = new Java21SIMDVector3D(1.0, 2.0, 3.0);
// vector2 = new Java21SIMDVector3D(4.0, 5.0, 6.0);
// }
//
// @Benchmark
// public double benchmarkGetX() {
// return vector1.getX();
// }
//
// @Benchmark
// public double benchmarkGetY() {
// return vector1.getY();
// }
//
// @Benchmark
// public double benchmarkGetZ() {
// return vector1.getZ();
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkSetX() {
// return (Java21SIMDVector3D) vector1.setX(10.0);
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkSetY() {
// return (Java21SIMDVector3D) vector1.setY(20.0);
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkSetZ() {
// return (Java21SIMDVector3D) vector1.setZ(30.0);
// }
//
// @Benchmark
// public double benchmarkLength() {
// return vector1.length();
// }
//
// @Benchmark
// public double benchmarkLengthSquared() {
// return vector1.lengthSquared();
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkMultiplyScalar() {
// return (Java21SIMDVector3D) vector1.multiply(2.0);
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkNormalize() {
// return (Java21SIMDVector3D) vector1.normalize();
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkCrossProduct() {
// return (Java21SIMDVector3D) vector1.crossProduct(vector2);
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkAdd() {
// return (Java21SIMDVector3D) vector1.add(vector2);
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkSubtract() {
// return (Java21SIMDVector3D) vector1.subtract(vector2);
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkMultiplyVector() {
// return (Java21SIMDVector3D) vector1.multiply(vector2);
// }
//
// @Benchmark
// public double benchmarkDistance() {
// return vector1.distance(vector2);
// }
//
// @Benchmark
// public double benchmarkDistanceSquared() {
// return vector1.distanceSquared(vector2);
// }
//
// @Benchmark
// public double benchmarkDotProduct() {
// return vector1.dot(vector2);
// }
//
// @Benchmark
// public Java21SIMDVector3D benchmarkClone() {
// return (Java21SIMDVector3D) vector1.clone();
// }
//}
@@ -1,114 +0,0 @@
package ac.grim.grimac.benchmark.vector;
import ac.grim.grimac.utils.vector.NalimVector3D;
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 2, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(1)
public class NalimVector3DBenchmark {
private NalimVector3D vector1;
private NalimVector3D vector2;
@Setup
public void setup() {
vector1 = new NalimVector3D(1.0, 2.0, 3.0);
vector2 = new NalimVector3D(4.0, 5.0, 6.0);
}
@Benchmark
public double benchmarkGetX() {
return vector1.getX();
}
@Benchmark
public double benchmarkGetY() {
return vector1.getY();
}
@Benchmark
public double benchmarkGetZ() {
return vector1.getZ();
}
@Benchmark
public NalimVector3D benchmarkSetX() {
return (NalimVector3D) vector1.setX(10.0);
}
@Benchmark
public NalimVector3D benchmarkSetY() {
return (NalimVector3D) vector1.setY(20.0);
}
@Benchmark
public NalimVector3D benchmarkSetZ() {
return (NalimVector3D) vector1.setZ(30.0);
}
@Benchmark
public double benchmarkLength() {
return vector1.length();
}
@Benchmark
public double benchmarkLengthSquared() {
return vector1.lengthSquared();
}
@Benchmark
public NalimVector3D benchmarkMultiplyScalar() {
return (NalimVector3D) vector1.multiply(2.0);
}
@Benchmark
public NalimVector3D benchmarkNormalize() {
return (NalimVector3D) vector1.normalize();
}
@Benchmark
public NalimVector3D benchmarkCrossProduct() {
return (NalimVector3D) vector1.crossProduct(vector2);
}
@Benchmark
public NalimVector3D benchmarkAdd() {
return (NalimVector3D) vector1.add(vector2);
}
@Benchmark
public NalimVector3D benchmarkSubtract() {
return (NalimVector3D) vector1.subtract(vector2);
}
@Benchmark
public NalimVector3D benchmarkMultiplyVector() {
return (NalimVector3D) vector1.multiply(vector2);
}
@Benchmark
public double benchmarkDistance() {
return vector1.distance(vector2);
}
@Benchmark
public double benchmarkDistanceSquared() {
return vector1.distanceSquared(vector2);
}
@Benchmark
public double benchmarkDotProduct() {
return vector1.dot(vector2);
}
@Benchmark
public NalimVector3D benchmarkClone() {
return (NalimVector3D) vector1.clone();
}
}
@@ -1,114 +0,0 @@
//package ac.grim.grimac.benchmark.vector;
//
//import ac.grim.grimac.utils.vector.NativeVector3D;
//import org.openjdk.jmh.annotations.*;
//
//import java.util.concurrent.TimeUnit;
//
//@BenchmarkMode(Mode.AverageTime)
//@OutputTimeUnit(TimeUnit.NANOSECONDS)
//@State(Scope.Thread)
//@Warmup(iterations = 2, time = 1)
//@Measurement(iterations = 3, time = 1)
//@Fork(1)
//public class NativeVector3DBenchmark {
//
// private NativeVector3D vector1;
// private NativeVector3D vector2;
//
// @Setup
// public void setup() {
// vector1 = new NativeVector3D(1.0, 2.0, 3.0);
// vector2 = new NativeVector3D(4.0, 5.0, 6.0);
// }
//
// @Benchmark
// public double benchmarkGetX() {
// return vector1.getX();
// }
//
// @Benchmark
// public double benchmarkGetY() {
// return vector1.getY();
// }
//
// @Benchmark
// public double benchmarkGetZ() {
// return vector1.getZ();
// }
//
// @Benchmark
// public NativeVector3D benchmarkSetX() {
// return (NativeVector3D) vector1.setX(10.0);
// }
//
// @Benchmark
// public NativeVector3D benchmarkSetY() {
// return (NativeVector3D) vector1.setY(20.0);
// }
//
// @Benchmark
// public NativeVector3D benchmarkSetZ() {
// return (NativeVector3D) vector1.setZ(30.0);
// }
//
// @Benchmark
// public double benchmarkLength() {
// return vector1.length();
// }
//
// @Benchmark
// public double benchmarkLengthSquared() {
// return vector1.lengthSquared();
// }
//
// @Benchmark
// public NativeVector3D benchmarkMultiplyScalar() {
// return (NativeVector3D) vector1.multiply(2.0);
// }
//
// @Benchmark
// public NativeVector3D benchmarkNormalize() {
// return (NativeVector3D) vector1.normalize();
// }
//
// @Benchmark
// public NativeVector3D benchmarkCrossProduct() {
// return (NativeVector3D) vector1.crossProduct(vector2);
// }
//
// @Benchmark
// public NativeVector3D benchmarkAdd() {
// return (NativeVector3D) vector1.add(vector2);
// }
//
// @Benchmark
// public NativeVector3D benchmarkSubtract() {
// return (NativeVector3D) vector1.subtract(vector2);
// }
//
// @Benchmark
// public NativeVector3D benchmarkMultiplyVector() {
// return (NativeVector3D) vector1.multiply(vector2);
// }
//
// @Benchmark
// public double benchmarkDistance() {
// return vector1.distance(vector2);
// }
//
// @Benchmark
// public double benchmarkDistanceSquared() {
// return vector1.distanceSquared(vector2);
// }
//
// @Benchmark
// public double benchmarkDotProduct() {
// return vector1.dot(vector2);
// }
//
// @Benchmark
// public NativeVector3D benchmarkClone() {
// return (NativeVector3D) vector1.clone();
// }
//}
@@ -1,114 +0,0 @@
package ac.grim.grimac.benchmark.vector;
import ac.grim.grimac.utils.vector.SIMDVector3D;
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 2, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(1)
public class SIMDVector3DBenchmark {
private SIMDVector3D vector1;
private SIMDVector3D vector2;
@Setup
public void setup() {
vector1 = new SIMDVector3D(1.0, 2.0, 3.0);
vector2 = new SIMDVector3D(4.0, 5.0, 6.0);
}
@Benchmark
public double benchmarkGetX() {
return vector1.getX();
}
@Benchmark
public double benchmarkGetY() {
return vector1.getY();
}
@Benchmark
public double benchmarkGetZ() {
return vector1.getZ();
}
@Benchmark
public SIMDVector3D benchmarkSetX() {
return (SIMDVector3D) vector1.setX(10.0);
}
@Benchmark
public SIMDVector3D benchmarkSetY() {
return (SIMDVector3D) vector1.setY(20.0);
}
@Benchmark
public SIMDVector3D benchmarkSetZ() {
return (SIMDVector3D) vector1.setZ(30.0);
}
@Benchmark
public double benchmarkLength() {
return vector1.length();
}
@Benchmark
public double benchmarkLengthSquared() {
return vector1.lengthSquared();
}
@Benchmark
public SIMDVector3D benchmarkMultiplyScalar() {
return (SIMDVector3D) vector1.multiply(2.0);
}
@Benchmark
public SIMDVector3D benchmarkNormalize() {
return (SIMDVector3D) vector1.normalize();
}
@Benchmark
public SIMDVector3D benchmarkCrossProduct() {
return (SIMDVector3D) vector1.crossProduct(vector2);
}
@Benchmark
public SIMDVector3D benchmarkAdd() {
return (SIMDVector3D) vector1.add(vector2);
}
@Benchmark
public SIMDVector3D benchmarkSubtract() {
return (SIMDVector3D) vector1.subtract(vector2);
}
@Benchmark
public SIMDVector3D benchmarkMultiplyVector() {
return (SIMDVector3D) vector1.multiply(vector2);
}
@Benchmark
public double benchmarkDistance() {
return vector1.distance(vector2);
}
@Benchmark
public double benchmarkDistanceSquared() {
return vector1.distanceSquared(vector2);
}
@Benchmark
public double benchmarkDotProduct() {
return vector1.dot(vector2);
}
@Benchmark
public SIMDVector3D benchmarkClone() {
return (SIMDVector3D) vector1.clone();
}
}
@@ -1,114 +0,0 @@
package ac.grim.grimac.benchmark.vector;
import ac.grim.grimac.utils.vector.ScalarVector3D;
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 2, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(1)
public class ScalarVector3DBenchmark {
private ScalarVector3D vector1;
private ScalarVector3D vector2;
@Setup
public void setup() {
vector1 = new ScalarVector3D(1.0, 2.0, 3.0);
vector2 = new ScalarVector3D(4.0, 5.0, 6.0);
}
@Benchmark
public double benchmarkGetX() {
return vector1.getX();
}
@Benchmark
public double benchmarkGetY() {
return vector1.getY();
}
@Benchmark
public double benchmarkGetZ() {
return vector1.getZ();
}
@Benchmark
public ScalarVector3D benchmarkSetX() {
return (ScalarVector3D) vector1.setX(10.0);
}
@Benchmark
public ScalarVector3D benchmarkSetY() {
return (ScalarVector3D) vector1.setY(20.0);
}
@Benchmark
public ScalarVector3D benchmarkSetZ() {
return (ScalarVector3D) vector1.setZ(30.0);
}
@Benchmark
public double benchmarkLength() {
return vector1.length();
}
@Benchmark
public double benchmarkLengthSquared() {
return vector1.lengthSquared();
}
@Benchmark
public ScalarVector3D benchmarkMultiplyScalar() {
return (ScalarVector3D) vector1.multiply(2.0);
}
@Benchmark
public ScalarVector3D benchmarkNormalize() {
return (ScalarVector3D) vector1.normalize();
}
@Benchmark
public ScalarVector3D benchmarkCrossProduct() {
return (ScalarVector3D) vector1.crossProduct(vector2);
}
@Benchmark
public ScalarVector3D benchmarkAdd() {
return (ScalarVector3D) vector1.add(vector2);
}
@Benchmark
public ScalarVector3D benchmarkSubtract() {
return (ScalarVector3D) vector1.subtract(vector2);
}
@Benchmark
public ScalarVector3D benchmarkMultiplyVector() {
return (ScalarVector3D) vector1.multiply(vector2);
}
@Benchmark
public double benchmarkDistance() {
return vector1.distance(vector2);
}
@Benchmark
public double benchmarkDistanceSquared() {
return vector1.distanceSquared(vector2);
}
@Benchmark
public double benchmarkDotProduct() {
return vector1.dot(vector2);
}
@Benchmark
public ScalarVector3D benchmarkClone() {
return (ScalarVector3D) vector1.clone();
}
}
@@ -8,8 +8,6 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.common.ConfigReloadObserver;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import lombok.Getter;
import lombok.Setter;
@@ -152,39 +150,6 @@ public class Check implements AbstractCheck, ConfigReloadObserver {
packetType == PacketType.Play.Client.WINDOW_CONFIRMATION;
}
public boolean isFlying(PacketTypeCommon packetType) {
return WrapperPlayClientPlayerFlying.isFlying(packetType);
}
public boolean isUpdate(PacketTypeCommon packetType) {
return isFlying(packetType)
|| packetType == PacketType.Play.Client.CLIENT_TICK_END
|| isTransaction(packetType);
}
public boolean isTickPacket(PacketTypeCommon packetType) {
if (isTickPacketIncludingNonMovement(packetType)) {
if (isFlying(packetType)) {
return !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate;
}
return true;
}
return false;
}
public boolean isTickPacketIncludingNonMovement(PacketTypeCommon packetType) {
// On 1.21.2+ fall back to the TICK_END packet IF the player did not send a movement packet for their tick
// TickTimer checks to see if player did not send a tick end packet before new flying packet is sent
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2)
&& !player.packetStateData.didSendMovementBeforeTickEnd) {
if (packetType == PacketType.Play.Client.CLIENT_TICK_END) {
return true;
}
}
return isFlying(packetType);
}
@Override
public void reload() {
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
@@ -6,7 +6,6 @@ import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "BadPacketsE")
@@ -24,12 +23,11 @@ public class BadPacketsE extends Check implements PacketCheck {
noReminderTicks = 0;
} else if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
noReminderTicks++;
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE
|| (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) && player.compensatedEntities.getSelf().inVehicle())) {
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE ||
event.getPacketType() == PacketType.Play.Client.VEHICLE_MOVE) {
noReminderTicks = 0; // Exempt vehicles
}
if (noReminderTicks > 20) {
flagAndAlert("ticks=" + noReminderTicks); // ban? I don't know how this would false
}
@@ -10,7 +10,8 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEn
@CheckData(name = "BadPacketsG")
public class BadPacketsG extends Check implements PacketCheck {
private boolean lastSneaking, respawn;
boolean wasTeleport;
boolean lastSneaking;
public BadPacketsG(GrimPlayer player) {
super(player);
@@ -18,12 +19,13 @@ public class BadPacketsG extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
wasTeleport = player.packetStateData.lastPacketWasTeleport || wasTeleport;
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
WrapperPlayClientEntityAction packet = new WrapperPlayClientEntityAction(event);
if (packet.getAction() == WrapperPlayClientEntityAction.Action.START_SNEAKING) {
// The player may send two START_SNEAKING packets if they respawned
if (lastSneaking && !respawn) {
if (lastSneaking && !wasTeleport) {
if (flagAndAlert("state=true") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -31,9 +33,8 @@ public class BadPacketsG extends Check implements PacketCheck {
} else {
lastSneaking = true;
}
respawn = false;
} else if (packet.getAction() == WrapperPlayClientEntityAction.Action.STOP_SNEAKING) {
if (!lastSneaking && !respawn) {
if (!lastSneaking && !wasTeleport) {
if (flagAndAlert("state=false") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -41,13 +42,7 @@ public class BadPacketsG extends Check implements PacketCheck {
} else {
lastSneaking = false;
}
respawn = false;
}
}
}
public void handleRespawn() {
// Clients could potentially not send a STOP_SNEAKING packet when they die, so we need to track it
respawn = true;
}
}
@@ -43,7 +43,7 @@ public class BadPacketsH extends Check implements PacketCheck {
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_8)) return;
if (!sentAnimation && flagAndAlert() && shouldModifyPackets()) {
if (!sentAnimation && flagAndAlert()) {
event.setCancelled(true);
player.onPacketCancel();
}
@@ -41,8 +41,9 @@ public class BadPacketsR extends Check implements PacketCheck {
if ((event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION ||
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) && !player.compensatedEntities.getSelf().inVehicle()) {
positions++;
} else if ((event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE || event.getPacketType() == PacketType.Play.Client.VEHICLE_MOVE)
&& player.inVehicle()) {
} else if ((event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE ||
event.getPacketType() == PacketType.Play.Client.VEHICLE_MOVE)
&& player.compensatedEntities.getSelf().inVehicle()) {
positions++;
}
}
@@ -0,0 +1,31 @@
package ac.grim.grimac.checks.impl.badpackets;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
@CheckData(name = "BadPacketsV", experimental = true)
public class BadPacketsV extends Check implements PacketCheck {
public BadPacketsV(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
WrapperPlayClientInteractEntity interactEntity = new WrapperPlayClientInteractEntity(event);
if (interactEntity.getAction() != WrapperPlayClientInteractEntity.InteractAction.ATTACK) return;
if (!player.packetStateData.isSlowedByUsingItem()) return;
ItemStack itemInUse = player.getInventory().getItemInHand(player.packetStateData.eatingHand);
if (flagAndAlert("UseItem=" + itemInUse.getType().getName().getKey()) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
@@ -5,13 +5,16 @@ import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
@CheckData(name = "BadPacketsX")
public class BadPacketsX extends Check implements PacketCheck {
@@ -26,26 +29,26 @@ public class BadPacketsX extends Check implements PacketCheck {
public final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_15_2);
public final void handle(BlockBreak blockBreak) {
if (blockBreak.action != DiggingAction.START_DIGGING && blockBreak.action != DiggingAction.FINISHED_DIGGING)
public final void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig, StateType block) {
if (dig.getAction() != DiggingAction.START_DIGGING && dig.getAction() != DiggingAction.FINISHED_DIGGING)
return;
final StateType block = blockBreak.block.getType();
// Fixes false from breaking kelp underwater
// The client sends two start digging packets to the server both in the same tick. BadPacketsX gets called twice, doesn't false the first time, but falses the second
// One ends up breaking the kelp, the other ends up doing nothing besides falsing this check because we think they're trying to mine water
// I am explicitly making this patch as narrow and specific as possible to potentially discover other blocks that exhibit similar behaviour
int newTick = GrimAPI.INSTANCE.getTickManager().currentTick;
if (lastTick == newTick
&& lastBreakLoc.equals(blockBreak.position)
&& lastBreakLoc.equals(dig.getBlockPosition())
&& !didLastFlag
&& lastBlockType.getHardness() == 0.0F
&& lastBlockType.getBlastResistance() == 0.0F
&& block == StateTypes.WATER
) return;
) {
return;
}
lastTick = newTick;
lastBreakLoc = blockBreak.position;
lastBreakLoc = dig.getBlockPosition();
lastBlockType = block;
// the block does not have a hitbox
@@ -55,13 +58,14 @@ public class BadPacketsX extends Check implements PacketCheck {
|| block == StateTypes.LAVA
|| block == StateTypes.BUBBLE_COLUMN
|| block == StateTypes.MOVING_PISTON
|| block == StateTypes.FIRE && noFireHitbox
|| (block == StateTypes.FIRE && noFireHitbox)
// or the client claims to have broken an unbreakable block
|| block.getHardness() == -1.0f && blockBreak.action == DiggingAction.FINISHED_DIGGING;
|| block.getHardness() == -1.0f && dig.getAction() == DiggingAction.FINISHED_DIGGING;
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + blockBreak.action) && shouldModifyPackets()) {
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + dig.getAction()) && shouldModifyPackets()) {
didLastFlag = true;
blockBreak.cancel();
event.setCancelled(true);
player.onPacketCancel();
} else {
didLastFlag = false;
}
@@ -5,12 +5,13 @@ import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import static ac.grim.grimac.events.packets.patch.ResyncWorldUtil.resyncPosition;
import static ac.grim.grimac.utils.nmsutil.BlockBreakSpeed.getBlockDamage;
@@ -39,9 +40,9 @@ public class BadPacketsZ extends Check implements PacketCheck {
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
}
public void handle(BlockBreak blockBreak) {
if (blockBreak.action == DiggingAction.START_DIGGING) {
final Vector3i pos = blockBreak.position;
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig) {
if (dig.getAction() == DiggingAction.START_DIGGING) {
final Vector3i pos = dig.getBlockPosition();
lastBlockWasInstantBreak = getBlockDamage(player, pos) >= 1;
lastCancelledBlock = null;
@@ -49,8 +50,8 @@ public class BadPacketsZ extends Check implements PacketCheck {
lastBlock = pos;
}
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
final Vector3i pos = blockBreak.position;
if (dig.getAction() == DiggingAction.CANCELLED_DIGGING) {
final Vector3i pos = dig.getBlockPosition();
if (shouldExempt(pos)) {
lastCancelledBlock = pos;
@@ -64,7 +65,8 @@ public class BadPacketsZ extends Check implements PacketCheck {
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || (!lastBlockWasInstantBreak && pos.equals(lastCancelledBlock))) {
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
if (shouldModifyPackets()) {
blockBreak.cancel();
event.setCancelled(true);
player.onPacketCancel();
resyncPosition(player, pos);
}
}
@@ -77,14 +79,15 @@ public class BadPacketsZ extends Check implements PacketCheck {
return;
}
if (blockBreak.action == DiggingAction.FINISHED_DIGGING) {
final Vector3i pos = blockBreak.position;
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
final Vector3i pos = dig.getBlockPosition();
// when a player looks away from the mined block, they send a cancel, and if they look at it again, they don't send another start. (thanks mojang!)
if (!pos.equals(lastCancelledBlock) && (!lastBlockWasInstantBreak || player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) && !pos.equals(lastBlock)) {
if (flagAndAlert("action=FINISHED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
if (shouldModifyPackets()) {
blockBreak.cancel();
event.setCancelled(true);
player.onPacketCancel();
resyncPosition(player, pos);
}
}
@@ -24,7 +24,6 @@ import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
@@ -34,14 +33,13 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.*;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
// You may not copy the check unless you are licensed under GPL
@CheckData(name = "Reach", configName = "Reach", setback = 10)
public class Reach extends Check implements PacketCheck {
@@ -110,7 +108,9 @@ public class Reach extends Check implements PacketCheck {
}
// If the player set their look, or we know they have a new tick
if (isUpdate(event.getPacketType())) {
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) ||
event.getPacketType() == PacketType.Play.Client.PONG ||
event.getPacketType() == PacketType.Play.Client.WINDOW_CONFIRMATION) {
tickBetterReachCheckWithAngle();
}
}
@@ -185,7 +185,7 @@ public class Reach extends Check implements PacketCheck {
double minDistance = Double.MAX_VALUE;
// https://bugs.mojang.com/browse/MC-67665
List<Vector3D> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
List<Vector> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
// If we are a tick behind, we don't know their next look so don't bother doing this
if (!isPrediction) {
@@ -205,12 +205,12 @@ public class Reach extends Check implements PacketCheck {
// +3 would be 3 + 3 = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE) + 3;
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (Vector3D lookVec : possibleLookDirs) {
for (Vector lookVec : possibleLookDirs) {
for (double eye : possibleEyeHeights) {
ac.grim.grimac.utils.vector.Vector3D eyePos = newVector3D(from.getX(), from.getY() + eye, from.getZ());
ac.grim.grimac.utils.vector.Vector3D endReachPos = eyePos.clone().add(newVector3D(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
Vector eyePos = new Vector(from.getX(), from.getY() + eye, from.getZ());
Vector endReachPos = eyePos.clone().add(new Vector(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
Vector3D intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
Vector intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
if (ReachUtils.isVecInside(targetBox, eyePos)) {
minDistance = 0;
@@ -1,32 +0,0 @@
package ac.grim.grimac.checks.impl.exploit;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEditBook;
@CheckData(name = "ExploitC")
public class ExploitC extends Check implements PacketCheck {
public ExploitC(GrimPlayer playerData) {
super(playerData);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.EDIT_BOOK) {
final String title = new WrapperPlayClientEditBook(event).getTitle();
if (title == null) return; // book was not signed
if (title.length() > 15) {
if (flagAndAlert("title=" + title) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
}
@@ -1,34 +0,0 @@
package ac.grim.grimac.checks.impl.movement;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "TickTimer", setback = 1)
public class TickTimer extends Check implements PostPredictionCheck {
private boolean receivedTickEnd = true;
private int flyingPackets = 0;
public TickTimer(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (!player.supportsEndTick()) return;
if (isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport) {
if (!receivedTickEnd) flagAndAlert("type=flying, packets=" + flyingPackets);
receivedTickEnd = false;
flyingPackets++;
} else if (event.getPacketType() == PacketType.Play.Client.CLIENT_TICK_END) {
receivedTickEnd = true;
if (flyingPackets > 1) flagAndAlert("type=end, packets=" + flyingPackets);
flyingPackets = 0;
}
}
}
@@ -8,6 +8,7 @@ import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "Timer", configName = "TimerA", setback = 10)
public class TimerCheck extends Check implements PacketCheck {
@@ -17,10 +18,10 @@ public class TimerCheck extends Check implements PacketCheck {
long knownPlayerClockTime = (long) (System.nanoTime() - 6e10);
long lastMovementPlayerClock = (long) (System.nanoTime() - 6e10);
// How long should the player be able to fall back behind their ping? (nanos)
// How long should the player be able to fall back behind their ping?
// Default: 120 milliseconds
long clockDrift;
// At what ping should we start to limit the balance advantage? (nanos)
long limitAbuseOverPing;
boolean hasGottenMovementAfterTransaction = false;
@@ -72,31 +73,35 @@ public class TimerCheck extends Check implements PacketCheck {
doCheck(event);
}
public void doCheck(final PacketReceiveEvent event) {
if (timerBalanceRealTime > System.nanoTime()) {
final double transactionPing = player.getTransactionPing();
// Limit using transaction ping if over 1000ms (default)
final boolean needsAdjustment = limitAbuseOverPing != -1 && transactionPing >= limitAbuseOverPing;
final boolean wouldFailNormal = timerBalanceRealTime > System.nanoTime();
final boolean failsAdjusted = needsAdjustment && (timerBalanceRealTime + ((transactionPing * 1e6) - clockDrift - 50e6)) > System.nanoTime();
if (wouldFailNormal || failsAdjusted) {
if (flag()) {
// Cancel the packet
// Only cancel if not an adjustment setback
if (shouldModifyPackets()) {
if (wouldFailNormal && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
if (isAboveSetbackVl()) player.getSetbackTeleportUtil().executeNonSimulatingSetback();
alert("");
if (wouldFailNormal) {
// Only alert if we would fail without adjusted limit
alert("");
}
}
// Reset the violation by 1 movement
timerBalanceRealTime -= 50e6;
}
// Limit using transaction ping if over 1000ms (default)
long playerClock = lastMovementPlayerClock;
if (System.nanoTime() - playerClock > limitAbuseOverPing) {
playerClock = System.nanoTime() - limitAbuseOverPing;
}
timerBalanceRealTime = Math.max(timerBalanceRealTime, playerClock - clockDrift);
timerBalanceRealTime = Math.max(timerBalanceRealTime, lastMovementPlayerClock - clockDrift);
}
public boolean checkForTransaction(PacketTypeCommon packetType) {
@@ -106,12 +111,13 @@ public class TimerCheck extends Check implements PacketCheck {
public boolean shouldCountPacketForTimer(PacketTypeCommon packetType) {
// If not flying, or this was a teleport, or this was a duplicate 1.17 mojang stupidity packet
return isTickPacket(packetType);
return WrapperPlayClientPlayerFlying.isFlying(packetType) &&
!player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate;
}
@Override
public void onReload(ConfigManager config) {
clockDrift = (long) (config.getDoubleElse(getConfigName() + ".drift", 120.0) * 1e6);
limitAbuseOverPing = (long) (config.getDoubleElse(getConfigName() + ".ping-abuse-limit-threshold", 1000) * 1e6);
limitAbuseOverPing = (long) (config.getDoubleElse(getConfigName() + ".ping-abuse-limit-threshold", 1000));
}
}
@@ -1,29 +0,0 @@
package ac.grim.grimac.checks.impl.multiactions;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
@CheckData(name = "MultiActionsA", experimental = true)
public class MultiActionsA extends Check implements PacketCheck {
public MultiActionsA(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
if (new WrapperPlayClientInteractEntity(event).getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
}
@@ -1,41 +0,0 @@
package ac.grim.grimac.checks.impl.multiactions;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import static ac.grim.grimac.events.packets.patch.ResyncWorldUtil.resyncPosition;
@CheckData(name = "MultiActionsB", experimental = true)
public class MultiActionsB extends Check implements PacketCheck {
public MultiActionsB(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
// this is vanilla on 1.7
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
return;
}
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
if (packet.getAction() == DiggingAction.START_DIGGING || packet.getAction() == DiggingAction.CANCELLED_DIGGING || packet.getAction() == DiggingAction.FINISHED_DIGGING) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
resyncPosition(player, packet.getBlockPosition());
}
}
}
}
}
@@ -1,31 +0,0 @@
package ac.grim.grimac.checks.impl.multiactions;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "MultiActionsC", experimental = true)
public class MultiActionsC extends Check implements PacketCheck {
public MultiActionsC(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
String verbose = player.isSprinting && !player.isSwimming ? "sprinting" : "";
if (player.packetStateData.isSlowedByUsingItem()) {
verbose += (verbose.isEmpty() ? "" : ", ") + "using";
}
if (!verbose.isEmpty() && flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
@@ -1,31 +0,0 @@
package ac.grim.grimac.checks.impl.multiactions;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "MultiActionsD", experimental = true)
public class MultiActionsD extends Check implements PacketCheck {
public MultiActionsD(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
String verbose = player.isSprinting && !player.isSwimming ? "sprinting" : "";
if (player.packetStateData.isSlowedByUsingItem()) {
verbose += (verbose.isEmpty() ? "" : ", ") + "using";
}
if (!verbose.isEmpty() && flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
@@ -1,32 +0,0 @@
package ac.grim.grimac.checks.impl.multiactions;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
@CheckData(name = "MultiActionsE", experimental = true)
public class MultiActionsE extends Check implements PacketCheck {
public MultiActionsE(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.ANIMATION) {
// this is possible to false on 1.7
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
return;
}
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
@@ -1,92 +0,0 @@
package ac.grim.grimac.checks.impl.multiactions;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockPlaceCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import java.util.ArrayList;
import java.util.List;
import static ac.grim.grimac.events.packets.patch.ResyncWorldUtil.resyncPosition;
@CheckData(name = "MultiActionsF", experimental = true)
public class MultiActionsF extends BlockPlaceCheck {
public MultiActionsF(GrimPlayer player) {
super(player);
}
private final List<String> flags = new ArrayList<>();
boolean entity, block;
@Override
public void onBlockPlace(BlockPlace place) {
block = true;
if (entity) {
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
if (flagAndAlert("place") && shouldModifyPackets() && shouldCancel()) {
place.resync();
}
} else {
flags.add("place");
}
}
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
entity = true;
if (block) {
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
if (flagAndAlert("entity") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add("entity");
}
}
}
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
if (packet.getAction() == DiggingAction.START_DIGGING || packet.getAction() == DiggingAction.FINISHED_DIGGING) {
block = true;
if (entity) {
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
if (flagAndAlert("dig") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
resyncPosition(player, packet.getBlockPosition());
}
} else {
flags.add("dig");
}
}
}
}
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
block = entity = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -15,6 +15,7 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
import java.util.ArrayDeque;
@@ -67,7 +68,12 @@ public class PostCheck extends Check implements PacketCheck, PostPredictionCheck
@Override
public void onPacketReceive(final PacketReceiveEvent event) {
if (isTickPacket(event.getPacketType())) { // Don't count teleports or duplicates as movements
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
// Don't count teleports or duplicates as movements
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
return;
}
post.clear();
sentFlying = true;
} else {
@@ -9,7 +9,7 @@ import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import ac.grim.grimac.utils.lists.EvictingQueue;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.Set;
@@ -45,8 +45,8 @@ public class DebugHandler extends Check implements PostPredictionCheck {
ChatColor color = pickColor(offset, offset);
Vector3D predicted = player.predictedVelocity.vector;
Vector3D actually = player.actualMovement;
Vector predicted = player.predictedVelocity.vector;
Vector actually = player.actualMovement;
ChatColor xColor = pickColor(Math.abs(predicted.getX() - actually.getX()), offset);
ChatColor yColor = pickColor(Math.abs(predicted.getY() - actually.getY()), offset);
@@ -9,9 +9,7 @@ import ac.grim.grimac.utils.math.VectorUtils;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import org.bukkit.util.Vector;
@CheckData(name = "FarPlace")
public class FarPlace extends BlockPlaceCheck {
@@ -29,8 +27,8 @@ public class FarPlace extends BlockPlaceCheck {
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (double d : possibleEyeHeights) {
SimpleCollisionBox box = new SimpleCollisionBox(blockPos);
Vector3D eyes = newVector3D(player.x, player.y + d, player.z);
Vector3D best = VectorUtils.cutBoxToVector(eyes, box);
Vector eyes = new Vector(player.x, player.y + d, player.z);
Vector best = VectorUtils.cutBoxToVector(eyes, box);
min = Math.min(min, eyes.distanceSquared(best));
}
@@ -11,6 +11,7 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import java.util.ArrayList;
import java.util.List;
@@ -55,7 +56,7 @@ public class MultiPlace extends BlockPlaceCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (isTickPacket(event.getPacketType())) {
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
hasPlaced = false;
}
}
@@ -8,7 +8,6 @@ import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.nmsutil.Ray;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
@@ -16,6 +15,7 @@ import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3f;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.Arrays;
@@ -111,7 +111,7 @@ public class RotationPlace extends BlockPlaceCheck {
Vector3d starting = new Vector3d(player.x, player.y + d, player.z);
// xRot and yRot are a tick behind
Ray trace = new Ray(player, starting.getX(), starting.getY(), starting.getZ(), lookDir.getX(), lookDir.getY());
Pair<Vector3D, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.first() != null) return true;
}
@@ -19,13 +19,12 @@ import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerExplosion;
import lombok.Getter;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
import java.util.Deque;
import java.util.LinkedList;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
@CheckData(name = "AntiExplosion", configName = "Explosion", setback = 10)
public class ExplosionHandler extends Check implements PostPredictionCheck {
Deque<VelocityData> firstBreadMap = new LinkedList<>();
@@ -122,7 +121,7 @@ public class ExplosionHandler extends Check implements PostPredictionCheck {
}
public void addPlayerExplosion(int breadOne, Vector3f explosion) {
firstBreadMap.add(new VelocityData(-1, breadOne, player.getSetbackTeleportUtil().isSendingSetback, newVector3D(explosion.getX(), explosion.getY(), explosion.getZ())));
firstBreadMap.add(new VelocityData(-1, breadOne, player.getSetbackTeleportUtil().isSendingSetback, new Vector(explosion.getX(), explosion.getY(), explosion.getZ())));
}
public void setPointThree(boolean isPointThree) {
@@ -15,14 +15,12 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity;
import lombok.Getter;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.Deque;
import java.util.LinkedList;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
// We are making a velocity sandwich between two pieces of transaction packets (bread)
@CheckData(name = "AntiKB", alternativeName = "AntiKnockback", configName = "Knockback", setback = 10, decay = 0.025)
public class KnockbackHandler extends Check implements PostPredictionCheck {
@@ -68,17 +66,16 @@ public class KnockbackHandler extends Check implements PostPredictionCheck {
if (playerVelocity.getY() == -0.04) {
velocity.setVelocity(playerVelocity.add(new Vector3d(0, 1 / 8000D, 0)));
playerVelocity = velocity.getVelocity();
event.markForReEncode(true);
}
// Wrap velocity between two transactions
player.sendTransaction();
addPlayerKnockback(entityId, player.lastTransactionSent.get(), newVector3D(playerVelocity.getX(), playerVelocity.getY(), playerVelocity.getZ()));
addPlayerKnockback(entityId, player.lastTransactionSent.get(), new Vector(playerVelocity.getX(), playerVelocity.getY(), playerVelocity.getZ()));
event.getTasksAfterSend().add(player::sendTransaction);
}
}
@NotNull public Pair<VelocityData, Vector3D> getFutureKnockback() {
@NotNull public Pair<VelocityData, Vector> getFutureKnockback() {
// Chronologically in the future
if (firstBreadMap.size() > 0) {
VelocityData data = firstBreadMap.peek();
@@ -100,7 +97,7 @@ public class KnockbackHandler extends Check implements PostPredictionCheck {
return new Pair<>(null, null);
}
private void addPlayerKnockback(int entityID, int breadOne, Vector3D knockback) {
private void addPlayerKnockback(int entityID, int breadOne, Vector knockback) {
firstBreadMap.add(new VelocityData(entityID, breadOne, player.getSetbackTeleportUtil().isSendingSetback, knockback));
}
@@ -1,10 +1,19 @@
package ac.grim.grimac.checks.type;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.utils.anticheat.update.PositionUpdate;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
public interface PacketCheck extends AbstractCheck {
default void onPacketReceive(final PacketReceiveEvent event) {}
default void onPacketSend(final PacketSendEvent event) {}
default void onPacketReceive(final PacketReceiveEvent event) {
}
default void onPacketSend(final PacketSendEvent event) {
}
default void onPositionUpdate(final PositionUpdate positionUpdate) {
}
}
@@ -17,8 +17,6 @@ import ac.grim.grimac.utils.latency.CompensatedWorld;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.nmsutil.*;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.VectorFactory;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
@@ -49,6 +47,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.*;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerAcknowledgeBlockChanges;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetSlot;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
@@ -372,7 +371,9 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
// Manual filter on FINISH_DIGGING to prevent clients setting non-breakable blocks to air
private static final Function<StateType, Boolean> BREAKABLE = type -> !type.isAir() && type.getHardness() != -1.0f && type != StateTypes.WATER && type != StateTypes.LAVA;
private static final Function<StateType, Boolean> BREAKABLE = type -> {
return !type.isAir() && type.getHardness() != -1.0f && type != StateTypes.WATER && type != StateTypes.LAVA;
};
@Override
public void onPacketReceive(PacketReceiveEvent event) {
@@ -454,43 +455,43 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
final BlockBreak blockBreak = new BlockBreak(packet, player);
WrapperPlayClientPlayerDigging dig = new WrapperPlayClientPlayerDigging(event);
final Vector3i digPosition = dig.getBlockPosition();
WrappedBlockState block = player.compensatedWorld.getWrappedBlockStateAt(digPosition);
final StateType type = block.getType();
player.checkManager.getPacketCheck(BadPacketsX.class).handle(blockBreak);
player.checkManager.getPacketCheck(BadPacketsZ.class).handle(blockBreak);
player.checkManager.getPacketCheck(BadPacketsX.class).handle(event, dig, type);
player.checkManager.getPacketCheck(BadPacketsZ.class).handle(event, dig);
if (blockBreak.isCancelled()) {
event.setCancelled(true);
player.onPacketCancel();
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
// Not unbreakable
if (BREAKABLE.apply(type) && !event.isCancelled()) {
player.compensatedWorld.startPredicting();
player.compensatedWorld.updateBlock(digPosition.getX(), digPosition.getY(), digPosition.getZ(), 0);
player.compensatedWorld.stopPredicting(dig);
}
}
if (dig.getAction() == DiggingAction.START_DIGGING && !event.isCancelled()) {
double damage = BlockBreakSpeed.getBlockDamage(player, digPosition);
//Instant breaking, no damage means it is unbreakable by creative players (with swords)
if (damage >= 1) {
player.compensatedWorld.startPredicting();
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && Materials.isWaterSource(player.getClientVersion(), block)) {
// Vanilla uses a method to grab water flowing, but as you can't break flowing water
// We can simply treat all waterlogged blocks or source blocks as source blocks
player.compensatedWorld.updateBlock(digPosition, StateTypes.WATER.createBlockState(CompensatedWorld.blockVersion));
} else {
player.compensatedWorld.updateBlock(digPosition.getX(), digPosition.getY(), digPosition.getZ(), 0);
}
player.compensatedWorld.stopPredicting(dig);
}
}
if (!event.isCancelled()) {
if (blockBreak.action == DiggingAction.FINISHED_DIGGING && BREAKABLE.apply(blockBreak.block.getType())) {
player.compensatedWorld.startPredicting();
player.compensatedWorld.updateBlock(blockBreak.position.x, blockBreak.position.y, blockBreak.position.z, 0);
player.compensatedWorld.stopPredicting(packet);
}
if (blockBreak.action == DiggingAction.START_DIGGING) {
double damage = BlockBreakSpeed.getBlockDamage(player, blockBreak.position);
// Instant breaking, no damage means it is unbreakable by creative players (with swords)
if (damage >= 1) {
player.compensatedWorld.startPredicting();
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && Materials.isWaterSource(player.getClientVersion(), blockBreak.block)) {
// Vanilla uses a method to grab water flowing, but as you can't break flowing water
// We can simply treat all waterlogged blocks or source blocks as source blocks
player.compensatedWorld.updateBlock(blockBreak.position, StateTypes.WATER.createBlockState(CompensatedWorld.blockVersion));
} else {
player.compensatedWorld.updateBlock(blockBreak.position.x, blockBreak.position.y, blockBreak.position.z, 0);
}
player.compensatedWorld.stopPredicting(packet);
}
}
if (blockBreak.action == DiggingAction.START_DIGGING || blockBreak.action == DiggingAction.FINISHED_DIGGING || blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
player.compensatedWorld.handleBlockBreakPrediction(packet);
if (dig.getAction() == DiggingAction.START_DIGGING || dig.getAction() == DiggingAction.FINISHED_DIGGING || dig.getAction() == DiggingAction.CANCELLED_DIGGING) {
player.compensatedWorld.handleBlockBreakPrediction(dig);
}
}
}
@@ -577,15 +578,6 @@ public class CheckManagerListener extends PacketListenerAbstract {
player.packetStateData.cancelDuplicatePacket = false;
}
if (event.getPacketType() == PacketType.Play.Client.CLIENT_TICK_END) {
if (!player.packetStateData.didSendMovementBeforeTickEnd) {
// The player didn't send a movement packet, so we can predict this like we had idle tick on 1.8
player.packetStateData.didLastLastMovementIncludePosition = player.packetStateData.didLastMovementIncludePosition;
player.packetStateData.didLastMovementIncludePosition = false;
}
player.packetStateData.didSendMovementBeforeTickEnd = false;
}
// Finally, remove the packet state variables on this packet
player.packetStateData.lastPacketWasOnePointSeventeenDuplicate = false;
player.packetStateData.lastPacketWasTeleport = false;
@@ -755,10 +747,6 @@ public class CheckManagerListener extends PacketListenerAbstract {
player.packetStateData.didLastLastMovementIncludePosition = player.packetStateData.didLastMovementIncludePosition;
player.packetStateData.didLastMovementIncludePosition = hasPosition;
if (!player.packetStateData.lastPacketWasTeleport) {
player.packetStateData.didSendMovementBeforeTickEnd = true;
}
}
private static void placeLilypad(GrimPlayer player, InteractionHand hand) {
@@ -794,10 +782,10 @@ public class CheckManagerListener extends PacketListenerAbstract {
private static HitData getNearestHitResult(GrimPlayer player, StateType heldItem, boolean sourcesHaveHitbox) {
Vector3d startingPos = new Vector3d(player.x, player.y + player.getEyeHeight(), player.z);
Vector3D startingVec = VectorFactory.newVector3D(startingPos.getX(), startingPos.getY(), startingPos.getZ());
Vector startingVec = new Vector(startingPos.getX(), startingPos.getY(), startingPos.getZ());
Ray trace = new Ray(player, startingPos.getX(), startingPos.getY(), startingPos.getZ(), player.xRot, player.yRot);
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
Vector3D endVec = trace.getPointAtDistance(distance);
Vector endVec = trace.getPointAtDistance(distance);
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
return traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
@@ -806,14 +794,14 @@ public class CheckManagerListener extends PacketListenerAbstract {
data.downCast(boxes);
double bestHitResult = Double.MAX_VALUE;
Vector3D bestHitLoc = null;
Vector bestHitLoc = null;
BlockFace bestFace = null;
for (SimpleCollisionBox box : boxes) {
Pair<Vector3D, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.first() == null) continue; // No intercept
Vector3D hitLoc = intercept.first();
Vector hitLoc = intercept.first();
if (hitLoc.distanceSquared(startingVec) < bestHitResult) {
bestHitResult = hitLoc.distanceSquared(startingVec);
@@ -831,7 +819,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
double waterHeight = player.compensatedWorld.getFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ());
SimpleCollisionBox box = new SimpleCollisionBox(vector3i.getX(), vector3i.getY(), vector3i.getZ(), vector3i.getX() + 1, vector3i.getY() + waterHeight, vector3i.getZ() + 1);
Pair<Vector3D, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.first() != null) {
return new HitData(vector3i, intercept.first(), intercept.second(), block);
@@ -13,7 +13,6 @@ import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.EntityPositionData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
@@ -22,6 +21,7 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.protocol.potion.PotionType;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.github.retrooper.packetevents.wrapper.play.server.*;
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
@@ -60,19 +60,22 @@ public class PacketEntityReplication extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
// Teleports don't interpolate, duplicate 1.17 packets don't interpolate
if (!isTickPacket(event.getPacketType())) return;
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
// Teleports don't interpolate, duplicate 1.17 packets don't interpolate
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate)
return;
boolean isTickingReliably = player.isTickingReliablyFor(3);
boolean isTickingReliably = player.isTickingReliablyFor(3);
PacketEntity playerVehicle = player.compensatedEntities.getSelf().getRiding();
for (PacketEntity entity : player.compensatedEntities.entityMap.values()) {
if (entity == playerVehicle && !player.vehicleData.lastDummy) {
// The player has this as their vehicle, so they aren't interpolating it.
// And it isn't a dummy position
entity.setPositionRaw(entity.getPossibleCollisionBoxes());
} else {
entity.onMovement(isTickingReliably);
PacketEntity playerVehicle = player.compensatedEntities.getSelf().getRiding();
for (PacketEntity entity : player.compensatedEntities.entityMap.values()) {
if (entity == playerVehicle && !player.vehicleData.lastDummy) {
// The player has this as their vehicle, so they aren't interpolating it.
// And it isn't a dummy position
entity.setPositionRaw(entity.getPossibleCollisionBoxes());
} else {
entity.onMovement(isTickingReliably);
}
}
}
}
@@ -83,55 +86,48 @@ public class PacketEntityReplication extends Check implements PacketCheck {
if ((event.getPacketType() == PacketType.Play.Server.PING || event.getPacketType() == PacketType.Play.Server.WINDOW_CONFIRMATION) && player.packetStateData.lastServerTransWasValid) {
despawnedEntitiesThisTransaction.clear();
}
else if (event.getPacketType() == PacketType.Play.Server.SPAWN_LIVING_ENTITY) {
if (event.getPacketType() == PacketType.Play.Server.SPAWN_LIVING_ENTITY) {
WrapperPlayServerSpawnLivingEntity packetOutEntity = new WrapperPlayServerSpawnLivingEntity(event);
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getEntityUUID(), packetOutEntity.getEntityType(), packetOutEntity.getPosition(), packetOutEntity.getYaw(), packetOutEntity.getPitch(), packetOutEntity.getEntityMetadata(), 0);
}
else if (event.getPacketType() == PacketType.Play.Server.SPAWN_ENTITY) {
if (event.getPacketType() == PacketType.Play.Server.SPAWN_ENTITY) {
WrapperPlayServerSpawnEntity packetOutEntity = new WrapperPlayServerSpawnEntity(event);
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getUUID().orElse(null), packetOutEntity.getEntityType(), packetOutEntity.getPosition(), packetOutEntity.getYaw(), packetOutEntity.getPitch(), null, packetOutEntity.getData());
}
else if (event.getPacketType() == PacketType.Play.Server.SPAWN_PLAYER) {
if (event.getPacketType() == PacketType.Play.Server.SPAWN_PLAYER) {
WrapperPlayServerSpawnPlayer packetOutEntity = new WrapperPlayServerSpawnPlayer(event);
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getUUID(), EntityTypes.PLAYER, packetOutEntity.getPosition(), packetOutEntity.getYaw(), packetOutEntity.getPitch(), packetOutEntity.getEntityMetadata(), 0);
}
else if (event.getPacketType() == PacketType.Play.Server.SPAWN_PAINTING) {
if (event.getPacketType() == PacketType.Play.Server.SPAWN_PAINTING) {
WrapperPlayServerSpawnPainting packetOutEntity = new WrapperPlayServerSpawnPainting(event);
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getUUID(), EntityTypes.PAINTING, packetOutEntity.getPosition().toVector3d(), 0, 0f, null, packetOutEntity.getDirection().getHorizontalIndex());
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getUUID(), EntityTypes.PAINTING, packetOutEntity.getPosition().toVector3d(), packetOutEntity.getDirection().getHorizontalIndex(), 0f, null, packetOutEntity.getType().isPresent() ? packetOutEntity.getType().get().getId() : -1);
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE) {
if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE) {
WrapperPlayServerEntityRelativeMove move = new WrapperPlayServerEntityRelativeMove(event);
handleMoveEntity(event, move.getEntityId(), move.getDeltaX(), move.getDeltaY(), move.getDeltaZ(), null, null, true, true);
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE_AND_ROTATION) {
if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE_AND_ROTATION) {
WrapperPlayServerEntityRelativeMoveAndRotation move = new WrapperPlayServerEntityRelativeMoveAndRotation(event);
handleMoveEntity(event, move.getEntityId(), move.getDeltaX(), move.getDeltaY(), move.getDeltaZ(), move.getYaw() * 0.7111111F, move.getPitch() * 0.7111111F, true, true);
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_TELEPORT) {
if (event.getPacketType() == PacketType.Play.Server.ENTITY_TELEPORT) {
WrapperPlayServerEntityTeleport move = new WrapperPlayServerEntityTeleport(event);
Vector3d pos = move.getPosition();
handleMoveEntity(event, move.getEntityId(), pos.getX(), pos.getY(), pos.getZ(), move.getYaw(), move.getPitch(), false, true);
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_POSITION_SYNC) {
// ENTITY_TELEPORT but without relative flags
WrapperPlayServerEntityPositionSync move = new WrapperPlayServerEntityPositionSync(event);
final EntityPositionData values = move.getValues();
final Vector3d pos = values.getPosition();
// TODO this isn't technically correct
// If the position sync is to a pos > 4096 from the entity pos, client does some special stuff without interpolation
handleMoveEntity(event, move.getId(), pos.getX(), pos.getY(), pos.getZ(), values.getYaw(), values.getPitch(), false, true);
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_ROTATION) { // Affects interpolation
if (event.getPacketType() == PacketType.Play.Server.ENTITY_ROTATION) { // Affects interpolation
WrapperPlayServerEntityRotation move = new WrapperPlayServerEntityRotation(event);
handleMoveEntity(event, move.getEntityId(), 0, 0, 0, move.getYaw() * 0.7111111F, move.getPitch() * 0.7111111F, true, false);
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
WrapperPlayServerEntityMetadata entityMetadata = new WrapperPlayServerEntityMetadata(event);
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.compensatedEntities.updateEntityMetadata(entityMetadata.getEntityId(), entityMetadata.getEntityMetadata()));
}
// 1.19.3+
else if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO_UPDATE) {
if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO_UPDATE) {
WrapperPlayServerPlayerInfoUpdate info = new WrapperPlayServerPlayerInfoUpdate(event);
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> {
for (WrapperPlayServerPlayerInfoUpdate.PlayerInfo entry : info.getEntries()) {
@@ -158,7 +154,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
});
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_EFFECT) {
if (event.getPacketType() == PacketType.Play.Server.ENTITY_EFFECT) {
WrapperPlayServerEntityEffect effect = new WrapperPlayServerEntityEffect(event);
PotionType type = effect.getPotionType();
@@ -190,7 +186,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
});
}
else if (event.getPacketType() == PacketType.Play.Server.REMOVE_ENTITY_EFFECT) {
if (event.getPacketType() == PacketType.Play.Server.REMOVE_ENTITY_EFFECT) {
WrapperPlayServerRemoveEntityEffect effect = new WrapperPlayServerRemoveEntityEffect(event);
if (isDirectlyAffectingPlayer(player, effect.getEntityId())) player.sendTransaction();
@@ -203,7 +199,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
});
}
else if (event.getPacketType() == PacketType.Play.Server.UPDATE_ATTRIBUTES) {
if (event.getPacketType() == PacketType.Play.Server.UPDATE_ATTRIBUTES) {
WrapperPlayServerUpdateAttributes attributes = new WrapperPlayServerUpdateAttributes(event);
int entityID = attributes.getEntityId();
@@ -215,7 +211,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
() -> player.compensatedEntities.updateAttributes(entityID, attributes.getProperties()));
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_STATUS) {
if (event.getPacketType() == PacketType.Play.Server.ENTITY_STATUS) {
WrapperPlayServerEntityStatus status = new WrapperPlayServerEntityStatus(event);
// This hasn't changed from 1.7.2 to 1.17
// Needed to exempt players on dead vehicles, as dead entities have strange physics.
@@ -249,7 +245,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
}
}
else if (event.getPacketType() == PacketType.Play.Server.SET_SLOT) {
if (event.getPacketType() == PacketType.Play.Server.SET_SLOT) {
WrapperPlayServerSetSlot slot = new WrapperPlayServerSetSlot(event);
if (slot.getWindowId() == 0) {
@@ -267,7 +263,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
}
}
else if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) {
if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) {
WrapperPlayServerWindowItems items = new WrapperPlayServerWindowItems(event);
if (items.getWindowId() == 0) { // Player inventory
@@ -277,16 +273,16 @@ public class PacketEntityReplication extends Check implements PacketCheck {
}
// 1.8 clients fail to send the RELEASE_USE_ITEM packet when a window is opened client sided while using an item
else if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.packetStateData.setSlowedByUsingItem(false));
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get() + 1, () -> player.packetStateData.setSlowedByUsingItem(false));
}
else if (event.getPacketType() == PacketType.Play.Server.OPEN_HORSE_WINDOW) {
if (event.getPacketType() == PacketType.Play.Server.OPEN_HORSE_WINDOW) {
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.packetStateData.setSlowedByUsingItem(false));
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get() + 1, () -> player.packetStateData.setSlowedByUsingItem(false));
}
else if (event.getPacketType() == PacketType.Play.Server.SET_PASSENGERS) {
if (event.getPacketType() == PacketType.Play.Server.SET_PASSENGERS) {
WrapperPlayServerSetPassengers mount = new WrapperPlayServerSetPassengers(event);
int vehicleID = mount.getEntityId();
@@ -295,7 +291,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
handleMountVehicle(event, vehicleID, passengers);
}
else if (event.getPacketType() == PacketType.Play.Server.ATTACH_ENTITY) {
if (event.getPacketType() == PacketType.Play.Server.ATTACH_ENTITY) {
WrapperPlayServerAttachEntity attach = new WrapperPlayServerAttachEntity(event);
// This packet was replaced by the mount packet on 1.9+ servers - to support multiple passengers on one vehicle
@@ -326,7 +322,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
}
}
else if (event.getPacketType() == PacketType.Play.Server.DESTROY_ENTITIES) {
if (event.getPacketType() == PacketType.Play.Server.DESTROY_ENTITIES) {
WrapperPlayServerDestroyEntities destroy = new WrapperPlayServerDestroyEntities(event);
int[] destroyEntityIds = destroy.getEntityIds();
@@ -421,13 +417,9 @@ public class PacketEntityReplication extends Check implements PacketCheck {
// As we don't want vehicles to fly, we need to replace it with a teleport if it is player vehicle
//
// Don't bother with client controlled vehicles though
boolean vanillaVehicleFlight = player.compensatedEntities.serverPlayerVehicle != null
&& player.compensatedEntities.serverPlayerVehicle == entityId
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)
// TODO: https://discord.com/channels/721686193061888071/721686193515003966/1310659538831020123
// Why does the server now send an entity rel move packet matching the player's vehicle movement every time?
&& PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_21_2)
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9);
boolean vanillaVehicleFlight = player.compensatedEntities.serverPlayerVehicle != null && player.compensatedEntities.serverPlayerVehicle == entityId
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) &&
PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9);
// ViaVersion sends two relative packets when moving more than 4 blocks
// This is broken and causes the client to interpolate like (0, 4) and (1, 3) instead of (1, 7)
@@ -36,9 +36,6 @@ public class PacketPlayerJoinQuit extends PacketListenerAbstract {
}
if (player.hasPermission("grim.alerts") && player.hasPermission("grim.alerts.enable-on-join")) {
GrimAPI.INSTANCE.getAlertManager().toggleAlerts(player);
if (player.hasPermission("grim.verbose") && player.hasPermission("grim.verbose.enable-on-join")) {
GrimAPI.INSTANCE.getAlertManager().toggleVerbose(player);
}
}
if (player.hasPermission("grim.spectate") && GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("spectators.hide-regardless", false)) {
GrimAPI.INSTANCE.getSpectateManager().onLogin(player);
@@ -3,7 +3,6 @@ package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.badpackets.BadPacketsE;
import ac.grim.grimac.checks.impl.badpackets.BadPacketsF;
import ac.grim.grimac.checks.impl.badpackets.BadPacketsG;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.TrackerData;
import ac.grim.grimac.utils.data.packetentity.PacketEntitySelf;
@@ -20,12 +19,11 @@ import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerJoinGame;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateHealth;
import org.bukkit.util.Vector;
import java.util.List;
import java.util.Objects;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
/**
* PlayerRespawnS2CPacket info (1.20.2+):
* If the world is different (check via registry key), world is recreated (all entities etc destroyed).
@@ -133,11 +131,7 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
}
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get() + 1, () -> {
// From 1.16 to 1.19, this doesn't get set to false for whatever reason
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_16) || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20)) {
player.isSneaking = false;
}
player.isSneaking = false;
player.lastOnGround = false;
player.onGround = false;
player.isInBed = false;
@@ -163,7 +157,6 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
}
player.checkManager.getPacketCheck(BadPacketsE.class).handleRespawn(); // Reminder ticks reset
player.checkManager.getPacketCheck(BadPacketsG.class).handleRespawn();
// compensate for immediate respawn gamerule
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_15)) {
@@ -192,7 +185,7 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
player.compensatedEntities.hasSprintingAttributeEnabled = false;
}
player.pose = Pose.STANDING;
player.clientVelocity = newVector3D();
player.clientVelocity = new Vector();
player.gamemode = respawn.getGameMode();
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_17)) {
player.compensatedWorld.setDimension(respawn.getDimensionType(), event.getUser());
@@ -3,7 +3,6 @@ package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.KnownInput;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.data.packetentity.PacketEntityHorse;
import com.github.retrooper.packetevents.PacketEvents;
@@ -13,7 +12,6 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerInput;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientSteerVehicle;
public class PacketPlayerSteer extends PacketListenerAbstract {
@@ -24,12 +22,13 @@ public class PacketPlayerSteer extends PacketListenerAbstract {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
//TODO: add support for 1.21.2 with new vehicle move packet
if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE) {
WrapperPlayClientSteerVehicle steer = new WrapperPlayClientSteerVehicle(event);
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
WrapperPlayClientSteerVehicle steer = new WrapperPlayClientSteerVehicle(event);
float forwards = steer.getForward();
float sideways = steer.getSideways();
@@ -100,33 +99,6 @@ public class PacketPlayerSteer extends PacketListenerAbstract {
}
player.packetStateData.receivedSteerVehicle = true;
} else if (event.getPacketType() == PacketType.Play.Client.PLAYER_INPUT) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
WrapperPlayClientPlayerInput input = new WrapperPlayClientPlayerInput(event);
byte forward = 0;
byte sideways = 0;
if (input.isForward()) {
forward++;
}
if (input.isBackward()) {
forward--;
}
if (input.isLeft()) {
sideways++;
}
if (input.isRight()) {
sideways--;
}
player.vehicleData.nextVehicleForward = forward * 0.98f;
player.vehicleData.nextVehicleHorizontal = sideways * 0.98f;
player.packetStateData.knownInput = new KnownInput(input.isForward(), input.isBackward(), input.isLeft(), input.isRight(), input.isJump(), input.isShift(), input.isSprint());
}
}
}
@@ -6,6 +6,7 @@ import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import lombok.Getter;
@Getter
@@ -26,7 +27,7 @@ public class ActionManager extends Check implements PacketCheck {
attacking = true;
lastAttack = System.currentTimeMillis();
}
} else if (isTickPacketIncludingNonMovement(event.getPacketType())) {
} else if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
player.totalFlyingPacketsSent++;
attacking = false;
}
@@ -11,14 +11,12 @@ import ac.grim.grimac.checks.impl.combat.Reach;
import ac.grim.grimac.checks.impl.crash.*;
import ac.grim.grimac.checks.impl.exploit.ExploitA;
import ac.grim.grimac.checks.impl.exploit.ExploitB;
import ac.grim.grimac.checks.impl.exploit.ExploitC;
import ac.grim.grimac.checks.impl.groundspoof.NoFallA;
import ac.grim.grimac.checks.impl.misc.ClientBrand;
import ac.grim.grimac.checks.impl.misc.FastBreak;
import ac.grim.grimac.checks.impl.misc.GhostBlockMitigation;
import ac.grim.grimac.checks.impl.misc.TransactionOrder;
import ac.grim.grimac.checks.impl.movement.*;
import ac.grim.grimac.checks.impl.multiactions.*;
import ac.grim.grimac.checks.impl.post.PostCheck;
import ac.grim.grimac.checks.impl.prediction.DebugHandler;
import ac.grim.grimac.checks.impl.prediction.NoFallB;
@@ -100,15 +98,11 @@ public class CheckManager {
.put(BadPacketsS.class, new BadPacketsS(player))
.put(BadPacketsT.class, new BadPacketsT(player))
.put(BadPacketsU.class, new BadPacketsU(player))
.put(BadPacketsV.class, new BadPacketsV(player))
.put(BadPacketsW.class, new BadPacketsW(player))
.put(BadPacketsX.class, new BadPacketsX(player))
.put(BadPacketsY.class, new BadPacketsY(player))
.put(BadPacketsZ.class, new BadPacketsZ(player))
.put(MultiActionsA.class, new MultiActionsA(player))
.put(MultiActionsB.class, new MultiActionsB(player))
.put(MultiActionsC.class, new MultiActionsC(player))
.put(MultiActionsD.class, new MultiActionsD(player))
.put(MultiActionsE.class, new MultiActionsE(player))
.put(FastBreak.class, new FastBreak(player))
.put(TransactionOrder.class, new TransactionOrder(player))
.put(NoSlowB.class, new NoSlowB(player))
@@ -157,7 +151,6 @@ public class CheckManager {
.put(InvalidPlaceB.class, new InvalidPlaceB(player))
.put(AirLiquidPlace.class, new AirLiquidPlace(player))
.put(MultiPlace.class, new MultiPlace(player))
.put(MultiActionsF.class, new MultiActionsF(player))
.put(FarPlace.class, new FarPlace(player))
.put(FabricatedPlace.class, new FabricatedPlace(player))
.put(PositionPlace.class, new PositionPlace(player))
@@ -168,7 +161,6 @@ public class CheckManager {
prePredictionChecks = new ImmutableClassToInstanceMap.Builder<PacketCheck>()
.put(TimerCheck.class, new TimerCheck(player))
.put(TickTimer.class, new TickTimer(player))
.put(CrashA.class, new CrashA(player))
.put(CrashB.class, new CrashB(player))
.put(CrashC.class, new CrashC(player))
@@ -179,7 +171,6 @@ public class CheckManager {
.put(CrashH.class, new CrashH(player))
.put(ExploitA.class, new ExploitA(player))
.put(ExploitB.class, new ExploitB(player))
.put(ExploitC.class, new ExploitC(player))
.put(VehicleTimer.class, new VehicleTimer(player))
.build();
@@ -70,12 +70,12 @@ public class DiscordManager implements Initable {
return list;
}
public void sendAlert(GrimPlayer player, String verbose, String checkName, int violations) {
public void sendAlert(GrimPlayer player, String verbose, String checkName, String violations) {
if (client != null) {
String content = staticContent;
content = content.replace("%check%", checkName);
content = content.replace("%violations%", Integer.toString(violations));
content = content.replace("%violations%", violations);
content = GrimAPI.INSTANCE.getExternalAPI().replaceVariables(player, content, false);
content = content.replace("_", "\\_");
@@ -11,6 +11,7 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
@@ -98,14 +99,16 @@ public class PunishmentManager implements ConfigReloadable {
}
}
private String replaceAlertPlaceholders(String original, int vl, PunishGroup group, Check check, String alertString, String verbose) {
private String replaceAlertPlaceholders(String original, PunishGroup group, Check check, String alertString, String verbose) {
// Streams are slow but this isn't a hot path... it's fine.
String vl = group.violations.values().stream().filter((e) -> e == check).count() + "";
original = MessageUtil.format(original
.replace("[alert]", alertString)
.replace("[proxy]", alertString)
.replace("%check_name%", check.getDisplayName())
.replace("%experimental%", check.isExperimental() ? experimentalSymbol : "")
.replace("%vl%", Integer.toString(vl))
.replace("%vl%", vl)
.replace("%verbose%", verbose)
.replace("%description%", check.getDescription())
);
@@ -121,13 +124,12 @@ public class PunishmentManager implements ConfigReloadable {
// Check commands
for (PunishGroup group : groups) {
if (group.getChecks().contains(check)) {
final int vl = getViolations(group, check);
final int violationCount = group.getViolations().size();
int violationCount = group.getViolations().size();
for (ParsedCommand command : group.getCommands()) {
String cmd = replaceAlertPlaceholders(command.getCommand(), vl, group, check, alertString, verbose);
String cmd = replaceAlertPlaceholders(command.getCommand(), group, check, alertString, verbose);
// Verbose that prints all flags
if (!GrimAPI.INSTANCE.getAlertManager().getEnabledVerbose().isEmpty() && command.command.equals("[alert]")) {
if (GrimAPI.INSTANCE.getAlertManager().getEnabledVerbose().size() > 0 && command.command.equals("[alert]")) {
sentDebug = true;
for (Player bukkitPlayer : GrimAPI.INSTANCE.getAlertManager().getEnabledVerbose()) {
bukkitPlayer.sendMessage(cmd);
@@ -147,9 +149,10 @@ public class PunishmentManager implements ConfigReloadable {
if (executeEvent.isCancelled()) continue;
if (command.command.equals("[webhook]")) {
String vl = group.violations.values().stream().filter((e) -> e == check).count() + "";
GrimAPI.INSTANCE.getDiscordManager().sendAlert(player, verbose, check.getDisplayName(), vl);
} else if (command.command.equals("[proxy]")) {
ProxyAlertMessenger.sendPluginMessage(replaceAlertPlaceholders(command.getCommand(), vl, group, check, proxyAlertString, verbose));
ProxyAlertMessenger.sendPluginMessage(replaceAlertPlaceholders(command.getCommand(), group, check, proxyAlertString, verbose));
} else {
if (command.command.equals("[alert]")) {
sentDebug = true;
@@ -181,19 +184,10 @@ public class PunishmentManager implements ConfigReloadable {
group.violations.put(currentTime, check);
// Remove violations older than the defined time in the config
group.violations.entrySet().removeIf(time -> currentTime - time.getKey() > group.removeViolationsAfter);
group.violations.long2ObjectEntrySet().removeIf(time -> currentTime - time.getLongKey() > group.removeViolationsAfter);
}
}
}
private int getViolations(PunishGroup group, Check check) {
int vl = 0;
for (Check value : group.violations.values()) {
if (value == check) vl++;
}
return vl;
}
}
class PunishGroup {
@@ -202,7 +196,7 @@ class PunishGroup {
@Getter
List<ParsedCommand> commands;
@Getter
public Map<Long, Check> violations = new HashMap<>();
Long2ObjectOpenHashMap<Check> violations = new Long2ObjectOpenHashMap<>();
@Getter
int removeViolationsAfter;
@@ -19,7 +19,6 @@ import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
@@ -32,15 +31,13 @@ import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
// Sync to netty
public final ConcurrentLinkedQueue<TeleportData> pendingTeleports = new ConcurrentLinkedQueue<>();
@@ -68,7 +65,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
// Grab friction now when we know player on ground and other variables
Vector3D afterTickFriction = player.clientVelocity.clone();
Vector afterTickFriction = player.clientVelocity.clone();
// We must first check if the player has accepted their setback
// If the setback isn't complete, then this position is illegitimate
@@ -118,7 +115,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
return false;
}
private void simulateFriction(Vector3D vector) {
private void simulateFriction(Vector vector) {
// We must always do this before simulating positions, as this is the last actual (safe) movement
// We must not do this for knockback or explosions, as they are at the start of the tick
if (player.wasTouchingWater) {
@@ -126,13 +123,12 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
} else if (player.wasTouchingLava) {
vector.multiply(0.5D);
if (player.hasGravity)
vector.add(newVector3D(0.0D, -player.gravity / 4.0D, 0.0D));
vector.add(new Vector(0.0D, -player.gravity / 4.0D, 0.0D));
} else if (player.isGliding) {
PredictionEngineElytra.getElytraMovement(player, vector, ReachUtils.getLook(player, player.xRot, player.yRot)).multiply(player.stuckSpeedMultiplier).multiply(newVector3D(0.99F, 0.98F, 0.99F));
PredictionEngineElytra.getElytraMovement(player, vector, ReachUtils.getLook(player, player.xRot, player.yRot)).multiply(player.stuckSpeedMultiplier).multiply(new Vector(0.99F, 0.98F, 0.99F));
vector.setY(vector.getY() - 0.05); // Make the player fall a bit
} else { // Gliding doesn't have friction, we handle it differently
PredictionEngineNormal.staticVectorEndOfTick(player, vector); // Lava and normal movement
vector.multiply(player.stuckSpeedMultiplier); // Prevent abusing setbacks to move out of blocks like webs
}
// stop 1.8 players from stepping onto 1.25 high blocks, because why not?
@@ -151,9 +147,9 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
lastWorldResync = System.currentTimeMillis();
}
Vector3D clientVel = lastKnownGoodPosition.vector.clone();
Vector clientVel = lastKnownGoodPosition.vector.clone();
Pair<VelocityData, Vector3D> futureKb = player.checkManager.getKnockbackHandler().getFutureKnockback();
Pair<VelocityData, Vector> futureKb = player.checkManager.getKnockbackHandler().getFutureKnockback();
VelocityData futureExplosion = player.checkManager.getExplosionHandler().getFutureExplosion();
// Velocity sets
@@ -173,7 +169,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
// Mini prediction engine - simulate collisions
if (simulateNextTickPosition) {
Vector3D collide = Collisions.collide(player, clientVel.getX(), clientVel.getY(), clientVel.getZ());
Vector collide = Collisions.collide(player, clientVel.getX(), clientVel.getY(), clientVel.getZ());
position = position.withX(position.getX() + collide.getX());
// 1.8 players need the collision epsilon to not phase into blocks when being setback
@@ -401,22 +397,22 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
Vector3d safePosition = new Vector3d(position.getX(), position.getY(), position.getZ());
// We must convert relative teleports to avoid them becoming client controlled in the case of setback
if (flags.has(RelativeFlag.X)) {
if (flags.isSet(RelativeFlag.X.getMask())) {
safePosition = safePosition.withX(safePosition.getX() + lastKnownGoodPosition.pos.getX());
}
if (flags.has(RelativeFlag.Y)) {
if (flags.isSet(RelativeFlag.Y.getMask())) {
safePosition = safePosition.withY(safePosition.getY() + lastKnownGoodPosition.pos.getY());
}
if (flags.has(RelativeFlag.Z)) {
if (flags.isSet(RelativeFlag.Z.getMask())) {
safePosition = safePosition.withZ(safePosition.getZ() + lastKnownGoodPosition.pos.getZ());
}
data = new TeleportData(safePosition, flags, transaction, teleportId);
requiredSetBack = new SetBackData(data, player.xRot, player.yRot, null, false, plugin);
this.lastKnownGoodPosition = new SetbackPosWithVector(safePosition, newVector3D());
this.lastKnownGoodPosition = new SetbackPosWithVector(safePosition, new Vector());
}
@AllArgsConstructor
@@ -424,6 +420,6 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
@Setter
public static class SetbackPosWithVector {
private Vector3d pos;
private Vector3D vector;
private Vector vector;
}
}
@@ -10,28 +10,26 @@ import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.lists.EvictingQueue;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import lombok.AllArgsConstructor;
import org.bukkit.util.Vector;
import java.util.*;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public final class SuperDebug extends Check implements PostPredictionCheck {
private static final StringBuilder[] flags = new StringBuilder[256]; // 17 MB of logs in memory
Object2IntMap<StringBuilder> continuedDebug = new Object2IntOpenHashMap<>();
List<VectorData> predicted = new EvictingQueue<>(60);
List<Vector3D> actually = new EvictingQueue<>(60);
List<Vector> actually = new EvictingQueue<>(60);
List<Location> locations = new EvictingQueue<>(60);
List<Vector3D> startTickClientVel = new EvictingQueue<>(60);
List<Vector3D> baseTickAddition = new EvictingQueue<>(60);
List<Vector3D> baseTickWater = new EvictingQueue<>(60);
List<Vector> startTickClientVel = new EvictingQueue<>(60);
List<Vector> baseTickAddition = new EvictingQueue<>(60);
List<Vector> baseTickWater = new EvictingQueue<>(60);
public SuperDebug(GrimPlayer player) {
super(player);
@@ -82,11 +80,11 @@ public final class SuperDebug extends Check implements PostPredictionCheck {
for (int i = 0; i < predicted.size(); i++) {
VectorData predict = predicted.get(i);
Vector3D actual = actually.get(i);
Vector actual = actually.get(i);
Location loc = locations.get(i);
Vector3D startTickVel = startTickClientVel.get(i);
Vector3D addition = baseTickAddition.get(i);
Vector3D water = baseTickWater.get(i);
Vector startTickVel = startTickClientVel.get(i);
Vector addition = baseTickAddition.get(i);
Vector water = baseTickWater.get(i);
appendDebug(sb, predict, actual, loc, startTickVel, addition, water);
}
@@ -191,7 +189,7 @@ public final class SuperDebug extends Check implements PostPredictionCheck {
continuedDebug.put(sb, 40);
}
private void appendDebug(StringBuilder sb, VectorData predict, Vector3D actual, Location location, Vector3D startTick, Vector3D addition, Vector3D water) {
private void appendDebug(StringBuilder sb, VectorData predict, Vector actual, Location location, Vector startTick, Vector addition, Vector water) {
if (predict.isZeroPointZeroThree()) {
sb.append("Movement threshold/tick skipping\n");
}
@@ -227,11 +225,11 @@ public final class SuperDebug extends Check implements PostPredictionCheck {
// Apply 0.003/0.005 to make numbers more accurate
Set<VectorData> set = new HashSet<>(Collections.singletonList(new VectorData(startTick.clone(), VectorData.VectorType.BestVelPicked)));
new PredictionEngine().applyMovementThreshold(player, set);
Vector3D trueStartVel = ((VectorData) set.toArray()[0]).vector;
Vector trueStartVel = ((VectorData) set.toArray()[0]).vector;
Vector3D clientMovement = getPlayerMathMovement(player, actual.clone().subtract(trueStartVel), location.xRot);
Vector3D simulatedMovement = getPlayerMathMovement(player, predict.vector.clone().subtract(trueStartVel), location.xRot);
Vector3D offset = actual.clone().subtract(predict.vector);
Vector clientMovement = getPlayerMathMovement(player, actual.clone().subtract(trueStartVel), location.xRot);
Vector simulatedMovement = getPlayerMathMovement(player, predict.vector.clone().subtract(trueStartVel), location.xRot);
Vector offset = actual.clone().subtract(predict.vector);
trueStartVel.add(addition);
trueStartVel.add(water);
@@ -270,14 +268,14 @@ public final class SuperDebug extends Check implements PostPredictionCheck {
sb.append("\n\n");
}
private Vector3D getPlayerMathMovement(GrimPlayer player, Vector3D wantedMovement, float f2) {
private Vector getPlayerMathMovement(GrimPlayer player, Vector wantedMovement, float f2) {
float f3 = player.trigHandler.sin(f2 * 0.017453292f);
float f4 = player.trigHandler.cos(f2 * 0.017453292f);
float bestTheoreticalX = (float) (f3 * wantedMovement.getZ() + f4 * wantedMovement.getX()) / (f3 * f3 + f4 * f4);
float bestTheoreticalZ = (float) (-f3 * wantedMovement.getX() + f4 * wantedMovement.getZ()) / (f3 * f3 + f4 * f4);
return newVector3D(bestTheoreticalX, 0, bestTheoreticalZ);
return new Vector(bestTheoreticalX, 0, bestTheoreticalZ);
}
@AllArgsConstructor
@@ -3,10 +3,7 @@ package ac.grim.grimac.manager.init.start;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.manager.init.Initable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.lists.HookedListWrapper;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.util.reflection.Reflection;
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
import sun.misc.Unsafe;
@@ -33,10 +30,6 @@ public class TickEndEvent implements Initable {
return;
}
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_11_2) && !Boolean.getBoolean("paper.explicit-flush")) {
LogUtil.warn("Reach.enable-post-packet=true but paper.explicit-flush=false, add \"-Dpaper.explicit-flush=true\" to your server's startup flags for fully functional extra reach accuracy.");
}
// Inject so we can add the final transaction pre-flush event
try {
Object connection = SpigotReflectionUtil.getMinecraftServerConnectionInstance();
@@ -54,7 +54,7 @@ import net.kyori.adventure.text.TranslatableComponent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -64,9 +64,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static ac.grim.grimac.utils.data.VectorData.VectorType.Normal;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
// Everything in this class should be sync'd to the anticheat thread.
// Put variables sync'd to the netty thread in PacketStateData
// Variables that need lag compensation should have their own class
@@ -93,7 +90,7 @@ public class GrimPlayer implements GrimUser {
public MovementCheckRunner movementCheckRunner;
public SyncedTags tagManager;
// End manager like classes
public ac.grim.grimac.utils.vector.Vector3D clientVelocity = newVector3D();
public Vector clientVelocity = new Vector();
PacketTracker packetTracker;
private long transactionPing = 0;
public long lastTransSent = 0;
@@ -106,9 +103,9 @@ public class GrimPlayer implements GrimUser {
public boolean hasGravity = true;
public final long joinTime = System.currentTimeMillis();
public boolean playerEntityHasGravity = true;
public VectorData predictedVelocity = new VectorData(newVector3D(), Normal);
public Vector3D actualMovement = newVector3D();
public Vector3D stuckSpeedMultiplier = newVector3D(1, 1, 1);
public VectorData predictedVelocity = new VectorData(new Vector(), VectorData.VectorType.Normal);
public Vector actualMovement = new Vector();
public Vector stuckSpeedMultiplier = new Vector(1, 1, 1);
public UncertaintyHandler uncertaintyHandler;
public double gravity;
public float friction;
@@ -187,9 +184,9 @@ public class GrimPlayer implements GrimUser {
public TrigHandler trigHandler;
public PacketStateData packetStateData;
// Keep track of basetick stuff
public Vector3D baseTickAddition = newVector3D();
public Vector3D baseTickWaterPushing = newVector3D();
public Vector3D startTickClientVel = newVector3D();
public Vector baseTickAddition = new Vector();
public Vector baseTickWaterPushing = new Vector();
public Vector startTickClientVel = new Vector();
// For syncing the player's full swing in 1.9+
public int movementPackets = 0;
public VelocityData firstBreadKB = null;
@@ -245,7 +242,6 @@ public class GrimPlayer implements GrimUser {
packetStateData = new PacketStateData();
uncertaintyHandler.riptideEntities.add(0);
uncertaintyHandler.collidingEntities.add(0);
if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) {
@@ -296,7 +292,7 @@ public class GrimPlayer implements GrimUser {
// If the player has that client sided riptide thing and has colliding with an entity
// This was determined in the previous tick but whatever just include the 2 ticks around it
// for a bit of safety as I doubt people will try to bypass this, it would be a very useless cheat
if (riptideSpinAttackTicks >= 0 && Collections.max(uncertaintyHandler.riptideEntities) > 0) {
if (riptideSpinAttackTicks >= 0 && Collections.max(uncertaintyHandler.collidingEntities) > 0) {
possibleMovements.add(new VectorData(clientVelocity.clone().multiply(-0.2), VectorData.VectorType.Trident));
}
@@ -364,15 +360,15 @@ public class GrimPlayer implements GrimUser {
return data != null && data.first() == id;
}
public void baseTickAddWaterPushing(ac.grim.grimac.utils.vector.Vector3D vector) {
public void baseTickAddWaterPushing(Vector vector) {
baseTickWaterPushing.add(vector);
}
public void baseTickAddVector(Vector3D vector) {
public void baseTickAddVector(Vector vector) {
clientVelocity.add(vector);
}
public void trackBaseTickAddition(Vector3D vector) {
public void trackBaseTickAddition(Vector vector) {
baseTickAddition.add(vector);
}
@@ -569,18 +565,11 @@ public class GrimPlayer implements GrimUser {
// - 3 ticks is a magic value, but it should buffer out incorrect predictions somewhat.
// 2. The player is in a vehicle
public boolean isTickingReliablyFor(int ticks) {
// 1.21.2+: Tick end packet, on servers 1.21.2+
// 1.8-: Flying packet
return supportsEndTick()
|| getClientVersion().isOlderThan(ClientVersion.V_1_9)
|| !uncertaintyHandler.lastPointThree.hasOccurredSince(ticks)
return (getClientVersion().isOlderThan(ClientVersion.V_1_9)
|| !uncertaintyHandler.lastPointThree.hasOccurredSince(ticks))
|| compensatedEntities.getSelf().inVehicle();
}
public boolean inVehicle() {
return compensatedEntities.getSelf().inVehicle();
}
public boolean canThePlayerBeCloseToZeroMovement(int ticks) {
return (!uncertaintyHandler.lastPointThree.hasOccurredSince(ticks));
}
@@ -708,11 +697,6 @@ public class GrimPlayer implements GrimUser {
return getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_10) || (gamemode == GameMode.CREATIVE && compensatedEntities.getSelf().getOpLevel() >= 2);
}
public boolean supportsEndTick() {
// TODO: Bypass viaversion
return getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2);
}
@Override
public void runSafely(Runnable runnable) {
ChannelHelper.runInEventLoop(this.user.getChannel(), runnable);
@@ -767,7 +751,6 @@ public class GrimPlayer implements GrimUser {
@Getter private boolean ignoreDuplicatePacketRotation = false;
@Getter private boolean experimentalChecks = false;
@Getter private boolean cancelDuplicatePacket = true;
@Getter private boolean exemptElytra = false;
@Override
public void reload(ConfigManager config) {
@@ -776,7 +759,6 @@ public class GrimPlayer implements GrimUser {
experimentalChecks = config.getBooleanElse("experimental-checks", false);
ignoreDuplicatePacketRotation = config.getBooleanElse("ignore-duplicate-packet-rotation", false);
cancelDuplicatePacket = config.getBooleanElse("cancel-duplicate-packet", true);
exemptElytra = config.getBooleanElse("exempt-elytra", false);
// reload all checks
for (AbstractCheck value : checkManager.allChecks.values()) value.reload(config);
// reload punishment manager
@@ -38,10 +38,7 @@ import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.data.VectorData.VectorType.Dead;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import org.bukkit.util.Vector;
public class MovementCheckRunner extends Check implements PositionCheck {
// Averaged over 500 predictions (Defaults set slightly above my 3600x results)
@@ -141,10 +138,10 @@ public class MovementCheckRunner extends Check implements PositionCheck {
double negX = Math.min(-0.05, GrimMath.clamp(player.actualMovement.getX(), -16, 16) - 0.05);
double negZ = Math.min(-0.05, GrimMath.clamp(player.actualMovement.getZ(), -16, 16) - 0.05);
Vector3D NE = Collisions.maybeBackOffFromEdge(newVector3D(posX, 0, negZ), player, true);
Vector3D NW = Collisions.maybeBackOffFromEdge(newVector3D(negX, 0, negZ), player, true);
Vector3D SE = Collisions.maybeBackOffFromEdge(newVector3D(posX, 0, posZ), player, true);
Vector3D SW = Collisions.maybeBackOffFromEdge(newVector3D(negX, 0, posZ), player, true);
Vector NE = Collisions.maybeBackOffFromEdge(new Vector(posX, 0, negZ), player, true);
Vector NW = Collisions.maybeBackOffFromEdge(new Vector(negX, 0, negZ), player, true);
Vector SE = Collisions.maybeBackOffFromEdge(new Vector(posX, 0, posZ), player, true);
Vector SW = Collisions.maybeBackOffFromEdge(new Vector(negX, 0, posZ), player, true);
boolean isEast = NE.getX() != posX || SE.getX() != posX;
boolean isWest = NW.getX() != negX || SW.getX() != negX;
@@ -187,7 +184,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
player.vehicleData.wasVehicleSwitch = false;
if (riding != null) {
Vector3D pos = newVector3D(player.x, player.y, player.z);
Vector pos = new Vector(player.x, player.y, player.z);
SimpleCollisionBox interTruePositions = riding.getPossibleCollisionBoxes();
// We shrink the expanded bounding box to what the packet positions can be, for a smaller box
@@ -197,7 +194,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
interTruePositions.expand(-width, 0, -width);
interTruePositions.expandMax(0, -height, 0);
Vector3D cutTo = VectorUtils.cutBoxToVector(pos, interTruePositions);
Vector cutTo = VectorUtils.cutBoxToVector(pos, interTruePositions);
// Now we need to simulate a tick starting at the most optimal position
// The start position is never sent, so we assume the most optimal start position
@@ -215,14 +212,14 @@ public class MovementCheckRunner extends Check implements PositionCheck {
} else {
// Server always teleports the player when they eject anyways,
// so just let the player control where they eject within reason, they get set back anyways
if (newVector3D(player.lastX, player.lastY, player.lastZ).distance(newVector3D(player.x, player.y, player.z)) > 3) {
if (new Vector(player.lastX, player.lastY, player.lastZ).distance(new Vector(player.x, player.y, player.z)) > 3) {
player.getSetbackTeleportUtil().executeForceResync(); // Too far! (I think this value is sane)
}
handleTeleport(update);
if (player.isClimbing) {
Vector3D ladder = player.clientVelocity.clone().setY(0.2);
Vector ladder = player.clientVelocity.clone().setY(0.2);
PredictionEngineNormal.staticVectorEndOfTick(player, ladder);
player.lastWasClimbing = ladder.getY();
}
@@ -302,7 +299,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
player.clientControlledVerticalCollision = Math.abs(player.y % (1 / 64D)) < 0.00001;
// This isn't the final velocity of the player in the tick, only the one applied to the player
player.actualMovement = newVector3D(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
player.actualMovement = new Vector(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
if (player.isSprinting != player.lastSprinting) {
player.compensatedEntities.hasSprintingAttributeEnabled = player.isSprinting;
@@ -429,9 +426,9 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// Exempt if the player is dead or is riding a dead entity
if (player.compensatedEntities.getSelf().isDead || (riding != null && riding.isDead)) {
// Dead players can't cheat, if you find a way how they could, open an issue
player.predictedVelocity = new VectorData(newVector3D(), Dead);
player.clientVelocity = newVector3D();
} else if (player.disableGrim || (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_8) && player.gamemode == GameMode.SPECTATOR) || player.isFlying || (player.isExemptElytra() && player.isGliding)) {
player.predictedVelocity = new VectorData(new Vector(), VectorData.VectorType.Dead);
player.clientVelocity = new Vector();
} else if (player.disableGrim || (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_8) && player.gamemode == GameMode.SPECTATOR) || player.isFlying) {
// We could technically check spectator but what's the point...
// Added complexity to analyze a gamemode used mainly by moderators
//
@@ -453,7 +450,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// Riptiding while on the ground moves the hitbox upwards before any movement code runs
// It's a pain to support and this is my best attempt
if (player.lastOnGround && player.packetStateData.tryingToRiptide && !player.compensatedEntities.getSelf().inVehicle()) {
Vector3D pushingMovement = Collisions.collide(player, 0, 1.1999999F, 0);
Vector pushingMovement = Collisions.collide(player, 0, 1.1999999F, 0);
player.verticalCollision = pushingMovement.getY() != 1.1999999F;
double currentY = player.clientVelocity.getY();
@@ -465,7 +462,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
player.lastY += pushingMovement.getY();
new PlayerBaseTick(player).updatePlayerPose();
player.boundingBox = GetBoundingBox.getPlayerBoundingBox(player, player.lastX, player.lastY, player.lastZ);
player.actualMovement = newVector3D(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
player.actualMovement = new Vector(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
player.couldSkipTick = true;
@@ -517,7 +514,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
//
// Checking for oldClientVel being too high fixes BleachHack vertical scaffold
if (player.getSetbackTeleportUtil().getRequiredSetBack() != null && player.getSetbackTeleportUtil().getRequiredSetBack().getTicksComplete() == 1) {
Vector3D setbackVel = player.getSetbackTeleportUtil().getRequiredSetBack().getVelocity();
Vector setbackVel = player.getSetbackTeleportUtil().getRequiredSetBack().getVelocity();
// A player must have velocity going INTO the ground to be able to jump
// Otherwise they could ignore upwards velocity that isn't useful into more useful upwards velocity (towering)
// So if they are supposed to be going upwards, or are supposed to be off the ground, resync
@@ -546,7 +543,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// Patch sprint jumping with elytra exploit
if (player.bukkitPlayer != null && player.isGliding && player.predictedVelocity.isJump() && player.isSprinting && !allowSprintJumpingWithElytra) {
SetbackTeleportUtil.SetbackPosWithVector lastKnownGoodPosition = player.getSetbackTeleportUtil().lastKnownGoodPosition;
lastKnownGoodPosition.setVector(lastKnownGoodPosition.getVector().multiply(newVector3D(0.6 * 0.91, 1, 0.6 * 0.91)));
lastKnownGoodPosition.setVector(lastKnownGoodPosition.getVector().multiply(new Vector(0.6 * 0.91, 1, 0.6 * 0.91)));
player.getSetbackTeleportUtil().executeNonSimulatingSetback();
}
@@ -623,7 +620,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
* @param pushingMovement The collision result when trying to move the player upwards by 1.2f
* @return Whether it is more likely that this player was on the ground the tick they riptided
*/
private boolean likelyGroundRiptide(Vector3D pushingMovement) {
private boolean likelyGroundRiptide(Vector pushingMovement) {
// Y velocity gets reset if the player collides vertically
double riptideYResult = Riptide.getRiptideVelocity(player).getY();
@@ -641,4 +638,5 @@ public class MovementCheckRunner extends Check implements PositionCheck {
public void onReload(ConfigManager config) {
allowSprintJumpingWithElytra = config.getBooleanElse("exploit.allow-sprint-jumping-when-using-elytra", true);
}
}
@@ -9,19 +9,16 @@ import ac.grim.grimac.utils.enums.Pose;
import ac.grim.grimac.utils.latency.CompensatedEntities;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.nmsutil.*;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.Optional;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class PlayerBaseTick {
GrimPlayer player;
@@ -43,11 +40,11 @@ public class PlayerBaseTick {
public void doBaseTick() {
// Keep track of basetick stuff
player.baseTickAddition = newVector3D();
player.baseTickWaterPushing = newVector3D();
player.baseTickAddition = new Vector();
player.baseTickWaterPushing = new Vector();
if (player.isFlying && player.isSneaking && !player.compensatedEntities.getSelf().inVehicle()) {
Vector3D flyingShift = newVector3D(0, player.flySpeed * -3, 0);
Vector flyingShift = new Vector(0, player.flySpeed * -3, 0);
player.baseTickAddVector(flyingShift);
player.trackBaseTickAddition(flyingShift);
}
@@ -63,7 +60,7 @@ public class PlayerBaseTick {
// You cannot crouch while flying, only shift - could be specific to 1.14?
// pre-1.13 clients don't have this code
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && player.wasTouchingWater && player.isSneaking && !player.isFlying && !player.compensatedEntities.getSelf().inVehicle()) {
Vector3D waterPushVector = newVector3D(0, -0.04f, 0);
Vector waterPushVector = new Vector(0, -0.04f, 0);
player.baseTickAddVector(waterPushVector);
player.trackBaseTickAddition(waterPushVector);
}
@@ -417,7 +414,7 @@ public class PlayerBaseTick {
}
boolean hasPushed = false;
Vector3D vec3 = newVector3D();
Vector vec3 = new Vector();
for (int x = floorX; x < ceilX; ++x) {
for (int y = floorY; y < ceilY; ++y) {
@@ -467,7 +464,7 @@ public class PlayerBaseTick {
}
double d2 = 0.0;
boolean hasTouched = false;
Vector3D vec3 = newVector3D();
Vector vec3 = new Vector();
int n7 = 0;
for (int x = floorX; x < ceilX; ++x) {
@@ -492,7 +489,7 @@ public class PlayerBaseTick {
d2 = Math.max(fluidHeightToWorld - aABB.minY, d2);
if (!player.isFlying) {
Vector3D vec32 = FluidTypeFlowing.getFlow(player, x, y, z);
Vector vec32 = FluidTypeFlowing.getFlow(player, x, y, z);
if (d2 < 0.4) {
vec32 = vec32.multiply(d2);
}
@@ -18,13 +18,11 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import lombok.Getter;
import lombok.Setter;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.OptionalInt;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
/**
* A lot of care was put into handling all the stupid stuff occurring between events
* <p>
@@ -143,7 +141,7 @@ public class PointThreeEstimator {
isNearBubbleColumn = true;
}
Vector3D fluidVector = FluidTypeFlowing.getFlow(player, x, y, z);
Vector fluidVector = FluidTypeFlowing.getFlow(player, x, y, z);
if (fluidVector.getX() != 0 || fluidVector.getZ() != 0) {
isNearHorizontalFlowingLiquid = true;
}
@@ -307,7 +305,7 @@ public class PointThreeEstimator {
player.boundingBox = player.boundingBox.copy().expand(0.03, 0, 0.03).offset(0, 0.03, 0);
// 0.16 magic value -> 0.03 plus gravity, plus some additional lenience
double searchDistance = -0.2 + Math.min(0, y);
Vector3D collisionResult = Collisions.collide(player, 0, searchDistance, 0);
Vector collisionResult = Collisions.collide(player, 0, searchDistance, 0);
player.boundingBox = playerBox;
return collisionResult.getY() != searchDistance;
}
@@ -316,7 +314,7 @@ public class PointThreeEstimator {
public boolean determineCanSkipTick(float speed, Set<VectorData> init) {
// If possible, check for idle packet
// TODO: Find a better way to fix slime without forcing 0.03 where there is none
if ((player.supportsEndTick() || player.getClientVersion().isOlderThan(ClientVersion.V_1_9)) && player.packetStateData.didLastMovementIncludePosition && !player.uncertaintyHandler.isSteppingOnSlime) {
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9) && player.packetStateData.didLastMovementIncludePosition && !player.uncertaintyHandler.isSteppingOnSlime) {
return false; // Last packet included a position so not 0.03
}
@@ -341,9 +339,9 @@ public class PointThreeEstimator {
// Takes 0.01 millis, on average, to compute... this should be improved eventually
for (VectorData data : init) {
// Try to get the vector as close to zero as possible to give the best chance at 0.03...
Vector3D toZeroVec = new PredictionEngine().handleStartingVelocityUncertainty(player, data, newVector3D());
Vector toZeroVec = new PredictionEngine().handleStartingVelocityUncertainty(player, data, new Vector());
// Collide to handle mostly gravity, but other scenarios similar to this.
Vector3D collisionResult = Collisions.collide(player, toZeroVec.getX(), toZeroVec.getY(), toZeroVec.getZ(), Integer.MIN_VALUE, null);
Vector collisionResult = Collisions.collide(player, toZeroVec.getX(), toZeroVec.getY(), toZeroVec.getZ(), Integer.MIN_VALUE, null);
// If this tick is the tick after y velocity was by 0, a stepping movement is POSSIBLE to have been hidden
// A bit hacky... is there a better way? I'm unsure...
@@ -13,12 +13,10 @@ import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.*;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class UncertaintyHandler {
private final GrimPlayer player;
// Handles uncertainty when a piston could have pushed a player in a direction
@@ -66,10 +64,8 @@ public class UncertaintyHandler {
public boolean lastMovementWasUnknown003VectorReset = false;
// Handles 0.03 vertical false where actual velocity is greater than predicted because of previous lenience
public boolean wasZeroPointThreeVertically = false;
// How many entities are within 0.5 blocks of the player's bounding box that are pushable?
// How many entities are within 0.5 blocks of the player's bounding box?
public EvictingQueue<Integer> collidingEntities = new EvictingQueue<>(3);
// How many entities are within 0.5 blocks of the player's bounding box? Should only exclude entities in spectator
public EvictingQueue<Integer> riptideEntities = new EvictingQueue<>(3);
// Fishing rod pulling is another method of adding to a player's velocity
public List<Integer> fishingRodPulls = new ArrayList<>();
public SimpleCollisionBox fireworksBox = null;
@@ -151,15 +147,15 @@ public class UncertaintyHandler {
entityBox.maxY -= height;
entityBox.expand(-width / 2, 0, -width / 2);
Vector3D maxLocation = newVector3D(entityBox.maxX, entityBox.maxY, entityBox.maxZ);
Vector3D minLocation = newVector3D(entityBox.minX, entityBox.minY, entityBox.minZ);
Vector maxLocation = new Vector(entityBox.maxX, entityBox.maxY, entityBox.maxZ);
Vector minLocation = new Vector(entityBox.minX, entityBox.minY, entityBox.minZ);
Vector3D diff = minLocation.subtract(newVector3D(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
Vector diff = minLocation.subtract(new Vector(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
fishingRodPullBox.minX = Math.min(0, diff.getX());
fishingRodPullBox.minY = Math.min(0, diff.getY());
fishingRodPullBox.minZ = Math.min(0, diff.getZ());
diff = maxLocation.subtract(newVector3D(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
diff = maxLocation.subtract(new Vector(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
fishingRodPullBox.maxX = Math.max(0, diff.getX());
fishingRodPullBox.maxY = Math.max(0, diff.getY());
fishingRodPullBox.maxZ = Math.max(0, diff.getZ());
@@ -174,8 +170,8 @@ public class UncertaintyHandler {
fireworksBox = new SimpleCollisionBox();
Vector3D currentLook = ReachUtils.getLook(player, player.xRot, player.yRot);
ac.grim.grimac.utils.vector.Vector3D lastLook = ReachUtils.getLook(player, player.lastXRot, player.lastYRot);
Vector currentLook = ReachUtils.getLook(player, player.xRot, player.yRot);
Vector lastLook = ReachUtils.getLook(player, player.lastXRot, player.lastYRot);
double antiTickSkipping = player.isPointThree() ? 0 : 0.05; // With 0.03, let that handle tick skipping
@@ -24,9 +24,7 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.viaversion.viaversion.api.Via;
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import org.bukkit.util.Vector;
public class MovementTicker {
public final GrimPlayer player;
@@ -43,7 +41,6 @@ public class MovementTicker {
&& (!ViaVersionUtil.isAvailable() || Via.getConfig().isPreventCollision()))) return;
int possibleCollidingEntities = 0;
int possibleRiptideEntities = 0;
// Players in vehicles do not have collisions
if (!player.compensatedEntities.getSelf().inVehicle()) {
@@ -55,23 +52,16 @@ public class MovementTicker {
final TeamHandler teamHandler = player.checkManager.getPacketCheck(TeamHandler.class);
for (PacketEntity entity : player.compensatedEntities.entityMap.values()) {
// TODO actually handle entity collisions instead of this awfulness
SimpleCollisionBox entityBox = entity.getPossibleCollisionBoxes();
boolean isCollided = playerBox.isCollided(entityBox);
if (isCollided) {
possibleRiptideEntities++;
}
// Filters out entities that can't be pushed/collided because of team collision rules
// Also handles 1.9+ player on 1.8- server with ViaVersion prevent-collision disabled.
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
&& !EntityPredicates.canBePushedBy(player, entity, teamHandler).test(player)) continue;
if (!entity.isPushable())
continue;
if (isCollided) {
// 1.9+ player on 1.8- server with ViaVersion prevent-collision disabled.
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
&& !EntityPredicates.canBePushedBy(player, entity, teamHandler).test(player)) continue;
SimpleCollisionBox entityBox = entity.getPossibleCollisionBoxes();
if (playerBox.isCollided(entityBox)) {
possibleCollidingEntities++;
}
}
@@ -84,13 +74,12 @@ public class MovementTicker {
player.uncertaintyHandler.yPositiveUncertainty += 0.05;
}
player.uncertaintyHandler.riptideEntities.add(possibleRiptideEntities);
player.uncertaintyHandler.collidingEntities.add(possibleCollidingEntities);
}
public void move(Vector3D inputVel, Vector3D collide) {
public void move(Vector inputVel, Vector collide) {
if (player.stuckSpeedMultiplier.getX() < 0.99) {
player.clientVelocity = newVector3D();
player.clientVelocity = new Vector();
}
if (inputVel.getX() != collide.getX()) {
@@ -183,21 +172,21 @@ public class MovementTicker {
// The game disregards movements smaller than 1e-7 (such as in boats)
if (collide.lengthSquared() < 1e-7) {
collide = newVector3D();
collide = new Vector();
}
// This is where vanilla moves the bounding box and sets it
player.predictedVelocity = new VectorData(collide.clone(), player.predictedVelocity.lastVector, player.predictedVelocity.vectorType);
float f = BlockProperties.getBlockSpeedFactor(player, player.mainSupportingBlockData, new Vector3d(player.x, player.y, player.z));
player.clientVelocity.multiply(newVector3D(f, 1, f));
player.clientVelocity.multiply(new Vector(f, 1, f));
// Reset stuck speed so it can update
if (player.stuckSpeedMultiplier.getX() < 0.99) {
player.uncertaintyHandler.lastStuckSpeedMultiplier.reset();
}
player.stuckSpeedMultiplier = newVector3D(1, 1, 1);
player.stuckSpeedMultiplier = new Vector(1, 1, 1);
// 1.15 and older clients use the handleInsideBlocks method for lava
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_16))
@@ -212,7 +201,7 @@ public class MovementTicker {
// Flying players are not affected by cobwebs/sweet berry bushes
if (player.isFlying) {
player.stuckSpeedMultiplier = newVector3D(1, 1, 1);
player.stuckSpeedMultiplier = new Vector(1, 1, 1);
}
}
@@ -399,14 +388,14 @@ public class MovementTicker {
// Lava movement changed in 1.16
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_16) && player.slightlyTouchingLava) {
player.clientVelocity = player.clientVelocity.multiply(newVector3D(0.5D, 0.800000011920929D, 0.5D));
player.clientVelocity = player.clientVelocity.multiply(new Vector(0.5D, 0.800000011920929D, 0.5D));
player.clientVelocity = FluidFallingAdjustedMovement.getFluidFallingAdjustedMovement(player, playerGravity, isFalling, player.clientVelocity);
} else {
player.clientVelocity.multiply(0.5D);
}
if (player.hasGravity)
player.clientVelocity.add(newVector3D(0.0D, -playerGravity / 4.0D, 0.0D));
player.clientVelocity.add(new Vector(0.0D, -playerGravity / 4.0D, 0.0D));
} else if (player.isGliding) {
player.friction = 0.99F; // Not vanilla, just useful for other grim stuff
@@ -5,8 +5,7 @@ import ac.grim.grimac.utils.data.packetentity.PacketEntityHorse;
import ac.grim.grimac.utils.nmsutil.Collisions;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import org.bukkit.util.Vector;
public class MovementTickerHorse extends MovementTickerLivingVehicle {
@@ -27,7 +26,7 @@ public class MovementTickerHorse extends MovementTickerLivingVehicle {
forwardsInput *= 0.25F;
}
this.movementInput = newVector3D(horizInput, 0, forwardsInput);
this.movementInput = new Vector(horizInput, 0, forwardsInput);
if (movementInput.lengthSquared() > 1) movementInput.normalize();
}
@@ -7,13 +7,10 @@ import ac.grim.grimac.predictionengine.predictions.rideable.PredictionEngineRide
import ac.grim.grimac.predictionengine.predictions.rideable.PredictionEngineRideableWaterLegacy;
import ac.grim.grimac.utils.nmsutil.BlockProperties;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import org.bukkit.util.Vector;
public class MovementTickerLivingVehicle extends MovementTicker {
Vector3D movementInput = newVector3D();
Vector movementInput = new Vector();
public MovementTickerLivingVehicle(GrimPlayer player) {
super(player);
@@ -3,13 +3,12 @@ package ac.grim.grimac.predictionengine.movementtick;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.packetentity.PacketEntityRideable;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import org.bukkit.util.Vector;
public class MovementTickerPig extends MovementTickerRideable {
public MovementTickerPig(GrimPlayer player) {
super(player);
movementInput = newVector3D(0, 0, 1);
movementInput = new Vector(0, 0, 1);
}
@Override
@@ -11,16 +11,15 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class MovementTickerStrider extends MovementTickerRideable {
public MovementTickerStrider(GrimPlayer player) {
super(player);
movementInput = newVector3D(0, 0, 1);
movementInput = new Vector(0, 0, 1);
}
public static void floatStrider(GrimPlayer player) {
@@ -28,7 +27,7 @@ public class MovementTickerStrider extends MovementTickerRideable {
if (isAbove(player) && player.compensatedWorld.getLavaFluidLevelAt((int) Math.floor(player.x), (int) Math.floor(player.y + 1), (int) Math.floor(player.z)) == 0) {
player.onGround = true;
} else {
player.clientVelocity.multiply(0.5).add(newVector3D(0, 0.05, 0));
player.clientVelocity.multiply(0.5).add(new Vector(0, 0.05, 0));
}
}
}
@@ -4,7 +4,6 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.SneakingEstimator;
import ac.grim.grimac.predictionengine.movementtick.MovementTickerPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.KnownInput;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.math.VectorUtils;
@@ -12,29 +11,20 @@ import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.JumpPower;
import ac.grim.grimac.utils.nmsutil.Riptide;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.*;
import static ac.grim.grimac.utils.data.VectorData.VectorType.ZeroPointZeroThree;
import static ac.grim.grimac.utils.nmsutil.Collisions.isEmpty;
import static ac.grim.grimac.utils.nmsutil.GetBoundingBox.getBoundingBoxFromPosAndSize;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.attribute.Attributes.GENERIC_GRAVITY;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_13;
import static java.lang.Math.*;
import static java.util.Collections.max;
public class PredictionEngine {
public static Vector3D clampMovementToHardBorder(GrimPlayer player, Vector3D outputVel) {
public static Vector clampMovementToHardBorder(GrimPlayer player, Vector outputVel) {
// TODO: Reimplement
return outputVel;
}
public static Vector3D transformInputsToVector(GrimPlayer player, Vector3D theoreticalInput) {
public static Vector transformInputsToVector(GrimPlayer player, Vector theoreticalInput) {
float bestPossibleX;
float bestPossibleZ;
@@ -52,15 +42,15 @@ public class PredictionEngine {
bestPossibleZ *= 0.2F;
}
Vector3D inputVector = newVector3D(bestPossibleX, 0, bestPossibleZ);
Vector inputVector = new Vector(bestPossibleX, 0, bestPossibleZ);
inputVector.multiply(0.98F);
// Simulate float rounding imprecision
inputVector = newVector3D((float) inputVector.getX(), (float) inputVector.getY(), (float) inputVector.getZ());
inputVector = new Vector((float) inputVector.getX(), (float) inputVector.getY(), (float) inputVector.getZ());
if (inputVector.lengthSquared() > 1) {
double d0 = sqrt(inputVector.getX() * inputVector.getX() + inputVector.getY() * inputVector.getY() + inputVector.getZ() * inputVector.getZ());
inputVector = newVector3D(inputVector.getX() / d0, inputVector.getY() / d0, inputVector.getZ() / d0);
double d0 = Math.sqrt(inputVector.getX() * inputVector.getX() + inputVector.getY() * inputVector.getY() + inputVector.getZ() * inputVector.getZ());
inputVector = new Vector(inputVector.getX() / d0, inputVector.getY() / d0, inputVector.getZ() / d0);
}
return inputVector;
@@ -72,7 +62,7 @@ public class PredictionEngine {
if (player.uncertaintyHandler.influencedByBouncyBlock()) {
for (VectorData data : init) {
// Try to get the vector as close to zero as possible to give the best chance at 0.03...
Vector3D toZeroVec = new PredictionEngine().handleStartingVelocityUncertainty(player, data, newVector3D(0, -1000000000, 0)); // Downwards without overflow risk
Vector toZeroVec = new PredictionEngine().handleStartingVelocityUncertainty(player, data, new Vector(0, -1000000000, 0)); // Downwards without overflow risk
player.uncertaintyHandler.nextTickSlimeBlockUncertainty = Math.max(Math.abs(toZeroVec.getY()), player.uncertaintyHandler.nextTickSlimeBlockUncertainty);
}
@@ -115,22 +105,20 @@ public class PredictionEngine {
double bestInput = Double.MAX_VALUE;
VectorData bestCollisionVel = null;
Vector3D beforeCollisionMovement = null;
Vector3D originalClientVel = player.clientVelocity.clone();
Vector beforeCollisionMovement = null;
Vector originalClientVel = player.clientVelocity.clone();
SimpleCollisionBox originalBB = player.boundingBox;
// 0.03 doesn't exist with vehicles, thank god
// 1.13+ clients have stupid poses that desync because mojang brilliantly removed the idle packet in 1.9
SimpleCollisionBox pointThreeThanksMojang = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13)
? GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.lastX, player.lastY, player.lastZ, 0.6f, 0.6f)
: originalBB;
SimpleCollisionBox pointThreeThanksMojang = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) ? GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.lastX, player.lastY, player.lastZ, 0.6f, 0.6f) : originalBB;
player.skippedTickInActualMovement = false;
for (VectorData clientVelAfterInput : possibleVelocities) {
Vector3D primaryPushMovement = handleStartingVelocityUncertainty(player, clientVelAfterInput, player.actualMovement);
Vector primaryPushMovement = handleStartingVelocityUncertainty(player, clientVelAfterInput, player.actualMovement);
Vector3D bestTheoreticalCollisionResult = VectorUtils.cutBoxToVector(player.actualMovement, new SimpleCollisionBox(0, Math.min(0, primaryPushMovement.getY()), 0, primaryPushMovement.getX(), Math.max(0.6, primaryPushMovement.getY()), primaryPushMovement.getZ()).sort());
Vector bestTheoreticalCollisionResult = VectorUtils.cutBoxToVector(player.actualMovement, new SimpleCollisionBox(0, Math.min(0, primaryPushMovement.getY()), 0, primaryPushMovement.getX(), Math.max(0.6, primaryPushMovement.getY()), primaryPushMovement.getZ()).sort());
// Check if this vector could ever possible beat the last vector in terms of accuracy
// This is quite a good optimization :)
if (bestTheoreticalCollisionResult.distanceSquared(player.actualMovement) > bestInput && !clientVelAfterInput.isKnockback() && !clientVelAfterInput.isExplosion()) {
@@ -144,9 +132,9 @@ public class PredictionEngine {
}
// Returns pair of primary push movement, and then outputvel
Pair<Vector3D, Vector3D> output = doSeekingWallCollisions(player, primaryPushMovement, originalClientVel, clientVelAfterInput);
Pair<Vector, Vector> output = doSeekingWallCollisions(player, primaryPushMovement, originalClientVel, clientVelAfterInput);
primaryPushMovement = output.first();
Vector3D outputVel = clampMovementToHardBorder(player, output.second());
Vector outputVel = clampMovementToHardBorder(player, output.second());
double resultAccuracy = outputVel.distanceSquared(player.actualMovement);
@@ -220,7 +208,7 @@ public class PredictionEngine {
}
}
private Pair<Vector3D, Vector3D> doSeekingWallCollisions(GrimPlayer player, Vector3D primaryPushMovement, Vector3D originalClientVel, VectorData clientVelAfterInput) {
private Pair<Vector, Vector> doSeekingWallCollisions(GrimPlayer player, Vector primaryPushMovement, Vector originalClientVel, VectorData clientVelAfterInput) {
boolean vehicleKB = player.compensatedEntities.getSelf().inVehicle() && clientVelAfterInput.isKnockback() && clientVelAfterInput.vector.getY() == 0;
// Extra collision epsilon required for vehicles to be accurate
double xAdditional = Math.signum(primaryPushMovement.getX()) * SimpleCollisionBox.COLLISION_EPSILON;
@@ -233,9 +221,9 @@ public class PredictionEngine {
double testX = primaryPushMovement.getX() + xAdditional;
double testY = primaryPushMovement.getY() + yAdditional;
double testZ = primaryPushMovement.getZ() + zAdditional;
primaryPushMovement = newVector3D(testX, testY, testZ);
primaryPushMovement = new Vector(testX, testY, testZ);
Vector3D outputVel = Collisions.collide(player, primaryPushMovement.getX(), primaryPushMovement.getY(), primaryPushMovement.getZ(), originalClientVel.getY(), clientVelAfterInput);
Vector outputVel = Collisions.collide(player, primaryPushMovement.getX(), primaryPushMovement.getY(), primaryPushMovement.getZ(), originalClientVel.getY(), clientVelAfterInput);
if (testX == outputVel.getX()) { // the player didn't have X collision, don't ruin offset by collision epsilon
primaryPushMovement.setX(primaryPushMovement.getX() - xAdditional);
@@ -261,20 +249,20 @@ public class PredictionEngine {
// For now just let the player control their Y velocity within 0.03. Gravity should stop exploits.
// 0.03 - 0.784 < -0.03 = can't skip next tick
Vector3D pointThreeVector = newVector3D();
Vector pointThreeVector = new Vector();
// Stop a bypass (and fix falses) by carrying over the player's current velocity IF they couldn't have modified it
if (!player.pointThreeEstimator.controlsVerticalMovement()) {
pointThreeVector.setY(player.clientVelocity.getY());
} else { // Carry over the current Y velocity to try and help with gravity issues
pointThreePossibilities.add(new VectorData(newVector3D(0, player.clientVelocity.getY(), 0), ZeroPointZeroThree));
pointThreePossibilities.add(new VectorData(new Vector(0, player.clientVelocity.getY(), 0), VectorData.VectorType.ZeroPointZeroThree));
}
pointThreePossibilities.add(new VectorData(pointThreeVector, VectorData.VectorType.ZeroPointZeroThree));
// Swim hop
if (player.pointThreeEstimator.isNearFluid && !Collisions.isEmpty(player, player.boundingBox.copy().expand(0.4, 0, 0.4)) && !player.onGround) { // onGround can still be used here, else generic 0.03
pointThreePossibilities.add(new VectorData(newVector3D(0, 0.3, 0), ZeroPointZeroThree));
pointThreePossibilities.add(new VectorData(new Vector(0, 0.3, 0), VectorData.VectorType.ZeroPointZeroThree));
}
// Swimming vertically can add more Y velocity than normal
@@ -291,7 +279,7 @@ public class PredictionEngine {
player.clientVelocity.getX(), 0, player.clientVelocity.getZ()).expand(0.5, -SimpleCollisionBox.COLLISION_EPSILON, 0.5)))) {
// Calculate the Y velocity after friction
Vector3D hackyClimbVector = newVector3D(0, 0.2, 0);
Vector hackyClimbVector = new Vector(0, 0.2, 0);
PredictionEngineNormal.staticVectorEndOfTick(player, hackyClimbVector);
pointThreePossibilities.add(new VectorData(hackyClimbVector, VectorData.VectorType.ZeroPointZeroThree));
@@ -302,8 +290,8 @@ public class PredictionEngine {
addExplosionToPossibilities(player, pointThreePossibilities);
if (player.packetStateData.tryingToRiptide) {
Vector3D riptideAddition = Riptide.getRiptideVelocity(player);
pointThreePossibilities.add(new VectorData(player.clientVelocity.clone().add(riptideAddition), new VectorData(newVector3D(), ZeroPointZeroThree), VectorData.VectorType.Trident));
Vector riptideAddition = Riptide.getRiptideVelocity(player);
pointThreePossibilities.add(new VectorData(player.clientVelocity.clone().add(riptideAddition), new VectorData(new Vector(), VectorData.VectorType.ZeroPointZeroThree), VectorData.VectorType.Trident));
}
possibleVelocities.addAll(applyInputsToVelocityPossibilities(player, pointThreePossibilities, speed));
@@ -324,7 +312,7 @@ public class PredictionEngine {
// Water pushing movement is affected by initial velocity due to 0.003 eating pushing in the past
if (vectorData.isKnockback() && player.baseTickWaterPushing.lengthSquared() != 0) {
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13)) {
Vector3D vec3 = player.baseTickWaterPushing.clone();
Vector vec3 = player.baseTickWaterPushing.clone();
if (Math.abs(vectorData.vector.getX()) < 0.003 && Math.abs(vectorData.vector.getZ()) < 0.003 && player.baseTickWaterPushing.length() < 0.0045000000000000005D) {
vec3 = vec3.normalize().multiply(0.0045000000000000005);
}
@@ -344,7 +332,7 @@ public class PredictionEngine {
addExplosionToPossibilities(player, velocities);
if (player.packetStateData.tryingToRiptide) {
Vector3D riptideAddition = Riptide.getRiptideVelocity(player);
Vector riptideAddition = Riptide.getRiptideVelocity(player);
velocities.add(new VectorData(player.clientVelocity.clone().add(riptideAddition), VectorData.VectorType.Trident));
}
@@ -373,7 +361,7 @@ public class PredictionEngine {
private void addAttackSlowToPossibilities(GrimPlayer player, Set<VectorData> velocities) {
for (int x = 1; x <= Math.min(player.maxPlayerAttackSlow, 5); x++) {
for (VectorData data : new HashSet<>(velocities)) {
velocities.add(data.returnNewModified(data.vector.clone().multiply(newVector3D(0.6, 1, 0.6)), VectorData.VectorType.AttackSlow));
velocities.add(data.returnNewModified(data.vector.clone().multiply(new Vector(0.6, 1, 0.6)), VectorData.VectorType.AttackSlow));
}
}
}
@@ -476,15 +464,15 @@ public class PredictionEngine {
return Double.compare(a.vector.distanceSquared(player.actualMovement), b.vector.distanceSquared(player.actualMovement));
}
public Vector3D handleStartingVelocityUncertainty(GrimPlayer player, VectorData vector, Vector3D targetVec) {
double avgColliding = max(player.uncertaintyHandler.collidingEntities);
public Vector handleStartingVelocityUncertainty(GrimPlayer player, VectorData vector, Vector targetVec) {
double avgColliding = Collections.max(player.uncertaintyHandler.collidingEntities);
double additionHorizontal = player.uncertaintyHandler.getOffsetHorizontal(vector);
double additionVertical = player.uncertaintyHandler.getVerticalOffset(vector);
double pistonX = max(player.uncertaintyHandler.pistonX);
double pistonY = max(player.uncertaintyHandler.pistonY);
double pistonZ = max(player.uncertaintyHandler.pistonZ);
double pistonX = Collections.max(player.uncertaintyHandler.pistonX);
double pistonY = Collections.max(player.uncertaintyHandler.pistonY);
double pistonZ = Collections.max(player.uncertaintyHandler.pistonZ);
additionHorizontal += player.uncertaintyHandler.lastHorizontalOffset;
additionVertical += player.uncertaintyHandler.lastVerticalOffset;
@@ -527,13 +515,13 @@ public class PredictionEngine {
// 0.075 seems safe?
//
// Be somewhat careful as there is an antikb (for horizontal) that relies on this lenience
Vector3D uncertainty = newVector3D(avgColliding * 0.08, additionVertical, avgColliding * 0.08);
Vector uncertainty = new Vector(avgColliding * 0.08, additionVertical, avgColliding * 0.08);
Vector3D min = newVector3D(player.uncertaintyHandler.xNegativeUncertainty - additionHorizontal, -bonusY + player.uncertaintyHandler.yNegativeUncertainty, player.uncertaintyHandler.zNegativeUncertainty - additionHorizontal);
Vector3D max = newVector3D(player.uncertaintyHandler.xPositiveUncertainty + additionHorizontal, bonusY + player.uncertaintyHandler.yPositiveUncertainty, player.uncertaintyHandler.zPositiveUncertainty + additionHorizontal);
Vector min = new Vector(player.uncertaintyHandler.xNegativeUncertainty - additionHorizontal, -bonusY + player.uncertaintyHandler.yNegativeUncertainty, player.uncertaintyHandler.zNegativeUncertainty - additionHorizontal);
Vector max = new Vector(player.uncertaintyHandler.xPositiveUncertainty + additionHorizontal, bonusY + player.uncertaintyHandler.yPositiveUncertainty, player.uncertaintyHandler.zPositiveUncertainty + additionHorizontal);
Vector3D minVector = vector.vector.clone().add(min.subtract(uncertainty));
Vector3D maxVector = vector.vector.clone().add(max.add(uncertainty));
Vector minVector = vector.vector.clone().add(min.subtract(uncertainty));
Vector maxVector = vector.vector.clone().add(max.add(uncertainty));
// Handle the player landing within 0.03 movement, which resets Y velocity
if (player.uncertaintyHandler.onGroundUncertain && vector.vector.getY() < 0) {
@@ -560,7 +548,7 @@ public class PredictionEngine {
// We can't simulate the player's Y velocity, unknown number of ticks with a gravity change
// Feel free to simulate all 104857600000000000000000000 possibilities!
if (!player.pointThreeEstimator.canPredictNextVerticalMovement()) {
minVector.setY(minVector.getY() - player.compensatedEntities.getSelf().getAttributeValue(GENERIC_GRAVITY));
minVector.setY(minVector.getY() - player.compensatedEntities.getSelf().getAttributeValue(Attributes.GENERIC_GRAVITY));
}
// Hidden slime block bounces by missing idle tick and 0.03
@@ -600,9 +588,9 @@ public class PredictionEngine {
box.maxZ += sneaking.getSneakingPotentialHiddenVelocity().maxZ;
if (player.uncertaintyHandler.fireworksBox != null) {
double minXdiff = min(0, player.uncertaintyHandler.fireworksBox.minX - originalVec.vector.getX());
double minYdiff = min(0, player.uncertaintyHandler.fireworksBox.minY - originalVec.vector.getY());
double minZdiff = min(0, player.uncertaintyHandler.fireworksBox.minZ - originalVec.vector.getZ());
double minXdiff = Math.min(0, player.uncertaintyHandler.fireworksBox.minX - originalVec.vector.getX());
double minYdiff = Math.min(0, player.uncertaintyHandler.fireworksBox.minY - originalVec.vector.getY());
double minZdiff = Math.min(0, player.uncertaintyHandler.fireworksBox.minZ - originalVec.vector.getZ());
double maxXdiff = Math.max(0, player.uncertaintyHandler.fireworksBox.maxX - originalVec.vector.getX());
double maxYdiff = Math.max(0, player.uncertaintyHandler.fireworksBox.maxY - originalVec.vector.getY());
double maxZdiff = Math.max(0, player.uncertaintyHandler.fireworksBox.maxZ - originalVec.vector.getZ());
@@ -658,7 +646,7 @@ public class PredictionEngine {
//
// Or the player is switching in and out of controlling a vehicle, in which friction messes it up
//
if (player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0) || player.uncertaintyHandler.lastHardCollidingLerpingEntity.hasOccurredSince(3) || (player.getClientVersion().isNewerThanOrEquals(V_1_13) && vector.vector.getY() > 0 && vector.isZeroPointZeroThree() && !isEmpty(player, getBoundingBoxFromPosAndSize(player, player.lastX, vector.vector.getY() + player.lastY + 0.6, player.lastZ, 0.6f, 1.26f)))) {
if (player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0) || player.uncertaintyHandler.lastHardCollidingLerpingEntity.hasOccurredSince(3) || (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && vector.vector.getY() > 0 && vector.isZeroPointZeroThree() && !Collisions.isEmpty(player, GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.lastX, vector.vector.getY() + player.lastY + 0.6, player.lastZ, 0.6f, 1.26f)))) {
box.expandToAbsoluteCoordinates(0, 0, 0);
}
@@ -670,9 +658,9 @@ public class PredictionEngine {
if (player.wasTouchingWater) trueFriction = 0.96;
double maxY = Math.max(box.maxY, box.maxY + ((box.maxY - player.gravity) * 0.91));
double minY = min(box.minY, box.minY + ((box.minY - player.gravity) * 0.91));
double minX = min(box.minX, box.minX + (-player.speed * trueFriction));
double minZ = min(box.minZ, box.minZ + (-player.speed * trueFriction));
double minY = Math.min(box.minY, box.minY + ((box.minY - player.gravity) * 0.91));
double minX = Math.min(box.minX, box.minX + (-player.speed * trueFriction));
double minZ = Math.min(box.minZ, box.minZ + (-player.speed * trueFriction));
double maxX = Math.max(box.maxX, box.maxX + (player.speed * trueFriction));
double maxZ = Math.max(box.maxZ, box.maxZ + (player.speed * trueFriction));
@@ -688,15 +676,15 @@ public class PredictionEngine {
maxVector = box.max();
if (pistonX != 0) {
minVector.setX(min(minVector.getX() - pistonX, pistonX));
minVector.setX(Math.min(minVector.getX() - pistonX, pistonX));
maxVector.setX(Math.max(maxVector.getX() + pistonX, pistonX));
}
if (pistonY != 0) {
minVector.setY(min(minVector.getY() - pistonY, pistonY));
minVector.setY(Math.min(minVector.getY() - pistonY, pistonY));
maxVector.setY(Math.max(maxVector.getY() + pistonY, pistonY));
}
if (pistonZ != 0) {
minVector.setZ(min(minVector.getZ() - pistonZ, pistonZ));
minVector.setZ(Math.min(minVector.getZ() - pistonZ, pistonZ));
maxVector.setZ(Math.max(maxVector.getZ() + pistonZ, pistonZ));
}
return VectorUtils.cutBoxToVector(targetVec, minVector, maxVector);
@@ -712,36 +700,7 @@ public class PredictionEngine {
// Optimization - Also cuts down scenarios by 2/3
// For some reason the player sprints while swimming no matter what
// Probably as a way to tell the server it is swimming
int forwardMin = player.isSprinting && !player.isSwimming ? 1 : -1;
int forwardMax = 1;
int strafeMin = -1;
int strafeMax = 1;
// Calculate inputs by the players known inputs on 1.21.2+
if (player.supportsEndTick()) {
forwardMin = forwardMax = strafeMin = strafeMax = 0;
final KnownInput knownInput = player.packetStateData.knownInput;
if (knownInput.forward()) {
forwardMax++;
forwardMin++;
}
if (knownInput.backward() && (!player.isSprinting || player.isSwimming)) {
forwardMax--;
forwardMin--;
}
if (knownInput.left()) {
strafeMax++;
strafeMin++;
}
if (knownInput.right()) {
strafeMax--;
strafeMin--;
}
}
int zMin = player.isSprinting && !player.isSwimming ? 1 : -1;
for (int loopSlowed = 0; loopSlowed <= 1; loopSlowed++) {
// Loop twice for the using item status if the player is using a trident
@@ -753,11 +712,9 @@ public class PredictionEngine {
for (VectorData possibleLastTickOutput : possibleVectors) {
// Only do this when there is tick skipping
if (loopSlowed == 1 && !possibleLastTickOutput.isZeroPointZeroThree()) continue;
for (int strafe = strafeMin; strafe <= strafeMax; strafe++) {
for (int forward = forwardMin; forward <= forwardMax; forward++) {
VectorData result = new VectorData(possibleLastTickOutput.vector.clone()
.add(getMovementResultFromInput(player, transformInputsToVector(player, newVector3D(strafe, 0, forward)), speed, player.xRot)),
possibleLastTickOutput, VectorData.VectorType.InputResult);
for (int x = -1; x <= 1; x++) {
for (int z = zMin; z <= 1; z++) {
VectorData result = new VectorData(possibleLastTickOutput.vector.clone().add(getMovementResultFromInput(player, transformInputsToVector(player, new Vector(x, 0, z)), speed, player.xRot)), possibleLastTickOutput, VectorData.VectorType.InputResult);
result = result.returnNewModified(result.vector.clone().multiply(player.stuckSpeedMultiplier), VectorData.VectorType.StuckMultiplier);
result = result.returnNewModified(handleOnClimbable(result.vector.clone(), player), VectorData.VectorType.Climbable);
// Signal that we need to flip sneaking bounding box
@@ -824,21 +781,21 @@ public class PredictionEngine {
// This is just the vanilla equation, which accepts invalid inputs greater than 1
// We need it because of collision support when a player is using speed
public Vector3D getMovementResultFromInput(GrimPlayer player, Vector3D inputVector, float f, float f2) {
public Vector getMovementResultFromInput(GrimPlayer player, Vector inputVector, float f, float f2) {
float f3 = player.trigHandler.sin(f2 * 0.017453292f);
float f4 = player.trigHandler.cos(f2 * 0.017453292f);
double xResult = inputVector.getX() * f4 - inputVector.getZ() * f3;
double zResult = inputVector.getZ() * f4 + inputVector.getX() * f3;
return newVector3D(xResult * f, 0, zResult * f);
return new Vector(xResult * f, 0, zResult * f);
}
public Vector3D handleOnClimbable(Vector3D vector, GrimPlayer player) {
public Vector handleOnClimbable(Vector vector, GrimPlayer player) {
return vector;
}
public void doJump(GrimPlayer player, Vector3D vector) {
public void doJump(GrimPlayer player, Vector vector) {
if (!player.lastOnGround || player.onGround)
return;
@@ -3,33 +3,28 @@ package ac.grim.grimac.predictionengine.predictions;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.attribute.Attributes.GENERIC_GRAVITY;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_18_2;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_20_5;
import static java.lang.Math.*;
public class PredictionEngineElytra extends PredictionEngine {
// Inputs have no effect on movement
@Override
public List<VectorData> applyInputsToVelocityPossibilities(GrimPlayer player, Set<VectorData> possibleVectors, float speed) {
List<VectorData> results = new ArrayList<>();
Vector3D currentLook = ReachUtils.getLook(player, player.xRot, player.yRot);
Vector currentLook = ReachUtils.getLook(player, player.xRot, player.yRot);
for (VectorData data : possibleVectors) {
Vector3D elytraResult = getElytraMovement(player, data.vector.clone(), currentLook).multiply(player.stuckSpeedMultiplier).multiply(newVector3D(0.99F, 0.98F, 0.99F));
Vector elytraResult = getElytraMovement(player, data.vector.clone(), currentLook).multiply(player.stuckSpeedMultiplier).multiply(new Vector(0.99F, 0.98F, 0.99F));
results.add(data.returnNewModified(elytraResult, VectorData.VectorType.InputResult));
// We must bruteforce Optifine ShitMath
player.trigHandler.toggleShitMath();
elytraResult = getElytraMovement(player, data.vector.clone(), ReachUtils.getLook(player, player.xRot, player.yRot)).multiply(player.stuckSpeedMultiplier).multiply(newVector3D(0.99F, 0.98F, 0.99F));
elytraResult = getElytraMovement(player, data.vector.clone(), ReachUtils.getLook(player, player.xRot, player.yRot)).multiply(player.stuckSpeedMultiplier).multiply(new Vector(0.99F, 0.98F, 0.99F));
player.trigHandler.toggleShitMath();
results.add(data.returnNewModified(elytraResult, VectorData.VectorType.InputResult));
}
@@ -37,42 +32,42 @@ public class PredictionEngineElytra extends PredictionEngine {
return results;
}
public static Vector3D getElytraMovement(GrimPlayer player, Vector3D vector, Vector3D lookVector) {
public static Vector getElytraMovement(GrimPlayer player, Vector vector, Vector lookVector) {
float yRotRadians = player.yRot * 0.017453292F;
double horizontalSqrt = sqrt(lookVector.getX() * lookVector.getX() + lookVector.getZ() * lookVector.getZ());
double horizontalSqrt = Math.sqrt(lookVector.getX() * lookVector.getX() + lookVector.getZ() * lookVector.getZ());
double horizontalLength = vector.clone().setY(0).length();
double length = lookVector.length();
// Mojang changed from using their math to using regular java math in 1.18.2 elytra movement
double vertCosRotation = player.getClientVersion().isNewerThanOrEquals(V_1_18_2) ? cos(yRotRadians) : player.trigHandler.cos(yRotRadians);
vertCosRotation = (float) (vertCosRotation * vertCosRotation * min(1.0D, length / 0.4D));
double vertCosRotation = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_18_2) ? Math.cos(yRotRadians) : player.trigHandler.cos(yRotRadians);
vertCosRotation = (float) (vertCosRotation * vertCosRotation * Math.min(1.0D, length / 0.4D));
// So we actually use the player's actual movement to get the gravity/slow falling status
// However, this is wrong with elytra movement because players can control vertical movement after gravity is calculated
// Yeah, slow falling needs a refactor in grim.
double recalculatedGravity = player.compensatedEntities.getSelf().getAttributeValue(GENERIC_GRAVITY);
double recalculatedGravity = player.compensatedEntities.getSelf().getAttributeValue(Attributes.GENERIC_GRAVITY);
if (player.clientVelocity.getY() <= 0 && player.compensatedEntities.getSlowFallingAmplifier().isPresent()) {
recalculatedGravity = player.getClientVersion().isOlderThan(V_1_20_5) ? 0.01 : min(recalculatedGravity, 0.01);
recalculatedGravity = player.getClientVersion().isOlderThan(ClientVersion.V_1_20_5) ? 0.01 : Math.min(recalculatedGravity, 0.01);
}
vector.add(newVector3D(0.0D, recalculatedGravity * (-1.0D + vertCosRotation * 0.75D), 0.0D));
vector.add(new Vector(0.0D, recalculatedGravity * (-1.0D + vertCosRotation * 0.75D), 0.0D));
double d5;
// Handle slowing the player down when falling
if (vector.getY() < 0.0D && horizontalSqrt > 0.0D) {
d5 = vector.getY() * -0.1D * vertCosRotation;
vector.add(newVector3D(lookVector.getX() * d5 / horizontalSqrt, d5, lookVector.getZ() * d5 / horizontalSqrt));
vector.add(new Vector(lookVector.getX() * d5 / horizontalSqrt, d5, lookVector.getZ() * d5 / horizontalSqrt));
}
// Handle accelerating the player when they are looking down
if (yRotRadians < 0.0F && horizontalSqrt > 0.0D) {
d5 = horizontalLength * (double) (-player.trigHandler.sin(yRotRadians)) * 0.04D;
vector.add(newVector3D(-lookVector.getX() * d5 / horizontalSqrt, d5 * 3.2D, -lookVector.getZ() * d5 / horizontalSqrt));
vector.add(new Vector(-lookVector.getX() * d5 / horizontalSqrt, d5 * 3.2D, -lookVector.getZ() * d5 / horizontalSqrt));
}
// Handle accelerating the player sideways
if (horizontalSqrt > 0) {
vector.add(newVector3D((lookVector.getX() / horizontalSqrt * horizontalLength - vector.getX()) * 0.1D, 0.0D, (lookVector.getZ() / horizontalSqrt * horizontalLength - vector.getZ()) * 0.1D));
vector.add(new Vector((lookVector.getX() / horizontalSqrt * horizontalLength - vector.getX()) * 0.1D, 0.0D, (lookVector.getZ() / horizontalSqrt * horizontalLength - vector.getZ()) * 0.1D));
}
return vector;
@@ -3,13 +3,11 @@ package ac.grim.grimac.predictionengine.predictions;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class PredictionEngineLava extends PredictionEngine {
@Override
public void addJumpsToPossibilities(GrimPlayer player, Set<VectorData> existingVelocities) {
@@ -18,11 +16,11 @@ public class PredictionEngineLava extends PredictionEngine {
double extraVelFromVertTickSkipUpwards = GrimMath.clamp(player.actualMovement.getY(), vector.vector.clone().getY(), vector.vector.clone().getY() + 0.05f);
existingVelocities.add(new VectorData(vector.vector.clone().setY(extraVelFromVertTickSkipUpwards), vector, VectorData.VectorType.Jump));
} else {
existingVelocities.add(new VectorData(vector.vector.clone().add(newVector3D(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
}
if (player.slightlyTouchingLava && player.lastOnGround && !player.onGround) {
Vector3D withJump = vector.vector.clone();
Vector withJump = vector.vector.clone();
super.doJump(player, withJump);
existingVelocities.add(new VectorData(withJump, vector, VectorData.VectorType.Jump));
}
@@ -3,28 +3,23 @@ package ac.grim.grimac.predictionengine.predictions;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.JumpPower;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.OptionalInt;
import java.util.Set;
import static ac.grim.grimac.utils.math.GrimMath.clamp;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.world.states.type.StateTypes.SCAFFOLDING;
import static java.lang.Math.max;
public class PredictionEngineNormal extends PredictionEngine {
public static void staticVectorEndOfTick(GrimPlayer player, Vector3D vector) {
public static void staticVectorEndOfTick(GrimPlayer player, Vector vector) {
double adjustedY = vector.getY();
final OptionalInt levitation = player.compensatedEntities.getPotionLevelForPlayer(PotionTypes.LEVITATION);
if (levitation.isPresent()) {
@@ -42,12 +37,8 @@ public class PredictionEngineNormal extends PredictionEngine {
@Override
public void addJumpsToPossibilities(GrimPlayer player, Set<VectorData> existingVelocities) {
if (player.supportsEndTick() && !player.packetStateData.knownInput.jump()) {
return;
}
for (VectorData vector : new HashSet<>(existingVelocities)) {
Vector3D jump = vector.vector.clone();
Vector jump = vector.vector.clone();
if (!player.isFlying) {
// Negative jump boost does not allow the player to leave the ground
@@ -61,9 +52,9 @@ public class PredictionEngineNormal extends PredictionEngine {
JumpPower.jumpFromGround(player, jump);
} else {
jump.add(newVector3D(0, player.flySpeed * 3, 0));
jump.add(new Vector(0, player.flySpeed * 3, 0));
if (!player.wasFlying) {
Vector3D edgeCaseJump = jump.clone();
Vector edgeCaseJump = jump.clone();
JumpPower.jumpFromGround(player, edgeCaseJump);
existingVelocities.add(vector.returnNewModified(edgeCaseJump, VectorData.VectorType.Jump));
}
@@ -91,7 +82,7 @@ public class PredictionEngineNormal extends PredictionEngine {
if (player.lastWasClimbing == 0 && (player.pointThreeEstimator.isNearClimbable() || player.isClimbing) && (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)
|| !Collisions.isEmpty(player, player.boundingBox.copy().expand(
player.clientVelocity.getX(), 0, player.clientVelocity.getZ()).expand(0.5, -SimpleCollisionBox.COLLISION_EPSILON, 0.5))) || walkingOnPowderSnow) {
Vector3D ladderVelocity = player.clientVelocity.clone().setY(0.2);
Vector ladderVelocity = player.clientVelocity.clone().setY(0.2);
staticVectorEndOfTick(player, ladderVelocity);
player.lastWasClimbing = ladderVelocity.getY();
}
@@ -102,17 +93,17 @@ public class PredictionEngineNormal extends PredictionEngine {
}
@Override
public Vector3D handleOnClimbable(Vector3D vector, GrimPlayer player) {
public Vector handleOnClimbable(Vector vector, GrimPlayer player) {
if (player.isClimbing) {
// Reset fall distance when climbing
player.fallDistance = 0;
vector.setX(clamp(vector.getX(), -0.15F, 0.15F));
vector.setZ(clamp(vector.getZ(), -0.15F, 0.15F));
vector.setY(max(vector.getY(), -0.15F));
vector.setX(GrimMath.clamp(vector.getX(), -0.15F, 0.15F));
vector.setZ(GrimMath.clamp(vector.getZ(), -0.15F, 0.15F));
vector.setY(Math.max(vector.getY(), -0.15F));
// Yes, this uses shifting not crouching
if (vector.getY() < 0.0 && !(player.compensatedWorld.getStateTypeAt(player.lastX, player.lastY, player.lastZ) == SCAFFOLDING) && player.isSneaking && !player.isFlying) {
if (vector.getY() < 0.0 && !(player.compensatedWorld.getStateTypeAt(player.lastX, player.lastY, player.lastZ) == StateTypes.SCAFFOLDING) && player.isSneaking && !player.isFlying) {
vector.setY(0.0);
}
}
@@ -9,14 +9,11 @@ import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.FluidFallingAdjustedMovement;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.Set;
import static ac.grim.grimac.utils.data.VectorData.VectorType.SwimmingSpace;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class PredictionEngineWater extends PredictionEngine {
boolean isFalling;
double playerGravity;
@@ -24,9 +21,9 @@ public class PredictionEngineWater extends PredictionEngine {
float swimmingFriction;
double lastY;
public static void staticVectorEndOfTick(GrimPlayer player, Vector3D vector, float swimmingFriction, double playerGravity, boolean isFalling) {
vector.multiply(newVector3D(swimmingFriction, 0.8F, swimmingFriction));
Vector3D fluidVector = FluidFallingAdjustedMovement.getFluidFallingAdjustedMovement(player, playerGravity, isFalling, vector);
public static void staticVectorEndOfTick(GrimPlayer player, Vector vector, float swimmingFriction, double playerGravity, boolean isFalling) {
vector.multiply(new Vector(swimmingFriction, 0.8F, swimmingFriction));
Vector fluidVector = FluidFallingAdjustedMovement.getFluidFallingAdjustedMovement(player, playerGravity, isFalling, vector);
vector.setX(fluidVector.getX());
vector.setY(fluidVector.getY());
vector.setZ(fluidVector.getZ());
@@ -50,7 +47,7 @@ public class PredictionEngineWater extends PredictionEngine {
double scalar = lookYAmount < -0.2 ? 0.085 : 0.06;
// The player can always press jump and activate this
swimmingVelocities.add(vector.returnNewModified(newVector3D(vector.vector.getX(), vector.vector.getY() + ((lookYAmount - vector.vector.getY()) * scalar), vector.vector.getZ()), SwimmingSpace));
swimmingVelocities.add(vector.returnNewModified(new Vector(vector.vector.getX(), vector.vector.getY() + ((lookYAmount - vector.vector.getY()) * scalar), vector.vector.getZ()), VectorData.VectorType.SwimmingSpace));
// This scenario will occur if the player does not press jump and the other conditions are met
// Theoretically we should check this BEFORE allowing no look, but there isn't a cheat that takes advantage of this yet
@@ -83,11 +80,11 @@ public class PredictionEngineWater extends PredictionEngine {
double extraVelFromVertTickSkipUpwards = GrimMath.clamp(player.actualMovement.getY(), vector.vector.clone().getY(), vector.vector.clone().getY() + 0.05f);
existingVelocities.add(new VectorData(vector.vector.clone().setY(extraVelFromVertTickSkipUpwards), vector, VectorData.VectorType.Jump));
} else {
existingVelocities.add(new VectorData(vector.vector.clone().add(newVector3D(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
}
if (player.slightlyTouchingWater && player.lastOnGround && !player.onGround) {
Vector3D withJump = vector.vector.clone();
Vector withJump = vector.vector.clone();
super.doJump(player, withJump);
existingVelocities.add(new VectorData(withJump, vector, VectorData.VectorType.Jump));
}
@@ -2,15 +2,11 @@ package ac.grim.grimac.predictionengine.predictions;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static java.lang.Math.sqrt;
public class PredictionEngineWaterLegacy extends PredictionEngine {
double playerGravity;
float swimmingSpeed;
@@ -27,11 +23,11 @@ public class PredictionEngineWaterLegacy extends PredictionEngine {
// This is just the vanilla equation for legacy water movement
@Override
public Vector3D getMovementResultFromInput(GrimPlayer player, Vector3D inputVector, float f, float f2) {
public Vector getMovementResultFromInput(GrimPlayer player, Vector inputVector, float f, float f2) {
float lengthSquared = (float) inputVector.lengthSquared();
if (lengthSquared >= 1.0E-4F) {
lengthSquared = (float) sqrt(lengthSquared);
lengthSquared = (float) Math.sqrt(lengthSquared);
if (lengthSquared < 1.0F) {
lengthSquared = 1.0F;
@@ -42,20 +38,21 @@ public class PredictionEngineWaterLegacy extends PredictionEngine {
float sinResult = player.trigHandler.sin(player.xRot * 0.017453292F);
float cosResult = player.trigHandler.cos(player.xRot * 0.017453292F);
return newVector3D(inputVector.getX() * cosResult - inputVector.getZ() * sinResult, inputVector.getY(), inputVector.getZ() * cosResult + inputVector.getX() * sinResult);
return new Vector(inputVector.getX() * cosResult - inputVector.getZ() * sinResult,
inputVector.getY(), inputVector.getZ() * cosResult + inputVector.getX() * sinResult);
}
return newVector3D();
return new Vector();
}
@Override
public void addJumpsToPossibilities(GrimPlayer player, Set<VectorData> existingVelocities) {
for (VectorData vector : new HashSet<>(existingVelocities)) {
existingVelocities.add(new VectorData(vector.vector.clone().add(newVector3D(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
if (player.skippedTickInActualMovement) {
existingVelocities.add(new VectorData(vector.vector.clone().add(newVector3D(0, 0.02f, 0)), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector(0, 0.02f, 0)), vector, VectorData.VectorType.Jump));
}
}
}
@@ -65,7 +62,7 @@ public class PredictionEngineWaterLegacy extends PredictionEngine {
super.endOfTick(player, playerGravity);
for (VectorData vector : player.getPossibleVelocitiesMinusKnockback()) {
vector.vector.multiply(newVector3D(swimmingFriction, 0.8F, swimmingFriction));
vector.vector.multiply(new Vector(swimmingFriction, 0.8F, swimmingFriction));
// Gravity
vector.vector.setY(vector.vector.getY() - 0.02D);
@@ -13,15 +13,12 @@ import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static java.lang.Math.PI;
public class BoatPredictionEngine extends PredictionEngine {
public BoatPredictionEngine(GrimPlayer player) {
player.uncertaintyHandler.collidingEntities.add(0); // We don't do collisions like living entities
@@ -150,7 +147,7 @@ public class BoatPredictionEngine extends PredictionEngine {
// so if a player tries to move in both directions, a packet will
// show that the player is staying, but the boat will move anyway
if (player.vehicleData.vehicleForward == 0) {
Vector3D vector = data.vector.clone();
Vector vector = data.vector.clone();
controlBoat(player, vector, true);
vector.multiply(player.stuckSpeedMultiplier);
vectors.add(data.returnNewModified(vector, VectorData.VectorType.InputResult));
@@ -187,7 +184,7 @@ public class BoatPredictionEngine extends PredictionEngine {
return false;
}
private void floatBoat(GrimPlayer player, Vector3D vector) {
private void floatBoat(GrimPlayer player, Vector vector) {
double d1 = player.hasGravity ? -0.04f : 0;
double d2 = 0.0D;
float invFriction = 0.05F;
@@ -197,7 +194,7 @@ public class BoatPredictionEngine extends PredictionEngine {
player.lastY = getWaterLevelAbove(player) - 0.5625F + 0.101D;
player.boundingBox = GetBoundingBox.getCollisionBoxForPlayer(player, player.lastX, player.lastY, player.lastZ);
player.actualMovement = newVector3D(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
player.actualMovement = new Vector(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
vector.setY(0);
player.vehicleData.lastYd = 0.0D;
@@ -263,7 +260,7 @@ public class BoatPredictionEngine extends PredictionEngine {
return (float) (l + 1);
}
private void controlBoat(GrimPlayer player, Vector3D vector, boolean intermediate) {
private void controlBoat(GrimPlayer player, Vector vector, boolean intermediate) {
float f = 0.0F;
if (player.vehicleData.vehicleHorizontal != 0 && (!intermediate && player.vehicleData.vehicleForward == 0)) {
f += 0.005F;
@@ -278,6 +275,6 @@ public class BoatPredictionEngine extends PredictionEngine {
f -= 0.005F;
}
vector.add(newVector3D(player.trigHandler.sin(-player.xRot * ((float) PI / 180F)) * f, 0, (double) (player.trigHandler.cos(player.xRot * ((float) PI / 180F)) * f)));
vector.add(new Vector(player.trigHandler.sin(-player.xRot * ((float) Math.PI / 180F)) * f, 0, (double) (player.trigHandler.cos(player.xRot * ((float) Math.PI / 180F)) * f)));
}
}
@@ -3,16 +3,16 @@ package ac.grim.grimac.predictionengine.predictions.rideable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngineLava;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.List;
import java.util.Set;
public class PredictionEngineRideableLava extends PredictionEngineLava {
Vector3D movementVector;
Vector movementVector;
public PredictionEngineRideableLava(Vector3D movementVector) {
public PredictionEngineRideableLava(Vector movementVector) {
this.movementVector = movementVector;
}
@@ -3,16 +3,16 @@ package ac.grim.grimac.predictionengine.predictions.rideable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngineNormal;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.List;
import java.util.Set;
public class PredictionEngineRideableNormal extends PredictionEngineNormal {
Vector3D movementVector;
Vector movementVector;
public PredictionEngineRideableNormal(Vector3D movementVector) {
public PredictionEngineRideableNormal(Vector movementVector) {
this.movementVector = movementVector;
}
@@ -8,15 +8,13 @@ import ac.grim.grimac.utils.data.packetentity.PacketEntityHorse;
import ac.grim.grimac.utils.nmsutil.JumpPower;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class PredictionEngineRideableUtils {
public static Set<VectorData> handleJumps(GrimPlayer player, Set<VectorData> possibleVectors) {
if (!(player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityHorse horse)) return possibleVectors;
@@ -57,7 +55,7 @@ public class PredictionEngineRideableUtils {
for (VectorData vectorData : possibleVectors) {
vectorData.vector.setY(d1);
if (f1 > 0.0F) {
vectorData.vector.add(newVector3D(-0.4F * f2 * player.vehicleData.horseJump, 0.0D, 0.4F * f3 * player.vehicleData.horseJump));
vectorData.vector.add(new Vector(-0.4F * f2 * player.vehicleData.horseJump, 0.0D, 0.4F * f3 * player.vehicleData.horseJump));
}
}
@@ -73,7 +71,7 @@ public class PredictionEngineRideableUtils {
return possibleVectors;
}
public static List<VectorData> applyInputsToVelocityPossibilities(Vector3D movementVector, GrimPlayer player, Set<VectorData> possibleVectors, float speed) {
public static List<VectorData> applyInputsToVelocityPossibilities(Vector movementVector, GrimPlayer player, Set<VectorData> possibleVectors, float speed) {
List<VectorData> returnVectors = new ArrayList<>();
for (VectorData possibleLastTickOutput : possibleVectors) {
@@ -3,16 +3,16 @@ package ac.grim.grimac.predictionengine.predictions.rideable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngineWater;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.List;
import java.util.Set;
public class PredictionEngineRideableWater extends PredictionEngineWater {
Vector3D movementVector;
Vector movementVector;
public PredictionEngineRideableWater(Vector3D movementVector) {
public PredictionEngineRideableWater(Vector movementVector) {
this.movementVector = movementVector;
}
@@ -3,15 +3,15 @@ package ac.grim.grimac.predictionengine.predictions.rideable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngineWaterLegacy;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.List;
import java.util.Set;
public class PredictionEngineRideableWaterLegacy extends PredictionEngineWaterLegacy {
Vector3D movementVector;
Vector movementVector;
public PredictionEngineRideableWaterLegacy(Vector3D movementVector) {
public PredictionEngineRideableWaterLegacy(Vector movementVector) {
this.movementVector = movementVector;
}
@@ -1,34 +0,0 @@
package ac.grim.grimac.utils.anticheat.update;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import lombok.Getter;
public class BlockBreak {
public final Vector3i position;
public final BlockFace face;
public final DiggingAction action;
@Getter
private boolean cancelled;
public final WrappedBlockState block;
public BlockBreak(WrapperPlayClientPlayerDigging packet, GrimPlayer player) {
this(packet.getBlockPosition(), packet.getBlockFace(), packet.getAction(), player.compensatedWorld.getWrappedBlockStateAt(packet.getBlockPosition()));
}
public BlockBreak(Vector3i position, BlockFace face, DiggingAction action, WrappedBlockState block) {
this.position = position;
this.face = face;
this.action = action;
this.block = block;
}
public void cancel() {
this.cancelled = true;
}
}
@@ -16,7 +16,7 @@ import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.nmsutil.BoundingBoxSize;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.Materials;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
@@ -35,23 +35,18 @@ import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.Getter;
import lombok.Setter;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import static ac.grim.grimac.utils.nmsutil.ReachUtils.calculateIntercept;
import static ac.grim.grimac.utils.nmsutil.ReachUtils.getLook;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.attribute.Attributes.PLAYER_BLOCK_INTERACTION_RANGE;
public class BlockPlace {
protected static final BlockFace[] UPDATE_SHAPE_ORDER = new BlockFace[]{BlockFace.WEST, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.DOWN, BlockFace.UP};
private static final BlockFace[] BY_2D = new BlockFace[]{BlockFace.SOUTH, BlockFace.WEST, BlockFace.NORTH, BlockFace.EAST};
static final BlockFace[] BY_3D = new BlockFace[]{BlockFace.DOWN, BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST};
@Setter
public Vector3i blockPosition;
Vector3i blockPosition;
@Getter
InteractionHand hand;
@Getter
@@ -666,18 +661,18 @@ public class BlockPlace {
// You also have the desync caused by eye height as apparently tracking the player's ticks wasn't important to you
// No mojang, you really do need to track client ticks to get their accurate eye height.
// another damn desync added... maybe next decade it will get fixed and double the amount of issues.
public Vector3D getClickedLocation() {
public Vector getClickedLocation() {
SimpleCollisionBox box = new SimpleCollisionBox(getPlacedAgainstBlockLocation());
Vector3D look = getLook(player, player.xRot, player.yRot);
Vector look = ReachUtils.getLook(player, player.xRot, player.yRot);
final double distance = player.compensatedEntities.getSelf().getAttributeValue(PLAYER_BLOCK_INTERACTION_RANGE) + 3;
Vector3D eyePos = newVector3D(player.x, player.y + player.getEyeHeight(), player.z);
Vector3D endReachPos = eyePos.clone().add(newVector3D(look.getX() * distance, look.getY() * distance, look.getZ() * distance));
Vector3D intercept = calculateIntercept(box, eyePos, endReachPos).first();
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE) + 3;
Vector eyePos = new Vector(player.x, player.y + player.getEyeHeight(), player.z);
Vector endReachPos = eyePos.clone().add(new Vector(look.getX() * distance, look.getY() * distance, look.getZ() * distance));
Vector intercept = ReachUtils.calculateIntercept(box, eyePos, endReachPos).first();
// Bring this back to relative to the block
// The player didn't even click the block... (we should force resync BEFORE we get here!)
if (intercept == null) return newVector3D();
if (intercept == null) return new Vector();
intercept.setX(intercept.getX() - box.minX);
intercept.setY(intercept.getY() - box.minY);
@@ -21,13 +21,11 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.protocol.world.states.type.StateValue;
import com.github.retrooper.packetevents.util.Vector3i;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.stream.Collectors;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public enum BlockPlaceResult {
// If the block only has directional data
@@ -82,7 +80,7 @@ public enum BlockPlaceResult {
}, ItemTypes.SNOW),
SLAB((player, place) -> {
Vector3D clickedPos = place.getClickedLocation();
Vector clickedPos = place.getClickedLocation();
WrappedBlockState slabData = place.getMaterial().createBlockState(CompensatedWorld.blockVersion);
WrappedBlockState existing = place.getExistingBlockData();
@@ -911,7 +909,7 @@ public enum BlockPlaceResult {
WrappedBlockState ccwState = place.getDirectionalState(ccw);
CollisionBox ccwBox = CollisionData.getData(ccwState.getType()).getMovementCollisionBox(player, player.getClientVersion(), ccwState);
Vector3D aboveCCWPos = place.getClickedLocation().add(newVector3D(ccw.getModX(), ccw.getModY(), ccw.getModZ())).add(newVector3D(0, 1, 0));
Vector aboveCCWPos = place.getClickedLocation().add(new Vector(ccw.getModX(), ccw.getModY(), ccw.getModZ())).add(new Vector(0, 1, 0));
WrappedBlockState aboveCCWState = player.compensatedWorld.getWrappedBlockStateAt(aboveCCWPos);
CollisionBox aboveCCWBox = CollisionData.getData(aboveCCWState.getType()).getMovementCollisionBox(player, player.getClientVersion(), aboveCCWState);
@@ -919,7 +917,7 @@ public enum BlockPlaceResult {
WrappedBlockState cwState = place.getDirectionalState(cw);
CollisionBox cwBox = CollisionData.getData(cwState.getType()).getMovementCollisionBox(player, player.getClientVersion(), cwState);
Vector3D aboveCWPos = place.getClickedLocation().add(newVector3D(cw.getModX(), cw.getModY(), cw.getModZ())).add(newVector3D(0, 1, 0));
Vector aboveCWPos = place.getClickedLocation().add(new Vector(cw.getModX(), cw.getModY(), cw.getModZ())).add(new Vector(0, 1, 0));
WrappedBlockState aboveCWState = player.compensatedWorld.getWrappedBlockStateAt(aboveCWPos);
CollisionBox aboveCWBox = CollisionData.getData(aboveCWState.getType()).getMovementCollisionBox(player, player.getClientVersion(), aboveCWState);
@@ -936,7 +934,7 @@ public enum BlockPlaceResult {
if ((!isCWLower || isCCWLower) && i >= 0) {
int j = playerFacing.getModX();
int k = playerFacing.getModZ();
Vector3D vec3 = place.getClickedLocation();
Vector vec3 = place.getClickedLocation();
double d0 = vec3.getX();
double d1 = vec3.getY();
hinge = (j >= 0 || d1 >= 0.5D) && (j <= 0 || d1 <= 0.5D) && (k >= 0 || d0 <= 0.5D) && (k <= 0 || d0 >= 0.5D) ? Hinge.LEFT : Hinge.RIGHT;
@@ -1,8 +1,7 @@
package ac.grim.grimac.utils.blockstate.helper;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
public class BlockFaceHelper {
public static boolean isFaceVertical(BlockFace face) {
@@ -57,7 +56,7 @@ public class BlockFaceHelper {
};
}
public Vector3D offset(Vector3D toOffset, BlockFace face) {
public Vector offset(Vector toOffset, BlockFace face) {
toOffset.setX(toOffset.getX() + face.getModX());
toOffset.setY(toOffset.getY() + face.getModY());
toOffset.setZ(toOffset.getZ() + face.getModZ());
@@ -680,7 +680,7 @@ public enum CollisionData {
}, StateTypes.END_ROD, StateTypes.LIGHTNING_ROD),
CAULDRON((player, version, data, x, y, z) -> {
if (version.isNewerThan(ClientVersion.V_1_13_2)) { // changed in 19w13a, 1.14 Snapshot
if (version.isNewerThan(ClientVersion.getById(467))) { // changed in 19w13a, 1.14 Snapshot
return new ComplexCollisionBox(15,
new SimpleCollisionBox(0.0, 0.0, 0.0, 0.125, 1.0, 0.25, false),
new SimpleCollisionBox(0.0, 0.0, 0.75, 0.125, 1.0, 1.0, false),
@@ -1,9 +1,6 @@
package ac.grim.grimac.utils.collisions.datatypes;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import org.bukkit.util.Vector;
public class BoundingBox {
@@ -18,7 +15,7 @@ public class BoundingBox {
this.maxZ = maxZ;
}
public BoundingBox(Vector3D min, Vector3D max) {
public BoundingBox(Vector min, Vector max) {
this.minX = (float) Math.min(min.getX(), max.getX());
this.minY = (float) Math.min(min.getY(), max.getY());
this.minZ = (float) Math.min(min.getZ(), max.getZ());
@@ -47,7 +44,7 @@ public class BoundingBox {
return new BoundingBox(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ);
}
public BoundingBox add(Vector3D vector) {
public BoundingBox add(Vector vector) {
float x = (float) vector.getX(), y = (float) vector.getY(), z = (float) vector.getZ();
float newMinX = minX + x;
@@ -90,27 +87,27 @@ public class BoundingBox {
return new BoundingBox(this.minX - minX, this.minY - minY, this.minZ - minZ, this.maxX - maxX, this.maxY - maxY, this.maxZ - maxZ);
}
public boolean intersectsWithBox(Vector3D vector) {
public boolean intersectsWithBox(Vector vector) {
return (vector.getX() > this.minX && vector.getX() < this.maxX) && ((vector.getY() > this.minY && vector.getY() < this.maxY) && (vector.getZ() > this.minZ && vector.getZ() < this.maxZ));
}
public Vector3D getMinimum() {
return newVector3D(minX, minY, minZ);
public Vector getMinimum() {
return new Vector(minX, minY, minZ);
}
public Vector3D getMaximum() {
return newVector3D(maxX, maxY, maxZ);
public Vector getMaximum() {
return new Vector(maxX, maxY, maxZ);
}
public boolean collides(Vector3D vector) {
public boolean collides(Vector vector) {
return (vector.getX() >= this.minX && vector.getX() <= this.maxX) && ((vector.getY() >= this.minY && vector.getY() <= this.maxY) && (vector.getZ() >= this.minZ && vector.getZ() <= this.maxZ));
}
public boolean collidesHorizontally(Vector3D vector) {
public boolean collidesHorizontally(Vector vector) {
return (vector.getX() >= this.minX && vector.getX() <= this.maxX) && ((vector.getY() > this.minY && vector.getY() < this.maxY) && (vector.getZ() >= this.minZ && vector.getZ() <= this.maxZ));
}
public boolean collidesVertically(Vector3D vector) {
public boolean collidesVertically(Vector vector) {
return (vector.getX() > this.minX && vector.getX() < this.maxX) && ((vector.getY() >= this.minY && vector.getY() <= this.maxY) && (vector.getZ() > this.minZ && vector.getZ() < this.maxZ));
}
@@ -1,7 +1,6 @@
package ac.grim.grimac.utils.collisions.datatypes;
import ac.grim.grimac.utils.nmsutil.Ray;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
@@ -9,12 +8,10 @@ import it.unimi.dsi.fastutil.doubles.AbstractDoubleList;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleList;
import org.bukkit.Location;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.List;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class SimpleCollisionBox implements CollisionBox {
public static final double COLLISION_EPSILON = 1.0E-7;
@@ -49,7 +46,7 @@ public class SimpleCollisionBox implements CollisionBox {
isFullBlock = fullBlock;
}
public SimpleCollisionBox(Vector3D min, Vector3D max) {
public SimpleCollisionBox(Vector min, Vector max) {
this(min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ());
}
@@ -88,10 +85,10 @@ public class SimpleCollisionBox implements CollisionBox {
}
public SimpleCollisionBox(Location loc, double width, double height) {
this(newVector3D(loc.getX(), loc.getY(), loc.getZ()), width, height);
this(loc.toVector(), width, height);
}
public SimpleCollisionBox(Vector3D vec, double width, double height) {
public SimpleCollisionBox(Vector vec, double width, double height) {
this(vec.getX(), vec.getY(), vec.getZ(), vec.getX(), vec.getY(), vec.getZ());
expand(width / 2, 0, width / 2);
@@ -154,16 +151,16 @@ public class SimpleCollisionBox implements CollisionBox {
return this;
}
public Vector3D[] corners() {
Vector3D[] vectors = new Vector3D[8];
vectors[0] = newVector3D(minX, minY, minZ);
vectors[1] = newVector3D(minX, minY, maxZ);
vectors[2] = newVector3D(maxX, minY, minZ);
vectors[3] = newVector3D(maxX, minY, maxZ);
vectors[4] = newVector3D(minX, maxY, minZ);
vectors[5] = newVector3D(minX, maxY, maxZ);
vectors[6] = newVector3D(maxX, maxY, minZ);
vectors[7] = newVector3D(maxX, maxY, maxZ);
public Vector[] corners() {
Vector[] vectors = new Vector[8];
vectors[0] = new Vector(minX, minY, minZ);
vectors[1] = new Vector(minX, minY, maxZ);
vectors[2] = new Vector(maxX, minY, minZ);
vectors[3] = new Vector(maxX, minY, maxZ);
vectors[4] = new Vector(minX, maxY, minZ);
vectors[5] = new Vector(minX, maxY, maxZ);
vectors[6] = new Vector(maxX, maxY, minZ);
vectors[7] = new Vector(maxX, maxY, maxZ);
return vectors;
}
@@ -411,14 +408,14 @@ public class SimpleCollisionBox implements CollisionBox {
*/
// Copied from hawk lol
// I would like to point out that this is magic to me and I have not attempted to understand this code
public Vector3D intersectsRay(Ray ray, float minDist, float maxDist) {
Vector3D invDir = newVector3D(1f / ray.calculateDirection().getX(), 1f / ray.calculateDirection().getY(), 1f / ray.calculateDirection().getZ());
public Vector intersectsRay(Ray ray, float minDist, float maxDist) {
Vector invDir = new Vector(1f / ray.calculateDirection().getX(), 1f / ray.calculateDirection().getY(), 1f / ray.calculateDirection().getZ());
boolean signDirX = invDir.getX() < 0;
boolean signDirY = invDir.getY() < 0;
boolean signDirZ = invDir.getZ() < 0;
Vector3D bbox = signDirX ? max() : min();
Vector bbox = signDirX ? max() : min();
double tmin = (bbox.getX() - ray.getOrigin().getX()) * invDir.getX();
bbox = signDirX ? min() : max();
double tmax = (bbox.getX() - ray.getOrigin().getX()) * invDir.getX();
@@ -457,12 +454,12 @@ public class SimpleCollisionBox implements CollisionBox {
return null;
}
public Vector3D max() {
return newVector3D(maxX, maxY, maxZ);
public Vector max() {
return new Vector(maxX, maxY, maxZ);
}
public Vector3D min() {
return newVector3D(minX, minY, minZ);
public Vector min() {
return new Vector(minX, minY, minZ);
}
public DoubleList getYPointPositions() {
@@ -1,22 +1,22 @@
package ac.grim.grimac.utils.data;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.Getter;
import lombok.ToString;
import org.bukkit.util.Vector;
@Getter
@ToString
public class HitData {
Vector3i position;
Vector3D blockHitLocation;
Vector blockHitLocation;
WrappedBlockState state;
BlockFace closestDirection;
public HitData(Vector3i position, Vector3D blockHitLocation, BlockFace closestDirection, WrappedBlockState state) {
public HitData(Vector3i position, Vector blockHitLocation, BlockFace closestDirection, WrappedBlockState state) {
this.position = position;
this.blockHitLocation = blockHitLocation;
this.closestDirection = closestDirection;
@@ -1,4 +0,0 @@
package ac.grim.grimac.utils.data;
public record KnownInput(boolean forward, boolean backward, boolean left, boolean right, boolean jump, boolean shift, boolean sprint) {
}
@@ -24,9 +24,6 @@ public class PacketStateData {
// This works on 1.8 only
public boolean didLastLastMovementIncludePosition = false;
public boolean didLastMovementIncludePosition = false;
// This works on 1.21.2+ only
public boolean didSendMovementBeforeTickEnd = false;
public KnownInput knownInput = new KnownInput(false, false, false, false, false, false, false);
public Vector3d lastClaimedPosition = new Vector3d(0, 0, 0);
public float lastHealth, lastSaturation;
@@ -18,4 +18,20 @@
package ac.grim.grimac.utils.data;
public record Pair<A, B>(A first, B second) {}
import java.util.Objects;
public record Pair<A, B>(A first, B second) {
public static <T, K> Pair<T, K> of(T a, K b) {
return new Pair<>(a, b);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) {
return false;
}
Pair b = (Pair) o;
return Objects.equals(this.first, b.first) && Objects.equals(this.second, b.second);
}
}
@@ -3,7 +3,7 @@ package ac.grim.grimac.utils.data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
@Getter
@Setter
@@ -11,14 +11,14 @@ import ac.grim.grimac.utils.vector.Vector3D;
public class SetBackData {
TeleportData teleportData;
float xRot, yRot;
Vector3D velocity;
Vector velocity;
boolean vehicle;
boolean isComplete = false;
// TODO: Rethink when we block movements for teleports, perhaps after 10 ticks or 5 blocks?
boolean isPlugin = false;
int ticksComplete = 0;
public SetBackData(TeleportData teleportData, float xRot, float yRot, Vector3D velocity, boolean vehicle, boolean isPlugin) {
public SetBackData(TeleportData teleportData, float xRot, float yRot, Vector velocity, boolean vehicle, boolean isPlugin) {
this.teleportData = teleportData;
this.xRot = xRot;
this.yRot = yRot;
@@ -1,7 +1,7 @@
package ac.grim.grimac.utils.data;
import lombok.Getter;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.Objects;
@@ -9,13 +9,13 @@ public class VectorData {
public VectorType vectorType;
public VectorData lastVector;
public VectorData preUncertainty;
public Vector3D vector;
public Vector vector;
@Getter
private boolean isKnockback, firstBreadKb, isExplosion, firstBreadExplosion, isTrident, isZeroPointZeroThree, isSwimHop, isFlipSneaking, isFlipItem, isJump, isAttackSlow = false;
// For handling replacing the type of vector it is while keeping data
public VectorData(Vector3D vector, VectorData lastVector, VectorType vectorType) {
public VectorData(Vector vector, VectorData lastVector, VectorType vectorType) {
this.vector = vector;
this.lastVector = lastVector;
this.vectorType = vectorType;
@@ -38,7 +38,7 @@ public class VectorData {
addVectorType(vectorType);
}
public VectorData(Vector3D vector, VectorType vectorType) {
public VectorData(Vector vector, VectorType vectorType) {
this.vector = vector;
this.vectorType = vectorType;
addVectorType(vectorType);
@@ -48,7 +48,7 @@ public class VectorData {
return new VectorData(vector, this, type);
}
public VectorData returnNewModified(Vector3D newVec, VectorType type) {
public VectorData returnNewModified(Vector newVec, VectorType type) {
return new VectorData(newVec, this, type);
}
@@ -65,7 +65,7 @@ public class VectorData {
return Objects.hash(vectorType, lastVector, preUncertainty, vector, isKnockback, firstBreadKb, isExplosion, firstBreadExplosion, isTrident, isZeroPointZeroThree, isSwimHop, isFlipSneaking, isFlipItem, isJump, isAttackSlow);
}
protected void addVectorType(VectorType type) {
private void addVectorType(VectorType type) {
switch (type) {
case Knockback:
isKnockback = true;
@@ -1,15 +1,15 @@
package ac.grim.grimac.utils.data;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
public class VelocityData {
public final Vector3D vector;
public final Vector vector;
public final int entityID;
public final int transaction;
public double offset = Integer.MAX_VALUE;
public boolean isSetback;
public VelocityData(int entityID, int transaction, boolean isSetback, Vector3D vector) {
public VelocityData(int entityID, int transaction, boolean isSetback, Vector vector) {
this.entityID = entityID;
this.vector = vector;
this.transaction = transaction;
@@ -17,7 +17,7 @@ public class VelocityData {
}
// First bread last tick -> Required this tick = don't require kb twice
public VelocityData(int entityID, int transaction, Vector3D vector, boolean isSetback, double offset) {
public VelocityData(int entityID, int transaction, Vector vector, boolean isSetback, double offset) {
this.entityID = entityID;
this.vector = vector;
this.transaction = transaction;
@@ -3,17 +3,21 @@ package ac.grim.grimac.utils.data.packetentity;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.world.Direction;
import com.github.retrooper.packetevents.protocol.world.PaintingType;
import lombok.Getter;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
@Getter
public class PacketEntityPainting extends PacketEntity {
private final @Nullable PaintingType paintingType;
private final Direction direction;
public PacketEntityPainting(GrimPlayer player, UUID uuid, double x, double y, double z, Direction direction) {
public PacketEntityPainting(GrimPlayer player, UUID uuid, double x, double y, double z, @Nullable PaintingType paintingType, Direction direction) {
super(player, uuid, EntityTypes.PAINTING, x, y, z);
this.paintingType = paintingType;
this.direction = direction;
}
}
@@ -39,48 +39,24 @@ public enum MenuType {
private final int id;
private static final MenuType[] MENU_BY_ID_ARRAY;
static {
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
MenuType[] menuTypes = MenuType.values();
int menuIdLimit;
if (version.isOlderThan(ServerVersion.V_1_20_3)) {
// versions under 1.20.3
menuIdLimit = 23;
} else {
// 1.20.3 & greater
menuIdLimit = menuTypes.length - 1; // Don't iterate the UNKNOWN menu type
}
MENU_BY_ID_ARRAY = new MenuType[menuIdLimit];
for (int itr = 0; itr < menuIdLimit; itr++) {
MENU_BY_ID_ARRAY[itr] = menuTypes[itr];
}
}
//TODO: could be optimized
public static MenuType getMenuType(int id) {
if (id < 0) {
return UNKNOWN;
}
if (id < 0) return UNKNOWN;
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
// versions under 1.20.3
if (version.isOlderThan(ServerVersion.V_1_20_3)) { // TODO: Can this be moved to the static block?
if (id >= 7) {
id++;
}
if (version.isOlderThan(ServerVersion.V_1_20_3)) {
if (id > 23) return UNKNOWN;
MenuType[] values = MenuType.values();
if (id >= 7) id++;
return values[id];
}
if (id >= MENU_BY_ID_ARRAY.length) {
return UNKNOWN;
}
return MENU_BY_ID_ARRAY[id];
// 1.20.3 & greater
MenuType[] values = MenuType.values();
if (id >= values.length) return UNKNOWN;
return MenuType.values()[id];
}
public static AbstractContainerMenu getMenuFromID(GrimPlayer player, Inventory playerInventory, MenuType type) {
return switch (type) {
case GENERIC_9x1, GENERIC_9x2, GENERIC_9x3, GENERIC_9x4, GENERIC_9x5, GENERIC_9x6 ->
@@ -21,6 +21,7 @@ import com.github.retrooper.packetevents.protocol.potion.PotionType;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.Direction;
import com.github.retrooper.packetevents.protocol.world.PaintingType;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
@@ -181,8 +182,8 @@ public class CompensatedEntities {
packetEntity = new PacketEntityHook(player, uuid, entityType, position.getX(), position.getY(), position.getZ(), data);
} else if (EntityTypes.ENDER_DRAGON.equals(entityType)) {
packetEntity = new PacketEntityEnderDragon(player, uuid, entityID, position.getX(), position.getY(), position.getZ());
} else if (EntityTypes.PAINTING.equals(entityType)) {
packetEntity = new PacketEntityPainting(player, uuid, position.x, position.y, position.z, Direction.getByHorizontalIndex(data));
} else if (entityType == EntityTypes.PAINTING) {
packetEntity = new PacketEntityPainting(player, uuid, position.x, position.y, position.z, data == -1 ? null : PaintingType.getById(data), Direction.getByHorizontalIndex((int) xRot));
} else {
packetEntity = new PacketEntity(player, uuid, entityType, position.getX(), position.getY(), position.getZ());
}
@@ -49,7 +49,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import org.bukkit.Bukkit;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.*;
@@ -686,7 +686,7 @@ public class CompensatedWorld {
return maxHeight;
}
public WrappedBlockState getWrappedBlockStateAt(Vector3D aboveCCWPos) {
public WrappedBlockState getWrappedBlockStateAt(Vector aboveCCWPos) {
return getWrappedBlockStateAt(aboveCCWPos.getX(), aboveCCWPos.getY(), aboveCCWPos.getZ());
}
}
@@ -7,6 +7,7 @@ import ac.grim.grimac.utils.inventory.InventoryStorage;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import org.bukkit.inventory.InventoryView;
import java.util.*;
@@ -43,7 +44,7 @@ public class CorrectingPlayerInventoryStorage extends InventoryStorage {
// The key for this map is the inventory slot ID
// The value for this map is the transaction that we care about
// Returns -1 if the entry is null
Map<Integer, Integer> serverIsCurrentlyProcessingThesePredictions = new ConcurrentHashMap<>();
Int2IntOpenHashMap serverIsCurrentlyProcessingThesePredictions = new Int2IntOpenHashMap();
// A list of predictions the client has made for inventory changes
// Remove if the server rejects these changes
Map<Integer, Integer> pendingFinalizedSlot = new ConcurrentHashMap<>();
@@ -55,6 +56,7 @@ public class CorrectingPlayerInventoryStorage extends InventoryStorage {
public CorrectingPlayerInventoryStorage(GrimPlayer player, int size) {
super(size);
this.player = player;
this.serverIsCurrentlyProcessingThesePredictions.defaultReturnValue(-1);
}
// 1.17+ clients send what slots they have changed. This makes our jobs much easier.
@@ -76,7 +78,7 @@ public class CorrectingPlayerInventoryStorage extends InventoryStorage {
@Override
public void setItem(int item, ItemStack stack) {
// If there is a more recent change to this one, don't override it
int finalTransaction = serverIsCurrentlyProcessingThesePredictions.getOrDefault(item, -1);
int finalTransaction = serverIsCurrentlyProcessingThesePredictions.get(item);
// If the server is currently sending a packet to the player AND it is the final change to the slot
// OR, the client was in control of setting this slot
@@ -1,14 +1,9 @@
package ac.grim.grimac.utils.math;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import lombok.Getter;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_8;
import static java.lang.Math.abs;
import org.bukkit.util.Vector;
public class TrigHandler {
GrimPlayer player;
@@ -24,24 +19,24 @@ public class TrigHandler {
isVanillaMath = !isVanillaMath;
}
public Vector3D getVanillaMathMovement(Vector3D wantedMovement, float f, float f2) {
public Vector getVanillaMathMovement(Vector wantedMovement, float f, float f2) {
float f3 = VanillaMath.sin(f2 * 0.017453292f);
float f4 = VanillaMath.cos(f2 * 0.017453292f);
float bestTheoreticalX = (float) (f3 * wantedMovement.getZ() + f4 * wantedMovement.getX()) / (f3 * f3 + f4 * f4) / f;
float bestTheoreticalZ = (float) (-f3 * wantedMovement.getX() + f4 * wantedMovement.getZ()) / (f3 * f3 + f4 * f4) / f;
return newVector3D(bestTheoreticalX, 0, bestTheoreticalZ);
return new Vector(bestTheoreticalX, 0, bestTheoreticalZ);
}
public Vector3D getShitMathMovement(Vector3D wantedMovement, float f, float f2) {
float f3 = player.getClientVersion().isNewerThanOrEquals(V_1_8) ? OptifineFastMath.sin(f2 * 0.017453292f) : LegacyFastMath.sin(f2 * 0.017453292f);
float f4 = player.getClientVersion().isNewerThanOrEquals(V_1_8) ? OptifineFastMath.cos(f2 * 0.017453292f) : LegacyFastMath.cos(f2 * 0.017453292f);
public Vector getShitMathMovement(Vector wantedMovement, float f, float f2) {
float f3 = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? OptifineFastMath.sin(f2 * 0.017453292f) : LegacyFastMath.sin(f2 * 0.017453292f);
float f4 = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? OptifineFastMath.cos(f2 * 0.017453292f) : LegacyFastMath.cos(f2 * 0.017453292f);
float bestTheoreticalX = (float) (f3 * wantedMovement.getZ() + f4 * wantedMovement.getX()) / (f3 * f3 + f4 * f4) / f;
float bestTheoreticalZ = (float) (-f3 * wantedMovement.getX() + f4 * wantedMovement.getZ()) / (f3 * f3 + f4 * f4) / f;
return newVector3D(bestTheoreticalX, 0, bestTheoreticalZ);
return new Vector(bestTheoreticalX, 0, bestTheoreticalZ);
}
public void setOffset(double offset) {
@@ -54,12 +49,12 @@ public class TrigHandler {
}
if (offset > 1e-5) {
Vector3D trueMovement = player.actualMovement.clone().subtract(player.startTickClientVel);
Vector3D correctMath = getVanillaMathMovement(trueMovement, 0.1f, player.xRot);
Vector3D fastMath = getShitMathMovement(trueMovement, 0.1f, player.xRot);
Vector trueMovement = player.actualMovement.clone().subtract(player.startTickClientVel);
Vector correctMath = getVanillaMathMovement(trueMovement, 0.1f, player.xRot);
Vector fastMath = getShitMathMovement(trueMovement, 0.1f, player.xRot);
correctMath = newVector3D(abs(correctMath.getX()), 0, abs(correctMath.getZ()));
fastMath = newVector3D(abs(fastMath.getX()), 0, abs(fastMath.getZ()));
correctMath = new Vector(Math.abs(correctMath.getX()), 0, Math.abs(correctMath.getZ()));
fastMath = new Vector(Math.abs(fastMath.getX()), 0, Math.abs(fastMath.getZ()));
double minCorrectHorizontal = Math.min(correctMath.getX(), correctMath.getZ());
// Support diagonal inputs
@@ -1,25 +1,23 @@
package ac.grim.grimac.utils.math;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.util.Vector3d;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.math.GrimMath.clamp;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import org.bukkit.util.Vector;
public class VectorUtils {
public static Vector3D cutBoxToVector(Vector3D vectorToCutTo, Vector3D min, Vector3D max) {
public static Vector cutBoxToVector(Vector vectorToCutTo, Vector min, Vector max) {
SimpleCollisionBox box = new SimpleCollisionBox(min, max).sort();
return cutBoxToVector(vectorToCutTo, box);
}
public static Vector3D cutBoxToVector(Vector3D vectorCutTo, SimpleCollisionBox box) {
return newVector3D(clamp(vectorCutTo.getX(), box.minX, box.maxX), clamp(vectorCutTo.getY(), box.minY, box.maxY), clamp(vectorCutTo.getZ(), box.minZ, box.maxZ));
public static Vector cutBoxToVector(Vector vectorCutTo, SimpleCollisionBox box) {
return new Vector(GrimMath.clamp(vectorCutTo.getX(), box.minX, box.maxX),
GrimMath.clamp(vectorCutTo.getY(), box.minY, box.maxY),
GrimMath.clamp(vectorCutTo.getZ(), box.minZ, box.maxZ));
}
public static Vector3D fromVec3d(Vector3d vector3d) {
return newVector3D(vector3d.getX(), vector3d.getY(), vector3d.getZ());
public static Vector fromVec3d(Vector3d vector3d) {
return new Vector(vector3d.getX(), vector3d.getY(), vector3d.getZ());
}
// Clamping stops the player from causing an integer overflow and crashing the netty thread
@@ -45,8 +45,8 @@ public class BlockProperties {
}
// In 1.19.4, air sprinting is based on current sprinting, not last sprinting
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_19_4)) {
return player.isSprinting ? 0.025999999F : 0.02f;
if (player.getClientVersion().getProtocolVersion() > ClientVersion.V_1_19_3.getProtocolVersion()) {
return player.isSprinting ? (float) ((double) 0.02f + 0.005999999865889549D) : 0.02f;
}
return player.lastSprintingForSpeed ? (float) ((double) 0.02f + 0.005999999865889549D) : 0.02f;
@@ -1 +0,0 @@
@@ -12,7 +12,6 @@ import ac.grim.grimac.utils.data.tags.SyncedTags;
import ac.grim.grimac.utils.latency.CompensatedWorld;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
@@ -27,7 +26,7 @@ import it.unimi.dsi.fastutil.floats.FloatArraySet;
import it.unimi.dsi.fastutil.floats.FloatArrays;
import it.unimi.dsi.fastutil.floats.FloatSet;
import org.bukkit.Location;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.Arrays;
@@ -35,13 +34,6 @@ import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import static ac.grim.grimac.utils.nmsutil.Collisions.Axis.*;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.*;
import static java.lang.Double.MAX_VALUE;
import static java.lang.Math.max;
import static java.lang.Math.min;
public class Collisions {
private static final double COLLISION_EPSILON = 1.0E-7;
@@ -80,12 +72,12 @@ public class Collisions {
}
// Call this when there isn't uncertainty on the Y axis
public static Vector3D collide(GrimPlayer player, double desiredX, double desiredY, double desiredZ) {
public static Vector collide(GrimPlayer player, double desiredX, double desiredY, double desiredZ) {
return collide(player, desiredX, desiredY, desiredZ, desiredY, null);
}
public static Vector3D collide(GrimPlayer player, double desiredX, double desiredY, double desiredZ, double clientVelY, VectorData data) {
if (desiredX == 0 && desiredY == 0 && desiredZ == 0) return newVector3D();
public static Vector collide(GrimPlayer player, double desiredX, double desiredY, double desiredZ, double clientVelY, VectorData data) {
if (desiredX == 0 && desiredY == 0 && desiredZ == 0) return new Vector();
final SimpleCollisionBox grabBoxesBB = player.boundingBox.copy();
final double stepUpHeight = player.getMaxUpStep();
@@ -103,7 +95,7 @@ public class Collisions {
grabBoxesBB.expandToCoordinate(desiredX, desiredY, desiredZ);
grabBoxesBB.maxY += stepUpHeight;
} else {
grabBoxesBB.expandToCoordinate(desiredX, max(stepUpHeight, desiredY), desiredZ);
grabBoxesBB.expandToCoordinate(desiredX, Math.max(stepUpHeight, desiredY), desiredZ);
}
} else {
grabBoxesBB.expandToCoordinate(desiredX, desiredY, desiredZ);
@@ -113,14 +105,14 @@ public class Collisions {
List<SimpleCollisionBox> desiredMovementCollisionBoxes = new ArrayList<>();
getCollisionBoxes(player, grabBoxesBB, desiredMovementCollisionBoxes, false);
double bestInput = MAX_VALUE;
Vector3D bestOrderResult = null;
double bestInput = Double.MAX_VALUE;
Vector bestOrderResult = null;
Vector3D bestTheoreticalCollisionResult = VectorUtils.cutBoxToVector(player.actualMovement, new SimpleCollisionBox(0, min(0, desiredY), 0, desiredX, max(stepUpHeight, desiredY), desiredZ).sort());
Vector bestTheoreticalCollisionResult = VectorUtils.cutBoxToVector(player.actualMovement, new SimpleCollisionBox(0, Math.min(0, desiredY), 0, desiredX, Math.max(stepUpHeight, desiredY), desiredZ).sort());
int zeroCount = (desiredX == 0 ? 1 : 0) + (desiredY == 0 ? 1 : 0) + (desiredZ == 0 ? 1 : 0);
for (List<Axis> order : (data != null && data.isZeroPointZeroThree() ? allAxisCombinations : nonStupidityCombinations)) {
Vector3D collisionResult = collideBoundingBoxLegacy(newVector3D(desiredX, desiredY, desiredZ), player.boundingBox, desiredMovementCollisionBoxes, order);
Vector collisionResult = collideBoundingBoxLegacy(new Vector(desiredX, desiredY, desiredZ), player.boundingBox, desiredMovementCollisionBoxes, order);
// While running up stairs and holding space, the player activates the "lastOnGround" part without otherwise being able to step
// 0.03 movement must compensate for stepping elsewhere. Too much of a hack to include in this met5hod.
@@ -132,7 +124,7 @@ public class Collisions {
if (stepUpHeight > 0.0F && movingIntoGround && (collisionResult.getX() != desiredX || collisionResult.getZ() != desiredZ)) {
player.uncertaintyHandler.isStepMovement = true;
// 1.21 significantly refactored this
if (player.getClientVersion().isNewerThanOrEquals(V_1_21)) {
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21)) {
SimpleCollisionBox box2 = movingIntoGroundReal ? player.boundingBox.copy().offset(0.0, collisionResult.getY(), 0.0) : player.boundingBox.copy();
SimpleCollisionBox box3 = box2.copy().expandToCoordinate(desiredX, stepUpHeight, desiredZ);
if (!movingIntoGroundReal) {
@@ -144,21 +136,21 @@ public class Collisions {
final float[] stepHeights = collectStepHeights(box2, list2, (float) stepUpHeight, (float) collisionResult.getY());
for (float stepHeight : stepHeights) {
Vector3D vec3d2 = collideBoundingBoxLegacy(newVector3D(desiredX, stepHeight, desiredZ), box2, list2, order);
Vector vec3d2 = collideBoundingBoxLegacy(new Vector(desiredX, stepHeight, desiredZ), box2, list2, order);
if (getHorizontalDistanceSqr(vec3d2) > getHorizontalDistanceSqr(collisionResult)) {
final double d = player.boundingBox.minY - box2.minY;
collisionResult = vec3d2.add(newVector3D(0.0, -d, 0.0));
collisionResult = vec3d2.add(new Vector(0.0, -d, 0.0));
break;
}
}
} else {
Vector3D regularStepUp = collideBoundingBoxLegacy(newVector3D(desiredX, stepUpHeight, desiredZ), player.boundingBox, desiredMovementCollisionBoxes, order);
Vector regularStepUp = collideBoundingBoxLegacy(new Vector(desiredX, stepUpHeight, desiredZ), player.boundingBox, desiredMovementCollisionBoxes, order);
// 1.7 clients do not have this stepping bug fix
if (player.getClientVersion().isNewerThanOrEquals(V_1_8)) {
Vector3D stepUpBugFix = collideBoundingBoxLegacy(newVector3D(0, stepUpHeight, 0), player.boundingBox.copy().expandToCoordinate(desiredX, 0, desiredZ), desiredMovementCollisionBoxes, order);
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8)) {
Vector stepUpBugFix = collideBoundingBoxLegacy(new Vector(0, stepUpHeight, 0), player.boundingBox.copy().expandToCoordinate(desiredX, 0, desiredZ), desiredMovementCollisionBoxes, order);
if (stepUpBugFix.getY() < stepUpHeight) {
Vector3D stepUpBugFixResult = collideBoundingBoxLegacy(newVector3D(desiredX, 0, desiredZ), player.boundingBox.copy().offset(0, stepUpBugFix.getY(), 0), desiredMovementCollisionBoxes, order).add(stepUpBugFix);
Vector stepUpBugFixResult = collideBoundingBoxLegacy(new Vector(desiredX, 0, desiredZ), player.boundingBox.copy().offset(0, stepUpBugFix.getY(), 0), desiredMovementCollisionBoxes, order).add(stepUpBugFix);
if (getHorizontalDistanceSqr(stepUpBugFixResult) > getHorizontalDistanceSqr(regularStepUp)) {
regularStepUp = stepUpBugFixResult;
}
@@ -166,7 +158,7 @@ public class Collisions {
}
if (getHorizontalDistanceSqr(regularStepUp) > getHorizontalDistanceSqr(collisionResult)) {
collisionResult = regularStepUp.add(collideBoundingBoxLegacy(newVector3D(0, -regularStepUp.getY() + (player.getClientVersion().isNewerThanOrEquals(V_1_14) ? desiredY : 0), 0), player.boundingBox.copy().offset(regularStepUp.getX(), regularStepUp.getY(), regularStepUp.getZ()), desiredMovementCollisionBoxes, order));
collisionResult = regularStepUp.add(collideBoundingBoxLegacy(new Vector(0, -regularStepUp.getY() + (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14) ? desiredY : 0), 0), player.boundingBox.copy().offset(regularStepUp.getX(), regularStepUp.getY(), regularStepUp.getZ()), desiredMovementCollisionBoxes, order));
}
}
}
@@ -351,7 +343,7 @@ public class Collisions {
return false;
}
public static Vector3D collideBoundingBoxLegacy(Vector3D toCollide, SimpleCollisionBox
public static Vector collideBoundingBoxLegacy(Vector toCollide, SimpleCollisionBox
box, List<SimpleCollisionBox> desiredMovementCollisionBoxes, List<Axis> order) {
double x = toCollide.getX();
double y = toCollide.getY();
@@ -360,17 +352,17 @@ public class Collisions {
SimpleCollisionBox setBB = box.copy();
for (Axis axis : order) {
if (axis == X) {
if (axis == Axis.X) {
for (SimpleCollisionBox bb : desiredMovementCollisionBoxes) {
x = bb.collideX(setBB, x);
}
setBB.offset(x, 0.0D, 0.0D);
} else if (axis == Y) {
} else if (axis == Axis.Y) {
for (SimpleCollisionBox bb : desiredMovementCollisionBoxes) {
y = bb.collideY(setBB, y);
}
setBB.offset(0.0D, y, 0.0D);
} else if (axis == Z) {
} else if (axis == Axis.Z) {
for (SimpleCollisionBox bb : desiredMovementCollisionBoxes) {
z = bb.collideZ(setBB, z);
}
@@ -378,23 +370,23 @@ public class Collisions {
}
}
return newVector3D(x, y, z);
return new Vector(x, y, z);
}
public static boolean isEmpty(GrimPlayer player, SimpleCollisionBox playerBB) {
return !getCollisionBoxes(player, playerBB, null, true);
}
private static double getHorizontalDistanceSqr(Vector3D vector) {
private static double getHorizontalDistanceSqr(Vector vector) {
return vector.getX() * vector.getX() + vector.getZ() * vector.getZ();
}
public static Vector3D maybeBackOffFromEdge(Vector3D vec3, GrimPlayer player, boolean overrideVersion) {
public static Vector maybeBackOffFromEdge(Vector vec3, GrimPlayer player, boolean overrideVersion) {
if (!player.isFlying && player.isSneaking && isAboveGround(player)) {
double x = vec3.getX();
double z = vec3.getZ();
double maxStepDown = overrideVersion || player.getClientVersion().isNewerThanOrEquals(V_1_11) ? -player.getMaxUpStep() : -1 + COLLISION_EPSILON;
double maxStepDown = overrideVersion || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_11) ? -player.getMaxUpStep() : -1 + COLLISION_EPSILON;
while (x != 0.0 && isEmpty(player, player.boundingBox.copy().offset(x, maxStepDown, 0.0))) {
if (x < 0.05D && x >= -0.05D) {
@@ -431,7 +423,7 @@ public class Collisions {
z += 0.05D;
}
}
vec3 = newVector3D(x, vec3.getY(), z);
vec3 = new Vector(x, vec3.getY(), z);
}
return vec3;
@@ -462,20 +454,20 @@ public class Collisions {
if (blockType == StateTypes.COBWEB) {
if (player.compensatedEntities.hasPotionEffect(PotionTypes.WEAVING)) {
player.stuckSpeedMultiplier = newVector3D(0.5, 0.25, 0.5);
player.stuckSpeedMultiplier = new Vector(0.5, 0.25, 0.5);
} else {
player.stuckSpeedMultiplier = newVector3D(0.25, 0.05000000074505806, 0.25);
player.stuckSpeedMultiplier = new Vector(0.25, 0.05000000074505806, 0.25);
}
}
if (blockType == StateTypes.SWEET_BERRY_BUSH
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) {
player.stuckSpeedMultiplier = newVector3D(0.800000011920929, 0.75, 0.800000011920929);
player.stuckSpeedMultiplier = new Vector(0.800000011920929, 0.75, 0.800000011920929);
}
if (blockType == StateTypes.POWDER_SNOW && i == Math.floor(player.x) && j == Math.floor(player.y) && k == Math.floor(player.z)
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_17)) {
player.stuckSpeedMultiplier = newVector3D(0.8999999761581421, 1.5, 0.8999999761581421);
player.stuckSpeedMultiplier = new Vector(0.8999999761581421, 1.5, 0.8999999761581421);
}
if (blockType == StateTypes.SOUL_SAND && player.getClientVersion().isOlderThan(ClientVersion.V_1_15)) {
@@ -542,7 +534,7 @@ public class Collisions {
}
}
private static boolean isSlidingDown(Vector3D vector, GrimPlayer player, int locationX, int locationY,
private static boolean isSlidingDown(Vector vector, GrimPlayer player, int locationX, int locationY,
int locationZ) {
if (player.onGround) {
return false;
@@ -1,19 +1,15 @@
package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_14;
import static java.lang.Math.abs;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import org.bukkit.util.Vector;
public class FluidFallingAdjustedMovement {
public static Vector3D getFluidFallingAdjustedMovement(GrimPlayer player, double d, boolean bl, Vector3D vec3) {
public static Vector getFluidFallingAdjustedMovement(GrimPlayer player, double d, boolean bl, Vector vec3) {
if (player.hasGravity && !player.isSprinting) {
boolean falling = player.getClientVersion().isNewerThanOrEquals(V_1_14) ? bl : vec3.getY() < 0;
double d2 = falling && abs(vec3.getY() - 0.005) >= 0.003 && abs(vec3.getY() - d / 16.0) < 0.003 ? -0.003 : vec3.getY() - d / 16.0;
return newVector3D(vec3.getX(), d2, vec3.getZ());
boolean falling = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14) ? bl : vec3.getY() < 0;
double d2 = falling && Math.abs(vec3.getY() - 0.005) >= 0.003 && Math.abs(vec3.getY() - d / 16.0) < 0.003 ? -0.003 : vec3.getY() - d / 16.0;
return new Vector(vec3.getX(), d2, vec3.getZ());
}
return vec3;
}
@@ -3,37 +3,29 @@ package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.CollisionData;
import ac.grim.grimac.utils.collisions.blocks.DoorHandler;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.nmsutil.Materials.isSolidBlockingBlacklist;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.world.BlockFace.*;
import static com.github.retrooper.packetevents.protocol.world.states.type.StateTypes.LAVA;
import static com.github.retrooper.packetevents.protocol.world.states.type.StateTypes.WATER;
import static java.lang.Math.min;
import org.bukkit.util.Vector;
public class FluidTypeFlowing {
public static Vector3D getFlow(GrimPlayer player, int originalX, int originalY, int originalZ) {
float fluidLevel = (float) min(player.compensatedWorld.getFluidLevelAt(originalX, originalY, originalZ), 8 / 9D);
public static Vector getFlow(GrimPlayer player, int originalX, int originalY, int originalZ) {
float fluidLevel = (float) Math.min(player.compensatedWorld.getFluidLevelAt(originalX, originalY, originalZ), 8 / 9D);
ClientVersion version = player.getClientVersion();
if (fluidLevel == 0) return newVector3D();
if (fluidLevel == 0) return new Vector();
double d0 = 0.0D;
double d1 = 0.0D;
for (BlockFace enumdirection : new BlockFace[]{NORTH, EAST, SOUTH, WEST}) {
for (BlockFace enumdirection : new BlockFace[]{BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST}) {
int modifiedX = originalX + enumdirection.getModX();
int modifiedZ = originalZ + enumdirection.getModZ();
if (affectsFlow(player, originalX, originalY, originalZ, modifiedX, originalY, modifiedZ)) {
float f = (float) min(player.compensatedWorld.getFluidLevelAt(modifiedX, originalY, modifiedZ), 8 / 9D);
float f = (float) Math.min(player.compensatedWorld.getFluidLevelAt(modifiedX, originalY, modifiedZ), 8 / 9D);
float f1 = 0.0F;
if (f == 0.0F) {
StateType mat = player.compensatedWorld.getStateTypeAt(modifiedX, originalY, modifiedZ);
@@ -41,9 +33,9 @@ public class FluidTypeFlowing {
// Grim's definition of solid is whether the block has a hitbox
// Minecraft is... it's whatever Mojang was feeling like, but it's very consistent
// Use method call to support 1.13-1.15 clients and banner oddity
if (isSolidBlockingBlacklist(mat, version)) {
if (Materials.isSolidBlockingBlacklist(mat, version)) {
if (affectsFlow(player, originalX, originalY, originalZ, modifiedX, originalY - 1, modifiedZ)) {
f = (float) min(player.compensatedWorld.getFluidLevelAt(modifiedX, originalY - 1, modifiedZ), 8 / 9D);
f = (float) Math.min(player.compensatedWorld.getFluidLevelAt(modifiedX, originalY - 1, modifiedZ), 8 / 9D);
if (f > 0.0F) {
f1 = fluidLevel - (f - 0.8888889F);
}
@@ -61,15 +53,15 @@ public class FluidTypeFlowing {
}
}
Vector3D vec3d = newVector3D(d0, 0.0D, d1);
Vector vec3d = new Vector(d0, 0.0D, d1);
// Fluid level 1-7 is for regular fluid heights
// Fluid level 8-15 is for falling fluids
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(originalX, originalY, originalZ);
if ((state.getType() == WATER || state.getType() == LAVA) && state.getLevel() >= 8) {
for (BlockFace enumdirection : new BlockFace[]{NORTH, EAST, SOUTH, WEST}) {
if ((state.getType() == StateTypes.WATER || state.getType() == StateTypes.LAVA) && state.getLevel() >= 8) {
for (BlockFace enumdirection : new BlockFace[]{BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST}) {
if (isSolidFace(player, originalX, originalY, originalZ, enumdirection) || isSolidFace(player, originalX, originalY + 1, originalZ, enumdirection)) {
vec3d = normalizeVectorWithoutNaN(vec3d).add(newVector3D(0.0D, -6.0D, 0.0D));
vec3d = normalizeVectorWithoutNaN(vec3d).add(new Vector(0.0D, -6.0D, 0.0D));
break;
}
}
@@ -158,9 +150,9 @@ public class FluidTypeFlowing {
}
}
private static Vector3D normalizeVectorWithoutNaN(Vector3D vector) {
private static Vector normalizeVectorWithoutNaN(Vector vector) {
double var0 = vector.length();
return var0 < 1.0E-4 ? newVector3D() : vector.multiply(1 / var0);
return var0 < 1.0E-4 ? new Vector() : vector.multiply(1 / var0);
}
public static boolean isEmpty(GrimPlayer player, int x, int y, int z) {
@@ -5,14 +5,12 @@ import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import ac.grim.grimac.utils.vector.Vector3D;
import org.bukkit.util.Vector;
import java.util.OptionalInt;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class JumpPower {
public static void jumpFromGround(GrimPlayer player, Vector3D vector) {
public static void jumpFromGround(GrimPlayer player, Vector vector) {
float jumpPower = getJumpPower(player);
final OptionalInt jumpBoost = player.compensatedEntities.getPotionLevelForPlayer(PotionTypes.JUMP_BOOST);
@@ -22,11 +20,11 @@ public class JumpPower {
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20_5) && jumpPower <= 1.0E-5F) return;
vector.setY(player.getClientVersion().isOlderThan(ClientVersion.V_1_21_2) ? jumpPower : Math.max(jumpPower, vector.getY()));
vector.setY(jumpPower);
if (player.isSprinting) {
float radRotation = player.xRot * ((float) Math.PI / 180);
vector.add(newVector3D(-player.trigHandler.sin(radRotation) * 0.2, 0.0, player.trigHandler.cos(radRotation) * 0.2));
float radRotation = player.xRot * ((float) Math.PI / 180F);
vector.add(new Vector(-player.trigHandler.sin(radRotation) * 0.2f, 0.0, player.trigHandler.cos(radRotation) * 0.2f));
}
}
@@ -2,34 +2,30 @@ package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static java.lang.Math.toRadians;
import org.bukkit.util.Vector;
// Copied directly from Hawk
public class Ray implements Cloneable {
private Vector3D origin;
private Vector3D direction;
private Vector origin;
private Vector direction;
public Ray(Vector3D origin, Vector3D direction) {
public Ray(Vector origin, Vector direction) {
this.origin = origin;
this.direction = direction;
}
public Ray(GrimPlayer player, double x, double y, double z, float xRot, float yRot) {
this.origin = newVector3D(x, y, z);
this.origin = new Vector(x, y, z);
this.direction = calculateDirection(player, xRot, yRot);
}
// Account for FastMath by using player's trig handler
// Copied from hawk which probably copied it from NMS
public static Vector3D calculateDirection(GrimPlayer player, float xRot, float yRot) {
Vector3D vector = newVector3D();
float rotX = (float) toRadians(xRot);
float rotY = (float) toRadians(yRot);
public static Vector calculateDirection(GrimPlayer player, float xRot, float yRot) {
Vector vector = new Vector();
float rotX = (float) Math.toRadians(xRot);
float rotY = (float) Math.toRadians(yRot);
vector.setY(-player.trigHandler.sin(rotY));
double xz = player.trigHandler.cos(rotY);
vector.setX(-xz * player.trigHandler.sin(rotX));
@@ -54,28 +50,28 @@ public class Ray implements Cloneable {
return "origin: " + origin + " direction: " + direction;
}
public Vector3D getPointAtDistance(double distance) {
Vector3D dir = newVector3D(direction.getX(), direction.getY(), direction.getZ());
Vector3D orig = newVector3D(origin.getX(), origin.getY(), origin.getZ());
public Vector getPointAtDistance(double distance) {
Vector dir = new Vector(direction.getX(), direction.getY(), direction.getZ());
Vector orig = new Vector(origin.getX(), origin.getY(), origin.getZ());
return orig.add(dir.multiply(distance));
}
//https://en.wikipedia.org/wiki/Skew_lines#Nearest_Points
public Pair<Vector3D, Vector3D> closestPointsBetweenLines(Ray other) {
Vector3D n1 = direction.clone().crossProduct(other.direction.clone().crossProduct(direction));
Vector3D n2 = other.direction.clone().crossProduct(direction.clone().crossProduct(other.direction));
public Pair<Vector, Vector> closestPointsBetweenLines(Ray other) {
Vector n1 = direction.clone().crossProduct(other.direction.clone().crossProduct(direction));
Vector n2 = other.direction.clone().crossProduct(direction.clone().crossProduct(other.direction));
Vector3D c1 = origin.clone().add(direction.clone().multiply(other.origin.clone().subtract(origin).dot(n2) / direction.dot(n2)));
Vector3D c2 = other.origin.clone().add(other.direction.clone().multiply(origin.clone().subtract(other.origin).dot(n1) / other.direction.dot(n1)));
Vector c1 = origin.clone().add(direction.clone().multiply(other.origin.clone().subtract(origin).dot(n2) / direction.dot(n2)));
Vector c2 = other.origin.clone().add(other.direction.clone().multiply(origin.clone().subtract(other.origin).dot(n1) / other.direction.dot(n1)));
return new Pair<>(c1, c2);
}
public Vector3D getOrigin() {
public Vector getOrigin() {
return origin;
}
public Vector3D calculateDirection() {
public Vector calculateDirection() {
return direction;
}
}
@@ -5,24 +5,19 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_12_2;
import static java.lang.Math.PI;
import org.bukkit.util.Vector;
public class ReachUtils {
// Copied from 1.8... I couldn't figure out 1.14+. "Enterprise" java code is unreadable!
public static Pair<Vector3D, BlockFace> calculateIntercept(SimpleCollisionBox self, Vector3D origin, Vector3D end) {
Vector3D minX = getIntermediateWithXValue(origin, end, self.minX);
Vector3D maxX = getIntermediateWithXValue(origin, end, self.maxX);
Vector3D minY = getIntermediateWithYValue(origin, end, self.minY);
Vector3D maxY = getIntermediateWithYValue(origin, end, self.maxY);
Vector3D minZ = getIntermediateWithZValue(origin, end, self.minZ);
Vector3D maxZ = getIntermediateWithZValue(origin, end, self.maxZ);
public static Pair<Vector, BlockFace> calculateIntercept(SimpleCollisionBox self, Vector origin, Vector end) {
Vector minX = getIntermediateWithXValue(origin, end, self.minX);
Vector maxX = getIntermediateWithXValue(origin, end, self.maxX);
Vector minY = getIntermediateWithYValue(origin, end, self.minY);
Vector maxY = getIntermediateWithYValue(origin, end, self.maxY);
Vector minZ = getIntermediateWithZValue(origin, end, self.minZ);
Vector maxZ = getIntermediateWithZValue(origin, end, self.maxZ);
BlockFace bestFace = null;
@@ -50,7 +45,7 @@ public class ReachUtils {
maxZ = null;
}
Vector3D best = null;
Vector best = null;
if (minX != null) {
best = minX;
@@ -89,7 +84,7 @@ public class ReachUtils {
* Returns a new vector with x value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public static Vector3D getIntermediateWithXValue(Vector3D self, Vector3D other, double x) {
public static Vector getIntermediateWithXValue(Vector self, Vector other, double x) {
double d0 = other.getX() - self.getX();
double d1 = other.getY() - self.getY();
double d2 = other.getZ() - self.getZ();
@@ -98,7 +93,7 @@ public class ReachUtils {
return null;
} else {
double d3 = (x - self.getX()) / d0;
return d3 >= 0.0D && d3 <= 1.0D ? newVector3D(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
return d3 >= 0.0D && d3 <= 1.0D ? new Vector(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
}
}
@@ -106,7 +101,7 @@ public class ReachUtils {
* Returns a new vector with y value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public static Vector3D getIntermediateWithYValue(Vector3D self, Vector3D other, double y) {
public static Vector getIntermediateWithYValue(Vector self, Vector other, double y) {
double d0 = other.getX() - self.getX();
double d1 = other.getY() - self.getY();
double d2 = other.getZ() - self.getZ();
@@ -115,7 +110,7 @@ public class ReachUtils {
return null;
} else {
double d3 = (y - self.getY()) / d1;
return d3 >= 0.0D && d3 <= 1.0D ? newVector3D(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
return d3 >= 0.0D && d3 <= 1.0D ? new Vector(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
}
}
@@ -123,7 +118,7 @@ public class ReachUtils {
* Returns a new vector with z value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public static Vector3D getIntermediateWithZValue(Vector3D self, Vector3D other, double z) {
public static Vector getIntermediateWithZValue(Vector self, Vector other, double z) {
double d0 = other.getX() - self.getX();
double d1 = other.getY() - self.getY();
double d2 = other.getZ() - self.getZ();
@@ -132,51 +127,51 @@ public class ReachUtils {
return null;
} else {
double d3 = (z - self.getZ()) / d2;
return d3 >= 0.0D && d3 <= 1.0D ? newVector3D(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
return d3 >= 0.0D && d3 <= 1.0D ? new Vector(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
}
}
/**
* Checks if the specified vector is within the YZ dimensions of the bounding box. Args: Vec3D
*/
private static boolean isVecInYZ(SimpleCollisionBox self, Vector3D vec) {
private static boolean isVecInYZ(SimpleCollisionBox self, Vector vec) {
return vec != null && vec.getY() >= self.minY && vec.getY() <= self.maxY && vec.getZ() >= self.minZ && vec.getZ() <= self.maxZ;
}
/**
* Checks if the specified vector is within the XZ dimensions of the bounding box. Args: Vec3D
*/
private static boolean isVecInXZ(SimpleCollisionBox self, Vector3D vec) {
private static boolean isVecInXZ(SimpleCollisionBox self, Vector vec) {
return vec != null && vec.getX() >= self.minX && vec.getX() <= self.maxX && vec.getZ() >= self.minZ && vec.getZ() <= self.maxZ;
}
/**
* Checks if the specified vector is within the XY dimensions of the bounding box. Args: Vec3D
*/
private static boolean isVecInXY(SimpleCollisionBox self, Vector3D vec) {
private static boolean isVecInXY(SimpleCollisionBox self, Vector vec) {
return vec != null && vec.getX() >= self.minX && vec.getX() <= self.maxX && vec.getY() >= self.minY && vec.getY() <= self.maxY;
}
// Look vector accounting for optifine FastMath, and client version differences
public static Vector3D getLook(GrimPlayer player, float yaw, float pitch) {
if (player.getClientVersion().isOlderThanOrEquals(V_1_12_2)) {
float f = player.trigHandler.cos(-yaw * 0.017453292F - (float) PI);
float f1 = player.trigHandler.sin(-yaw * 0.017453292F - (float) PI);
public static Vector getLook(GrimPlayer player, float yaw, float pitch) {
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_12_2)) {
float f = player.trigHandler.cos(-yaw * 0.017453292F - (float)Math.PI);
float f1 = player.trigHandler.sin(-yaw * 0.017453292F - (float)Math.PI);
float f2 = -player.trigHandler.cos(-pitch * 0.017453292F);
float f3 = player.trigHandler.sin(-pitch * 0.017453292F);
return newVector3D(f1 * f2, f3, f * f2);
return new Vector(f1 * f2, f3, f * f2);
} else {
float f = pitch * ((float) PI / 180F);
float f1 = -yaw * ((float) PI / 180F);
float f = pitch * ((float) Math.PI / 180F);
float f1 = -yaw * ((float) Math.PI / 180F);
float f2 = player.trigHandler.cos(f1);
float f3 = player.trigHandler.sin(f1);
float f4 = player.trigHandler.cos(f);
float f5 = player.trigHandler.sin(f);
return newVector3D(f3 * f4, -f5, (double) (f2 * f4));
return new Vector(f3 * f4, -f5, (double) (f2 * f4));
}
}
public static boolean isVecInside(SimpleCollisionBox self, Vector3D vec) {
public static boolean isVecInside(SimpleCollisionBox self, Vector vec) {
return vec.getX() > self.minX && vec.getX() < self.maxX && (vec.getY() > self.minY && vec.getY() < self.maxY && vec.getZ() > self.minZ && vec.getZ() < self.maxZ);
}
@@ -189,8 +184,8 @@ public class ReachUtils {
if (giveMovementThresholdLenience) targetBox.expand(player.getMovementThreshold());
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (double eyes : possibleEyeHeights) {
Vector3D from = newVector3D(player.x, player.y + eyes, player.z);
Vector3D closestPoint = VectorUtils.cutBoxToVector(from, targetBox);
Vector from = new Vector(player.x, player.y + eyes, player.z);
Vector closestPoint = VectorUtils.cutBoxToVector(from, targetBox);
lowest = Math.min(lowest, closestPoint.distance(from));
}
@@ -1,37 +1,32 @@
package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.PacketEvents.getAPI;
import static com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes.RIPTIDE;
import static com.github.retrooper.packetevents.protocol.item.type.ItemTypes.TRIDENT;
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import org.bukkit.util.Vector;
public class Riptide {
public static Vector3D getRiptideVelocity(GrimPlayer player) {
public static Vector getRiptideVelocity(GrimPlayer player) {
ItemStack main = player.getInventory().getHeldItem();
ItemStack off = player.getInventory().getOffHand();
int j;
if (main.getType() == TRIDENT) {
j = main.getEnchantmentLevel(RIPTIDE, getAPI().getServerManager().getVersion().toClientVersion());
} else if (off.getType() == TRIDENT) {
j = off.getEnchantmentLevel(RIPTIDE, getAPI().getServerManager().getVersion().toClientVersion());
if (main.getType() == ItemTypes.TRIDENT) {
j = main.getEnchantmentLevel(EnchantmentTypes.RIPTIDE, PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
} else if (off.getType() == ItemTypes.TRIDENT) {
j = off.getEnchantmentLevel(EnchantmentTypes.RIPTIDE, PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
} else {
return newVector3D(); // Can't riptide
return new Vector(); // Can't riptide
}
float f7 = player.xRot;
float f = player.yRot;
float f1 = -player.trigHandler.sin(f7 * ((float) PI / 180F)) * player.trigHandler.cos(f * ((float) PI / 180F));
float f2 = -player.trigHandler.sin(f * ((float) PI / 180F));
float f3 = player.trigHandler.cos(f7 * ((float) PI / 180F)) * player.trigHandler.cos(f * ((float) PI / 180F));
float f4 = (float) sqrt(f1 * f1 + f2 * f2 + f3 * f3);
float f1 = -player.trigHandler.sin(f7 * ((float) Math.PI / 180F)) * player.trigHandler.cos(f * ((float) Math.PI / 180F));
float f2 = -player.trigHandler.sin(f * ((float) Math.PI / 180F));
float f3 = player.trigHandler.cos(f7 * ((float) Math.PI / 180F)) * player.trigHandler.cos(f * ((float) Math.PI / 180F));
float f4 = (float) Math.sqrt(f1 * f1 + f2 * f2 + f3 * f3);
float f5 = 3.0F * ((1.0F + j) / 4.0F);
f1 = f1 * (f5 / f4);
f2 = f2 * (f5 / f4);
@@ -39,8 +34,8 @@ public class Riptide {
// If the player collided vertically with the 1.199999F pushing movement, then the Y additional movement was added
// (We switched the order around as our prediction engine isn't designed for the proper implementation)
if (player.verticalCollision) return newVector3D(f1, 0, f3);
if (player.verticalCollision) return new Vector(f1, 0, f3);
return newVector3D(f1, f2, f3);
return new Vector(f1, f2, f3);
}
}
@@ -1,9 +0,0 @@
package ac.grim.grimac.utils.vector;
public class BasicVectorOps implements VectorOperations {
@Override
public Vector3D newVector(double x, double y, double z) {
return new ScalarVector3D(x, y, z);
}
}
@@ -1,157 +0,0 @@
package ac.grim.grimac.utils.vector;
import one.nalim.Library;
import one.nalim.Link;
import one.nalim.Linker;
import org.jetbrains.annotations.NotNull;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import java.lang.reflect.Array;
import java.util.Arrays;
@Library("vector_ops")
public class NalimVector3D implements Vector3D {
static {
Linker.linkClass(NalimVector3D.class);
}
double[] loc;
// public final long nativePtr; // Holds pointer to SimdVector
// @Link(name = "create_vector")
// private static native long create_vector(double x, double y, double z);
public NalimVector3D(double x, double y, double z) {
loc = new double[]{x, y, z};
// nativePtr = create_vector(0, 0, 0);
}
@Override
public double getX() {
return loc[0];
}
@Override
public double getY() {
return loc[1];
}
@Override
public double getZ() {
return loc[2];
}
@Override
public Vector3D setX(double x) {
loc[0] = x;
return this;
}
@NotNull
public Vector3D setY(double y) {
loc[1] =y;
return this;
}
@Override
public Vector3D setZ(double z) {
loc[2] = z;
return this;
}
@Override
public double length() {
return Math.sqrt(loc[0] * loc[0] + loc[1] * loc[1] + loc[2] * loc[2]);
}
@Override
public double lengthSquared() {
return loc[0] * loc[0] + loc[1] * loc[1] + loc[2] * loc[2];
}
@Override
public @NotNull Vector3D multiply(double m) {
loc[0] *= m;
loc[1] *= m;
loc[2] *= m;
return this;
}
@Override
public @NotNull Vector3D normalize() {
double length = this.length();
loc[0] /= length;
loc[1] /= length;
loc[2] /= length;
return this;
}
// @Link(name = "delete_vector2")
// private static native void delete_vector(long[] x);
@IntrinsicCandidate @ForceInline @Link(name = "cross_product2")
private static native void crossProduct(double[] a, double[] b);
@IntrinsicCandidate @ForceInline @Link(name = "cross_product")
private static native void cross_product(long a, long b);
@Override
public @NotNull Vector3D crossProduct(@NotNull Vector3D o) {
// cross_product(nativePtr, ((NalimVector3D) o).nativePtr);
crossProduct(this.loc, ((NalimVector3D) o).loc);
return this;
}
@NotNull
public Vector3D add(@NotNull Vector3D vec) {
loc[0] += vec.getX();
loc[1] += vec.getY();
loc[2] += vec.getZ();
return this;
}
@NotNull
public Vector3D subtract(@NotNull Vector3D vec) {
loc[0] -= vec.getX();
loc[1] -= vec.getY();
loc[2] -= vec.getZ();
return this;
}
@NotNull
public Vector3D multiply(@NotNull Vector3D vec) {
loc[0] *= vec.getX();
loc[1] *= vec.getY();
loc[2] *= vec.getZ();
return this;
}
@Override
public double distance(@NotNull Vector3D o) {
return Math.sqrt(distanceSquared(o));
}
@Override
public double distanceSquared(@NotNull Vector3D o) {
return (loc[0] - o.getX()) * (loc[0] - o.getX())
+ (loc[1] - o.getY()) * (loc[1] - o.getY())
+ (loc[2] - o.getZ()) * (loc[2] - o.getZ());
}
@Override
public double dot(@NotNull Vector3D other) {
return loc[0] * other.getX() + loc[1] * other.getY() + loc[2] * other.getZ();
}
@NotNull
public Vector3D clone() {
try {
return (Vector3D) super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
}
Loaded 100 of 113 files, more files were not shown because too many files have changed in this diff. Show more