Compare commits
122
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
513e42c58e | ||
|
|
e1281c24fa | ||
|
|
82bb743120 | ||
|
|
85ed18e108 | ||
|
|
61a9bae878 | ||
|
|
d0ff246b03 | ||
|
|
f84321b7e7 | ||
|
|
72b1ec2665 | ||
|
|
2337386b37 | ||
|
|
d1288bf4af | ||
|
|
0072bfdee5 | ||
|
|
6b2153f03e | ||
|
|
ab86e65a65 | ||
|
|
1f2b6977b9 | ||
|
|
d5847f73d3 | ||
|
|
4e5e20280f | ||
|
|
baba4d6f6e | ||
|
|
97abaaf8ad | ||
|
|
1f3ac2a174 | ||
|
|
ff0629d0b7 | ||
|
|
9936984534 | ||
|
|
ca56975136 | ||
|
|
348daf6a52 | ||
|
|
d67b470ff6 | ||
|
|
130f9e1023 | ||
|
|
eaac8ad908 | ||
|
|
89f8696d88 | ||
|
|
940a1f819f | ||
|
|
3f01edba9d | ||
|
|
24409a5771 | ||
|
|
88e0f98241 | ||
|
|
fde99a7cbf | ||
|
|
1c3929834a | ||
|
|
3a839d7240 | ||
|
|
7737337a86 | ||
|
|
88dc6a42a9 | ||
|
|
bcc93aab4a | ||
|
|
b88561284c | ||
|
|
5fd8230884 | ||
|
|
ca0fa88a77 | ||
|
|
cbb3c1cc0f | ||
|
|
519968b85a | ||
|
|
6314b78e47 | ||
|
|
b791897dbc | ||
|
|
61af1d1e72 | ||
|
|
bf3fc94d92 | ||
|
|
1bb0bf7e76 | ||
|
|
c6cabe7ed6 | ||
|
|
4f2fe70300 | ||
|
|
52a611bf94 | ||
|
|
354564485a | ||
|
|
4887415912 | ||
|
|
7f0838832d | ||
|
|
336efafbd3 | ||
|
|
782f8f8a09 | ||
|
|
c1858e49d8 | ||
|
|
7dce3a7a12 | ||
|
|
7786da7296 | ||
|
|
bc365176b1 | ||
|
|
7fe224c206 | ||
|
|
48e5f54341 | ||
|
|
5edf92f124 | ||
|
|
1c3e938f0f | ||
|
|
ec71581eae | ||
|
|
0904b61df0 | ||
|
|
c9e082257c | ||
|
|
8875bbf991 | ||
|
|
e933186d2e | ||
|
|
89bec80b34 | ||
|
|
cc78eca02f | ||
|
|
77a91ec627 | ||
|
|
1036563b24 | ||
|
|
dd5ea74ae4 | ||
|
|
aa7a4dc155 | ||
|
|
3387365732 | ||
|
|
411aa4f2b2 | ||
|
|
63a8e394a9 | ||
|
|
9804b8b62f | ||
|
|
f82cce32f6 | ||
|
|
474ae7dd27 | ||
|
|
d85c1d267b | ||
|
|
6ce2bcb9e9 | ||
|
|
48eff610c3 | ||
|
|
677dd044ff | ||
|
|
87f30eea37 | ||
|
|
370da407ce | ||
|
|
1ef4b4eec9 | ||
|
|
954eb8b51c | ||
|
|
84ceaa29dc | ||
|
|
6974d61b9d | ||
|
|
d9a3a890c8 | ||
|
|
c4495d995a | ||
|
|
9bd5c2db0b | ||
|
|
2518b23f8b | ||
|
|
bd2ceeeed4 | ||
|
|
a6d082b355 | ||
|
|
8af0dbc46d | ||
|
|
3fedd558d6 | ||
|
|
547a2965dd | ||
|
|
c19914e83f | ||
|
|
6c14faa51d | ||
|
|
6b4060e0c4 | ||
|
|
483706151b | ||
|
|
9dc128cc1d | ||
|
|
50b7e84f58 | ||
|
|
a77067ffe5 | ||
|
|
2a49635497 | ||
|
|
a158019d66 | ||
|
|
5f7d296b4d | ||
|
|
c4cd8136bf | ||
|
|
dbc0c11795 | ||
|
|
d30b024bd3 | ||
|
|
a3e979abc8 | ||
|
|
93f14a5b40 | ||
|
|
2de0f49af9 | ||
|
|
39a53db067 | ||
|
|
9bfc7d7d9b | ||
|
|
7c93eda985 | ||
|
|
1e7a858aa0 | ||
|
|
11fba1b6bd | ||
|
|
ce9d66c199 | ||
|
|
330a9782bc |
No files matched your search
+139
-6
@@ -26,9 +26,13 @@ spotless {
|
||||
}
|
||||
|
||||
group = "ac.grim.grimac"
|
||||
version = "2.3.69"
|
||||
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))
|
||||
}
|
||||
|
||||
// Set to false for debug builds
|
||||
// You cannot live reload classes if the jar relocates dependencies
|
||||
// Checks Project properties -> environment variable -> defaults true
|
||||
@@ -55,6 +59,13 @@ 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")
|
||||
@@ -67,11 +78,17 @@ dependencies {
|
||||
implementation("com.github.grimanticheat:grimapi:fc5634e444")
|
||||
|
||||
implementation("org.jetbrains:annotations:24.1.0")
|
||||
compileOnly("org.geysermc.floodgate:api:2.2.3-SNAPSHOT")
|
||||
compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT")
|
||||
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
|
||||
compileOnly("com.viaversion:viaversion-api:5.1.1-SNAPSHOT")
|
||||
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 {
|
||||
@@ -139,6 +156,16 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,22 +190,50 @@ java {
|
||||
}
|
||||
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_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(21))
|
||||
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> {
|
||||
@@ -215,3 +270,81 @@ 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")
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import jdk.incubator.vector.*;
|
||||
|
||||
public final class SIMDVector3D implements Vector3D {
|
||||
|
||||
private static final VectorSpecies<Double> SPECIES = DoubleVector.SPECIES_PREFERRED;
|
||||
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);
|
||||
@@ -13,7 +13,7 @@ public final class SIMDVector3D implements Vector3D {
|
||||
private DoubleVector vector;
|
||||
|
||||
public SIMDVector3D(double x, double y, double z) {
|
||||
this.vector = DoubleVector.fromArray(SPECIES, new double[]{x, y, z, 0}, 0);
|
||||
this.vector = DoubleVector.fromArray(SPECIES, new double[]{x, y, z, 0}, 0, LENGTH_3_ARRAY_MASK);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,8 +72,7 @@ public final class SIMDVector3D implements Vector3D {
|
||||
// double length = Math.sqrt(sum);
|
||||
// this.vector = this.vector.div(length);
|
||||
// return this;
|
||||
double length = length();
|
||||
this.vector = this.vector.div(length).blend(FOURTH_COMPONENT_ZERO, LENGTH_3_ARRAY_MASK.not());
|
||||
this.vector = this.vector.div(length());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package ac.grim.grimac.utils.vector;
|
||||
|
||||
import jdk.incubator.vector.VectorMask;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
import jdk.incubator.vector.DoubleVector;
|
||||
|
||||
public class VectorOperationsJava18 implements VectorOperations {
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
//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();
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,114 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
//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();
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,114 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
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,6 +8,8 @@ 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;
|
||||
@@ -150,6 +152,39 @@ 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());
|
||||
|
||||
@@ -59,15 +59,15 @@ public class AimProcessor extends Check implements RotationCheck {
|
||||
|
||||
if (this.xRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
Pair<Double, Integer> modeX = this.xRotMode.getMode();
|
||||
if (modeX.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
this.modeX = modeX.getFirst();
|
||||
if (modeX.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
this.modeX = modeX.first();
|
||||
this.sensitivityX = convertToSensitivity(this.modeX);
|
||||
}
|
||||
}
|
||||
if (this.yRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
Pair<Double, Integer> modeY = this.yRotMode.getMode();
|
||||
if (modeY.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
this.modeY = modeY.getFirst();
|
||||
if (modeY.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
this.modeY = modeY.first();
|
||||
this.sensitivityY = convertToSensitivity(this.modeY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ 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")
|
||||
@@ -23,10 +24,12 @@ 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) {
|
||||
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE
|
||||
|| (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) && player.compensatedEntities.getSelf().inVehicle())) {
|
||||
noReminderTicks = 0; // Exempt vehicles
|
||||
}
|
||||
|
||||
|
||||
if (noReminderTicks > 20) {
|
||||
flagAndAlert("ticks=" + noReminderTicks); // ban? I don't know how this would false
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEn
|
||||
|
||||
@CheckData(name = "BadPacketsG")
|
||||
public class BadPacketsG extends Check implements PacketCheck {
|
||||
boolean wasTeleport;
|
||||
boolean lastSneaking;
|
||||
private boolean lastSneaking, respawn;
|
||||
|
||||
public BadPacketsG(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -19,13 +18,12 @@ 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) {
|
||||
if (lastSneaking && !wasTeleport) {
|
||||
// The player may send two START_SNEAKING packets if they respawned
|
||||
if (lastSneaking && !respawn) {
|
||||
if (flagAndAlert("state=true") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
@@ -33,8 +31,9 @@ public class BadPacketsG extends Check implements PacketCheck {
|
||||
} else {
|
||||
lastSneaking = true;
|
||||
}
|
||||
respawn = false;
|
||||
} else if (packet.getAction() == WrapperPlayClientEntityAction.Action.STOP_SNEAKING) {
|
||||
if (!lastSneaking && !wasTeleport) {
|
||||
if (!lastSneaking && !respawn) {
|
||||
if (flagAndAlert("state=false") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
@@ -42,7 +41,13 @@ 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;
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
@@ -11,15 +11,15 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
|
||||
@CheckData(name = "PacketOrderB")
|
||||
public class PacketOrderB extends Check implements PacketCheck {
|
||||
@CheckData(name = "BadPacketsH")
|
||||
public class BadPacketsH extends Check implements PacketCheck {
|
||||
|
||||
// 1.9 packet order: INTERACT -> ANIMATION
|
||||
// 1.8 packet order: ANIMATION -> INTERACT
|
||||
// I personally think 1.8 made much more sense. You swing and THEN you hit!
|
||||
private boolean sentAnimation = player.getClientVersion().isNewerThan(ClientVersion.V_1_8);
|
||||
|
||||
public PacketOrderB(final GrimPlayer player) {
|
||||
public BadPacketsH(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class PacketOrderB 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()) {
|
||||
if (!sentAnimation && flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
+10
-40
@@ -1,4 +1,4 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
@@ -9,33 +9,25 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "PacketOrderC", experimental = true)
|
||||
public class PacketOrderC extends Check implements PacketCheck {
|
||||
public PacketOrderC(final GrimPlayer player) {
|
||||
@CheckData(name = "BadPacketsM", experimental = true)
|
||||
public class BadPacketsM extends Check implements PacketCheck {
|
||||
public BadPacketsM(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
// 1.7 players do not send INTERACT_AT, so we cannot check them
|
||||
private final boolean exempt = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10);
|
||||
private boolean sentInteractAt = false;
|
||||
private int requiredEntity;
|
||||
private InteractionHand requiredHand;
|
||||
private boolean requiredSneaking;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (exempt) {
|
||||
return;
|
||||
}
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY && !exempt) {
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
final WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
|
||||
final WrapperPlayClientInteractEntity wrapper = new WrapperPlayClientInteractEntity(event);
|
||||
|
||||
final PacketEntity entity = player.compensatedEntities.entityMap.get(packet.getEntityId());
|
||||
final PacketEntity entity = player.compensatedEntities.entityMap.get(wrapper.getEntityId());
|
||||
|
||||
// For armor stands, vanilla clients send:
|
||||
// - when renaming the armor stand or in spectator mode: INTERACT_AT + INTERACT
|
||||
@@ -43,49 +35,27 @@ public class PacketOrderC extends Check implements PacketCheck {
|
||||
// Just exempt armor stands to be safe
|
||||
if (entity != null && entity.getType() == EntityTypes.ARMOR_STAND) return;
|
||||
|
||||
final boolean sneaking = packet.isSneaking().orElse(false);
|
||||
|
||||
switch (packet.getAction()) {
|
||||
switch (wrapper.getAction()) {
|
||||
// INTERACT_AT then INTERACT
|
||||
case INTERACT:
|
||||
if (!sentInteractAt) {
|
||||
if (flagAndAlert("Skipped Interact-At") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else if (packet.getEntityId() != requiredEntity || packet.getHand() != requiredHand || sneaking != requiredSneaking) {
|
||||
String verbose = "requiredEntity=" + requiredEntity + ", entity=" + packet.getEntityId()
|
||||
+ ", requiredHand=" + requiredHand + ", hand=" + packet.getHand()
|
||||
+ ", requiredSneaking=" + requiredSneaking + ", sneaking=" + sneaking;
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
if (flagAndAlert("Missed Interact-At") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
sentInteractAt = false;
|
||||
break;
|
||||
case INTERACT_AT:
|
||||
if (sentInteractAt) {
|
||||
if (flagAndAlert("Skipped Interact") && shouldModifyPackets()) {
|
||||
if (flagAndAlert("Missed Interact") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
requiredHand = packet.getHand();
|
||||
requiredEntity = packet.getEntityId();
|
||||
requiredSneaking = sneaking;
|
||||
sentInteractAt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
|
||||
if (sentInteractAt) {
|
||||
sentInteractAt = false;
|
||||
flagAndAlert("Skipped Interact (Tick)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ public class BadPacketsO extends Check implements PacketCheck {
|
||||
boolean hasID = false;
|
||||
|
||||
for (Pair<Long, Long> iterator : keepaliveMap) {
|
||||
if (iterator.getFirst() == id) {
|
||||
if (iterator.first() == id) {
|
||||
hasID = true;
|
||||
break;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class BadPacketsO extends Check implements PacketCheck {
|
||||
do {
|
||||
data = keepaliveMap.poll();
|
||||
if (data == null) break;
|
||||
} while (data.getFirst() != id);
|
||||
} while (data.first() != id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ 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 && player.compensatedEntities.getSelf().inVehicle()) {
|
||||
} else if ((event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE || event.getPacketType() == PacketType.Play.Client.VEHICLE_MOVE)
|
||||
&& player.inVehicle()) {
|
||||
positions++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,53 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
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 ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
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.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
|
||||
@CheckData(name = "BadPacketsX", experimental = true)
|
||||
@CheckData(name = "BadPacketsX")
|
||||
public class BadPacketsX extends Check implements PacketCheck {
|
||||
public BadPacketsX(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int lastTick;
|
||||
private boolean didLastFlag;
|
||||
private Vector3i lastBreakLoc;
|
||||
private StateType lastBlockType;
|
||||
|
||||
public final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_15_2);
|
||||
|
||||
public final void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig, StateType block) {
|
||||
if (dig.getAction() != DiggingAction.START_DIGGING && dig.getAction() != DiggingAction.FINISHED_DIGGING)
|
||||
public final void handle(BlockBreak blockBreak) {
|
||||
if (blockBreak.action != DiggingAction.START_DIGGING && blockBreak.action != 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)
|
||||
&& !didLastFlag
|
||||
&& lastBlockType.getHardness() == 0.0F
|
||||
&& lastBlockType.getBlastResistance() == 0.0F
|
||||
&& block == StateTypes.WATER
|
||||
) return;
|
||||
lastTick = newTick;
|
||||
lastBreakLoc = blockBreak.position;
|
||||
lastBlockType = block;
|
||||
|
||||
// the block does not have a hitbox
|
||||
boolean invalid = (block == StateTypes.LIGHT && !(player.getInventory().getHeldItem().is(ItemTypes.LIGHT) || player.getInventory().getOffHand().is(ItemTypes.LIGHT)))
|
||||
|| block.isAir()
|
||||
@@ -31,13 +55,15 @@ 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 && dig.getAction() == DiggingAction.FINISHED_DIGGING;
|
||||
|| block.getHardness() == -1.0f && blockBreak.action == DiggingAction.FINISHED_DIGGING;
|
||||
|
||||
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + dig.getAction()) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + blockBreak.action) && shouldModifyPackets()) {
|
||||
didLastFlag = true;
|
||||
blockBreak.cancel();
|
||||
} else {
|
||||
didLastFlag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,18 +5,17 @@ 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;
|
||||
|
||||
@CheckData(name = "BadPacketsZ", experimental = true)
|
||||
@CheckData(name = "BadPacketsZ")
|
||||
public class BadPacketsZ extends Check implements PacketCheck {
|
||||
public BadPacketsZ(final GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -40,9 +39,9 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
|
||||
}
|
||||
|
||||
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig) {
|
||||
if (dig.getAction() == DiggingAction.START_DIGGING) {
|
||||
final Vector3i pos = dig.getBlockPosition();
|
||||
public void handle(BlockBreak blockBreak) {
|
||||
if (blockBreak.action == DiggingAction.START_DIGGING) {
|
||||
final Vector3i pos = blockBreak.position;
|
||||
|
||||
lastBlockWasInstantBreak = getBlockDamage(player, pos) >= 1;
|
||||
lastCancelledBlock = null;
|
||||
@@ -50,8 +49,8 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
lastBlock = pos;
|
||||
}
|
||||
|
||||
if (dig.getAction() == DiggingAction.CANCELLED_DIGGING) {
|
||||
final Vector3i pos = dig.getBlockPosition();
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
|
||||
final Vector3i pos = blockBreak.position;
|
||||
|
||||
if (shouldExempt(pos)) {
|
||||
lastCancelledBlock = pos;
|
||||
@@ -65,8 +64,7 @@ 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()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
blockBreak.cancel();
|
||||
resyncPosition(player, pos);
|
||||
}
|
||||
}
|
||||
@@ -79,15 +77,14 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
|
||||
final Vector3i pos = dig.getBlockPosition();
|
||||
if (blockBreak.action == DiggingAction.FINISHED_DIGGING) {
|
||||
final Vector3i pos = blockBreak.position;
|
||||
|
||||
// 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()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
blockBreak.cancel();
|
||||
resyncPosition(player, pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public class MultiInteractA extends Check implements PostPredictionCheck {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
if (player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class MultiInteractB extends Check implements PostPredictionCheck {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
if (player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
|
||||
@@ -21,10 +21,7 @@ import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.HitData;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
|
||||
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
|
||||
import ac.grim.grimac.utils.nmsutil.ReachUtils;
|
||||
import ac.grim.grimac.utils.vector.Vector3D;
|
||||
@@ -35,22 +32,13 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
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.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
|
||||
|
||||
@@ -60,15 +48,11 @@ public class Reach extends Check implements PacketCheck {
|
||||
// Only one flag per reach attack, per entity, per tick.
|
||||
// We store position because lastX isn't reliable on teleports.
|
||||
private final Int2ObjectMap<Vector3d> playerAttackQueue = new Int2ObjectOpenHashMap<>();
|
||||
// Used to prevent falses in the wall hit check
|
||||
private final Set<Vector3i> blocksChangedThisTick = new HashSet<>();
|
||||
|
||||
private static final List<EntityType> blacklisted = Arrays.asList(
|
||||
EntityTypes.BOAT,
|
||||
EntityTypes.CHEST_BOAT,
|
||||
EntityTypes.SHULKER);
|
||||
|
||||
private boolean ignoreNonPlayerTargets;
|
||||
private boolean cancelImpossibleHits;
|
||||
private double threshold;
|
||||
private double cancelBuffer; // For the next 4 hits after using reach, we aggressively cancel reach
|
||||
@@ -102,10 +86,6 @@ public class Reach extends Check implements PacketCheck {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ignoreNonPlayerTargets && !entity.getType().equals(EntityTypes.PLAYER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dead entities cause false flags (https://github.com/GrimAnticheat/Grim/issues/546)
|
||||
if (entity.isDead) return;
|
||||
|
||||
@@ -130,11 +110,8 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
// If the player set their look, or we know they have a new tick
|
||||
final boolean isFlying = WrapperPlayClientPlayerFlying.isFlying(event.getPacketType());
|
||||
if (isFlying ||
|
||||
event.getPacketType() == PacketType.Play.Client.PONG ||
|
||||
event.getPacketType() == PacketType.Play.Client.WINDOW_CONFIRMATION) {
|
||||
tickBetterReachCheckWithAngle(isFlying);
|
||||
if (isUpdate(event.getPacketType())) {
|
||||
tickBetterReachCheckWithAngle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +143,7 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
private void tickBetterReachCheckWithAngle(boolean isFlying) {
|
||||
private void tickBetterReachCheckWithAngle() {
|
||||
for (Int2ObjectMap.Entry<Vector3d> attack : playerAttackQueue.int2ObjectEntrySet()) {
|
||||
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getIntKey());
|
||||
if (reachEntity != null) {
|
||||
@@ -181,9 +158,6 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
playerAttackQueue.clear();
|
||||
// We can't use transactions for this because of this problem:
|
||||
// transaction -> block changed applied -> 2nd transaction -> list cleared -> attack packet -> flying -> reach block hit checked, falses
|
||||
if (isFlying) blocksChangedThisTick.clear();
|
||||
}
|
||||
|
||||
private String checkReach(PacketEntity reachEntity, Vector3d from, boolean isPrediction) {
|
||||
@@ -236,7 +210,7 @@ public class Reach extends Check implements PacketCheck {
|
||||
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));
|
||||
|
||||
Vector3D intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).getFirst();
|
||||
Vector3D intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
|
||||
|
||||
if (ReachUtils.isVecInside(targetBox, eyePos)) {
|
||||
minDistance = 0;
|
||||
@@ -249,25 +223,9 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
HitData foundHitData = null;
|
||||
// If the entity is within range of the player (we'll flag anyway if not, so no point checking blocks in this case)
|
||||
// Ignore when could be hitting through a moving shulker, piston blocks. They are just too glitchy/uncertain to check.
|
||||
if (minDistance <= 3 && !player.compensatedWorld.isNearHardEntity(player.boundingBox.copy().expand(4))) {
|
||||
final @Nullable Pair<Double, HitData> targetBlock = getTargetBlock(player, possibleLookDirs, from, minDistance);
|
||||
// And if the target block is closer to the player than the entity box, they should hit the block instead
|
||||
// So, this hit is invalid.
|
||||
if (targetBlock != null && targetBlock.getFirst() < (minDistance * minDistance)) { // targetBlock is squared
|
||||
minDistance = Double.MIN_VALUE;
|
||||
foundHitData = targetBlock.getSecond();
|
||||
}
|
||||
}
|
||||
|
||||
// if the entity is not exempt and the entity is alive
|
||||
if ((!blacklisted.contains(reachEntity.getType()) && reachEntity.isLivingEntity()) || reachEntity.getType() == EntityTypes.END_CRYSTAL) {
|
||||
if (minDistance == Double.MIN_VALUE && foundHitData != null) {
|
||||
cancelBuffer = 1;
|
||||
return "Hit block block=" + foundHitData.getState().getType().getName();
|
||||
} else if (minDistance == Double.MAX_VALUE) {
|
||||
if (minDistance == Double.MAX_VALUE) {
|
||||
cancelBuffer = 1;
|
||||
return "Missed hitbox";
|
||||
} else if (minDistance > player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE)) {
|
||||
@@ -281,48 +239,8 @@ public class Reach extends Check implements PacketCheck {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void handleBlockChange(Vector3i vector3i, WrappedBlockState state) {
|
||||
if (blocksChangedThisTick.size() >= 40) return; // Don't let players freeze movement packets to grow this
|
||||
// Only do this for nearby blocks
|
||||
if (newVector3D(vector3i.x, vector3i.y, vector3i.z).distanceSquared(newVector3D(player.x, player.y, player.z)) > 6) return;
|
||||
// Only do this if the state really had any world impact
|
||||
if (state.equals(player.compensatedWorld.getWrappedBlockStateAt(vector3i))) return;
|
||||
blocksChangedThisTick.add(vector3i);
|
||||
}
|
||||
|
||||
// Returns a pair so we can check the block type in the flag
|
||||
@Nullable
|
||||
private Pair<Double, HitData> getTargetBlock(GrimPlayer player, List<Vector3D> possibleLookDirs, Vector3d from, double minDistance) {
|
||||
// Check every possible look direction and every possible eye height
|
||||
// IF *NONE* of them allow the player to hit the entity, this is an invalid hit
|
||||
HitData bestHitData = null;
|
||||
double min = Double.MAX_VALUE;
|
||||
for (Vector3D lookVec : possibleLookDirs) {
|
||||
for (double eye : player.getPossibleEyeHeights()) {
|
||||
Vector3D eyes = newVector3D(from.getX(), from.getY() + eye, from.getZ());
|
||||
final double reach = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
|
||||
final HitData hitResult = BlockRayTrace.getNearestReachHitResult(player, eyes, lookVec, minDistance, reach);
|
||||
if (hitResult == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final double distance = eyes.distanceSquared(hitResult.getBlockHitLocation());
|
||||
// Block changes are uncertain, can't check this tick
|
||||
if (distance < (minDistance * minDistance) && blocksChangedThisTick.contains(hitResult.getPosition())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
bestHitData = hitResult;
|
||||
min = Math.min(min, distance);
|
||||
}
|
||||
}
|
||||
|
||||
return bestHitData == null ? null : Pair.of(min, bestHitData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
this.ignoreNonPlayerTargets = config.getBooleanElse("Reach.ignore-non-player-targets", false);
|
||||
this.cancelImpossibleHits = config.getBooleanElse("Reach.block-impossible-hits", true);
|
||||
this.threshold = config.getDoubleElse("Reach.threshold", 0.0005);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
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,41 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
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.WrapperPlayClientInteractEntity.InteractAction;
|
||||
|
||||
@CheckData(name = "InventoryA", setback = 3, description = "Attacked an entity while inventory is open")
|
||||
public class InventoryA extends InventoryCheck {
|
||||
public InventoryA(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
super.onPacketReceive(event);
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
WrapperPlayClientInteractEntity wrapper = new WrapperPlayClientInteractEntity(event);
|
||||
|
||||
if (wrapper.getAction() != InteractAction.ATTACK) return;
|
||||
|
||||
// Is not possible to attack while the inventory is open.
|
||||
if (player.hasInventoryOpen) {
|
||||
if (flagAndAlert()) {
|
||||
// Cancel the packet
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
closeInventory();
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
@CheckData(name = "InventoryB", setback = 3, description = "Started digging blocks while inventory is open")
|
||||
public class InventoryB extends InventoryCheck {
|
||||
public InventoryB(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging wrapper) {
|
||||
if (wrapper.getAction() != DiggingAction.START_DIGGING) return;
|
||||
|
||||
// Is not possible to start digging a block while the inventory is open.
|
||||
if (player.hasInventoryOpen) {
|
||||
if (flagAndAlert()) {
|
||||
// Cancel the packet
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
closeInventory();
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
|
||||
|
||||
@CheckData(name = "InventoryC", setback = 3, description = "Placed a block while inventory is open")
|
||||
public class InventoryC extends InventoryCheck {
|
||||
|
||||
public InventoryC(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
public void onBlockPlace(final BlockPlace place) {
|
||||
// It is not possible to place a block while the inventory is open
|
||||
if (player.hasInventoryOpen) {
|
||||
if (flagAndAlert()) {
|
||||
if (shouldModifyPackets()) {
|
||||
place.resync();
|
||||
}
|
||||
closeInventory();
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import ac.grim.grimac.utils.data.VectorData;
|
||||
import ac.grim.grimac.utils.data.VectorData.MoveVectorData;
|
||||
import ac.grim.grimac.utils.data.VehicleData;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@CheckData(name = "InventoryD", setback = 1, decay = 0.25)
|
||||
public class InventoryD extends InventoryCheck {
|
||||
private int horseJumpVerbose;
|
||||
|
||||
public InventoryD(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(final PredictionComplete predictionComplete) {
|
||||
if (!predictionComplete.isChecked() ||
|
||||
predictionComplete.getData().isTeleport() ||
|
||||
player.getSetbackTeleportUtil().blockOffsets ||
|
||||
player.packetStateData.lastPacketWasTeleport ||
|
||||
player.packetStateData.isSlowedByUsingItem() ||
|
||||
System.currentTimeMillis() - player.lastBlockPlaceUseItem < 50L) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.hasInventoryOpen) {
|
||||
boolean inVehicle = player.compensatedEntities.getSelf().inVehicle();
|
||||
boolean isJumping, isMoving;
|
||||
|
||||
if (inVehicle) {
|
||||
VehicleData vehicle = player.vehicleData;
|
||||
|
||||
// Will flag once if player open anything with pressed space bar
|
||||
isJumping = vehicle.nextHorseJump > 0 && horseJumpVerbose++ >= 1;
|
||||
isMoving = vehicle.nextVehicleForward != 0 || vehicle.nextVehicleHorizontal != 0;
|
||||
} else {
|
||||
MoveVectorData move = findMovement(player.predictedVelocity);
|
||||
|
||||
isJumping = player.predictedVelocity.isJump();
|
||||
isMoving = move != null && (move.x != 0 || move.z != 0);
|
||||
}
|
||||
|
||||
if (!isMoving && !isJumping) {
|
||||
reward();
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag()) {
|
||||
closeInventory();
|
||||
|
||||
StringJoiner joiner = new StringJoiner(" ");
|
||||
|
||||
if (isMoving) joiner.add("moving");
|
||||
if (isJumping) joiner.add("jumping");
|
||||
if (inVehicle) joiner.add("inVehicle");
|
||||
|
||||
alert(joiner.toString());
|
||||
}
|
||||
} else {
|
||||
horseJumpVerbose = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private MoveVectorData findMovement(VectorData vectorData) {
|
||||
if (vectorData instanceof MoveVectorData) {
|
||||
return (MoveVectorData) vectorData;
|
||||
}
|
||||
|
||||
while (vectorData != null) {
|
||||
vectorData = vectorData.lastVector;
|
||||
if (vectorData instanceof MoveVectorData) {
|
||||
return (MoveVectorData) vectorData;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
|
||||
@CheckData(name = "InventoryE", setback = 3, description = "Sent a held item change packet while inventory is open")
|
||||
public class InventoryE extends InventoryCheck {
|
||||
private long lastTransaction = Long.MAX_VALUE; // Impossible transaction ID
|
||||
|
||||
public InventoryE(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
super.onPacketReceive(event);
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
|
||||
// It is not possible to change hotbar slots with held item change while the inventory is open
|
||||
// A container click packet would be sent instead
|
||||
if (player.hasInventoryOpen) {
|
||||
if (this.lastTransaction < player.lastTransactionReceived.get()
|
||||
&& flagAndAlert()) {
|
||||
// Cancel the packet
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.getInventory().needResend = true;
|
||||
}
|
||||
closeInventory();
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.HELD_ITEM_CHANGE) {
|
||||
this.lastTransaction = player.lastTransactionSent.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.inventory.InventoryDesyncStatus;
|
||||
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.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
|
||||
@CheckData(name = "InventoryF", setback = 3, description = "Sent a click window packet without a open inventory", experimental = true)
|
||||
public class InventoryF extends InventoryCheck {
|
||||
|
||||
public InventoryF(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
// Exempt on 1.9+ server version due to the Via hack done in PacketPlayerWindow, the exemption can be deleted
|
||||
// once we are ahead of ViaVersion
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
|
||||
|| player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) return;
|
||||
|
||||
super.onPacketReceive(event);
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
if (!player.hasInventoryOpen && player.inventoryDesyncStatus == InventoryDesyncStatus.NOT_DESYNCED) {
|
||||
if (flagAndAlert()) {
|
||||
// Cancel the packet
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
closeInventory();
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
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.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "InventoryG", setback = 3, description = "Sent a entity action packet while inventory is open", experimental = true)
|
||||
public class InventoryG extends InventoryCheck {
|
||||
|
||||
public InventoryG(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.packetStateData.lastPacketWasTeleport) return;
|
||||
super.onPacketReceive(event);
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
|
||||
WrapperPlayClientEntityAction wrapper = new WrapperPlayClientEntityAction(event);
|
||||
WrapperPlayClientEntityAction.Action action = wrapper.getAction();
|
||||
|
||||
if (action == WrapperPlayClientEntityAction.Action.STOP_SNEAKING
|
||||
|| action == WrapperPlayClientEntityAction.Action.STOP_SPRINTING) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.hasInventoryOpen) {
|
||||
if (flagAndAlert()) {
|
||||
closeInventory();
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package ac.grim.grimac.checks.impl.misc;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@CheckData(name = "TransactionOrder", experimental = false)
|
||||
public class TransactionOrder extends Check implements PacketCheck {
|
||||
|
||||
public TransactionOrder(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
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,7 +8,6 @@ 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 {
|
||||
@@ -18,10 +17,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?
|
||||
// How long should the player be able to fall back behind their ping? (nanos)
|
||||
// Default: 120 milliseconds
|
||||
long clockDrift;
|
||||
|
||||
// At what ping should we start to limit the balance advantage? (nanos)
|
||||
long limitAbuseOverPing;
|
||||
|
||||
boolean hasGottenMovementAfterTransaction = false;
|
||||
@@ -73,35 +72,31 @@ public class TimerCheck extends Check implements PacketCheck {
|
||||
doCheck(event);
|
||||
}
|
||||
|
||||
|
||||
public void doCheck(final PacketReceiveEvent event) {
|
||||
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 (timerBalanceRealTime > System.nanoTime()) {
|
||||
if (flag()) {
|
||||
// Cancel the packet
|
||||
// Only cancel if not an adjustment setback
|
||||
if (wouldFailNormal && shouldModifyPackets()) {
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
|
||||
if (isAboveSetbackVl()) player.getSetbackTeleportUtil().executeNonSimulatingSetback();
|
||||
|
||||
if (wouldFailNormal) {
|
||||
// Only alert if we would fail without adjusted limit
|
||||
alert("");
|
||||
}
|
||||
alert("");
|
||||
}
|
||||
|
||||
// Reset the violation by 1 movement
|
||||
timerBalanceRealTime -= 50e6;
|
||||
}
|
||||
|
||||
timerBalanceRealTime = Math.max(timerBalanceRealTime, lastMovementPlayerClock - clockDrift);
|
||||
// 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);
|
||||
}
|
||||
|
||||
public boolean checkForTransaction(PacketTypeCommon packetType) {
|
||||
@@ -111,13 +106,12 @@ 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 WrapperPlayClientPlayerFlying.isFlying(packetType) &&
|
||||
!player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate;
|
||||
return isTickPacket(packetType);
|
||||
}
|
||||
|
||||
@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));
|
||||
limitAbuseOverPing = (long) (config.getDoubleElse(getConfigName() + ".ping-abuse-limit-threshold", 1000) * 1e6);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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.wrapper.play.client.WrapperPlayClientClickWindow;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow.WindowClickType;
|
||||
|
||||
@CheckData(name = "PacketOrderA", experimental = true)
|
||||
public class PacketOrderA extends Check implements PostPredictionCheck {
|
||||
public PacketOrderA(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
final WindowClickType clickType = new WrapperPlayClientClickWindow(event).getWindowClickType();
|
||||
|
||||
if ((clickType == WindowClickType.PICKUP || clickType == WindowClickType.PICKUP_ALL) && player.packetOrderProcessor.isQuickMoveClicking()
|
||||
|| clickType == WindowClickType.QUICK_MOVE && player.packetOrderProcessor.isPickUpClicking()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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;
|
||||
|
||||
@CheckData(name = "PacketOrderD")
|
||||
public class PacketOrderD extends Check implements PacketCheck {
|
||||
public PacketOrderD(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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;
|
||||
|
||||
@CheckData(name = "PacketOrderE", experimental = true)
|
||||
public class PacketOrderE extends Check implements PostPredictionCheck {
|
||||
public PacketOrderE(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
private boolean setback;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
|
||||
if (player.packetOrderProcessor.isAttacking()
|
||||
|| player.packetOrderProcessor.isRightClicking()
|
||||
|| player.packetOrderProcessor.isOpeningInventory()
|
||||
|| player.packetOrderProcessor.isReleasing()
|
||||
|| player.packetOrderProcessor.isSneaking()
|
||||
|| player.packetOrderProcessor.isSprinting()
|
||||
|| player.packetOrderProcessor.isLeavingBed()
|
||||
|| player.packetOrderProcessor.isStartingToGlide()
|
||||
|| player.packetOrderProcessor.isJumpingWithMount()
|
||||
) {
|
||||
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) || flagAndAlert()) {
|
||||
invalid++;
|
||||
|
||||
if (player.packetOrderProcessor.isUsing()) {
|
||||
setback = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (setback) {
|
||||
setback = false;
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
if (flagAndAlert() && setback) {
|
||||
setback = false;
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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.WrapperPlayClientClientStatus;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
@CheckData(name = "PacketOrderF", experimental = true)
|
||||
public class PacketOrderF extends Check implements PostPredictionCheck {
|
||||
public PacketOrderF(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY
|
||||
|| event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
|
||||
|| event.getPacketType() == PacketType.Play.Client.USE_ITEM
|
||||
|| event.getPacketType() == PacketType.Play.Client.PICK_ITEM
|
||||
|| event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING
|
||||
|| (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS
|
||||
&& new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT)
|
||||
) if (player.packetOrderProcessor.isSprinting() || player.packetOrderProcessor.isSneaking()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING
|
||||
&& new WrapperPlayClientPlayerDigging(event).getAction() == DiggingAction.RELEASE_USE_ITEM
|
||||
) return; // don't cause a noslow
|
||||
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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.WrapperPlayClientClientStatus;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
@CheckData(name = "PacketOrderG", experimental = true)
|
||||
public class PacketOrderG extends Check implements PostPredictionCheck {
|
||||
public PacketOrderG(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING
|
||||
|| (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS
|
||||
&& new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT)
|
||||
) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
final DiggingAction action = new WrapperPlayClientPlayerDigging(event).getAction();
|
||||
if (action == DiggingAction.RELEASE_USE_ITEM
|
||||
|| action == DiggingAction.START_DIGGING
|
||||
|| action == DiggingAction.CANCELLED_DIGGING
|
||||
|| action == DiggingAction.FINISHED_DIGGING
|
||||
) return;
|
||||
}
|
||||
|
||||
if (player.packetOrderProcessor.isAttacking()
|
||||
|| player.packetOrderProcessor.isReleasing()
|
||||
|| player.packetOrderProcessor.isRightClicking()
|
||||
|| player.packetOrderProcessor.isPicking()
|
||||
|| player.packetOrderProcessor.isDigging()
|
||||
) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "PacketOrderH", experimental = true)
|
||||
public class PacketOrderH extends Check implements PostPredictionCheck {
|
||||
public PacketOrderH(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
|
||||
switch (new WrapperPlayClientEntityAction(event).getAction()) {
|
||||
case START_SPRINTING:
|
||||
case STOP_SPRINTING:
|
||||
if (player.packetOrderProcessor.isSneaking()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
flagAndAlert();
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
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 ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockBreakSpeed;
|
||||
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.GameMode;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@CheckData(name = "PacketOrderI", experimental = true)
|
||||
public class PacketOrderI extends Check implements PostPredictionCheck {
|
||||
public PacketOrderI(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean exemptPlacingWhileDigging;
|
||||
|
||||
private boolean setback;
|
||||
private boolean digging; // for placing
|
||||
private final ArrayDeque<String> flags = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
if (new WrapperPlayClientInteractEntity(event).getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
|
||||
if (player.packetOrderProcessor.isRightClicking() || player.packetOrderProcessor.isPicking() || player.packetOrderProcessor.isReleasing() || player.packetOrderProcessor.isDigging()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert("attack") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add("attack");
|
||||
}
|
||||
}
|
||||
} else if (player.packetOrderProcessor.isReleasing() || player.packetOrderProcessor.isDigging()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert("interact") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add("interact");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT || event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
|
||||
if (player.packetOrderProcessor.isReleasing() || digging) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert("place/use") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add("place");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case RELEASE_USE_ITEM:
|
||||
if (player.packetOrderProcessor.isAttacking() || player.packetOrderProcessor.isRightClicking() || player.packetOrderProcessor.isPicking() || player.packetOrderProcessor.isDigging()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert("release")) {
|
||||
setback = true;
|
||||
}
|
||||
} else {
|
||||
flags.add("release");
|
||||
setback = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case START_DIGGING:
|
||||
double damage = BlockBreakSpeed.getBlockDamage(player, packet.getBlockPosition());
|
||||
if (damage >= 1 || damage <= 0 && player.gamemode == GameMode.CREATIVE) {
|
||||
return;
|
||||
}
|
||||
case CANCELLED_DIGGING:
|
||||
case FINISHED_DIGGING:
|
||||
if (exemptPlacingWhileDigging || player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
|
||||
return;
|
||||
}
|
||||
digging = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) {
|
||||
digging = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
} else if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
if (flagAndAlert(verbose) && setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
setback = digging = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
exemptPlacingWhileDigging = config.getBooleanElse(getConfigName() + ".exempt-placing-while-digging", false);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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;
|
||||
|
||||
@CheckData(name = "PacketOrderJ", experimental = true)
|
||||
public class PacketOrderJ extends Check implements PostPredictionCheck {
|
||||
public PacketOrderJ(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT || event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
|
||||
if (player.packetOrderProcessor.isAttacking() && !player.packetOrderProcessor.isInteracting()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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.wrapper.play.client.WrapperPlayClientClientStatus;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@CheckData(name = "PacketOrderK", experimental = true)
|
||||
public class PacketOrderK extends Check implements PostPredictionCheck {
|
||||
public PacketOrderK(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final ArrayDeque<String> flags = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS) {
|
||||
if (new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT) {
|
||||
if (player.packetOrderProcessor.isClickingInInventory() || player.packetOrderProcessor.isClosingInventory()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
flagAndAlert("open");
|
||||
} else {
|
||||
flags.add("open");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW || event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
|
||||
if (player.packetOrderProcessor.isOpeningInventory()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert(event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW ? "click" : "close") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add(event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW ? "click" : "close");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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.WrapperPlayClientClientStatus;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@CheckData(name = "PacketOrderL", experimental = true)
|
||||
public class PacketOrderL extends Check implements PostPredictionCheck {
|
||||
public PacketOrderL(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final ArrayDeque<String> flags = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS) {
|
||||
if (new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT) {
|
||||
if (player.packetOrderProcessor.isDropping()) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert("inventory") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add("inventory");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
if (new WrapperPlayClientPlayerDigging(event).getAction() == DiggingAction.SWAP_ITEM_WITH_OFFHAND) {
|
||||
if (player.packetOrderProcessor.isDropping()) {
|
||||
flags.add("swap");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "PacketOrderM", experimental = true)
|
||||
public class PacketOrderM extends Check implements PostPredictionCheck {
|
||||
public PacketOrderM(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
private boolean usingWithoutInteract, interacting;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
if (new WrapperPlayClientInteractEntity(event).getAction() != WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
|
||||
interacting = true;
|
||||
if (usingWithoutInteract) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.USE_ITEM
|
||||
|| event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
|
||||
&& new WrapperPlayClientPlayerBlockPlacement(event).getFace() == BlockFace.OTHER) {
|
||||
if (!interacting) {
|
||||
usingWithoutInteract = true;
|
||||
}
|
||||
|
||||
interacting = false;
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) {
|
||||
usingWithoutInteract = interacting = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
usingWithoutInteract = interacting = false;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "PacketOrderN", experimental = true)
|
||||
public class PacketOrderN extends BlockPlaceCheck {
|
||||
public PacketOrderN(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
private boolean usingWithoutPlacing, placing;
|
||||
|
||||
@Override
|
||||
public void onBlockPlace(BlockPlace place) {
|
||||
placing = true;
|
||||
if (usingWithoutPlacing) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
|
||||
place.resync();
|
||||
}
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.USE_ITEM
|
||||
|| event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
|
||||
&& new WrapperPlayClientPlayerBlockPlacement(event).getFace() == BlockFace.OTHER) {
|
||||
if (!placing) {
|
||||
usingWithoutPlacing = true;
|
||||
}
|
||||
|
||||
placing = false;
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) {
|
||||
usingWithoutPlacing = placing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
usingWithoutPlacing = placing = false;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 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.InteractionHand;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "PacketOrderO", experimental = true)
|
||||
public class PacketOrderO extends BlockPlaceCheck {
|
||||
public PacketOrderO(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean sentMainhand;
|
||||
|
||||
@Override
|
||||
public void onBlockPlace(BlockPlace place) {
|
||||
if (!isSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (place.getHand() == InteractionHand.OFF_HAND) {
|
||||
if (!sentMainhand) {
|
||||
if (flagAndAlert("Skipped Mainhand") && shouldModifyPackets() && shouldCancel()) {
|
||||
place.resync();
|
||||
}
|
||||
}
|
||||
|
||||
sentMainhand = false;
|
||||
} else {
|
||||
if (sentMainhand) {
|
||||
if (flagAndAlert("Skipped Offhand") && shouldModifyPackets() && shouldCancel()) {
|
||||
place.resync();
|
||||
}
|
||||
}
|
||||
|
||||
sentMainhand = !place.isBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
|
||||
if (sentMainhand) {
|
||||
sentMainhand = false;
|
||||
flagAndAlert("Skipped Offhand (Tick)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSupported() {
|
||||
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity.InteractAction;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "PacketOrderP", experimental = true)
|
||||
public class PacketOrderP extends Check implements PacketCheck {
|
||||
public PacketOrderP(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean sentMainhand;
|
||||
private int requiredEntity;
|
||||
private boolean requiredSneaking;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
final WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
|
||||
InteractAction action = packet.getAction();
|
||||
if (action != InteractAction.ATTACK) {
|
||||
final boolean sneaking = packet.isSneaking().orElse(false);
|
||||
final int entity = packet.getEntityId();
|
||||
|
||||
if (packet.getHand() == InteractionHand.OFF_HAND) {
|
||||
if (action == InteractAction.INTERACT) {
|
||||
if (!sentMainhand) {
|
||||
if (flagAndAlert("Skipped Mainhand") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
sentMainhand = false;
|
||||
} else if (sneaking != requiredSneaking || entity != requiredEntity) {
|
||||
String verbose = "requiredEntity=" + requiredEntity + ", entity=" + entity
|
||||
+ ", requiredSneaking=" + requiredSneaking + ", sneaking=" + sneaking;
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
requiredEntity = entity;
|
||||
requiredSneaking = sneaking;
|
||||
sentMainhand = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
|
||||
sentMainhand = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
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.packettype.PacketTypeCommon;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.*;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
@Getter
|
||||
public final class PacketOrderProcessor extends Check implements PostPredictionCheck {
|
||||
public PacketOrderProcessor(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean openingInventory; // only pre 1.9 clients on pre 1.9 servers
|
||||
private boolean swapping;
|
||||
private boolean dropping;
|
||||
private boolean interacting;
|
||||
private boolean attacking;
|
||||
private boolean releasing;
|
||||
private boolean digging;
|
||||
private boolean sprinting;
|
||||
private boolean sneaking;
|
||||
private boolean placing;
|
||||
private boolean using;
|
||||
private boolean picking;
|
||||
private boolean clickingInInventory;
|
||||
private boolean closingInventory;
|
||||
private boolean quickMoveClicking;
|
||||
private boolean pickUpClicking;
|
||||
private boolean leavingBed;
|
||||
private boolean startingToGlide;
|
||||
private boolean jumpingWithMount;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
final PacketTypeCommon packetType = event.getPacketType();
|
||||
|
||||
if (packetType == PacketType.Play.Client.CLIENT_STATUS) {
|
||||
if (new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT) {
|
||||
openingInventory = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (packetType == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
if (new WrapperPlayClientInteractEntity(event).getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
|
||||
attacking = true;
|
||||
} else {
|
||||
interacting = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (packetType == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
switch (new WrapperPlayClientPlayerDigging(event).getAction()) {
|
||||
case SWAP_ITEM_WITH_OFFHAND:
|
||||
swapping = true;
|
||||
break;
|
||||
case DROP_ITEM:
|
||||
case DROP_ITEM_STACK:
|
||||
dropping = true;
|
||||
break;
|
||||
case RELEASE_USE_ITEM:
|
||||
releasing = true;
|
||||
break;
|
||||
case FINISHED_DIGGING:
|
||||
case CANCELLED_DIGGING:
|
||||
case START_DIGGING:
|
||||
digging = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (packetType == PacketType.Play.Client.ENTITY_ACTION) {
|
||||
switch (new WrapperPlayClientEntityAction(event).getAction()) {
|
||||
case START_SPRINTING:
|
||||
case STOP_SPRINTING:
|
||||
sprinting = true;
|
||||
break;
|
||||
case STOP_SNEAKING:
|
||||
case START_SNEAKING:
|
||||
sneaking = true;
|
||||
break;
|
||||
case LEAVE_BED:
|
||||
leavingBed = true;
|
||||
break;
|
||||
case START_FLYING_WITH_ELYTRA:
|
||||
startingToGlide = true;
|
||||
break;
|
||||
case OPEN_HORSE_INVENTORY:
|
||||
openingInventory = true;
|
||||
break;
|
||||
case START_JUMPING_WITH_HORSE:
|
||||
case STOP_JUMPING_WITH_HORSE:
|
||||
jumpingWithMount = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (packetType == PacketType.Play.Client.USE_ITEM) {
|
||||
using = true;
|
||||
}
|
||||
|
||||
if (packetType == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT) {
|
||||
if (new WrapperPlayClientPlayerBlockPlacement(event).getFace() == BlockFace.OTHER) {
|
||||
using = true;
|
||||
} else {
|
||||
placing = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (packetType == PacketType.Play.Client.PICK_ITEM) {
|
||||
picking = true;
|
||||
}
|
||||
|
||||
if (packetType == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
clickingInInventory = true;
|
||||
|
||||
switch (new WrapperPlayClientClickWindow(event).getWindowClickType()) {
|
||||
case QUICK_MOVE:
|
||||
quickMoveClicking = true;
|
||||
break;
|
||||
case PICKUP:
|
||||
case PICKUP_ALL:
|
||||
pickUpClicking = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (packetType == PacketType.Play.Client.CLOSE_WINDOW) {
|
||||
closingInventory = true;
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) {
|
||||
onTick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
onTick();
|
||||
}
|
||||
}
|
||||
|
||||
private void onTick() {
|
||||
openingInventory = false;
|
||||
swapping = false;
|
||||
dropping = false;
|
||||
attacking = false;
|
||||
interacting = false;
|
||||
releasing = false;
|
||||
digging = false;
|
||||
placing = false;
|
||||
using = false;
|
||||
picking = false;
|
||||
sprinting = false;
|
||||
sneaking = false;
|
||||
clickingInInventory = false;
|
||||
closingInventory = false;
|
||||
quickMoveClicking = false;
|
||||
pickUpClicking = false;
|
||||
leavingBed = false;
|
||||
startingToGlide = false;
|
||||
jumpingWithMount = false;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
public boolean isRightClicking() {
|
||||
return placing || using || interacting;
|
||||
}
|
||||
}
|
||||
+5
-10
@@ -2,6 +2,7 @@ package ac.grim.grimac.checks.impl.post;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
@@ -14,7 +15,6 @@ 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;
|
||||
@@ -24,7 +24,7 @@ import java.util.Locale;
|
||||
import static com.github.retrooper.packetevents.protocol.packettype.PacketType.Play.Client.*;
|
||||
|
||||
@CheckData(name = "Post")
|
||||
public class Post extends Check implements PostPredictionCheck {
|
||||
public class PostCheck extends Check implements PacketCheck, PostPredictionCheck {
|
||||
private final ArrayDeque<PacketTypeCommon> post = new ArrayDeque<>();
|
||||
// Due to 1.9+ missing the idle packet, we must queue flags
|
||||
// 1.8 clients will have the same logic for simplicity, although it's not needed
|
||||
@@ -32,7 +32,7 @@ public class Post extends Check implements PostPredictionCheck {
|
||||
private boolean sentFlying = false;
|
||||
private int isExemptFromSwingingCheck = Integer.MIN_VALUE;
|
||||
|
||||
public Post(GrimPlayer playerData) {
|
||||
public PostCheck(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class Post extends Check implements PostPredictionCheck {
|
||||
// Okay, the user might be cheating, let's double check
|
||||
// 1.8 clients have the idle packet, and this shouldn't false on 1.8 clients
|
||||
// 1.9+ clients have predictions, which will determine if hidden tick skipping occurred
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
if (player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
|
||||
for (String flag : flags) {
|
||||
flagAndAlert(flag);
|
||||
}
|
||||
@@ -67,12 +67,7 @@ public class Post extends Check implements PostPredictionCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(final PacketReceiveEvent event) {
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
|
||||
// Don't count teleports or duplicates as movements
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTickPacket(event.getPacketType())) { // Don't count teleports or duplicates as movements
|
||||
post.clear();
|
||||
sentFlying = true;
|
||||
} else {
|
||||
@@ -1,224 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.scaffolding;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
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.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.HitData;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
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.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 java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@CheckData(name = "LineOfSightPlace")
|
||||
public class LineOfSightPlace extends BlockPlaceCheck {
|
||||
|
||||
private double flagBuffer = 0; // If the player flags once, force them to play legit, or we will cancel the tick before.
|
||||
private boolean ignorePost = false;
|
||||
private boolean useBlockWhitelist;
|
||||
private HashSet<StateType> blockWhitelist;
|
||||
|
||||
// 15 is the maximum set of Collision boxes that will be used in the ray trace check
|
||||
// it corresponds to the size of the collision boxes from the modern Cauldron
|
||||
// Since this is used per-player we can avoid calling new[] by allocating it per-player in the check
|
||||
private final SimpleCollisionBox[] collisionBoxBuffer = new SimpleCollisionBox[15];
|
||||
|
||||
public final ConcurrentHashMap<Vector3i, WrappedBlockState> blocksChangedList = new ConcurrentHashMap<>();
|
||||
|
||||
public LineOfSightPlace(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockPlace(final BlockPlace place) {
|
||||
if (checkIfShouldSkip(place)) return;
|
||||
|
||||
// if (flagBuffer > 0 && !didRayTraceHit(place)) {
|
||||
// ignorePost = true;
|
||||
// // If the player hit and has flagged this check recently
|
||||
// if (flagAndAlert("pre-flying: " + player.compensatedWorld.getWrappedBlockStateAt(place.getPlacedAgainstBlockLocation()).getType()) && shouldModifyPackets() && shouldCancel()) {
|
||||
// place.resync(); // Deny the block placement.
|
||||
// }
|
||||
// }
|
||||
// Only flag (which will only happen in post) if we miss pre
|
||||
if (didRayTraceHit(place)) {
|
||||
ignorePost = true;
|
||||
} else if (flagBuffer > 0) {
|
||||
if (flagAndAlert("pre-flying: " + player.compensatedWorld.getWrappedBlockStateAt(place.getPlacedAgainstBlockLocation()).getType()) && shouldModifyPackets() && shouldCancel()) {
|
||||
place.resync(); // Deny the block placement.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use post flying because it has the correct rotation, and can't false easily.
|
||||
@Override
|
||||
public void onPostFlyingBlockPlace(BlockPlace place) {
|
||||
if (checkIfShouldSkip(place)) return;
|
||||
|
||||
// Don't flag twice
|
||||
if (ignorePost) {
|
||||
ignorePost = false;
|
||||
return;
|
||||
}
|
||||
blocksChangedList.clear();
|
||||
// Ray trace to try and hit the target block.
|
||||
boolean hit = didRayTraceHit(place);
|
||||
// This can false with rapidly moving yaw in 1.8+ clients
|
||||
if (!hit) {
|
||||
flagBuffer = 1;
|
||||
flagAndAlert("post-flying: " + player.compensatedWorld.getWrappedBlockStateAt(place.getPlacedAgainstBlockLocation()).getType());
|
||||
}
|
||||
else {
|
||||
flagBuffer = Math.max(0, flagBuffer - 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkIfShouldSkip(BlockPlace place) {
|
||||
StateType targetBlockStateType = player.compensatedWorld.getWrappedBlockStateAt(place.getPlacedAgainstBlockLocation()).getType();
|
||||
if (player.gamemode == GameMode.SPECTATOR) return true; // A waste to check creative mode players
|
||||
if (targetBlockStateType == StateTypes.REDSTONE_WIRE) return true; // Redstone too buggy
|
||||
if (player.compensatedWorld.isNearHardEntity(player.boundingBox.copy().expand(4))) return true; // Shulkers and Pistons are too buggy
|
||||
|
||||
if (useBlockWhitelist) {
|
||||
return !isBlockTypeWhitelisted(targetBlockStateType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void handleBlockChange(Vector3i vector3i, WrappedBlockState state) {
|
||||
if (blocksChangedList.size() >= 60) return; // Don't let players freeze movement packets to grow this
|
||||
// Only do this for nearby blocks
|
||||
if (new Vector3d(vector3i.x, vector3i.y, vector3i.z).distanceSquared(new Vector3d(player.x, player.y, player.z)) > 36) return;
|
||||
// Only do this if the state really had any world impact
|
||||
// this line always just returns the current world state in compensatedWorld
|
||||
// if (state.equals(player.compensatedWorld.getWrappedBlockStateAt(vector3i))) return;
|
||||
blocksChangedList.put(vector3i, state);
|
||||
}
|
||||
|
||||
private boolean didRayTraceHit(BlockPlace place) {
|
||||
double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
|
||||
// Start checking if player is in the block
|
||||
double minEyeHeight = Double.MAX_VALUE;
|
||||
double maxEyeHeight = Double.MIN_VALUE;
|
||||
for (double height : possibleEyeHeights) {
|
||||
minEyeHeight = Math.min(minEyeHeight, height);
|
||||
maxEyeHeight = Math.max(maxEyeHeight, height);
|
||||
}
|
||||
|
||||
double movementThreshold = player.getMovementThreshold();
|
||||
|
||||
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
|
||||
eyePositions.expand(movementThreshold);
|
||||
|
||||
int[] interactBlockVec = new int[]{place.blockPosition.x, place.blockPosition.y, place.blockPosition.z};
|
||||
BlockFace expectedBlockFace = place.getDirection();
|
||||
|
||||
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
|
||||
// This may potentially be exploitable as a minor bypass
|
||||
if (eyePositions.isIntersected(new SimpleCollisionBox(interactBlockVec[0], interactBlockVec[1], interactBlockVec[2]))) {
|
||||
return true;
|
||||
}
|
||||
// End checking if the player is in the block
|
||||
double[][] possibleLookDirs;
|
||||
// 1.9+ players could be a tick behind because we don't get skipped ticks
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
possibleLookDirs = new double[][]{
|
||||
{player.xRot, player.yRot},
|
||||
{player.lastXRot, player.lastYRot},
|
||||
{player.lastXRot, player.yRot}
|
||||
};
|
||||
} else if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
|
||||
// 1.7 players do not have any of these issues! They are always on the latest look vector
|
||||
possibleLookDirs = new double[][]{{player.xRot, player.yRot}};
|
||||
} else {
|
||||
possibleLookDirs = new double[][]{
|
||||
{player.xRot, player.yRot},
|
||||
{player.lastXRot, player.yRot}
|
||||
};
|
||||
}
|
||||
|
||||
// We do not need to add 0.03/0.0002 to maxDistance to ensure our raytrace hits blocks
|
||||
// Since we expand the hitboxes of the expectedTargetBlock by 0.03/0.002 already later
|
||||
double maxDistance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
|
||||
|
||||
// Define possible offsets
|
||||
// TODO, vectorize this with SIMD or AVX for performance
|
||||
double[][] offsets = {
|
||||
{0, 0, 0},
|
||||
{movementThreshold, 0, 0},
|
||||
{-movementThreshold, 0, 0},
|
||||
{0, movementThreshold, 0},
|
||||
{0, -movementThreshold, 0},
|
||||
{0, 0, movementThreshold},
|
||||
{0, 0, -movementThreshold}
|
||||
};
|
||||
|
||||
double[] eyePosition = new double[3];
|
||||
double[] eyeLookDir = new double[3];
|
||||
|
||||
for (double eyeHeight : possibleEyeHeights) {
|
||||
for (double[] lookDir : possibleLookDirs) {
|
||||
for (double[] offset : offsets) {
|
||||
eyePosition[0] = player.x + offset[0];
|
||||
eyePosition[1] = player.y + eyeHeight + offset[1];
|
||||
eyePosition[2] = player.z + offset[2];
|
||||
|
||||
calculateDirection(eyeLookDir, lookDir[0], lookDir[1]);
|
||||
|
||||
if (didRayTraceHitTargetBlock(eyePosition, eyeLookDir, maxDistance, interactBlockVec, expectedBlockFace)) {
|
||||
return true; // If any possible face matches the client-side placement, assume it's legitimate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false; // No matching face found
|
||||
}
|
||||
|
||||
// Helper method to calculate direction (replace the Ray class method)
|
||||
private void calculateDirection(double[] result, double xRot, double yRot) {
|
||||
float rotX = (float) Math.toRadians(xRot);
|
||||
float rotY = (float) Math.toRadians(yRot);
|
||||
result[1] = -player.trigHandler.sin(rotY);
|
||||
double xz = player.trigHandler.cos(rotY);
|
||||
result[0] = -xz * player.trigHandler.sin(rotX);
|
||||
result[2] = xz * player.trigHandler.cos(rotX);
|
||||
}
|
||||
|
||||
private boolean didRayTraceHitTargetBlock(double[] eyePos, double[] eyeDir, double maxDistance, int[] targetBlockVec, BlockFace expectedBlockFace) {
|
||||
HitData hitData = BlockRayTrace.getNearestReachHitResult(player, eyePos, eyeDir, maxDistance, maxDistance, targetBlockVec, expectedBlockFace, collisionBoxBuffer, null, false);
|
||||
if (hitData == null || !hitData.success)
|
||||
hitData = BlockRayTrace.getNearestReachHitResult(player, eyePos, eyeDir, maxDistance, maxDistance, targetBlockVec,
|
||||
expectedBlockFace, collisionBoxBuffer, player.checkManager.getBlockPlaceCheck(LineOfSightPlace.class).blocksChangedList, false);
|
||||
|
||||
// we check for hitdata != null because of being in expanded hitbox, or there was no result, do we still need this?
|
||||
return hitData != null && hitData.success;
|
||||
}
|
||||
|
||||
private boolean isBlockTypeWhitelisted(StateType type) {
|
||||
return blockWhitelist.contains(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
useBlockWhitelist = config.getBooleanElse("LineOfSightPlace.use-block-whitelist", false);
|
||||
blockWhitelist = new HashSet<>();
|
||||
List<String> blocks = config.getStringList("LineOfSightPlace.block-whitelist");
|
||||
for (String block : blocks) {
|
||||
blockWhitelist.add(StateTypes.getByName(block));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ 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;
|
||||
@@ -56,14 +55,14 @@ public class MultiPlace extends BlockPlaceCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
|
||||
if (isTickPacket(event.getPacketType())) {
|
||||
hasPlaced = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && player.isTickingReliablyFor(3)) {
|
||||
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
|
||||
@@ -48,27 +48,21 @@ public class PositionPlace extends BlockPlaceCheck {
|
||||
|
||||
// So now we have the player's possible eye positions
|
||||
// So then look at the face that the player has clicked
|
||||
boolean flag = false;
|
||||
switch (place.getDirection()) {
|
||||
case NORTH: // Z- face
|
||||
flag = eyePositions.minZ > combined.minZ;
|
||||
break;
|
||||
case SOUTH: // Z+ face
|
||||
flag = eyePositions.maxZ < combined.maxZ;
|
||||
break;
|
||||
case EAST: // X+ face
|
||||
flag = eyePositions.maxX < combined.maxX;
|
||||
break;
|
||||
case WEST: // X- face
|
||||
flag = eyePositions.minX > combined.minX;
|
||||
break;
|
||||
case UP: // Y+ face
|
||||
flag = eyePositions.maxY < combined.maxY;
|
||||
break;
|
||||
case DOWN: // Y- face
|
||||
flag = eyePositions.minY > combined.minY;
|
||||
break;
|
||||
}
|
||||
boolean flag = switch (place.getDirection()) {
|
||||
case NORTH -> // Z- face
|
||||
eyePositions.minZ > combined.minZ;
|
||||
case SOUTH -> // Z+ face
|
||||
eyePositions.maxZ < combined.maxZ;
|
||||
case EAST -> // X+ face
|
||||
eyePositions.maxX < combined.maxX;
|
||||
case WEST -> // X- face
|
||||
eyePositions.minX > combined.minX;
|
||||
case UP -> // Y+ face
|
||||
eyePositions.maxY < combined.maxY;
|
||||
case DOWN -> // Y- face
|
||||
eyePositions.minY > combined.minY;
|
||||
default -> false;
|
||||
};
|
||||
|
||||
if (flag) {
|
||||
if (flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
|
||||
|
||||
@@ -1 +1,122 @@
|
||||
package ac.grim.grimac.checks.impl.scaffolding;
|
||||
|
||||
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.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;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@CheckData(name = "RotationPlace")
|
||||
public class RotationPlace extends BlockPlaceCheck {
|
||||
double flagBuffer = 0; // If the player flags once, force them to play legit, or we will cancel the tick before.
|
||||
boolean ignorePost = false;
|
||||
|
||||
public RotationPlace(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockPlace(final BlockPlace place) {
|
||||
if (place.getMaterial() == StateTypes.SCAFFOLDING) return;
|
||||
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
|
||||
if (flagBuffer > 0 && !didRayTraceHit(place)) {
|
||||
ignorePost = true;
|
||||
// If the player hit and has flagged this check recently
|
||||
if (flagAndAlert("pre-flying") && shouldModifyPackets() && shouldCancel()) {
|
||||
place.resync(); // Deny the block placement.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use post flying because it has the correct rotation, and can't false easily.
|
||||
@Override
|
||||
public void onPostFlyingBlockPlace(BlockPlace place) {
|
||||
if (place.getMaterial() == StateTypes.SCAFFOLDING) return;
|
||||
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
|
||||
|
||||
// Don't flag twice
|
||||
if (ignorePost) {
|
||||
ignorePost = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Ray trace to try and hit the target block.
|
||||
boolean hit = didRayTraceHit(place);
|
||||
// This can false with rapidly moving yaw in 1.8+ clients
|
||||
if (!hit) {
|
||||
flagBuffer = 1;
|
||||
flagAndAlert("post-flying");
|
||||
} else {
|
||||
flagBuffer = Math.max(0, flagBuffer - 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean didRayTraceHit(BlockPlace place) {
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(place.getPlacedAgainstBlockLocation());
|
||||
|
||||
List<Vector3f> possibleLookDirs = new ArrayList<>(Arrays.asList(
|
||||
new Vector3f(player.xRot, player.yRot, 0),
|
||||
new Vector3f(player.lastXRot, player.yRot, 0)
|
||||
));
|
||||
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
|
||||
// Start checking if player is in the block
|
||||
double minEyeHeight = Double.MAX_VALUE;
|
||||
double maxEyeHeight = Double.MIN_VALUE;
|
||||
for (double height : possibleEyeHeights) {
|
||||
minEyeHeight = Math.min(minEyeHeight, height);
|
||||
maxEyeHeight = Math.max(maxEyeHeight, height);
|
||||
}
|
||||
|
||||
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
|
||||
eyePositions.expand(player.getMovementThreshold());
|
||||
|
||||
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
|
||||
if (eyePositions.isIntersected(box)) {
|
||||
return true;
|
||||
}
|
||||
// End checking if the player is in the block
|
||||
|
||||
// 1.9+ players could be a tick behind because we don't get skipped ticks
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
possibleLookDirs.add(new Vector3f(player.lastXRot, player.lastYRot, 0));
|
||||
}
|
||||
|
||||
// 1.7 players do not have any of these issues! They are always on the latest look vector
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
|
||||
possibleLookDirs = Collections.singletonList(new Vector3f(player.xRot, player.yRot, 0));
|
||||
}
|
||||
|
||||
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
|
||||
for (double d : possibleEyeHeights) {
|
||||
for (Vector3f lookDir : possibleLookDirs) {
|
||||
// x, y, z are correct for the block placement even after post tick because of code elsewhere
|
||||
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));
|
||||
|
||||
if (intercept.first() != null) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ 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 ac.grim.grimac.utils.vector.Vector3D;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Deque;
|
||||
|
||||
@@ -68,6 +68,7 @@ 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
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
package ac.grim.grimac.checks.type;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientCloseWindow;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerCloseWindow;
|
||||
import org.jetbrains.annotations.MustBeInvokedByOverriders;
|
||||
|
||||
public class InventoryCheck extends BlockPlaceCheck implements PacketCheck {
|
||||
// Impossible transaction ID
|
||||
protected static final long NONE = Long.MAX_VALUE;
|
||||
|
||||
protected long closeTransaction = NONE;
|
||||
protected int closePacketsToSkip;
|
||||
|
||||
public InventoryCheck(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MustBeInvokedByOverriders
|
||||
public void onPacketReceive(final PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
// Disallow any clicks if inventory is closing
|
||||
if (closeTransaction != NONE && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.getInventory().needResend = true;
|
||||
}
|
||||
} else if (event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
|
||||
// Players with high ping can close inventory faster than send transaction back
|
||||
if (closeTransaction != NONE && closePacketsToSkip-- <= 0) {
|
||||
closeTransaction = NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void closeInventory() {
|
||||
if (closeTransaction != NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
int windowId = player.getInventory().openWindowID;
|
||||
|
||||
player.user.writePacket(new WrapperPlayServerCloseWindow(windowId));
|
||||
|
||||
// Force close inventory on server side
|
||||
closePacketsToSkip = 1; // Sending close packet to itself, so skip it
|
||||
PacketEvents.getAPI().getProtocolManager().receivePacket(
|
||||
player.user.getChannel(), new WrapperPlayClientCloseWindow(windowId)
|
||||
);
|
||||
|
||||
player.sendTransaction();
|
||||
|
||||
int transaction = player.lastTransactionSent.get();
|
||||
closeTransaction = transaction;
|
||||
player.latencyUtils.addRealTimeTask(transaction, () -> {
|
||||
if (closeTransaction == transaction) {
|
||||
closeTransaction = NONE;
|
||||
}
|
||||
});
|
||||
|
||||
player.user.flushPackets();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,10 @@
|
||||
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 onPositionUpdate(final PositionUpdate positionUpdate) {
|
||||
}
|
||||
default void onPacketReceive(final PacketReceiveEvent event) {}
|
||||
default void onPacketSend(final PacketSendEvent event) {}
|
||||
}
|
||||
@@ -23,8 +23,7 @@ public class GrimSpectate extends BaseCommand {
|
||||
@CommandPermission("grim.spectate")
|
||||
@CommandCompletion("@players")
|
||||
public void onSpectate(CommandSender sender, @Optional OnlinePlayer target) {
|
||||
if (!(sender instanceof Player)) return;
|
||||
Player player = (Player) sender;
|
||||
if (!(sender instanceof Player player)) return;
|
||||
|
||||
if (target != null && target.getPlayer().getUniqueId().equals(player.getUniqueId())) {
|
||||
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("cannot-run-on-self", "%prefix% &cYou cannot use this command on yourself!");
|
||||
|
||||
@@ -3,6 +3,8 @@ package ac.grim.grimac.commands;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.BukkitCommandCompletionContext;
|
||||
import co.aikar.commands.CommandCompletions.CommandCompletionHandler;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
@@ -10,17 +12,21 @@ import co.aikar.commands.annotation.Subcommand;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@CommandAlias("grim|grimac")
|
||||
public class GrimStopSpectating extends BaseCommand {
|
||||
public static final CommandCompletionHandler<BukkitCommandCompletionContext> completionHandler = context -> context.getSender().hasPermission("grim.spectate.stophere") ? List.of("here") : List.of();
|
||||
|
||||
@Subcommand("stopspectating")
|
||||
@CommandPermission("grim.spectate")
|
||||
@CommandCompletion("here")
|
||||
@CommandCompletion("@stopspectating")
|
||||
public void onStopSpectate(CommandSender sender, String[] args) {
|
||||
String string = args.length > 0 ? args[0] : null;
|
||||
if (!(sender instanceof Player)) return;
|
||||
Player player = (Player) sender;
|
||||
if (GrimAPI.INSTANCE.getSpectateManager().isSpectating(player.getUniqueId())) {
|
||||
boolean teleportBack = string == null || !string.equalsIgnoreCase("here");
|
||||
boolean teleportBack = string == null || !string.equalsIgnoreCase("here") || !sender.hasPermission("grim.spectate.stophere");
|
||||
GrimAPI.INSTANCE.getSpectateManager().disable(player, teleportBack);
|
||||
} else {
|
||||
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("cannot-spectate-return", "%prefix% &cYou can only do this after spectating a player.");
|
||||
|
||||
@@ -3,17 +3,22 @@ package ac.grim.grimac.events.packets;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.checks.impl.badpackets.BadPacketsX;
|
||||
import ac.grim.grimac.checks.impl.badpackets.BadPacketsZ;
|
||||
import ac.grim.grimac.checks.impl.inventory.InventoryB;
|
||||
import ac.grim.grimac.events.packets.patch.ResyncWorldUtil;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.*;
|
||||
import ac.grim.grimac.utils.blockplace.BlockPlaceResult;
|
||||
import ac.grim.grimac.utils.blockplace.ConsumesBlockPlace;
|
||||
import ac.grim.grimac.utils.collisions.HitboxData;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.*;
|
||||
import ac.grim.grimac.utils.inventory.Inventory;
|
||||
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;
|
||||
@@ -21,6 +26,7 @@ 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.ConnectionState;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
@@ -44,6 +50,9 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerAc
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetSlot;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class CheckManagerListener extends PacketListenerAbstract {
|
||||
@@ -52,8 +61,79 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
super(PacketListenerPriority.LOW);
|
||||
}
|
||||
|
||||
// Copied from MCP...
|
||||
// Returns null if there isn't anything.
|
||||
//
|
||||
// I do have to admit that I'm starting to like bifunctions/new java 8 things more than I originally did.
|
||||
// although I still don't understand Mojang's obsession with streams in some of the hottest methods... that kills performance
|
||||
public static HitData traverseBlocks(GrimPlayer player, Vector3d start, Vector3d end, BiFunction<WrappedBlockState, Vector3i, HitData> predicate) {
|
||||
// I guess go back by the collision epsilon?
|
||||
double endX = GrimMath.lerp(-1.0E-7D, end.x, start.x);
|
||||
double endY = GrimMath.lerp(-1.0E-7D, end.y, start.y);
|
||||
double endZ = GrimMath.lerp(-1.0E-7D, end.z, start.z);
|
||||
double startX = GrimMath.lerp(-1.0E-7D, start.x, end.x);
|
||||
double startY = GrimMath.lerp(-1.0E-7D, start.y, end.y);
|
||||
double startZ = GrimMath.lerp(-1.0E-7D, start.z, end.z);
|
||||
int floorStartX = GrimMath.floor(startX);
|
||||
int floorStartY = GrimMath.floor(startY);
|
||||
int floorStartZ = GrimMath.floor(startZ);
|
||||
|
||||
|
||||
if (start.equals(end)) return null;
|
||||
|
||||
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
|
||||
HitData apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
|
||||
|
||||
if (apply != null) {
|
||||
return apply;
|
||||
}
|
||||
|
||||
double xDiff = endX - startX;
|
||||
double yDiff = endY - startY;
|
||||
double zDiff = endZ - startZ;
|
||||
double xSign = Math.signum(xDiff);
|
||||
double ySign = Math.signum(yDiff);
|
||||
double zSign = Math.signum(zDiff);
|
||||
|
||||
double posXInverse = xSign == 0 ? Double.MAX_VALUE : xSign / xDiff;
|
||||
double posYInverse = ySign == 0 ? Double.MAX_VALUE : ySign / yDiff;
|
||||
double posZInverse = zSign == 0 ? Double.MAX_VALUE : zSign / zDiff;
|
||||
|
||||
double d12 = posXInverse * (xSign > 0 ? 1.0D - GrimMath.frac(startX) : GrimMath.frac(startX));
|
||||
double d13 = posYInverse * (ySign > 0 ? 1.0D - GrimMath.frac(startY) : GrimMath.frac(startY));
|
||||
double d14 = posZInverse * (zSign > 0 ? 1.0D - GrimMath.frac(startZ) : GrimMath.frac(startZ));
|
||||
|
||||
// Can't figure out what this code does currently
|
||||
while (d12 <= 1.0D || d13 <= 1.0D || d14 <= 1.0D) {
|
||||
if (d12 < d13) {
|
||||
if (d12 < d14) {
|
||||
floorStartX += xSign;
|
||||
d12 += posXInverse;
|
||||
} else {
|
||||
floorStartZ += zSign;
|
||||
d14 += posZInverse;
|
||||
}
|
||||
} else if (d13 < d14) {
|
||||
floorStartY += ySign;
|
||||
d13 += posYInverse;
|
||||
} else {
|
||||
floorStartZ += zSign;
|
||||
d14 += posZInverse;
|
||||
}
|
||||
|
||||
state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
|
||||
apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
|
||||
|
||||
if (apply != null) {
|
||||
return apply;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void placeWaterLavaSnowBucket(GrimPlayer player, ItemStack held, StateType toPlace, InteractionHand hand) {
|
||||
HitData data = BlockRayTrace.getNearestHitResult(player, StateTypes.AIR, false);
|
||||
HitData data = getNearestHitResult(player, StateTypes.AIR, false);
|
||||
if (data != null) {
|
||||
BlockPlace blockPlace = new BlockPlace(player, hand, data.getPosition(), data.getClosestDirection().getFaceValue(), data.getClosestDirection(), held, data);
|
||||
|
||||
@@ -148,9 +228,8 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
|
||||
private static void handleBlockPlaceOrUseItem(PacketWrapper<?> packet, GrimPlayer player) {
|
||||
// Legacy "use item" packet
|
||||
if (packet instanceof WrapperPlayClientPlayerBlockPlacement &&
|
||||
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place &&
|
||||
PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
|
||||
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
|
||||
|
||||
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
|
||||
|
||||
@@ -165,9 +244,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
if (packet instanceof WrapperPlayClientUseItem) {
|
||||
WrapperPlayClientUseItem place = (WrapperPlayClientUseItem) packet;
|
||||
|
||||
if (packet instanceof WrapperPlayClientUseItem place) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
|
||||
|
||||
ItemStack placedWith = player.getInventory().getHeldItem();
|
||||
@@ -179,9 +256,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
}
|
||||
|
||||
// Check for interactable first (door, etc)
|
||||
if (packet instanceof WrapperPlayClientPlayerBlockPlacement) {
|
||||
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
|
||||
|
||||
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place) {
|
||||
ItemStack placedWith = player.getInventory().getHeldItem();
|
||||
ItemStack offhand = player.getInventory().getOffHand();
|
||||
|
||||
@@ -190,7 +265,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
// The offhand is unable to interact with blocks like this... try to stop some desync points before they happen
|
||||
if ((!player.isSneaking || onlyAir) && place.getHand() == InteractionHand.MAIN_HAND) {
|
||||
Vector3i blockPosition = place.getBlockPosition();
|
||||
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), place.getFace(), placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
|
||||
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), place.getFace(), placedWith, getNearestHitResult(player, null, true));
|
||||
|
||||
// Right-clicking a trapdoor/door/etc.
|
||||
StateType placedAgainst = blockPlace.getPlacedAgainstMaterial();
|
||||
@@ -217,8 +292,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
if (packet instanceof WrapperPlayClientPlayerBlockPlacement) {
|
||||
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
|
||||
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place) {
|
||||
Vector3i blockPosition = place.getBlockPosition();
|
||||
BlockFace face = place.getFace();
|
||||
|
||||
@@ -230,7 +304,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
placedWith = player.getInventory().getOffHand();
|
||||
}
|
||||
|
||||
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), face, placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
|
||||
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), face, placedWith, getNearestHitResult(player, null, true));
|
||||
// At this point, it is too late to cancel, so we can only flag, and cancel subsequent block places more aggressively
|
||||
if (!player.compensatedEntities.getSelf().inVehicle()) {
|
||||
player.checkManager.onPostFlyingBlockPlace(blockPlace);
|
||||
@@ -298,9 +372,7 @@ 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 -> {
|
||||
return !type.isAir() && type.getHardness() != -1.0f && type != StateTypes.WATER && type != StateTypes.LAVA;
|
||||
};
|
||||
private static final Function<StateType, Boolean> BREAKABLE = type -> !type.isAir() && type.getHardness() != -1.0f && type != StateTypes.WATER && type != StateTypes.LAVA;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
@@ -382,45 +454,43 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
WrapperPlayClientPlayerDigging dig = new WrapperPlayClientPlayerDigging(event);
|
||||
final Vector3i digPosition = dig.getBlockPosition();
|
||||
WrappedBlockState block = player.compensatedWorld.getWrappedBlockStateAt(digPosition);
|
||||
final StateType type = block.getType();
|
||||
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
|
||||
final BlockBreak blockBreak = new BlockBreak(packet, player);
|
||||
|
||||
player.checkManager.getPacketCheck(InventoryB.class).handle(event, dig);
|
||||
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 (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 (blockBreak.isCancelled()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
if (dig.getAction() == DiggingAction.START_DIGGING || dig.getAction() == DiggingAction.FINISHED_DIGGING || dig.getAction() == DiggingAction.CANCELLED_DIGGING) {
|
||||
player.compensatedWorld.handleBlockBreakPrediction(dig);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -439,7 +509,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
player.placeUseItemPackets.add(new BlockPlaceSnapshot(packet, player.isSneaking));
|
||||
} else {
|
||||
// Anti-air place
|
||||
BlockPlace blockPlace = new BlockPlace(player, packet.getHand(), packet.getBlockPosition(), packet.getFaceId(), packet.getFace(), placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
|
||||
BlockPlace blockPlace = new BlockPlace(player, packet.getHand(), packet.getBlockPosition(), packet.getFaceId(), packet.getFace(), placedWith, getNearestHitResult(player, null, true));
|
||||
blockPlace.setCursor(packet.getCursorPosition());
|
||||
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_11) && player.getClientVersion().isOlderThan(ClientVersion.V_1_11)) {
|
||||
@@ -507,13 +577,22 @@ 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;
|
||||
}
|
||||
|
||||
private static void placeBucket(GrimPlayer player, InteractionHand hand) {
|
||||
HitData data = BlockRayTrace.getNearestHitResult(player, null, true);
|
||||
HitData data = getNearestHitResult(player, null, true);
|
||||
|
||||
if (data != null) {
|
||||
BlockPlace blockPlace = new BlockPlace(player, hand, data.getPosition(), data.getClosestDirection().getFaceValue(), data.getClosestDirection(), ItemStack.EMPTY, data);
|
||||
@@ -676,10 +755,14 @@ 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) {
|
||||
HitData data = BlockRayTrace.getNearestHitResult(player, null, true);
|
||||
HitData data = getNearestHitResult(player, null, true);
|
||||
|
||||
if (data != null) {
|
||||
// A lilypad cannot replace a fluid
|
||||
@@ -709,6 +792,56 @@ 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());
|
||||
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);
|
||||
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
|
||||
|
||||
return traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
|
||||
CollisionBox data = HitboxData.getBlockHitbox(player, heldItem, player.getClientVersion(), block, vector3i.getX(), vector3i.getY(), vector3i.getZ());
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
data.downCast(boxes);
|
||||
|
||||
double bestHitResult = Double.MAX_VALUE;
|
||||
Vector3D bestHitLoc = null;
|
||||
BlockFace bestFace = null;
|
||||
|
||||
for (SimpleCollisionBox box : boxes) {
|
||||
Pair<Vector3D, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
|
||||
if (intercept.first() == null) continue; // No intercept
|
||||
|
||||
Vector3D hitLoc = intercept.first();
|
||||
|
||||
if (hitLoc.distanceSquared(startingVec) < bestHitResult) {
|
||||
bestHitResult = hitLoc.distanceSquared(startingVec);
|
||||
bestHitLoc = hitLoc;
|
||||
bestFace = intercept.second();
|
||||
}
|
||||
}
|
||||
if (bestHitLoc != null) {
|
||||
return new HitData(vector3i, bestHitLoc, bestFace, block);
|
||||
}
|
||||
|
||||
if (sourcesHaveHitbox &&
|
||||
(player.compensatedWorld.isWaterSourceBlock(vector3i.getX(), vector3i.getY(), vector3i.getZ())
|
||||
|| player.compensatedWorld.getLavaFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ()) == (8 / 9f))) {
|
||||
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));
|
||||
|
||||
if (intercept.first() != null) {
|
||||
return new HitData(vector3i, intercept.first(), intercept.second(), block);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
if (event.getConnectionState() != ConnectionState.PLAY) return;
|
||||
|
||||
@@ -13,6 +13,7 @@ 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;
|
||||
@@ -21,7 +22,6 @@ 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,22 +60,19 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
|
||||
// Teleports don't interpolate, duplicate 1.17 packets don't interpolate
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate)
|
||||
return;
|
||||
// Teleports don't interpolate, duplicate 1.17 packets don't interpolate
|
||||
if (!isTickPacket(event.getPacketType())) 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,44 +83,55 @@ 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();
|
||||
}
|
||||
if (event.getPacketType() == PacketType.Play.Server.SPAWN_LIVING_ENTITY) {
|
||||
else 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);
|
||||
}
|
||||
if (event.getPacketType() == PacketType.Play.Server.SPAWN_ENTITY) {
|
||||
else 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());
|
||||
}
|
||||
if (event.getPacketType() == PacketType.Play.Server.SPAWN_PLAYER) {
|
||||
else 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);
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE) {
|
||||
else 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());
|
||||
}
|
||||
else 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);
|
||||
}
|
||||
if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE_AND_ROTATION) {
|
||||
else 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);
|
||||
}
|
||||
if (event.getPacketType() == PacketType.Play.Server.ENTITY_TELEPORT) {
|
||||
else 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);
|
||||
}
|
||||
if (event.getPacketType() == PacketType.Play.Server.ENTITY_ROTATION) { // Affects interpolation
|
||||
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
|
||||
WrapperPlayServerEntityRotation move = new WrapperPlayServerEntityRotation(event);
|
||||
handleMoveEntity(event, move.getEntityId(), 0, 0, 0, move.getYaw() * 0.7111111F, move.getPitch() * 0.7111111F, true, false);
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
|
||||
else 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+
|
||||
if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO_UPDATE) {
|
||||
else 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()) {
|
||||
@@ -150,7 +158,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
});
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.ENTITY_EFFECT) {
|
||||
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_EFFECT) {
|
||||
WrapperPlayServerEntityEffect effect = new WrapperPlayServerEntityEffect(event);
|
||||
|
||||
PotionType type = effect.getPotionType();
|
||||
@@ -182,7 +190,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
});
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.REMOVE_ENTITY_EFFECT) {
|
||||
else if (event.getPacketType() == PacketType.Play.Server.REMOVE_ENTITY_EFFECT) {
|
||||
WrapperPlayServerRemoveEntityEffect effect = new WrapperPlayServerRemoveEntityEffect(event);
|
||||
|
||||
if (isDirectlyAffectingPlayer(player, effect.getEntityId())) player.sendTransaction();
|
||||
@@ -195,7 +203,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
});
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.UPDATE_ATTRIBUTES) {
|
||||
else if (event.getPacketType() == PacketType.Play.Server.UPDATE_ATTRIBUTES) {
|
||||
WrapperPlayServerUpdateAttributes attributes = new WrapperPlayServerUpdateAttributes(event);
|
||||
|
||||
int entityID = attributes.getEntityId();
|
||||
@@ -207,7 +215,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
() -> player.compensatedEntities.updateAttributes(entityID, attributes.getProperties()));
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.ENTITY_STATUS) {
|
||||
else 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.
|
||||
@@ -227,9 +235,8 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
|
||||
if (status.getStatus() == 31) {
|
||||
PacketEntity hook = player.compensatedEntities.getEntity(status.getEntityId());
|
||||
if (!(hook instanceof PacketEntityHook)) return;
|
||||
if (!(hook instanceof PacketEntityHook hookEntity)) return;
|
||||
|
||||
PacketEntityHook hookEntity = (PacketEntityHook) hook;
|
||||
if (hookEntity.attached == player.entityID) {
|
||||
player.sendTransaction();
|
||||
// We don't transaction sandwich this, it's too rare to be a real problem.
|
||||
@@ -242,7 +249,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.SET_SLOT) {
|
||||
else if (event.getPacketType() == PacketType.Play.Server.SET_SLOT) {
|
||||
WrapperPlayServerSetSlot slot = new WrapperPlayServerSetSlot(event);
|
||||
|
||||
if (slot.getWindowId() == 0) {
|
||||
@@ -260,7 +267,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) {
|
||||
else if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) {
|
||||
WrapperPlayServerWindowItems items = new WrapperPlayServerWindowItems(event);
|
||||
|
||||
if (items.getWindowId() == 0) { // Player inventory
|
||||
@@ -270,16 +277,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
|
||||
if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
|
||||
else 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));
|
||||
}
|
||||
if (event.getPacketType() == PacketType.Play.Server.OPEN_HORSE_WINDOW) {
|
||||
else 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));
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.SET_PASSENGERS) {
|
||||
else if (event.getPacketType() == PacketType.Play.Server.SET_PASSENGERS) {
|
||||
WrapperPlayServerSetPassengers mount = new WrapperPlayServerSetPassengers(event);
|
||||
|
||||
int vehicleID = mount.getEntityId();
|
||||
@@ -288,7 +295,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
handleMountVehicle(event, vehicleID, passengers);
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.ATTACH_ENTITY) {
|
||||
else 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
|
||||
@@ -319,7 +326,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Server.DESTROY_ENTITIES) {
|
||||
else if (event.getPacketType() == PacketType.Play.Server.DESTROY_ENTITIES) {
|
||||
WrapperPlayServerDestroyEntities destroy = new WrapperPlayServerDestroyEntities(event);
|
||||
|
||||
int[] destroyEntityIds = destroy.getEntityIds();
|
||||
@@ -414,9 +421,13 @@ 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) &&
|
||||
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)
|
||||
// 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);
|
||||
|
||||
// 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)
|
||||
@@ -454,8 +465,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
player.latencyUtils.addRealTimeTask(lastTrans, () -> {
|
||||
PacketEntity entity = player.compensatedEntities.getEntity(entityId);
|
||||
if (entity == null) return;
|
||||
if (entity instanceof PacketEntityTrackXRot && yaw != null) {
|
||||
PacketEntityTrackXRot xRotEntity = (PacketEntityTrackXRot) entity;
|
||||
if (entity instanceof PacketEntityTrackXRot xRotEntity && yaw != null) {
|
||||
xRotEntity.packetYaw = yaw;
|
||||
xRotEntity.steps = entity.isBoat() ? 10 : 3;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ 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,6 +3,7 @@ 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;
|
||||
@@ -19,7 +20,6 @@ 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 ac.grim.grimac.utils.vector.Vector3D;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -133,7 +133,11 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
|
||||
}
|
||||
|
||||
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get() + 1, () -> {
|
||||
player.isSneaking = false;
|
||||
// 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.lastOnGround = false;
|
||||
player.onGround = false;
|
||||
player.isInBed = false;
|
||||
@@ -159,6 +163,7 @@ 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)) {
|
||||
|
||||
@@ -3,6 +3,7 @@ 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;
|
||||
@@ -12,6 +13,7 @@ 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 {
|
||||
@@ -22,13 +24,12 @@ public class PacketPlayerSteer extends PacketListenerAbstract {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
|
||||
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();
|
||||
|
||||
@@ -99,6 +100,33 @@ 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
package ac.grim.grimac.events.packets;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntitySelf;
|
||||
import ac.grim.grimac.utils.inventory.InventoryDesyncStatus;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
|
||||
import com.github.retrooper.packetevents.event.PacketListenerPriority;
|
||||
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.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus.Action;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOpenWindow;
|
||||
|
||||
public class PacketPlayerWindow extends PacketListenerAbstract {
|
||||
|
||||
public PacketPlayerWindow() {
|
||||
super(PacketListenerPriority.LOWEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !event.isCancelled()) {
|
||||
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
|
||||
if (player == null) return;
|
||||
|
||||
if (player.hasInventoryOpen && isNearNetherPortal(player)) {
|
||||
handleInventoryClose(player, InventoryDesyncStatus.NETHER_PORTAL);
|
||||
}
|
||||
}
|
||||
|
||||
// Client Status is sent in 1.7-1.8
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS) {
|
||||
WrapperPlayClientClientStatus wrapper = new WrapperPlayClientClientStatus(event);
|
||||
|
||||
if (wrapper.getAction() == Action.OPEN_INVENTORY_ACHIEVEMENT) {
|
||||
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
|
||||
if (player == null) return;
|
||||
|
||||
handleInventoryOpen(player);
|
||||
}
|
||||
}
|
||||
|
||||
// We need to do this due to 1.9 not sending anymore the inventory action in the Client Status
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
|
||||
if (player == null) return;
|
||||
|
||||
// TODO: Remove this check after we finish the before ViaVersion injection
|
||||
// Explanation: On 1.7 and 1.8 we have OPEN_INVENTORY_ACHIEVEMENT on CLIENT_STATUS packet
|
||||
// but after Via translation this information gets lost
|
||||
// This is a workaround to atleast make our inventory checks work "decently" in 1.8 clients for 1.9+ servers
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
|
||||
&& player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
handleInventoryOpen(player);
|
||||
}
|
||||
|
||||
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8)) {
|
||||
handleInventoryOpen(player);
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
|
||||
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
|
||||
if (player == null) return;
|
||||
|
||||
handleInventoryClose(player, InventoryDesyncStatus.NOT_DESYNCED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.RESPAWN) {
|
||||
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
|
||||
if (player == null) return;
|
||||
|
||||
player.sendTransaction();
|
||||
|
||||
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(),
|
||||
() -> handleInventoryClose(player, InventoryDesyncStatus.NOT_DESYNCED));
|
||||
} else if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
|
||||
WrapperPlayServerOpenWindow wrapper = new WrapperPlayServerOpenWindow(event);
|
||||
|
||||
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
|
||||
if (player == null) return;
|
||||
|
||||
player.sendTransaction();
|
||||
|
||||
String legacyType = wrapper.getLegacyType();
|
||||
int modernType = wrapper.getType();
|
||||
InventoryDesyncStatus inventoryDesyncStatus = getContainerDesyncStatus(player, legacyType, modernType);
|
||||
|
||||
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(),
|
||||
() -> {
|
||||
if (inventoryDesyncStatus == InventoryDesyncStatus.NOT_DESYNCED) {
|
||||
handleInventoryOpen(player);
|
||||
} else {
|
||||
handleInventoryClose(player, inventoryDesyncStatus);
|
||||
}
|
||||
});
|
||||
} else if (event.getPacketType() == PacketType.Play.Server.OPEN_HORSE_WINDOW) {
|
||||
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
|
||||
if (player == null) return;
|
||||
|
||||
player.sendTransaction();
|
||||
|
||||
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(),
|
||||
() -> handleInventoryOpen(player));
|
||||
} else if (event.getPacketType() == PacketType.Play.Server.CLOSE_WINDOW) {
|
||||
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
|
||||
if (player == null) return;
|
||||
|
||||
player.sendTransaction();
|
||||
|
||||
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(),
|
||||
() -> handleInventoryClose(player, InventoryDesyncStatus.NOT_DESYNCED));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInventoryOpen(GrimPlayer player) {
|
||||
if (!player.hasInventoryOpen) {
|
||||
player.lastInventoryOpen = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
player.hasInventoryOpen = true;
|
||||
}
|
||||
|
||||
private void handleInventoryClose(GrimPlayer player, InventoryDesyncStatus desyncStatus) {
|
||||
player.hasInventoryOpen = false;
|
||||
player.inventoryDesyncStatus = desyncStatus;
|
||||
}
|
||||
|
||||
public InventoryDesyncStatus getContainerDesyncStatus(GrimPlayer player, String legacyType, int modernType) {
|
||||
// Closing beacon with the cross button cause desync in 1.7-1.8
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) &&
|
||||
("minecraft:beacon".equals(legacyType) || modernType == 8)) {
|
||||
return player.inventoryDesyncStatus = InventoryDesyncStatus.BEACON;
|
||||
}
|
||||
|
||||
if (isNearNetherPortal(player)) {
|
||||
return player.inventoryDesyncStatus = InventoryDesyncStatus.NETHER_PORTAL;
|
||||
}
|
||||
|
||||
return player.inventoryDesyncStatus = InventoryDesyncStatus.NOT_DESYNCED;
|
||||
}
|
||||
|
||||
public boolean isNearNetherPortal(GrimPlayer player) {
|
||||
// Going inside nether portal with opened inventory cause desync, fixed in 1.12.2
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_12_1) &&
|
||||
player.pointThreeEstimator.isNearNetherPortal) {
|
||||
PacketEntitySelf playerEntity = player.compensatedEntities.getSelf();
|
||||
// Client ignore nether portal if player has passengers or riding an entity
|
||||
if (!playerEntity.inVehicle() && playerEntity.passengers.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerMultiBlockChange;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
@@ -35,19 +36,20 @@ public class ResyncWorldUtil {
|
||||
|| !player.compensatedWorld.isChunkLoaded(maxBlockX >> 4, minBlockZ >> 4) || !player.compensatedWorld.isChunkLoaded(maxBlockX >> 4, maxBlockZ >> 4))
|
||||
return;
|
||||
|
||||
if (player.bukkitPlayer == null) return;
|
||||
World world = player.bukkitPlayer.getWorld();
|
||||
|
||||
// Takes 0.15ms or so to complete. Not bad IMO. Unsure how I could improve this other than sending packets async.
|
||||
// But that's on PacketEvents.
|
||||
FoliaScheduler.getRegionScheduler().execute(GrimAPI.INSTANCE.getPlugin(), player.bukkitPlayer.getWorld(),
|
||||
FoliaScheduler.getRegionScheduler().execute(GrimAPI.INSTANCE.getPlugin(), world,
|
||||
minBlockX >> 4, minBlockZ >> 4, () -> {
|
||||
boolean flat = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13);
|
||||
|
||||
if (player.bukkitPlayer == null) return;
|
||||
// Player hasn't spawned, don't spam packets
|
||||
if (!player.getSetbackTeleportUtil().hasAcceptedSpawnTeleport) return;
|
||||
|
||||
// Check the 4 corners of the BB for loaded chunks, don't freeze main thread to load chunks.
|
||||
if (!player.bukkitPlayer.getWorld().isChunkLoaded(minBlockX >> 4, minBlockZ >> 4) || !player.bukkitPlayer.getWorld().isChunkLoaded(minBlockX >> 4, maxBlockZ >> 4)
|
||||
|| !player.bukkitPlayer.getWorld().isChunkLoaded(maxBlockX >> 4, minBlockZ >> 4) || !player.bukkitPlayer.getWorld().isChunkLoaded(maxBlockX >> 4, maxBlockZ >> 4))
|
||||
if (!world.isChunkLoaded(minBlockX >> 4, minBlockZ >> 4) || !world.isChunkLoaded(minBlockX >> 4, maxBlockZ >> 4)
|
||||
|| !world.isChunkLoaded(maxBlockX >> 4, minBlockZ >> 4) || !world.isChunkLoaded(maxBlockX >> 4, maxBlockZ >> 4))
|
||||
return;
|
||||
|
||||
// This is based on Tuinity's code, thanks leaf. Now merged into paper.
|
||||
@@ -76,7 +78,7 @@ public class ResyncWorldUtil {
|
||||
int minX = currChunkX == minChunkX ? minBlockX & 15 : 0; // coordinate in chunk
|
||||
int maxX = currChunkX == maxChunkX ? maxBlockX & 15 : 15; // coordinate in chunk
|
||||
|
||||
Chunk chunk = player.bukkitPlayer.getWorld().getChunkAt(currChunkX, currChunkZ);
|
||||
Chunk chunk = world.getChunkAt(currChunkX, currChunkZ);
|
||||
|
||||
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
|
||||
int minY = currChunkY == minChunkY ? minBlockY & 15 : 0; // coordinate in chunk
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.util.BitSet;
|
||||
public class PacketWorldReaderEight extends BasePacketWorldReader {
|
||||
@Override
|
||||
public void handleMapChunkBulk(final GrimPlayer player, final PacketSendEvent event) {
|
||||
PacketWrapper wrapper = new PacketWrapper(event);
|
||||
PacketWrapper<?> wrapper = new PacketWrapper<>(event);
|
||||
ByteBuf buffer = (ByteBuf) wrapper.getBuffer();
|
||||
|
||||
boolean skylight = wrapper.readBoolean();
|
||||
@@ -47,7 +47,7 @@ public class PacketWorldReaderEight extends BasePacketWorldReader {
|
||||
|
||||
@Override
|
||||
public void handleMapChunk(final GrimPlayer player, final PacketSendEvent event) {
|
||||
PacketWrapper wrapper = new PacketWrapper(event);
|
||||
PacketWrapper<?> wrapper = new PacketWrapper<>(event);
|
||||
|
||||
final int chunkX = wrapper.readInt();
|
||||
final int chunkZ = wrapper.readInt();
|
||||
|
||||
@@ -6,7 +6,6 @@ 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
|
||||
@@ -27,7 +26,7 @@ public class ActionManager extends Check implements PacketCheck {
|
||||
attacking = true;
|
||||
lastAttack = System.currentTimeMillis();
|
||||
}
|
||||
} else if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
|
||||
} else if (isTickPacketIncludingNonMovement(event.getPacketType())) {
|
||||
player.totalFlyingPacketsSent++;
|
||||
attacking = false;
|
||||
}
|
||||
|
||||
@@ -11,14 +11,15 @@ 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.inventory.*;
|
||||
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.packetorder.*;
|
||||
import ac.grim.grimac.checks.impl.post.Post;
|
||||
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;
|
||||
import ac.grim.grimac.checks.impl.prediction.OffsetHandler;
|
||||
@@ -86,10 +87,12 @@ public class CheckManager {
|
||||
.put(BadPacketsE.class, new BadPacketsE(player))
|
||||
.put(BadPacketsF.class, new BadPacketsF(player))
|
||||
.put(BadPacketsG.class, new BadPacketsG(player))
|
||||
.put(BadPacketsH.class, new BadPacketsH(player))
|
||||
.put(BadPacketsI.class, new BadPacketsI(player))
|
||||
.put(BadPacketsJ.class, new BadPacketsJ(player))
|
||||
.put(BadPacketsK.class, new BadPacketsK(player))
|
||||
.put(BadPacketsL.class, new BadPacketsL(player))
|
||||
.put(BadPacketsM.class, new BadPacketsM(player))
|
||||
.put(BadPacketsN.class, new BadPacketsN(player))
|
||||
.put(BadPacketsP.class, new BadPacketsP(player))
|
||||
.put(BadPacketsQ.class, new BadPacketsQ(player))
|
||||
@@ -97,21 +100,17 @@ 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(InventoryA.class, new InventoryA(player))
|
||||
.put(InventoryB.class, new InventoryB(player))
|
||||
.put(InventoryE.class, new InventoryE(player))
|
||||
.put(InventoryF.class, new InventoryF(player))
|
||||
.put(InventoryG.class, new InventoryG(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(PacketOrderB.class, new PacketOrderB(player))
|
||||
.put(PacketOrderC.class, new PacketOrderC(player))
|
||||
.put(PacketOrderD.class, new PacketOrderD(player))
|
||||
.put(PacketOrderP.class, new PacketOrderP(player))
|
||||
.put(TransactionOrder.class, new TransactionOrder(player))
|
||||
.put(NoSlowB.class, new NoSlowB(player))
|
||||
.put(SetbackBlocker.class, new SetbackBlocker(player)) // Must be last class otherwise we can't check while blocking packets
|
||||
.build();
|
||||
@@ -134,20 +133,8 @@ public class CheckManager {
|
||||
.put(ExplosionHandler.class, new ExplosionHandler(player))
|
||||
.put(KnockbackHandler.class, new KnockbackHandler(player))
|
||||
.put(GhostBlockDetector.class, new GhostBlockDetector(player))
|
||||
.put(InventoryD.class, new InventoryD(player))
|
||||
.put(Phase.class, new Phase(player))
|
||||
.put(PacketOrderProcessor.class, player.packetOrderProcessor)
|
||||
.put(Post.class, new Post(player))
|
||||
.put(PacketOrderA.class, new PacketOrderA(player))
|
||||
.put(PacketOrderE.class, new PacketOrderE(player))
|
||||
.put(PacketOrderF.class, new PacketOrderF(player))
|
||||
.put(PacketOrderG.class, new PacketOrderG(player))
|
||||
.put(PacketOrderH.class, new PacketOrderH(player))
|
||||
.put(PacketOrderI.class, new PacketOrderI(player))
|
||||
.put(PacketOrderJ.class, new PacketOrderJ(player))
|
||||
.put(PacketOrderK.class, new PacketOrderK(player))
|
||||
.put(PacketOrderL.class, new PacketOrderL(player))
|
||||
.put(PacketOrderM.class, new PacketOrderM(player))
|
||||
.put(PostCheck.class, new PostCheck(player))
|
||||
.put(NoFallB.class, new NoFallB(player))
|
||||
.put(OffsetHandler.class, new OffsetHandler(player))
|
||||
.put(SuperDebug.class, new SuperDebug(player))
|
||||
@@ -166,23 +153,22 @@ public class CheckManager {
|
||||
.build();
|
||||
|
||||
blockPlaceCheck = new ImmutableClassToInstanceMap.Builder<BlockPlaceCheck>()
|
||||
.put(InventoryC.class, new InventoryC(player))
|
||||
.put(InvalidPlaceA.class, new InvalidPlaceA(player))
|
||||
.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))
|
||||
.put(PacketOrderN.class, new PacketOrderN(player))
|
||||
.put(PacketOrderO.class, new PacketOrderO(player))
|
||||
.put(RotationPlace.class, new RotationPlace(player))
|
||||
.put(DuplicateRotPlace.class, new DuplicateRotPlace(player))
|
||||
.put(LineOfSightPlace.class, new LineOfSightPlace(player))
|
||||
.put(GhostBlockMitigation.class, new GhostBlockMitigation(player))
|
||||
.build();
|
||||
|
||||
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))
|
||||
@@ -193,6 +179,7 @@ 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();
|
||||
|
||||
@@ -308,17 +295,11 @@ public class CheckManager {
|
||||
return (T) packetChecks.get(check);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends BlockPlaceCheck> T getBlockPlaceCheck(Class<T> check) {
|
||||
return (T) blockPlaceCheck.get(check);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends PacketCheck> T getPrePredictionCheck(Class<T> check) {
|
||||
return (T) prePredictionChecks.get(check);
|
||||
}
|
||||
|
||||
|
||||
private PacketEntityReplication packetEntityReplication = null;
|
||||
|
||||
public PacketEntityReplication getEntityReplication() {
|
||||
|
||||
@@ -70,12 +70,12 @@ public class DiscordManager implements Initable {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void sendAlert(GrimPlayer player, String verbose, String checkName, String violations) {
|
||||
public void sendAlert(GrimPlayer player, String verbose, String checkName, int violations) {
|
||||
if (client != null) {
|
||||
|
||||
String content = staticContent;
|
||||
content = content.replace("%check%", checkName);
|
||||
content = content.replace("%violations%", violations);
|
||||
content = content.replace("%violations%", Integer.toString(violations));
|
||||
content = GrimAPI.INSTANCE.getExternalAPI().replaceVariables(player, content, false);
|
||||
content = content.replace("_", "\\_");
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ 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;
|
||||
@@ -99,16 +98,14 @@ public class PunishmentManager implements ConfigReloadable {
|
||||
}
|
||||
}
|
||||
|
||||
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() + "";
|
||||
private String replaceAlertPlaceholders(String original, int vl, PunishGroup group, Check check, String alertString, String verbose) {
|
||||
|
||||
original = MessageUtil.format(original
|
||||
.replace("[alert]", alertString)
|
||||
.replace("[proxy]", alertString)
|
||||
.replace("%check_name%", check.getDisplayName())
|
||||
.replace("%experimental%", check.isExperimental() ? experimentalSymbol : "")
|
||||
.replace("%vl%", vl)
|
||||
.replace("%vl%", Integer.toString(vl))
|
||||
.replace("%verbose%", verbose)
|
||||
.replace("%description%", check.getDescription())
|
||||
);
|
||||
@@ -124,12 +121,13 @@ public class PunishmentManager implements ConfigReloadable {
|
||||
// Check commands
|
||||
for (PunishGroup group : groups) {
|
||||
if (group.getChecks().contains(check)) {
|
||||
int violationCount = group.getViolations().size();
|
||||
final int vl = getViolations(group, check);
|
||||
final int violationCount = group.getViolations().size();
|
||||
for (ParsedCommand command : group.getCommands()) {
|
||||
String cmd = replaceAlertPlaceholders(command.getCommand(), group, check, alertString, verbose);
|
||||
String cmd = replaceAlertPlaceholders(command.getCommand(), vl, group, check, alertString, verbose);
|
||||
|
||||
// Verbose that prints all flags
|
||||
if (GrimAPI.INSTANCE.getAlertManager().getEnabledVerbose().size() > 0 && command.command.equals("[alert]")) {
|
||||
if (!GrimAPI.INSTANCE.getAlertManager().getEnabledVerbose().isEmpty() && command.command.equals("[alert]")) {
|
||||
sentDebug = true;
|
||||
for (Player bukkitPlayer : GrimAPI.INSTANCE.getAlertManager().getEnabledVerbose()) {
|
||||
bukkitPlayer.sendMessage(cmd);
|
||||
@@ -149,10 +147,9 @@ 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(), group, check, proxyAlertString, verbose));
|
||||
ProxyAlertMessenger.sendPluginMessage(replaceAlertPlaceholders(command.getCommand(), vl, group, check, proxyAlertString, verbose));
|
||||
} else {
|
||||
if (command.command.equals("[alert]")) {
|
||||
sentDebug = true;
|
||||
@@ -184,10 +181,19 @@ public class PunishmentManager implements ConfigReloadable {
|
||||
|
||||
group.violations.put(currentTime, check);
|
||||
// Remove violations older than the defined time in the config
|
||||
group.violations.long2ObjectEntrySet().removeIf(time -> currentTime - time.getLongKey() > group.removeViolationsAfter);
|
||||
group.violations.entrySet().removeIf(time -> currentTime - time.getKey() > 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 {
|
||||
@@ -196,7 +202,7 @@ class PunishGroup {
|
||||
@Getter
|
||||
List<ParsedCommand> commands;
|
||||
@Getter
|
||||
Long2ObjectOpenHashMap<Check> violations = new Long2ObjectOpenHashMap<>();
|
||||
public Map<Long, Check> violations = new HashMap<>();
|
||||
@Getter
|
||||
int removeViolationsAfter;
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
|
||||
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?
|
||||
@@ -156,12 +157,12 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
|
||||
VelocityData futureExplosion = player.checkManager.getExplosionHandler().getFutureExplosion();
|
||||
|
||||
// Velocity sets
|
||||
if (futureKb.getFirst() != null) {
|
||||
clientVel = futureKb.getSecond();
|
||||
if (futureKb.first() != null) {
|
||||
clientVel = futureKb.second();
|
||||
}
|
||||
|
||||
// Explosion adds
|
||||
if (futureExplosion != null && (futureKb.getFirst() == null || futureKb.getFirst().transaction < futureExplosion.transaction)) {
|
||||
if (futureExplosion != null && (futureKb.first() == null || futureKb.first().transaction < futureExplosion.transaction)) {
|
||||
clientVel.add(futureExplosion.vector);
|
||||
}
|
||||
|
||||
@@ -331,16 +332,16 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
|
||||
while (true) {
|
||||
Pair<Integer, Vector3d> teleportPos = player.vehicleData.vehicleTeleports.peek();
|
||||
if (teleportPos == null) break;
|
||||
if (lastTransaction < teleportPos.getFirst()) {
|
||||
if (lastTransaction < teleportPos.first()) {
|
||||
break;
|
||||
}
|
||||
|
||||
Vector3d position = teleportPos.getSecond();
|
||||
Vector3d position = teleportPos.second();
|
||||
if (position.getX() == x && position.getY() == y && position.getZ() == z) {
|
||||
player.vehicleData.vehicleTeleports.poll();
|
||||
|
||||
return true;
|
||||
} else if (lastTransaction > teleportPos.getFirst() + 1) {
|
||||
} else if (lastTransaction > teleportPos.first() + 1) {
|
||||
player.vehicleData.vehicleTeleports.poll();
|
||||
|
||||
// Vehicles have terrible netcode so just ignore it if the teleport wasn't from us setting the player back
|
||||
@@ -400,15 +401,15 @@ 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.isSet(RelativeFlag.X.getMask())) {
|
||||
if (flags.has(RelativeFlag.X)) {
|
||||
safePosition = safePosition.withX(safePosition.getX() + lastKnownGoodPosition.pos.getX());
|
||||
}
|
||||
|
||||
if (flags.isSet(RelativeFlag.Y.getMask())) {
|
||||
if (flags.has(RelativeFlag.Y)) {
|
||||
safePosition = safePosition.withY(safePosition.getY() + lastKnownGoodPosition.pos.getY());
|
||||
}
|
||||
|
||||
if (flags.isSet(RelativeFlag.Z.getMask())) {
|
||||
if (flags.has(RelativeFlag.Z)) {
|
||||
safePosition = safePosition.withZ(safePosition.getZ() + lastKnownGoodPosition.pos.getZ());
|
||||
}
|
||||
|
||||
|
||||
@@ -71,14 +71,8 @@ public class SpectateManager implements Initable {
|
||||
spectatingPlayers.remove(uuid);
|
||||
}
|
||||
|
||||
private static class PreviousState {
|
||||
public PreviousState(org.bukkit.GameMode gameMode, Location location) {
|
||||
this.gameMode = gameMode;
|
||||
this.location = location;
|
||||
}
|
||||
private record PreviousState(org.bukkit.GameMode gameMode, Location location) {
|
||||
|
||||
private final org.bukkit.GameMode gameMode;
|
||||
private final Location location;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import ac.grim.grimac.manager.tick.Tickable;
|
||||
import ac.grim.grimac.manager.tick.impl.ClientVersionSetter;
|
||||
import ac.grim.grimac.manager.tick.impl.ResetTick;
|
||||
import ac.grim.grimac.manager.tick.impl.TickInventory;
|
||||
import ac.grim.grimac.manager.tick.impl.UpdateChangedBlocksList;
|
||||
import com.google.common.collect.ClassToInstanceMap;
|
||||
import com.google.common.collect.ImmutableClassToInstanceMap;
|
||||
|
||||
@@ -23,7 +22,6 @@ public class TickManager {
|
||||
asyncTick = new ImmutableClassToInstanceMap.Builder<Tickable>()
|
||||
.put(ClientVersionSetter.class, new ClientVersionSetter()) // Async because permission lookups might take a while, depending on the plugin
|
||||
.put(TickInventory.class, new TickInventory()) // Async because I've never gotten an exception from this. It's probably safe.
|
||||
.put(UpdateChangedBlocksList.class, new UpdateChangedBlocksList())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
|
||||
GrimAPI.INSTANCE.getPlugin().getDataFolder().mkdirs();
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
upgrade();
|
||||
config.addSource(GrimAC.class, "config", getConfigFile("config.yml"));
|
||||
config.addSource(GrimAC.class, "messages", getConfigFile("messages.yml"));
|
||||
config.addSource(GrimAC.class, "discord", getConfigFile("discord.yml"));
|
||||
@@ -82,7 +81,7 @@ public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
|
||||
|
||||
configVersion = Integer.parseInt(configStringVersion);
|
||||
// TODO: Do we have to hardcode this?
|
||||
configString = configString.replaceAll("config-version: " + configStringVersion, "config-version: 10");
|
||||
configString = configString.replaceAll("config-version: " + configStringVersion, "config-version: 9");
|
||||
Files.write(config.toPath(), configString.getBytes());
|
||||
|
||||
upgradeModernConfig(config, configString, configVersion);
|
||||
@@ -124,9 +123,6 @@ public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
|
||||
if (configVersion < 9) {
|
||||
newOffsetHandlingAntiKB(config, configString);
|
||||
}
|
||||
if (configVersion < 10) {
|
||||
addInventoryPunishments();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLegacyTwoPointOne(File config) throws IOException {
|
||||
@@ -177,28 +173,6 @@ public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
|
||||
}
|
||||
}
|
||||
|
||||
private void addInventoryPunishments() {
|
||||
File config = new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), "punishments.yml");
|
||||
String configString;
|
||||
if (config.exists()) {
|
||||
try {
|
||||
configString = new String(Files.readAllBytes(config.toPath()));
|
||||
|
||||
// If it works, it isn't stupid. Only replace it if it exactly matches the default config.
|
||||
String reachSection = " Reach:";
|
||||
String inventorySection = " Inventory:\n remove-violations-after: 300\n checks:\n - \"Inventory\"\n commands:\n - \"10:10 [alert]\"\n - \"20:20 [webhook]\"\n - \"20:20 [proxy]\"\n";
|
||||
|
||||
int index = configString.indexOf(reachSection);
|
||||
if (index != -1) {
|
||||
configString = configString.substring(0, index) + inventorySection + configString.substring(index);
|
||||
}
|
||||
|
||||
Files.write(config.toPath(), configString.getBytes());
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fixBadPacketsAndAdjustPingConfig(File config, String configString) {
|
||||
try {
|
||||
configString = configString.replaceAll("max-ping: \\d+", "max-transaction-time: 60");
|
||||
|
||||
@@ -2,13 +2,14 @@ package ac.grim.grimac.manager.init.start;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import io.github.retrooper.packetevents.bstats.bukkit.Metrics;
|
||||
|
||||
public class BStats implements Initable {
|
||||
@Override
|
||||
public void start() {
|
||||
int pluginId = 12820; // <-- Replace with the id of your plugin!
|
||||
try {
|
||||
new io.github.retrooper.packetevents.bstats.bukkit.Metrics(GrimAPI.INSTANCE.getPlugin(), pluginId);
|
||||
new Metrics(GrimAPI.INSTANCE.getPlugin(), pluginId);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,5 +23,7 @@ public class CommandRegister implements Initable {
|
||||
commandManager.registerCommand(new GrimStopSpectating());
|
||||
commandManager.registerCommand(new GrimLog());
|
||||
commandManager.registerCommand(new GrimVerbose());
|
||||
|
||||
commandManager.getCommandCompletions().registerCompletion("stopspectating", GrimStopSpectating.completionHandler);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ public class PacketManager implements Initable {
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketConfigurationListener());
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerJoinQuit());
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketPingListener());
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerWindow());
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerDigging());
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerAttack());
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketEntityAction());
|
||||
|
||||
@@ -13,7 +13,6 @@ 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 com.github.retrooper.packetevents.util.Vector3d;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@@ -3,7 +3,10 @@ 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;
|
||||
@@ -30,6 +33,10 @@ 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();
|
||||
@@ -42,7 +49,7 @@ public class TickEndEvent implements Initable {
|
||||
// but whatever. At least plugins can't break it, I guess.
|
||||
//
|
||||
// Pledge injects into another list, so we should be safe injecting into this one
|
||||
List<?> wrapper = Collections.synchronizedList(new HookedListWrapper<Object>(endOfTickObject) {
|
||||
List<?> wrapper = Collections.synchronizedList(new HookedListWrapper<>(endOfTickObject) {
|
||||
@Override
|
||||
public void onIterator() {
|
||||
hasTicked = true;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package ac.grim.grimac.manager.tick.impl;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.manager.tick.Tickable;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
|
||||
|
||||
public class UpdateChangedBlocksList implements Tickable {
|
||||
@Override
|
||||
public void tick() {
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,7 @@ import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.impl.aim.processor.AimProcessor;
|
||||
import ac.grim.grimac.checks.impl.misc.ClientBrand;
|
||||
import ac.grim.grimac.checks.impl.packetorder.PacketOrderD;
|
||||
import ac.grim.grimac.checks.impl.packetorder.PacketOrderProcessor;
|
||||
import ac.grim.grimac.checks.impl.misc.TransactionOrder;
|
||||
import ac.grim.grimac.events.packets.CheckManagerListener;
|
||||
import ac.grim.grimac.manager.*;
|
||||
import ac.grim.grimac.predictionengine.MovementCheckRunner;
|
||||
@@ -22,7 +21,6 @@ import ac.grim.grimac.utils.data.packetentity.PacketEntitySelf;
|
||||
import ac.grim.grimac.utils.data.tags.SyncedTags;
|
||||
import ac.grim.grimac.utils.enums.FluidTag;
|
||||
import ac.grim.grimac.utils.enums.Pose;
|
||||
import ac.grim.grimac.utils.inventory.InventoryDesyncStatus;
|
||||
import ac.grim.grimac.utils.latency.*;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import ac.grim.grimac.utils.math.TrigHandler;
|
||||
@@ -66,7 +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;
|
||||
import static ac.grim.grimac.utils.data.VectorData.VectorType.Normal;
|
||||
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
|
||||
|
||||
@@ -98,7 +95,6 @@ public class GrimPlayer implements GrimUser {
|
||||
// End manager like classes
|
||||
public ac.grim.grimac.utils.vector.Vector3D clientVelocity = newVector3D();
|
||||
PacketTracker packetTracker;
|
||||
public final PacketOrderProcessor packetOrderProcessor = new PacketOrderProcessor(this);
|
||||
private long transactionPing = 0;
|
||||
public long lastTransSent = 0;
|
||||
public long lastTransReceived = 0;
|
||||
@@ -220,9 +216,6 @@ public class GrimPlayer implements GrimUser {
|
||||
}
|
||||
|
||||
public int totalFlyingPacketsSent;
|
||||
public boolean hasInventoryOpen;
|
||||
public long lastInventoryOpen;
|
||||
public InventoryDesyncStatus inventoryDesyncStatus;
|
||||
public Queue<BlockPlaceSnapshot> placeUseItemPackets = new LinkedBlockingQueue<>();
|
||||
// This variable is for support with test servers that want to be able to disable grim
|
||||
// Grim disabler 2022 still working!
|
||||
@@ -252,6 +245,7 @@ public class GrimPlayer implements GrimUser {
|
||||
|
||||
packetStateData = new PacketStateData();
|
||||
|
||||
uncertaintyHandler.riptideEntities.add(0);
|
||||
uncertaintyHandler.collidingEntities.add(0);
|
||||
|
||||
if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) {
|
||||
@@ -302,7 +296,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.collidingEntities) > 0) {
|
||||
if (riptideSpinAttackTicks >= 0 && Collections.max(uncertaintyHandler.riptideEntities) > 0) {
|
||||
possibleMovements.add(new VectorData(clientVelocity.clone().multiply(-0.2), VectorData.VectorType.Trident));
|
||||
}
|
||||
|
||||
@@ -336,7 +330,7 @@ public class GrimPlayer implements GrimUser {
|
||||
boolean hasID = false;
|
||||
int skipped = 0;
|
||||
for (Pair<Short, Long> iterator : transactionsSent) {
|
||||
if (iterator.getFirst() == id) {
|
||||
if (iterator.first() == id) {
|
||||
hasID = true;
|
||||
break;
|
||||
}
|
||||
@@ -348,7 +342,7 @@ public class GrimPlayer implements GrimUser {
|
||||
if (packetTracker != null) packetTracker.setIntervalPackets(packetTracker.getIntervalPackets() - 1);
|
||||
|
||||
if (skipped > 0 && System.currentTimeMillis() - joinTime > 5000)
|
||||
checkManager.getPacketCheck(PacketOrderD.class).flagAndAlert("skipped: " + skipped);
|
||||
checkManager.getPacketCheck(TransactionOrder.class).flagAndAlert("skipped: " + skipped);
|
||||
|
||||
do {
|
||||
data = transactionsSent.poll();
|
||||
@@ -357,9 +351,9 @@ public class GrimPlayer implements GrimUser {
|
||||
|
||||
lastTransactionReceived.incrementAndGet();
|
||||
lastTransReceived = System.currentTimeMillis();
|
||||
transactionPing = (System.nanoTime() - data.getSecond());
|
||||
playerClockAtLeast = data.getSecond();
|
||||
} while (data.getFirst() != id);
|
||||
transactionPing = (System.nanoTime() - data.second());
|
||||
playerClockAtLeast = data.second();
|
||||
} while (data.first() != id);
|
||||
|
||||
// A transaction means a new tick, so apply any block places
|
||||
CheckManagerListener.handleQueuedPlaces(this, false, 0, 0, System.currentTimeMillis());
|
||||
@@ -367,7 +361,7 @@ public class GrimPlayer implements GrimUser {
|
||||
}
|
||||
|
||||
// Were we the ones who sent the packet?
|
||||
return data != null && data.getFirst() == id;
|
||||
return data != null && data.first() == id;
|
||||
}
|
||||
|
||||
public void baseTickAddWaterPushing(ac.grim.grimac.utils.vector.Vector3D vector) {
|
||||
@@ -453,8 +447,7 @@ public class GrimPlayer implements GrimUser {
|
||||
|
||||
public void disconnect(Component reason) {
|
||||
String textReason;
|
||||
if (reason instanceof TranslatableComponent) {
|
||||
TranslatableComponent translatableComponent = (TranslatableComponent) reason;
|
||||
if (reason instanceof TranslatableComponent translatableComponent) {
|
||||
textReason = translatableComponent.key();
|
||||
} else {
|
||||
textReason = LegacyComponentSerializer.legacySection().serialize(reason);
|
||||
@@ -576,11 +569,18 @@ 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) {
|
||||
return (getClientVersion().isOlderThan(ClientVersion.V_1_9)
|
||||
|| !uncertaintyHandler.lastPointThree.hasOccurredSince(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)
|
||||
|| compensatedEntities.getSelf().inVehicle();
|
||||
}
|
||||
|
||||
public boolean inVehicle() {
|
||||
return compensatedEntities.getSelf().inVehicle();
|
||||
}
|
||||
|
||||
public boolean canThePlayerBeCloseToZeroMovement(int ticks) {
|
||||
return (!uncertaintyHandler.lastPointThree.hasOccurredSince(ticks));
|
||||
}
|
||||
@@ -708,6 +708,11 @@ 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);
|
||||
@@ -762,6 +767,7 @@ 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) {
|
||||
@@ -770,6 +776,7 @@ 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
|
||||
|
||||
@@ -40,7 +40,6 @@ import com.github.retrooper.packetevents.protocol.world.states.defaulttags.Block
|
||||
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;
|
||||
import static ac.grim.grimac.utils.data.VectorData.VectorType.Dead;
|
||||
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
|
||||
|
||||
@@ -262,8 +261,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
// When in control of the entity, the player sets the entity position to their current position
|
||||
riding.setPositionRaw(GetBoundingBox.getPacketEntityBoundingBox(player, player.x, player.y, player.z, riding));
|
||||
|
||||
if (riding instanceof PacketEntityTrackXRot) {
|
||||
PacketEntityTrackXRot boat = (PacketEntityTrackXRot) riding;
|
||||
if (riding instanceof PacketEntityTrackXRot boat) {
|
||||
boat.packetYaw = player.xRot;
|
||||
boat.interpYaw = player.xRot;
|
||||
boat.steps = 0;
|
||||
@@ -343,7 +341,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
boolean clientClaimsRiptide = player.packetStateData.tryingToRiptide;
|
||||
if (player.packetStateData.tryingToRiptide) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
boolean isInWater = player.compensatedWorld.isRaining || Collisions.hasMaterial(player, player.boundingBox.copy().expand(0.1f), (block) -> Materials.isWater(CompensatedWorld.blockVersion, block.getFirst()));
|
||||
boolean isInWater = player.compensatedWorld.isRaining || Collisions.hasMaterial(player, player.boundingBox.copy().expand(0.1f), (block) -> Materials.isWater(CompensatedWorld.blockVersion, block.first()));
|
||||
|
||||
if (currentTime - player.packetStateData.lastRiptide < 450 || !isInWater) {
|
||||
player.packetStateData.tryingToRiptide = false;
|
||||
@@ -352,9 +350,9 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
player.packetStateData.lastRiptide = currentTime;
|
||||
}
|
||||
|
||||
SimpleCollisionBox steppingOnBB = GetBoundingBox.getCollisionBoxForPlayer(player, player.x, player.y, player.z).expand(0.03).offset(0, -1, 0);
|
||||
SimpleCollisionBox steppingOnBB = GetBoundingBox.getCollisionBoxForPlayer(player, player.x, player.y, player.z).expand(player.getMovementThreshold()).offset(0, -1, 0);
|
||||
Collisions.hasMaterial(player, steppingOnBB, (pair) -> {
|
||||
WrappedBlockState data = pair.getFirst();
|
||||
WrappedBlockState data = pair.first();
|
||||
if (data.getType() == StateTypes.SLIME_BLOCK && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8)) {
|
||||
player.uncertaintyHandler.isSteppingOnSlime = true;
|
||||
player.uncertaintyHandler.isSteppingOnBouncyBlock = true;
|
||||
@@ -400,8 +398,8 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
|
||||
player.uncertaintyHandler.isNearGlitchyBlock = player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
|
||||
&& Collisions.hasMaterial(player, expandedBB.copy().expand(0.2),
|
||||
checkData -> BlockTags.ANVIL.contains(checkData.getFirst().getType())
|
||||
|| checkData.getFirst().getType() == StateTypes.CHEST || checkData.getFirst().getType() == StateTypes.TRAPPED_CHEST);
|
||||
checkData -> BlockTags.ANVIL.contains(checkData.first().getType())
|
||||
|| checkData.first().getType() == StateTypes.CHEST || checkData.first().getType() == StateTypes.TRAPPED_CHEST);
|
||||
|
||||
player.uncertaintyHandler.isOrWasNearGlitchyBlock = isGlitchy || player.uncertaintyHandler.isNearGlitchyBlock;
|
||||
player.uncertaintyHandler.checkForHardCollision();
|
||||
@@ -416,8 +414,8 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
player.uncertaintyHandler.lastUnderwaterFlyingHack.reset();
|
||||
}
|
||||
|
||||
boolean couldBeStuckSpeed = Collisions.checkStuckSpeed(player, 0.03);
|
||||
boolean couldLeaveStuckSpeed = player.isPointThree() && Collisions.checkStuckSpeed(player, -0.03);
|
||||
boolean couldBeStuckSpeed = Collisions.checkStuckSpeed(player, player.getMovementThreshold());
|
||||
boolean couldLeaveStuckSpeed = player.isPointThree() && Collisions.checkStuckSpeed(player, -player.getMovementThreshold());
|
||||
player.uncertaintyHandler.claimingLeftStuckSpeed = !player.compensatedEntities.getSelf().inVehicle() && player.stuckSpeedMultiplier.getX() < 1 && !couldLeaveStuckSpeed;
|
||||
|
||||
if (couldBeStuckSpeed) {
|
||||
@@ -433,7 +431,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
// 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) {
|
||||
} else if (player.disableGrim || (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_8) && player.gamemode == GameMode.SPECTATOR) || player.isFlying || (player.isExemptElytra() && player.isGliding)) {
|
||||
// We could technically check spectator but what's the point...
|
||||
// Added complexity to analyze a gamemode used mainly by moderators
|
||||
//
|
||||
@@ -643,5 +641,4 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
public void onReload(ConfigManager config) {
|
||||
allowSprintJumpingWithElytra = config.getBooleanElse("exploit.allow-sprint-jumping-when-using-elytra", true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -154,7 +154,7 @@ public class PlayerBaseTick {
|
||||
|
||||
// Might be null after respawn?
|
||||
final Optional<WrapperPlayServerUpdateAttributes.Property> property = playerSpeed.property();
|
||||
if (!property.isPresent()) return;
|
||||
if (property.isEmpty()) return;
|
||||
|
||||
// The client first desync's this attribute
|
||||
property.get().getModifiers().removeIf(modifier -> modifier.getUUID().equals(CompensatedEntities.SNOW_MODIFIER_UUID) || modifier.getName().getKey().equals("powder_snow"));
|
||||
@@ -271,13 +271,14 @@ public class PlayerBaseTick {
|
||||
|
||||
|
||||
private void moveTowardsClosestSpace(double xPosition, double zPosition) {
|
||||
player.boundingBox = player.boundingBox.expand(0.03, 0, 0.03); // 0.03... thanks mojang!
|
||||
double movementThreshold = player.getMovementThreshold();
|
||||
player.boundingBox = player.boundingBox.expand(movementThreshold, 0, movementThreshold); // 0.03... thanks mojang!
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) {
|
||||
moveTowardsClosestSpaceModern(xPosition, zPosition);
|
||||
} else {
|
||||
moveTowardsClosestSpaceLegacy(xPosition, zPosition);
|
||||
}
|
||||
player.boundingBox = player.boundingBox.expand(-0.03, 0, -0.03);
|
||||
player.boundingBox = player.boundingBox.expand(-movementThreshold, 0, -movementThreshold);
|
||||
}
|
||||
|
||||
// Mojang is incompetent and this will push the player out a lot when using elytras
|
||||
@@ -363,22 +364,12 @@ public class PlayerBaseTick {
|
||||
double d7 = direction2 == BlockFace.WEST || direction2 == BlockFace.EAST ? relativeXMovement : relativeZMovement;
|
||||
d6 = direction2 == BlockFace.EAST || direction2 == BlockFace.SOUTH ? 1.0 - d7 : d7;
|
||||
// d7 and d6 flip the movement direction based on desired movement direction
|
||||
boolean doesSuffocate;
|
||||
switch (direction2) {
|
||||
case EAST:
|
||||
doesSuffocate = this.suffocatesAt(blockX + 1, blockZ);
|
||||
break;
|
||||
case WEST:
|
||||
doesSuffocate = this.suffocatesAt(blockX - 1, blockZ);
|
||||
break;
|
||||
case NORTH:
|
||||
doesSuffocate = this.suffocatesAt(blockX, blockZ - 1);
|
||||
break;
|
||||
default:
|
||||
case SOUTH:
|
||||
doesSuffocate = this.suffocatesAt(blockX, blockZ + 1);
|
||||
break;
|
||||
}
|
||||
boolean doesSuffocate = switch (direction2) {
|
||||
case EAST -> this.suffocatesAt(blockX + 1, blockZ);
|
||||
case WEST -> this.suffocatesAt(blockX - 1, blockZ);
|
||||
case NORTH -> this.suffocatesAt(blockX, blockZ - 1);
|
||||
default -> this.suffocatesAt(blockX, blockZ + 1);
|
||||
};
|
||||
|
||||
if (d6 >= lowestValue || doesSuffocate) continue;
|
||||
lowestValue = d6;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package ac.grim.grimac.predictionengine;
|
||||
|
||||
import ac.grim.grimac.checks.impl.combat.Reach;
|
||||
import ac.grim.grimac.checks.impl.scaffolding.LineOfSightPlace;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.predictionengine.predictions.PredictionEngine;
|
||||
import ac.grim.grimac.utils.collisions.CollisionData;
|
||||
@@ -18,7 +16,6 @@ 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 com.github.retrooper.packetevents.util.Vector3i;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import ac.grim.grimac.utils.vector.Vector3D;
|
||||
@@ -109,7 +106,6 @@ public class PointThreeEstimator {
|
||||
private boolean isNearHorizontalFlowingLiquid = false; // We can't calculate the direction, only a toggle
|
||||
private boolean isNearVerticalFlowingLiquid = false; // We can't calculate exact values, once again a toggle
|
||||
private boolean isNearBubbleColumn = false; // We can't calculate exact values once again
|
||||
public boolean isNearNetherPortal = false; // We can't calculate exact values once again
|
||||
|
||||
private int maxPositiveLevitation = Integer.MIN_VALUE; // Positive potion effects [0, 128]
|
||||
private int minNegativeLevitation = Integer.MAX_VALUE; // Negative potion effects [-127, -1]r
|
||||
@@ -133,12 +129,13 @@ public class PointThreeEstimator {
|
||||
|
||||
// Calculate head hitters. Take a shortcut by checking if the player doesn't intersect with this block, but does
|
||||
// when the player vertically moves upwards by 0.03! This is equivalent to the move method, but MUCH faster.
|
||||
SimpleCollisionBox slightlyExpanded = normalBox.copy().expand(0.03, 0, 0.03);
|
||||
if (!slightlyExpanded.isIntersected(data) && slightlyExpanded.offset(0, 0.03, 0).isIntersected(data)) {
|
||||
double movementThreshold = player.getMovementThreshold();
|
||||
SimpleCollisionBox slightlyExpanded = normalBox.copy().expand(movementThreshold, 0, movementThreshold);
|
||||
if (!slightlyExpanded.isIntersected(data) && slightlyExpanded.offset(0, movementThreshold, 0).isIntersected(data)) {
|
||||
headHitter = true;
|
||||
}
|
||||
|
||||
SimpleCollisionBox pointThreeBox = GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.x, player.y - 0.03, player.z, 0.66f, 1.86f);
|
||||
SimpleCollisionBox pointThreeBox = GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.x, player.y - movementThreshold, player.z, 0.66f, 1.86f);
|
||||
if ((Materials.isWater(player.getClientVersion(), state) || stateType == StateTypes.LAVA) &&
|
||||
pointThreeBox.isIntersected(new SimpleCollisionBox(x, y, z))) {
|
||||
|
||||
@@ -157,10 +154,6 @@ public class PointThreeEstimator {
|
||||
isNearFluid = true;
|
||||
}
|
||||
|
||||
player.checkManager.getPacketCheck(Reach.class).handleBlockChange(new Vector3i(x, y, z), state);
|
||||
player.checkManager.getBlockPlaceCheck(LineOfSightPlace.class).handleBlockChange(new Vector3i(x, y, z), state);
|
||||
|
||||
|
||||
if (pointThreeBox.isIntersected(new SimpleCollisionBox(x, y, z))) {
|
||||
// https://github.com/MWHunter/Grim/issues/613
|
||||
int controllingEntityId = player.compensatedEntities.getSelf().inVehicle() ? player.getRidingVehicleId() : player.entityID;
|
||||
@@ -222,7 +215,8 @@ public class PointThreeEstimator {
|
||||
}
|
||||
|
||||
public void endOfTickTick() {
|
||||
SimpleCollisionBox pointThreeBox = GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.x, player.y - 0.03, player.z, 0.66f, 1.86f);
|
||||
double movementThreshold = player.getMovementThreshold();
|
||||
SimpleCollisionBox pointThreeBox = GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.x, player.y - movementThreshold, player.z, 0.66f, 1.86f);
|
||||
|
||||
// Determine the head hitter using the current Y position
|
||||
SimpleCollisionBox oldBB = player.boundingBox;
|
||||
@@ -232,7 +226,7 @@ public class PointThreeEstimator {
|
||||
for (float sizes : (player.skippedTickInActualMovement ? new float[]{0.6f, 1.5f, 1.8f} : new float[]{player.pose.height})) {
|
||||
// Try to limit collisions to be as small as possible, for maximum performance
|
||||
player.boundingBox = GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.x, player.y + (sizes - 0.01f), player.z, 0.6f, 0.01f);
|
||||
headHitter = headHitter || Collisions.collide(player, 0, 0.03, 0).getY() != 0.03;
|
||||
headHitter = headHitter || Collisions.collide(player, 0, movementThreshold, 0).getY() != movementThreshold;
|
||||
}
|
||||
|
||||
player.boundingBox = oldBB;
|
||||
@@ -255,32 +249,27 @@ public class PointThreeEstimator {
|
||||
isNearClimbable = false;
|
||||
isNearBubbleColumn = false;
|
||||
isNearFluid = false;
|
||||
isNearNetherPortal = false;
|
||||
|
||||
// Check for flowing water
|
||||
Collisions.hasMaterial(player, pointThreeBox, (pair) -> {
|
||||
final WrappedBlockState state = pair.getFirst();
|
||||
final WrappedBlockState state = pair.first();
|
||||
final StateType stateType = state.getType();
|
||||
if (player.tagManager.block(SyncedTags.CLIMBABLE).contains(stateType) || (stateType == StateTypes.POWDER_SNOW && !player.compensatedEntities.getSelf().inVehicle() && player.getInventory().getBoots().getType() == ItemTypes.LEATHER_BOOTS)) {
|
||||
isNearClimbable = true;
|
||||
}
|
||||
|
||||
if (BlockTags.TRAPDOORS.contains(stateType)) {
|
||||
isNearClimbable = isNearClimbable || Collisions.trapdoorUsableAsLadder(player, pair.getSecond().getX(), pair.getSecond().getY(), pair.getSecond().getZ(), state);
|
||||
isNearClimbable = isNearClimbable || Collisions.trapdoorUsableAsLadder(player, pair.second().getX(), pair.second().getY(), pair.second().getZ(), state);
|
||||
}
|
||||
|
||||
if (stateType == StateTypes.BUBBLE_COLUMN) {
|
||||
isNearBubbleColumn = true;
|
||||
}
|
||||
|
||||
if (Materials.isWater(player.getClientVersion(), pair.getFirst()) || pair.getFirst().getType() == StateTypes.LAVA) {
|
||||
if (Materials.isWater(player.getClientVersion(), pair.first()) || pair.first().getType() == StateTypes.LAVA) {
|
||||
isNearFluid = true;
|
||||
}
|
||||
|
||||
if (state.getType() == StateTypes.NETHER_PORTAL) {
|
||||
isNearNetherPortal = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
@@ -327,7 +316,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.getClientVersion().isOlderThan(ClientVersion.V_1_9) && player.packetStateData.didLastMovementIncludePosition && !player.uncertaintyHandler.isSteppingOnSlime) {
|
||||
if ((player.supportsEndTick() || player.getClientVersion().isOlderThan(ClientVersion.V_1_9)) && player.packetStateData.didLastMovementIncludePosition && !player.uncertaintyHandler.isSteppingOnSlime) {
|
||||
return false; // Last packet included a position so not 0.03
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,10 @@ 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?
|
||||
// How many entities are within 0.5 blocks of the player's bounding box that are pushable?
|
||||
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;
|
||||
@@ -305,8 +307,7 @@ public class UncertaintyHandler {
|
||||
// This is the end of that section.
|
||||
|
||||
// I can't figure out how the client exactly tracks boost time
|
||||
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityRideable) {
|
||||
PacketEntityRideable vehicle = (PacketEntityRideable) player.compensatedEntities.getSelf().getRiding();
|
||||
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityRideable vehicle) {
|
||||
if (vehicle.currentBoostTime < vehicle.boostTimeMax + 20)
|
||||
offset -= 0.01;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ 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()) {
|
||||
@@ -54,16 +55,23 @@ public class MovementTicker {
|
||||
final TeamHandler teamHandler = player.checkManager.getPacketCheck(TeamHandler.class);
|
||||
|
||||
for (PacketEntity entity : player.compensatedEntities.entityMap.values()) {
|
||||
if (!entity.isPushable())
|
||||
continue;
|
||||
// TODO actually handle entity collisions instead of this awfulness
|
||||
SimpleCollisionBox entityBox = entity.getPossibleCollisionBoxes();
|
||||
|
||||
// 1.9+ player on 1.8- server with ViaVersion prevent-collision disabled.
|
||||
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;
|
||||
|
||||
SimpleCollisionBox entityBox = entity.getPossibleCollisionBoxes();
|
||||
if (!entity.isPushable())
|
||||
continue;
|
||||
|
||||
if (playerBox.isCollided(entityBox)) {
|
||||
if (isCollided) {
|
||||
possibleCollidingEntities++;
|
||||
}
|
||||
}
|
||||
@@ -76,6 +84,7 @@ public class MovementTicker {
|
||||
player.uncertaintyHandler.yPositiveUncertainty += 0.05;
|
||||
}
|
||||
|
||||
player.uncertaintyHandler.riptideEntities.add(possibleRiptideEntities);
|
||||
player.uncertaintyHandler.collidingEntities.add(possibleCollidingEntities);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ 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 ac.grim.grimac.utils.vector.Vector3D;
|
||||
|
||||
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ 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 ac.grim.grimac.utils.vector.Vector3D;
|
||||
|
||||
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ 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 ac.grim.grimac.utils.vector.Vector3D;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ 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,13 +13,11 @@ 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 java.util.*;
|
||||
|
||||
import static ac.grim.grimac.utils.data.VectorData.VectorType;
|
||||
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;
|
||||
@@ -122,7 +121,9 @@ public class PredictionEngine {
|
||||
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;
|
||||
|
||||
@@ -144,8 +145,8 @@ public class PredictionEngine {
|
||||
|
||||
// Returns pair of primary push movement, and then outputvel
|
||||
Pair<Vector3D, Vector3D> output = doSeekingWallCollisions(player, primaryPushMovement, originalClientVel, clientVelAfterInput);
|
||||
primaryPushMovement = output.getFirst();
|
||||
Vector3D outputVel = clampMovementToHardBorder(player, output.getSecond());
|
||||
primaryPushMovement = output.first();
|
||||
Vector3D outputVel = clampMovementToHardBorder(player, output.second());
|
||||
|
||||
double resultAccuracy = outputVel.distanceSquared(player.actualMovement);
|
||||
|
||||
@@ -422,63 +423,52 @@ public class PredictionEngine {
|
||||
// Order priority (to avoid false positives and false flagging future predictions):
|
||||
// Knockback and explosions
|
||||
// 0.03 ticks
|
||||
// Movement without input
|
||||
// Normal movement
|
||||
// First bread knockback and explosions
|
||||
// Flagging groundspoof
|
||||
// Flagging flip items
|
||||
if (a.isExplosion())
|
||||
aScore -= 10;
|
||||
aScore -= 5;
|
||||
|
||||
if (a.isKnockback())
|
||||
aScore -= 10;
|
||||
aScore -= 5;
|
||||
|
||||
if (b.isExplosion())
|
||||
bScore -= 10;
|
||||
bScore -= 5;
|
||||
|
||||
if (b.isKnockback())
|
||||
bScore -= 10;
|
||||
bScore -= 5;
|
||||
|
||||
if (a.isFirstBreadExplosion())
|
||||
aScore += 2;
|
||||
aScore += 1;
|
||||
|
||||
if (b.isFirstBreadExplosion())
|
||||
bScore += 2;
|
||||
bScore += 1;
|
||||
|
||||
if (a.isFirstBreadKb())
|
||||
aScore += 2;
|
||||
aScore += 1;
|
||||
|
||||
if (b.isFirstBreadKb())
|
||||
bScore += 2;
|
||||
bScore += 1;
|
||||
|
||||
if (a.isFlipItem())
|
||||
aScore += 6;
|
||||
aScore += 3;
|
||||
|
||||
if (b.isFlipItem())
|
||||
bScore += 6;
|
||||
bScore += 3;
|
||||
|
||||
if (a.isZeroPointZeroThree())
|
||||
aScore -= 2;
|
||||
|
||||
if (b.isZeroPointZeroThree())
|
||||
bScore -= 2;
|
||||
|
||||
if (a.isWithInput() || a.isJump())
|
||||
aScore += 1;
|
||||
else
|
||||
aScore -= 1;
|
||||
|
||||
if (b.isWithInput() || b.isJump())
|
||||
bScore += 1;
|
||||
else
|
||||
if (b.isZeroPointZeroThree())
|
||||
bScore -= 1;
|
||||
|
||||
// If the player is on the ground but the vector leads the player off the ground
|
||||
if ((player.compensatedEntities.getSelf().inVehicle() ? player.clientControlledVerticalCollision : player.onGround) && a.vector.getY() >= 0)
|
||||
aScore += 4;
|
||||
aScore += 2;
|
||||
|
||||
if ((player.compensatedEntities.getSelf().inVehicle() ? player.clientControlledVerticalCollision : player.onGround) && b.vector.getY() >= 0)
|
||||
bScore += 4;
|
||||
bScore += 2;
|
||||
|
||||
if (aScore != bScore)
|
||||
return Integer.compare(aScore, bScore);
|
||||
@@ -722,7 +712,36 @@ 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 zMin = player.isSprinting && !player.isSwimming ? 1 : -1;
|
||||
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--;
|
||||
}
|
||||
}
|
||||
|
||||
for (int loopSlowed = 0; loopSlowed <= 1; loopSlowed++) {
|
||||
// Loop twice for the using item status if the player is using a trident
|
||||
@@ -734,9 +753,11 @@ public class PredictionEngine {
|
||||
for (VectorData possibleLastTickOutput : possibleVectors) {
|
||||
// Only do this when there is tick skipping
|
||||
if (loopSlowed == 1 && !possibleLastTickOutput.isZeroPointZeroThree()) continue;
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = zMin; z <= 1; z++) {
|
||||
VectorData result = new VectorData.MoveVectorData(possibleLastTickOutput.vector.clone().add(getMovementResultFromInput(player, transformInputsToVector(player, newVector3D(x, 0, z)), speed, player.xRot)), possibleLastTickOutput, VectorData.VectorType.InputResult, x, z);
|
||||
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);
|
||||
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
|
||||
|
||||
@@ -4,8 +4,6 @@ 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 com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import ac.grim.grimac.utils.vector.Vector3D;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
+5
-2
@@ -3,7 +3,6 @@ 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;
|
||||
@@ -43,6 +42,10 @@ 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();
|
||||
|
||||
@@ -53,7 +56,7 @@ public class PredictionEngineNormal extends PredictionEngine {
|
||||
// And 0.03 didn't affect onGround status
|
||||
// The player cannot jump
|
||||
final OptionalInt jumpBoost = player.compensatedEntities.getPotionLevelForPlayer(PotionTypes.JUMP_BOOST);
|
||||
if (((!jumpBoost.isPresent() || jumpBoost.getAsInt() >= 0) && player.onGround) || !player.lastOnGround)
|
||||
if (((jumpBoost.isEmpty() || jumpBoost.getAsInt() >= 0) && player.onGround) || !player.lastOnGround)
|
||||
return;
|
||||
|
||||
JumpPower.jumpFromGround(player, jump);
|
||||
|
||||
@@ -14,7 +14,6 @@ import ac.grim.grimac.utils.vector.Vector3D;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static ac.grim.grimac.utils.data.VectorData.VectorType;
|
||||
import static ac.grim.grimac.utils.data.VectorData.VectorType.SwimmingSpace;
|
||||
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
|
||||
|
||||
|
||||
Loaded 100 of 171 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user