added files.

This commit is contained in:
nitrogenoliquido committed 2026-11-01 21:25:46 -05:00
commit 277c85eacd
150 files changed
+16138

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
.gradle/
build/
.idea/
*.iml
+44
View File
@@ -0,0 +1,44 @@
<p align="center">
<img src="assets/ss.png" alt="Skid Solutions Banner" width="350" />
<br>
<font size="6"><b>OpenAAC5</b></font>
<br>
<font size="3">by Skid Solutions</font>
</p>
---
<p align="center">
<a href="https://discord.gg/AEwatvnvSf">https://discord.gg/AEwatvnvSf</a>
</p>
<p align="center">
<img src="assets/jak.jpg" alt="jak" height="150" />
<img src="assets/hack.jpg" alt="hack" height="150" />
<img src="assets/deobf2.png" alt="deobf2" height="150" />
<img src="assets/deobf.jpg" alt="deobf" height="150" />
</p>
---
## How to build
### Prerequisites
- **Java Development Kit**: JDK 17 (the Gradle wrapper 8.14.3 does not run on newer JDKs)
---
### Building AAC5
Run from this folder:
```powershell
$env:JAVA_HOME = "C:\Program Files\Java\jdk-17"
.\gradlew.bat clean build
```
Generated `build/libs/`:
- `AAC5-5.2.0-java17.jar`
- `AAC5-5.2.0-plain.jar`
- `AAC5-5.2.0-sources.jar`
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

+124
View File
@@ -0,0 +1,124 @@
plugins {
id 'java'
id 'idea'
id 'eclipse'
id 'com.gradleup.shadow' version '8.3.8'
}
group = 'me.konsolas.aac'
version = '5.2.0'
def javaVersion = 17
repositories {
mavenCentral()
maven { url = uri('https://hub.spigotmc.org/nexus/content/repositories/snapshots/') }
}
configurations {
apiGenerator
}
def generatorClasses = layout.buildDirectory.dir('api-generator/classes')
tasks.register('compileApiGenerator', JavaCompile) {
source = files('gradle/GenerateCompileApis.java')
classpath = configurations.apiGenerator
destinationDirectory = generatorClasses
javaCompiler = javaToolchains.compilerFor { languageVersion = JavaLanguageVersion.of(javaVersion) }
options.release = javaVersion
options.encoding = 'UTF-8'
}
tasks.register('generateCompileApis', JavaExec) {
group = 'build setup'
description = 'Generates compile-only API headers from text declarations.'
dependsOn tasks.named('compileApiGenerator')
inputs.dir('gradle/api-signatures')
outputs.dir(layout.buildDirectory.dir('compile-apis'))
classpath = files(generatorClasses) + configurations.apiGenerator
javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(javaVersion) }
mainClass = 'GenerateCompileApis'
maxHeapSize = '2g'
args file('gradle/api-signatures').absolutePath, layout.buildDirectory.dir('compile-apis').get().asFile.absolutePath
}
def compileApi = { String name ->
files(layout.buildDirectory.file("compile-apis/${name}.jar")).builtBy(tasks.named('generateCompileApis'))
}
tasks.register('prepareIde') {
group = 'ide'
description = 'Generates the compile-only API headers used by the IDE import.'
dependsOn tasks.named('generateCompileApis')
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
withSourcesJar()
}
dependencies {
apiGenerator 'org.ow2.asm:asm:9.8'
apiGenerator 'com.google.code.gson:gson:2.10.1'
implementation 'it.unimi.dsi:fastutil:8.5.2'
implementation 'org.hipparchus:hipparchus-core:1.8'
implementation 'org.hipparchus:hipparchus-stat:1.8'
implementation 'org.hipparchus:hipparchus-optim:1.8'
implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation 'org.jetbrains:annotations:20.1.0'
compileOnly compileApi('aac5')
compileOnly 'com.google.guava:guava:21.0'
compileOnly 'com.google.code.gson:gson:2.8.9'
compileOnly 'org.yaml:snakeyaml:1.27'
compileOnly 'commons-lang:commons-lang:2.6'
compileOnly 'net.md-5:bungeecord-chat:1.16-R0.4'
}
tasks.withType(JavaCompile).configureEach {
if (name != 'compileApiGenerator') {
dependsOn tasks.named('generateCompileApis')
}
options.release = javaVersion
options.encoding = 'UTF-8'
options.compilerArgs += ['-parameters']
options.debug = true
options.debugOptions.debugLevel = 'source,lines,vars'
}
tasks.withType(AbstractArchiveTask).configureEach {
preserveFileTimestamps = false
reproducibleFileOrder = true
filePermissions { unix('0644') }
dirPermissions { unix('0755') }
}
jar {
archiveClassifier = 'plain'
manifest.attributes('Implementation-Title': 'AAC', 'Implementation-Version': project.version)
}
shadowJar {
archiveClassifier = 'java17'
relocate 'it.unimi.dsi.fastutil', 'me.konsolas.aac.lib.fastutil'
relocate 'org.hipparchus', 'me.konsolas.aac.lib.hipparchus'
minimize()
mergeServiceFiles()
exclude 'META-INF/*.SF', 'META-INF/*.RSA', 'META-INF/*.DSA'
exclude 'META-INF/INDEX.LIST', 'META-INF/maven/**'
exclude 'META-INF/LICENSE', 'META-INF/LICENSE.txt', 'META-INF/NOTICE', 'META-INF/NOTICE.txt'
manifest.attributes('Implementation-Title': 'AAC', 'Implementation-Version': project.version)
}
assemble.dependsOn shadowJar
idea {
module {
downloadSources = true
downloadJavadoc = true
}
}
eclipse {
classpath {
downloadSources = true
downloadJavadoc = true
}
}
+3
View File
@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx3g -Dfile.encoding=UTF-8
org.gradle.workers.max=2
org.gradle.parallel=false
+66
View File
@@ -0,0 +1,66 @@
import com.google.gson.*;
import org.objectweb.asm.*;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.jar.*;
public final class GenerateCompileApis implements Opcodes {
static String text(JsonObject o,String k){return o.has(k)&&!o.get(k).isJsonNull()?o.get(k).getAsString():null;}
static int number(JsonObject o,String k){return o.get(k).getAsInt();}
static JsonArray array(JsonObject o,String k){return o.has(k)?o.getAsJsonArray(k):new JsonArray();}
static String[] strings(JsonObject o,String k){List<String> r=new ArrayList<>();for(JsonElement e:array(o,k))r.add(e.getAsString());return r.toArray(new String[0]);}
static Object scalar(JsonObject o){String v=text(o,"value");return switch(text(o,"type")){
case "Long"->Long.valueOf(v);case "Integer"->Integer.valueOf(v);case "Float"->Float.valueOf(v);case "Double"->Double.valueOf(v);case "Byte"->Byte.valueOf(v);case "Short"->Short.valueOf(v);case "Character"->v.charAt(0);default->throw new IllegalArgumentException(o.toString());};}
static Object constant(JsonElement e){if(e==null||e.isJsonNull())return null;if(e.isJsonObject())return scalar(e.getAsJsonObject());return e.getAsString();}
static void annotationValue(AnnotationVisitor visitor,String name,JsonElement value){
if(value.isJsonArray()){AnnotationVisitor nested=visitor.visitArray(name);for(JsonElement e:value.getAsJsonArray())annotationValue(nested,null,e);nested.visitEnd();}
else if(value.isJsonObject()){JsonObject o=value.getAsJsonObject();switch(text(o,"kind")){
case "scalar"->visitor.visit(name,scalar(o));case "type"->visitor.visit(name,Type.getType(text(o,"descriptor")));
case "enum"->visitor.visitEnum(name,text(o,"descriptor"),text(o,"name"));
case "annotation"->{JsonObject a=o.getAsJsonObject("annotation");writeAnnotation(visitor.visitAnnotation(name,text(a,"descriptor")),a);}
default->throw new IllegalArgumentException(o.toString());}}
else if(value.getAsJsonPrimitive().isBoolean())visitor.visit(name,value.getAsBoolean());
else visitor.visit(name,value.getAsString());
}
static void writeAnnotation(AnnotationVisitor visitor,JsonObject annotation){if(visitor==null)return;for(var e:annotation.getAsJsonObject("values").entrySet())annotationValue(visitor,e.getKey(),e.getValue());visitor.visitEnd();}
interface Factory {AnnotationVisitor create(JsonObject annotation);}
static void annotations(JsonObject o,String key,Factory factory){for(JsonElement a:array(o,key)){JsonObject obj=a.getAsJsonObject();writeAnnotation(factory.create(obj),obj);}}
static TypePath path(JsonObject o){return TypePath.fromString(text(o,"typePath"));}
static byte[] compile(JsonObject c){
ClassWriter cw=new ClassWriter(0);cw.visit(number(c,"version"),number(c,"access"),text(c,"name"),text(c,"signature"),text(c,"superName"),strings(c,"interfaces"));
if(c.has("outerClass"))cw.visitOuterClass(text(c,"outerClass"),text(c,"outerMethod"),text(c,"outerMethodDescriptor"));
if(c.has("nestHostClass"))cw.visitNestHost(text(c,"nestHostClass"));
for(String n:strings(c,"nestMembers"))cw.visitNestMember(n);for(String n:strings(c,"permittedSubclasses"))cw.visitPermittedSubclass(n);
annotations(c,"annotations",a->cw.visitAnnotation(text(a,"descriptor"),a.get("visible").getAsBoolean()));
annotations(c,"typeAnnotations",a->cw.visitTypeAnnotation(number(a,"typeRef"),path(a),text(a,"descriptor"),a.get("visible").getAsBoolean()));
for(JsonElement el:array(c,"innerClasses")){var n=el.getAsJsonObject();cw.visitInnerClass(text(n,"name"),text(n,"outerName"),text(n,"innerName"),number(n,"access"));}
for(JsonElement el:array(c,"recordComponents")){var r=el.getAsJsonObject();var rv=cw.visitRecordComponent(text(r,"name"),text(r,"descriptor"),text(r,"signature"));annotations(r,"annotations",a->rv.visitAnnotation(text(a,"descriptor"),a.get("visible").getAsBoolean()));annotations(r,"typeAnnotations",a->rv.visitTypeAnnotation(number(a,"typeRef"),path(a),text(a,"descriptor"),a.get("visible").getAsBoolean()));rv.visitEnd();}
for(JsonElement el:array(c,"fields")){var f=el.getAsJsonObject();var fv=cw.visitField(number(f,"access"),text(f,"name"),text(f,"descriptor"),text(f,"signature"),constant(f.get("constant")));annotations(f,"annotations",a->fv.visitAnnotation(text(a,"descriptor"),a.get("visible").getAsBoolean()));annotations(f,"typeAnnotations",a->fv.visitTypeAnnotation(number(a,"typeRef"),path(a),text(a,"descriptor"),a.get("visible").getAsBoolean()));fv.visitEnd();}
for(JsonElement el:array(c,"methods")){var m=el.getAsJsonObject();int access=number(m,"access");String descriptor=text(m,"descriptor");var mv=cw.visitMethod(access,text(m,"name"),descriptor,text(m,"signature"),strings(m,"exceptions"));
for(JsonElement pe:array(m,"parameters")){var p=pe.getAsJsonObject();mv.visitParameter(text(p,"name"),number(p,"access"));}
annotations(m,"annotations",a->mv.visitAnnotation(text(a,"descriptor"),a.get("visible").getAsBoolean()));annotations(m,"typeAnnotations",a->mv.visitTypeAnnotation(number(a,"typeRef"),path(a),text(a,"descriptor"),a.get("visible").getAsBoolean()));
annotations(m,"parameterAnnotations",a->mv.visitParameterAnnotation(number(a,"parameter"),text(a,"descriptor"),a.get("visible").getAsBoolean()));
if(m.has("annotationDefault")){var av=mv.visitAnnotationDefault();annotationValue(av,null,m.get("annotationDefault"));av.visitEnd();}
if((access&(ACC_ABSTRACT|ACC_NATIVE))==0){mv.visitCode();mv.visitTypeInsn(NEW,"java/lang/UnsupportedOperationException");mv.visitInsn(DUP);mv.visitLdcInsn("Compile-only API header; use the real server or library at runtime");mv.visitMethodInsn(INVOKESPECIAL,"java/lang/UnsupportedOperationException","<init>","(Ljava/lang/String;)V",false);mv.visitInsn(ATHROW);int locals=(access&ACC_STATIC)==0?1:0;for(Type t:Type.getArgumentTypes(descriptor))locals+=t.getSize();mv.visitMaxs(3,locals);}
mv.visitEnd();}
cw.visitEnd();return cw.toByteArray();
}
static SortedMap<String,JsonObject> declarations(Path input,Path schema,Set<Path> active)throws Exception {
if(!active.add(schema))throw new IllegalArgumentException("Cyclic API declaration inheritance: "+schema);
JsonObject data;try(Reader r=Files.newBufferedReader(schema)){data=JsonParser.parseReader(r).getAsJsonObject();}
SortedMap<String,JsonObject> classes=new TreeMap<>();
if(data.has("base"))classes.putAll(declarations(input,input.resolve(text(data,"base")+".json"),active));
for(JsonElement entry:array(data,"classes")){JsonObject c=entry.getAsJsonObject();classes.put(text(c,"name"),c);}
active.remove(schema);return classes;
}
public static void main(String[] args)throws Exception{
Path input=Path.of(args[0]),output=Path.of(args[1]);Files.createDirectories(output);
for(Path schema:Files.list(input).filter(p->p.toString().endsWith(".json")).sorted().toList()){
SortedMap<String,JsonObject> classes=declarations(input,schema,new HashSet<>());
String name=schema.getFileName().toString().replace(".json",".jar");Path jar=output.resolve(name);
try(var out=new JarOutputStream(Files.newOutputStream(jar))){for(JsonObject c:classes.values()){var entry=new JarEntry(text(c,"name")+".class");entry.setTime(0);out.putNextEntry(entry);out.write(compile(c));out.closeEntry();}}
System.out.println("Generated compile API "+name+" ("+classes.size()+" declarations)");
}
}
}
+1
View File
@@ -0,0 +1 @@
{"formatVersion":1,"purpose":"Compile-only API declarations; not runtime implementations","classes":[{"name":"com/comphenix/net/bytebuddy/ByteBuddy","version":49,"access":33,"superName":"java/lang/Object","innerClasses":[{"name":"com/comphenix/net/bytebuddy/ByteBuddy$RecordObjectMethod","outerName":"com/comphenix/net/bytebuddy/ByteBuddy","innerName":"RecordObjectMethod","access":16412},{"name":"com/comphenix/net/bytebuddy/ByteBuddy$RecordConstructorStrategy","outerName":"com/comphenix/net/bytebuddy/ByteBuddy","innerName":"RecordConstructorStrategy","access":16412},{"name":"com/comphenix/net/bytebuddy/ByteBuddy$EnumerationImplementation","outerName":"com/comphenix/net/bytebuddy/ByteBuddy","innerName":"EnumerationImplementation","access":12},{"name":"com/comphenix/net/bytebuddy/implementation/auxiliary/AuxiliaryType$NamingStrategy","outerName":"com/comphenix/net/bytebuddy/implementation/auxiliary/AuxiliaryType","innerName":"NamingStrategy","access":1545},{"name":"com/comphenix/net/bytebuddy/implementation/attribute/AnnotationValueFilter$Factory","outerName":"com/comphenix/net/bytebuddy/implementation/attribute/AnnotationValueFilter","innerName":"Factory","access":1545},{"name":"com/comphenix/net/bytebuddy/implementation/Implementation$Context","outerName":"com/comphenix/net/bytebuddy/implementation/Implementation","innerName":"Context","access":1545},{"name":"com/comphenix/net/bytebuddy/implementation/Implementation$Context$Factory","outerName":"com/comphenix/net/bytebuddy/implementation/Implementation$Context","innerName":"Factory","access":1545},{"name":"com/comphenix/net/bytebuddy/dynamic/scaffold/MethodGraph$Compiler","outerName":"com/comphenix/net/bytebuddy/dynamic/scaffold/MethodGraph","innerName":"Compiler","access":1545},{"name":"com/comphenix/net/bytebuddy/dynamic/scaffold/InstrumentedType$Factory","outerName":"com/comphenix/net/bytebuddy/dynamic/scaffold/InstrumentedType","innerName":"Factory","access":1545},{"name":"com/comphenix/net/bytebuddy/dynamic/DynamicType$Builder","outerName":"com/comphenix/net/bytebuddy/dynamic/DynamicType","innerName":"Builder","access":1545},{"name":"com/comphenix/net/bytebuddy/description/type/TypeDescription$Generic","outerName":"com/comphenix/net/bytebuddy/description/type/TypeDescription","innerName":"Generic","access":1545},{"name":"com/comphenix/net/bytebuddy/description/type/TypeList$Generic","outerName":"com/comphenix/net/bytebuddy/description/type/TypeList","innerName":"Generic","access":1545},{"name":"com/comphenix/net/bytebuddy/build/HashCodeAndEqualsPlugin$Enhance","outerName":"com/comphenix/net/bytebuddy/build/HashCodeAndEqualsPlugin","innerName":"Enhance","access":9737},{"name":"com/comphenix/net/bytebuddy/NamingStrategy$SuffixingRandom","outerName":"com/comphenix/net/bytebuddy/NamingStrategy","innerName":"SuffixingRandom","access":9},{"name":"com/comphenix/net/bytebuddy/implementation/auxiliary/AuxiliaryType$NamingStrategy$SuffixingRandom","outerName":"com/comphenix/net/bytebuddy/implementation/auxiliary/AuxiliaryType$NamingStrategy","innerName":"SuffixingRandom","access":9},{"name":"com/comphenix/net/bytebuddy/matcher/LatentMatcher$Resolved","outerName":"com/comphenix/net/bytebuddy/matcher/LatentMatcher","innerName":"Resolved","access":9},{"name":"com/comphenix/net/bytebuddy/description/type/TypeList$Generic$Explicit","outerName":"com/comphenix/net/bytebuddy/description/type/TypeList$Generic","innerName":"Explicit","access":9},{"name":"com/comphenix/net/bytebuddy/description/type/TypeList$Generic$Empty","outerName":"com/comphenix/net/bytebuddy/description/type/TypeList$Generic","innerName":"Empty","access":9},{"name":"com/comphenix/net/bytebuddy/description/modifier/ModifierContributor$ForType","outerName":"com/comphenix/net/bytebuddy/description/modifier/ModifierContributor","innerName":"ForType","access":1545},{"name":"com/comphenix/net/bytebuddy/description/type/TypeList$Generic$ForLoadedTypes","outerName":"com/comphenix/net/bytebuddy/description/type/TypeList$Generic","innerName":"ForLoadedTypes","access":9},{"name":"com/comphenix/net/bytebuddy/description/method/MethodDescription$Token","outerName":"com/comphenix/net/bytebuddy/description/method/MethodDescription","innerName":"Token","access":9},{"name":"com/comphenix/net/bytebuddy/description/modifier/ModifierContributor$ForMethod","outerName":"com/comphenix/net/bytebuddy/description/modifier/ModifierContributor","innerName":"ForMethod","access":1545},{"name":"com/comphenix/net/bytebuddy/description/type/PackageDescription$ForLoadedPackage","outerName":"com/comphenix/net/bytebuddy/description/type/PackageDescription","innerName":"ForLoadedPackage","access":9},{"name":"com/comphenix/net/bytebuddy/description/type/TypeDescription$ForPackageDescription","outerName":"com/comphenix/net/bytebuddy/description/type/TypeDescription","innerName":"ForPackageDescription","access":9},{"name":"com/comphenix/net/bytebuddy/implementation/attribute/AnnotationValueFilter$Default","outerName":"com/comphenix/net/bytebLine truncated
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531
Vendored
+251
View File
@@ -0,0 +1,251 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
+94
View File
@@ -0,0 +1,94 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+7
View File
@@ -0,0 +1,7 @@
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = 'AAC5'
+263
View File
@@ -0,0 +1,263 @@
package me.konsolas.aac;
import java.net.InetAddress;
import java.sql.SQLException;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.logging.Level;
import java.util.logging.Logger;
import me.clip.placeholderapi.PlaceholderAPI;
import me.konsolas.aac.analysis.AnalysisManager;
import me.konsolas.aac.api.AACAPI;
import me.konsolas.aac.api.internal.AACApiImplementation;
import me.konsolas.aac.command.AACCommandExecutor;
import me.konsolas.aac.database.PlayerDatabase;
import me.konsolas.aac.debug.DebugManager;
import me.konsolas.aac.metrics.MetricsLite;
import me.konsolas.aac.player.PlayerLoginInfo;
import me.konsolas.aac.protocol.PacketDispatcher;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.timings.CheckTask;
import me.konsolas.aac.timings.EntityTracker;
import me.konsolas.aac.timings.TPSCounter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
public class AAC extends JavaPlugin implements Listener {
private TPSCounter tpsCounter;
private final Map<UUID, PlayerLoginInfo> loginInfo = new ConcurrentHashMap();
private boolean databaseEnabled;
private PacketDispatcher packetDispatcher;
private BiFunction<Player, String, String> placeholderResolver;
private AnalysisManager analysisManager;
private AACAPI api;
private EntityTracker entityTracker;
private CheckTask checkTask;
private DebugManager debugManager;
private final Map<UUID, ProtocolVersion> protocolVersions = new ConcurrentHashMap();
private AACCommandExecutor commandExecutor;
private PlayerDatabase database;
public void loadLoginInfo(UUID uUID, InetAddress inetAddress) {
try {
this.loginInfo.put(uUID, this.database.findPlayerLoginInfo(uUID, inetAddress));
} catch (SQLException sQLException) {
this.getLogger().log(Level.SEVERE, "failed to retrieve login info for " + uUID, (Throwable) sQLException);
}
}
public PlayerDatabase getDatabase() {
return this.database;
}
public String resolvePlaceholders(Player player, String text) {
return (String) this.placeholderResolver.apply(player, text);
}
public PacketDispatcher getPacketDispatcher() {
return this.packetDispatcher;
}
public DebugManager getDebugManager() {
return this.debugManager;
}
private void updatePlayer(Player player, boolean matches) {
if (matches) {
this.packetDispatcher.addExemption(player, PacketDispatcher.COMMAND_EXEMPTION);
} else {
this.packetDispatcher.removeExemption(player, PacketDispatcher.COMMAND_EXEMPTION);
}
}
public PlayerLoginInfo findPlayerLoginInfo(UUID uUID) {
return (PlayerLoginInfo) this.loginInfo.get(uUID);
}
public TPSCounter getTpsCounter() {
return this.tpsCounter;
}
public EntityTracker getEntityTracker() {
return this.entityTracker;
}
public AACCommandExecutor getCommandExecutor() {
return this.commandExecutor;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuitEvent(PlayerQuitEvent playerQuitEvent) {
this.packetDispatcher.removePlayer(playerQuitEvent.getPlayer());
AnalysisManager analysisManager2 = this.analysisManager;
Player player = playerQuitEvent.getPlayer();
Player player2 = player;
analysisManager2.updatePlayer(player2);
this.loginInfo.remove(playerQuitEvent.getPlayer().getUniqueId());
this.protocolVersions.remove(playerQuitEvent.getPlayer().getUniqueId());
}
public boolean isDatabaseEnabled() {
return this.databaseEnabled;
}
public AnalysisManager getAnalysisManager() {
return this.analysisManager;
}
public boolean toggleExemption(Player player) {
UUID uniqueId = player.getUniqueId();
this.loginInfo.put(uniqueId, ((PlayerLoginInfo) this.loginInfo.get(uniqueId)).copy());
boolean exempt = ((PlayerLoginInfo) this.loginInfo.get(uniqueId)).isExempt();
try {
this.database.setExempt(uniqueId, exempt);
} catch (SQLException sQLException) {
this.getLogger().log(Level.WARNING, "could not save exemption", (Throwable) sQLException);
}
this.updatePlayer(player, exempt);
return exempt;
}
public ProtocolVersion getProtocolVersion(Player player) {
return this.protocolVersions.computeIfAbsent(player.getUniqueId(), result -> {
ProtocolVersion version = ProtocolVersion.detectPlayerVersion(player);
if (version != null) {
this.getLogger().info("Detected " + version + " for " + player.getName());
} else {
this.getLogger().warning("Unresolved version for " + player.getName() + " check your ViaVersion/ProtocolSupport build");
}
return version;
});
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoinEvent(PlayerJoinEvent playerJoinEvent) {
PacketDispatcher packetDispatcher2 = this.packetDispatcher;
Player player = playerJoinEvent.getPlayer();
Player player2 = player;
packetDispatcher2.initializePlayer(player2);
this.analysisManager.evaluateUpdatePlayer(playerJoinEvent.getPlayer());
UUID uniqueId = playerJoinEvent.getPlayer().getUniqueId();
if (this.findPlayerLoginInfo(uniqueId) == null) {
this.getServer().getScheduler().runTaskAsynchronously(this, () -> {
InetAddress address = Objects.requireNonNull(playerJoinEvent.getPlayer().getAddress()).getAddress();
UUID uniqueId2 = playerJoinEvent.getPlayer().getUniqueId();
this.loadLoginInfo(uniqueId2, address);
Player player3 = playerJoinEvent.getPlayer();
UUID uniqueId3 = playerJoinEvent.getPlayer().getUniqueId();
boolean exempt = this.findPlayerLoginInfo(uniqueId3).isExempt();
Player player4 = player3;
this.updatePlayer(player4, exempt);
});
} else {
Player player5 = playerJoinEvent.getPlayer();
UUID uniqueId4 = playerJoinEvent.getPlayer().getUniqueId();
boolean exempt2 = this.findPlayerLoginInfo(uniqueId4).isExempt();
Player player6 = player5;
this.updatePlayer(player6, exempt2);
}
}
public void onEnable() {
this.saveDefaultConfig();
this.reloadConfig();
try {
if (this.getConfig().getBoolean("mysql.enabled")) {
String string = this.getConfig().getString("mysql.host");
int intValue = this.getConfig().getInt("mysql.port");
String string2 = this.getConfig().getString("mysql.database");
String string3 = this.getConfig().getString("mysql.username");
String string4 = this.getConfig().getString("mysql.password");
this.database = PlayerDatabase.create(this, string, intValue, string2, string3, string4);
} else {
String string5 = this.getConfig().getString("sqlite_target");
this.database = PlayerDatabase.create(this, string5);
}
} catch (SQLException sQLException) {
throw new RuntimeException(sQLException);
}
this.tpsCounter = new TPSCounter(this);
this.entityTracker = new EntityTracker(this);
this.checkTask = new CheckTask(this);
this.packetDispatcher = new PacketDispatcher(this);
this.analysisManager = new AnalysisManager(this);
this.commandExecutor = new AACCommandExecutor(this);
Objects.requireNonNull(this.getCommand("aac")).setExecutor(this.commandExecutor);
Objects.requireNonNull(this.getCommand("aac")).setTabCompleter(this.commandExecutor);
this.getServer().getPluginManager().registerEvents(this, this);
if (!this.getServer().getOnlinePlayers().isEmpty()) {
Logger logger = this.getLogger();
Logger logger2 = logger;
logger2.warning((String) "Attempting to handle server reload");
for (Player player : this.getServer().getOnlinePlayers()) {
this.getServer().getScheduler().runTaskAsynchronously(this, () -> {
InetAddress address = Objects.requireNonNull(player.getAddress()).getAddress();
UUID uniqueId = player.getUniqueId();
this.loadLoginInfo(uniqueId, address);
});
this.packetDispatcher.initializePlayer(player);
this.analysisManager.evaluateUpdatePlayer(player);
}
logger = this.getLogger();
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder2 = stringBuilder;
stringBuilder = stringBuilder2.append((String) "Initialised ").append(this.getServer().getOnlinePlayers().size());
StringBuilder stringBuilder3 = stringBuilder;
StringBuilder stringBuilder4 = stringBuilder3.append((String) " players");
String text = stringBuilder4.toString();
Logger logger3 = logger;
logger3.warning(text);
}
this.databaseEnabled = this.getConfig().getBoolean("bungeecord");
if (this.databaseEnabled) {
this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
this.getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", this.analysisManager);
Logger logger4 = this.getLogger();
Logger logger5 = logger4;
logger5.info((String) "Registered BungeeCord plugin channels");
}
this.api = new AACApiImplementation(this);
this.getServer().getServicesManager().register(AACAPI.class, this.api, this, ServicePriority.Normal);
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
Logger logger6 = this.getLogger();
Logger logger7 = logger6;
logger7.info((String) "Hooking into PlaceholderAPI");
this.placeholderResolver = (result, result2) -> PlaceholderAPI.setPlaceholders(result, result2.replace("%player_name%", result.getName()));
} else {
this.placeholderResolver = (result, result2) -> result2.replace("%player_name%", result.getName());
}
this.debugManager = new DebugManager(this);
new MetricsLite(this, 2267);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onAsyncPlayerPreLoginEvent(AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent) {
InetAddress address = asyncPlayerPreLoginEvent.getAddress();
UUID uniqueId = asyncPlayerPreLoginEvent.getUniqueId();
this.loadLoginInfo(uniqueId, address);
}
}
@@ -0,0 +1,81 @@
package me.konsolas.aac.analysis;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import org.bukkit.configuration.ConfigurationSection;
public class AnalysisActionRule {
private final long delayTicks;
private final List<Pattern> includePatterns = new ArrayList();
private final List<Pattern> excludePatterns = new ArrayList();
private final Int2ObjectMap thresholdCommands = new Int2ObjectArrayMap();
public AnalysisActionRule(ConfigurationSection section) {
this.delayTicks = (long) (20.0 * section.getDouble("delay", 0.0));
for (String text : section.getStringList("features")) {
if (text.startsWith("-")) {
this.excludePatterns.add(Pattern.compile(("\\Q" + text.substring(1) + "\\E").replace("*", "\\E.*\\Q")));
} else {
this.includePatterns.add(Pattern.compile(("\\Q" + text + "\\E").replace("*", "\\E.*\\Q")));
}
}
ConfigurationSection configurationSection = section.getConfigurationSection("thresholds");
if (configurationSection != null) {
for (String text2 : configurationSection.getKeys(false)) {
if (configurationSection.get(text2) instanceof String) {
this.thresholdCommands.put(Integer.parseInt(text2), Collections.singletonList(configurationSection.getString(text2)));
} else {
this.thresholdCommands.put(Integer.parseInt(text2), configurationSection.getStringList(text2));
}
}
}
}
public long getDelayTicks() {
return this.delayTicks;
}
private boolean matchesFeature(String text) {
for (Pattern pattern : this.excludePatterns) {
if (pattern.matcher(text).matches()) {
return false;
}
}
for (Pattern pattern2 : this.includePatterns) {
if (pattern2.matcher(text).matches()) {
return true;
}
}
return false;
}
public List matchingCommands(PlayerAnalysisReport playerAnalysisReport) {
double value = 0.0;
for (FeatureResult result : playerAnalysisReport.getFeatures()) {
Object result2 = result.getDetails().get("id");
String text = (String) result2;
if (this.matchesFeature(text)) {
value += result.getScore();
}
}
Entry entry = null;
ObjectIterator objectIterator = this.thresholdCommands.int2ObjectEntrySet().iterator();
while (objectIterator.hasNext()) {
Entry entry2 = (Entry) objectIterator.next();
if (entry2.getIntKey() < value && (entry == null || entry2.getIntKey() > entry.getIntKey())) {
entry = entry2;
}
}
return entry == null ? null : (List) entry.getValue();
}
}
@@ -0,0 +1,277 @@
package me.konsolas.aac.analysis;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import java.sql.SQLException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import me.konsolas.aac.AAC;
import me.konsolas.aac.api.AACCustomFeature;
import me.konsolas.aac.api.AACCustomFeatureProvider;
import me.konsolas.aac.database.PlayerDatabase;
import me.konsolas.aac.player.PlayerLoginInfo;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
public class AnalysisManager implements PluginMessageListener {
private final ExecutorService executor = Executors.newSingleThreadExecutor(result -> new Thread(result, "AAC Report Generator Thread"));
private CompletableFuture<PlayerAnalysisReport> pendingAnalysis;
private final AAC plugin;
private final long historyMillis;
private final int yellowScore;
private final int redScore;
private final Map<String, AnalysisActionRule> actionRules = new HashMap();
private final FeatureRegistry featureRegistry;
private final List<AACCustomFeatureProvider> customFeatureProviders = new ArrayList();
private final Set<Player> alertRecipients = Collections.synchronizedSet(new LinkedHashSet());
private final Map<UUID, PlayerAnalysisReport> onlineReports = new ConcurrentHashMap();
private final Cache reportCache;
public AnalysisManager(AAC plugin) {
this.plugin = plugin;
this.featureRegistry = new FeatureRegistry(plugin);
double doubleValue = plugin.getConfig().getDouble("analysis.period");
long longValue = plugin.getConfig().getLong("analysis.history");
String string = plugin.getConfig().getString("analysis.history_time_unit");
long value;
try {
value = TimeUnit.MILLISECONDS.convert(longValue, TimeUnit.valueOf(string));
} catch (IllegalArgumentException illegalArgumentException) {
plugin.getLogger().severe("Failed to parse history_time_unit: " + illegalArgumentException.getMessage());
plugin.getLogger().severe("Using 1 DAY instead");
value = TimeUnit.MILLISECONDS.convert(1L, TimeUnit.DAYS);
}
this.historyMillis = value;
this.yellowScore = plugin.getConfig().getInt("analysis.yellow_score");
this.redScore = plugin.getConfig().getInt("analysis.red_score");
if (plugin.getConfig().getBoolean("analysis.clear_stale_entries")) {
try {
PlayerDatabase database = plugin.getDatabase();
long value2 = System.currentTimeMillis() - this.historyMillis;
int value3 = database.deleteEventsBefore(value2);
if (value3 == 0) {
plugin.getLogger().info("No stale entries to remove");
} else if (value3 == 1) {
plugin.getLogger().info("Removed 1 stale entry from the database");
} else {
plugin.getLogger().info("Removed " + value3 + " stale entries from the database");
}
} catch (SQLException sQLException) {
plugin.getLogger().log(Level.WARNING, "Failed to clear stale entries from the database", (Throwable) sQLException);
}
}
ConfigurationSection configurationSection = plugin.getConfig().getConfigurationSection("actions");
if (configurationSection != null) {
for (String text : configurationSection.getKeys(false)) {
ConfigurationSection configurationSection2 = configurationSection.getConfigurationSection(text);
if (configurationSection2 != null) {
this.actionRules.put(text, new AnalysisActionRule(configurationSection2));
} else {
plugin.getLogger().warning("Unexpected key " + text + " in config.yml:actions");
}
}
} else {
plugin.getLogger().warning("config.yml missing actions section. Consider regenerating your config.");
}
this.reportCache = CacheBuilder.newBuilder().maximumSize(100L).expireAfterAccess(10L, TimeUnit.MINUTES).build();
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this::tick, 100L, (long) (doubleValue * 20.0));
}
public void updatePlayerWithAlertRecipients(Player player) {
this.alertRecipients.add(player);
}
private void tick() {
this.alertRecipients.removeIf(result -> !result.isOnline());
if (!this.alertRecipients.isEmpty() && (this.pendingAnalysis == null || this.pendingAnalysis.isDone())) {
Player player;
synchronized (this.alertRecipients) {
player = (Player) this.alertRecipients.iterator().next();
this.alertRecipients.remove(player);
}
PlayerAnalysisReport report = this.getReport(player);
RiskLevel riskLevel = report == null ? RiskLevel.NEUTRAL : report.getRiskLevel();
this.pendingAnalysis = this.analyzeAsync(player).whenComplete((result2, result3) -> {
if (result2 != null && result2.getRiskLevel() != riskLevel && player.isOnline()) {
if (this.plugin.isDatabaseEnabled()) {
this.updatePlayerWithPlugin(player);
}
this.plugin.getServer().getScheduler().scheduleSyncDelayedTask(this.plugin, () -> this.plugin.getCommandExecutor().updatePlayer(player));
}
}).whenComplete((result4, result2) -> {
if (result4 != null) {
for (Entry entry : this.actionRules.entrySet()) {
List<String> values = ((AnalysisActionRule) entry.getValue()).matchingCommands(result4);
if (values != null) {
this.plugin.getServer().getScheduler().runTaskLater(this.plugin, () -> {
if (player.isOnline()) {
for (String text : values) {
text = this.plugin.resolvePlaceholders(player, text);
this.plugin.getLogger().info("actions." + (String) entry.getKey() + ": " + text);
this.plugin.getServer().dispatchCommand(Bukkit.getConsoleSender(), text);
}
}
}, ((AnalysisActionRule) entry.getValue()).getDelayTicks());
}
}
}
});
}
}
public PlayerAnalysisReport getReport(OfflinePlayer offlinePlayer) {
return offlinePlayer.isOnline() ? (PlayerAnalysisReport) this.onlineReports.get(offlinePlayer.getUniqueId()) : (PlayerAnalysisReport) this.reportCache.getIfPresent(offlinePlayer.getUniqueId());
}
public void registerFeatureProvider(AACCustomFeatureProvider aACCustomFeatureProvider) {
this.customFeatureProviders.add(aACCustomFeatureProvider);
}
public CompletableFuture<PlayerAnalysisReport> analyzeAsync(OfflinePlayer offlinePlayer) {
CompletableFuture<PlayerAnalysisReport> completableFuture = new CompletableFuture();
this.executor.execute(() -> {
try {
AAC aacPlugin = this.plugin;
UUID uniqueId = offlinePlayer.getUniqueId();
PlayerLoginInfo playerLoginInfo = aacPlugin.findPlayerLoginInfo(uniqueId);
if (playerLoginInfo == null) {
PlayerDatabase database = this.plugin.getDatabase();
UUID uniqueId2 = offlinePlayer.getUniqueId();
UUID uUID = uniqueId2;
playerLoginInfo = database.findPlayerLoginInfo(uUID);
}
completableFuture.complete(this.analyze(offlinePlayer, playerLoginInfo));
} catch (SQLException sQLException) {
this.plugin.getLogger().log(Level.SEVERE, "Failed to analyse player " + offlinePlayer.getName(), (Throwable) sQLException);
completableFuture.completeExceptionally(sQLException);
}
});
return completableFuture.whenComplete((result, result2) -> {
if (result != null) {
if (offlinePlayer.isOnline()) {
this.onlineReports.put(offlinePlayer.getUniqueId(), result);
} else {
this.reportCache.put(offlinePlayer.getUniqueId(), result);
}
}
});
}
private PlayerAnalysisReport analyze(OfflinePlayer offlinePlayer, PlayerLoginInfo playerLoginInfo) throws SQLException {
Instant instant = Instant.now();
PlayerDatabase database = this.plugin.getDatabase();
long value = System.currentTimeMillis() - this.historyMillis;
UUID uniqueId = offlinePlayer.getUniqueId();
UUID uUID = uniqueId;
long value2 = value;
List values = database.getEventsSince(value2, uUID);
List<FeatureResult> values2;
if (values.isEmpty()) {
values2 = new ArrayList();
} else {
values2 = this.featureRegistry.analyze(values, playerLoginInfo);
}
for (AACCustomFeatureProvider aACCustomFeatureProvider : this.customFeatureProviders) {
Collection featuresAsync = aACCustomFeatureProvider.getFeaturesAsync(offlinePlayer);
if (featuresAsync != null) {
((Collection<me.konsolas.aac.api.AACCustomFeature>) aACCustomFeatureProvider.getFeaturesAsync(offlinePlayer)).stream().map(result -> {
String text = "(API) " + result.getInfo();
double score = result.getScore();
Map tooltip = result.getTooltip();
String text2 = text;
return FeatureResult.create(text2, tooltip, score);
}).filter(Objects::nonNull).forEach(values2::add);
}
}
double value3 = values2.stream().mapToDouble(FeatureResult::getScore).sum();
RiskLevel riskLevel = value3 > this.redScore ? RiskLevel.HIGH : (value3 > this.yellowScore ? RiskLevel.SUSPICIOUS : RiskLevel.NEUTRAL);
return new PlayerAnalysisReport(offlinePlayer, riskLevel, instant, value3, (List) values2);
}
public void evaluateUpdatePlayer(Player player) {
this.analyzeAsync(player);
}
public void updatePlayer(Player player) {
if (this.onlineReports.containsKey(player.getUniqueId())) {
this.reportCache.put(player.getUniqueId(), (PlayerAnalysisReport) this.onlineReports.remove(player.getUniqueId()));
}
this.alertRecipients.remove(player);
}
private void updatePlayerWithPlugin(Player player) {
ByteArrayDataOutput byteArrayDataOutput = ByteStreams.newDataOutput();
byteArrayDataOutput.writeUTF("Forward");
byteArrayDataOutput.writeUTF("ONLINE");
byteArrayDataOutput.writeUTF("AACAlerts");
UUID uniqueId = player.getUniqueId();
this.plugin.getLogger().info("Sending UUID " + uniqueId);
byteArrayDataOutput.writeShort(16);
byteArrayDataOutput.writeLong(uniqueId.getMostSignificantBits());
byteArrayDataOutput.writeLong(uniqueId.getLeastSignificantBits());
player.sendPluginMessage(this.plugin, "BungeeCord", byteArrayDataOutput.toByteArray());
}
public void onPluginMessageReceived(String text, Player player, byte[] values) {
if (text.equals("BungeeCord")) {
ByteArrayDataInput byteArrayDataInput = ByteStreams.newDataInput(values);
String text2 = byteArrayDataInput.readUTF();
if (text2.equals("AACAlerts")) {
short value = byteArrayDataInput.readShort();
if (value != 16) {
this.plugin.getLogger().warning("Invalid bungee message: len = " + value);
return;
}
long value2 = byteArrayDataInput.readLong();
long value3 = byteArrayDataInput.readLong();
UUID uUID = new UUID(value2, value3);
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uUID);
if (offlinePlayer.getName() == null || offlinePlayer.getName().equals("null")) {
this.plugin.getLogger().warning("Invalid bungee message: uuid = " + uUID);
return;
}
CompletableFuture<PlayerAnalysisReport> completableFuture;
if (this.plugin.getAnalysisManager().getReport(offlinePlayer) == null) {
completableFuture = this.plugin.getAnalysisManager().analyzeAsync(offlinePlayer);
} else {
completableFuture = CompletableFuture.completedFuture(this.plugin.getAnalysisManager().getReport(offlinePlayer));
}
completableFuture.whenComplete((result, result2) -> this.plugin.getCommandExecutor().updatePlayer(offlinePlayer));
}
}
}
}
@@ -0,0 +1,119 @@
package me.konsolas.aac.analysis;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.analyzer.AccountFeatureAnalyzer;
import me.konsolas.aac.analysis.analyzer.AverageFeatureAnalyzer;
import me.konsolas.aac.analysis.analyzer.CountFeatureAnalyzer;
import me.konsolas.aac.analysis.analyzer.FeatureAnalyzer;
import me.konsolas.aac.analysis.analyzer.FrequencyFeatureAnalyzer;
import me.konsolas.aac.analysis.analyzer.PercentileFeatureAnalyzer;
import me.konsolas.aac.analysis.analyzer.RateFeatureAnalyzer;
import me.konsolas.aac.analysis.analyzer.TTestFeatureAnalyzer;
import me.konsolas.aac.analysis.analyzer.ThresholdFeatureAnalyzer;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.player.PlayerLoginInfo;
import org.bukkit.configuration.ConfigurationSection;
public class FeatureRegistry {
private static final Collection<FeatureAnalyzer> analyzers;
private final AAC plugin;
private final Map<FeatureAnalyzer, FeatureWeight> featureWeights = new HashMap();
public FeatureRegistry(AAC plugin) {
this.plugin = plugin;
ConfigurationSection section = Objects.requireNonNull(plugin.getConfig().getConfigurationSection("features"));
for (FeatureAnalyzer featureAnalyzer : analyzers) {
double value;
if ((value = section.getDouble(featureAnalyzer.getConfigurationPath() + ".weight")) > 0.0) {
this.featureWeights.put(featureAnalyzer, new FeatureWeight(section.getString(featureAnalyzer.getConfigurationPath() + ".format"), value));
}
}
}
public List<FeatureResult> analyze(List<FeatureEvent> values, PlayerLoginInfo playerLoginInfo) {
FeatureAccumulator featureAccumulator = new FeatureAccumulator();
for (FeatureEvent event : values) {
FeatureType type = event.getType();
float value = event.getValue();
FeatureType feature = type;
featureAccumulator.record(feature, value);
}
ArrayList<FeatureResult> values2 = new ArrayList();
for (Entry<FeatureAnalyzer, FeatureWeight> entry : this.featureWeights.entrySet()) {
FeatureAnalyzer featureAnalyzer = (FeatureAnalyzer) entry.getKey();
String text = FeatureWeight.findString((FeatureWeight) entry.getValue());
featureAnalyzer.analyze(values, featureAccumulator, playerLoginInfo, text).map(result -> {
double value2 = FeatureWeight.calculateValue((FeatureWeight) entry.getValue());
double value3 = value2;
return result.scaledBy(value3);
}).ifPresent(values2::add);
}
values2.sort(Comparator.comparingDouble(FeatureResult::getScore).reversed());
return values2;
}
static {
ArrayList values = new ArrayList();
values.add(new TTestFeatureAnalyzer("aac_delays_break", FeatureType.AAC_DELAYS_BREAK, 0.1, true));
values.add(new TTestFeatureAnalyzer("aac_delays_place", FeatureType.AAC_DELAYS_PLACE, 0.1, true));
values.add(new TTestFeatureAnalyzer("aac_delays_consume", FeatureType.AAC_DELAYS_CONSUME, 0.1, true));
values.add(new TTestFeatureAnalyzer("aac_delays_bow", FeatureType.AAC_DELAYS_BOW, 0.1, true));
values.add(new TTestFeatureAnalyzer("aac_delays_regen", FeatureType.AAC_DELAYS_REGEN, 0.1, true));
values.add(new TTestFeatureAnalyzer("aac_delays_sneak", FeatureType.AAC_DELAYS_UNSNEAK, 0.1, true));
values.add(new TTestFeatureAnalyzer("aac_delays_release", FeatureType.AAC_DELAYS_RELEASE, 0.1, true));
values.add(new TTestFeatureAnalyzer("aac_delays_breakdelay", FeatureType.AAC_DELAYS_BREAKDELAY, 0.1, true));
values.add(new FrequencyFeatureAnalyzer("aac_move_nofall", FeatureType.AAC_MOVE_NOFALL, FeatureType.AAC_NORM_MOVE, result -> 5.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_move_vel", FeatureType.AAC_MOVE_VEL, FeatureType.AAC_NORM_MOVE, result -> 5.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_move_vehicle", FeatureType.AAC_MOVE_VEHICLE, FeatureType.AAC_NORM_MOVE, result -> result));
values.add(new RateFeatureAnalyzer("aac_move_elytra", FeatureType.AAC_MOVE_ELYTRA, FeatureType.AAC_NORM_MOVE, result -> result));
values.add(new RateFeatureAnalyzer("aac_move_water", FeatureType.AAC_MOVE_WATER, FeatureType.AAC_NORM_MOVE, result -> result));
values.add(new RateFeatureAnalyzer("aac_move_lava", FeatureType.AAC_MOVE_LAVA, FeatureType.AAC_NORM_MOVE, result -> result));
values.add(new FrequencyFeatureAnalyzer("aac_move_noslow", FeatureType.AAC_MOVE_NOSLOW, FeatureType.AAC_NORM_MOVE, result -> result));
values.add(new RateFeatureAnalyzer("aac_move_generic", FeatureType.AAC_MOVE_GENERIC, FeatureType.AAC_NORM_MOVE, result -> result));
values.add(new FrequencyFeatureAnalyzer("aac_move_timer", FeatureType.AAC_MOVE_TIMER, FeatureType.AAC_NORM_MOVE, result -> 5.0 * result));
values.add(new CountFeatureAnalyzer("aac_move_inf", FeatureType.AAC_MOVE_INF, result -> 100.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_aimbot_spread", FeatureType.AAC_AIMBOT_PITCH_SPREAD, FeatureType.AAC_NORM_ATTACK, result -> 5.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_aimbot_sync", FeatureType.AAC_AIMBOT_SENS_MISMATCH, FeatureType.AAC_NORM_ATTACK, result -> 20.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_aimbot_horz", FeatureType.AAC_AIMBOT_SENS_X_OOR, FeatureType.AAC_NORM_ATTACK, result -> 20.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_aimbot_vert", FeatureType.AAC_AIMBOT_SENS_Y_OOR, FeatureType.AAC_NORM_ATTACK, result -> 20.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_aimbot_snap", FeatureType.AAC_AIMBOT_HEAD_SNAP, FeatureType.AAC_NORM_ATTACK, result -> 5.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_aimbot_zero", FeatureType.AAC_AIMBOT_ZERO_POINT, FeatureType.AAC_NORM_ATTACK, result -> 5.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_aimassist_horz", FeatureType.AAC_AIMBOT_BAD_DELTA_X, FeatureType.AAC_NORM_ATTACK, result -> 10.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_aimassist_vert", FeatureType.AAC_AIMBOT_BAD_DELTA_Y, FeatureType.AAC_NORM_ATTACK, result -> 10.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_clk_noswing", FeatureType.AAC_CLICK_NOSWING, FeatureType.AAC_NORM_ATTACK, result -> 20.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_clk_tick_align", FeatureType.AAC_CLICK_TICK_DELAY, FeatureType.AAC_NORM_ATTACK, result -> result));
values.add(new FrequencyFeatureAnalyzer("aac_clk_timing", FeatureType.AAC_CLICK_TIMING, FeatureType.AAC_NORM_ATTACK, result -> result));
values.add(new AverageFeatureAnalyzer("aac_clk_cps", FeatureType.AAC_CLICK_CPS, result -> result * result / 5.0));
values.add(new AverageFeatureAnalyzer("aac_clk_var", FeatureType.AAC_CLICK_VAR, result -> 0.01 / result));
values.add(new FrequencyFeatureAnalyzer("aac_hitbox_multi", FeatureType.AAC_HITBOX_COUNT, FeatureType.AAC_NORM_ATTACK, result -> 5.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_hitbox_miss", FeatureType.AAC_HITBOX_MISS, FeatureType.AAC_NORM_ATTACK, result -> 5.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_hitbox_walls", FeatureType.AAC_HITBOX_WALLS, FeatureType.AAC_NORM_ATTACK, result -> 5.0 * result));
values.add(new PercentileFeatureAnalyzer("aac_hitbox_reach", FeatureType.AAC_HITBOX_REACH, FeatureType.AAC_NORM_ATTACK, 90.0, result -> 200.0 * Math.cbrt(result)));
values.add(new FrequencyFeatureAnalyzer("aac_interact_generic", FeatureType.AAC_INTERACT_GEN, FeatureType.AAC_NORM_INTERACT, result -> 1.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_interact_break", FeatureType.AAC_INTERACT_BREAK, FeatureType.AAC_NORM_INTERACT, result -> 5.0 * result));
values.add(new FrequencyFeatureAnalyzer("aac_interact_place", FeatureType.AAC_INTERACT_PLACE, FeatureType.AAC_NORM_INTERACT, result -> 2.0 * result));
values.add(new CountFeatureAnalyzer("aac_misc_abilities", FeatureType.AAC_MISC_ABILITIES, result -> 100.0 * result));
values.add(new CountFeatureAnalyzer("aac_misc_pitch", FeatureType.AAC_MISC_PITCH, result -> 100.0 * result));
values.add(new CountFeatureAnalyzer("aac_misc_rotation", FeatureType.AAC_MISC_ROTATION, result -> 100.0 * result));
values.add(new AccountFeatureAnalyzer("aac_new_user", 20.0, PlayerLoginInfo::getFirstSeen));
values.add(new AccountFeatureAnalyzer("aac_new_addr", 20.0, PlayerLoginInfo::getLastSeen));
values.add(new ThresholdFeatureAnalyzer("aac_info_move", 10.0, FeatureType.AAC_NORM_MOVE));
values.add(new ThresholdFeatureAnalyzer("aac_info_combat", 10.0, FeatureType.AAC_NORM_ATTACK));
values.add(new ThresholdFeatureAnalyzer("aac_info_interact", 10.0, FeatureType.AAC_NORM_INTERACT));
analyzers = Collections.unmodifiableCollection(values);
}
}
@@ -0,0 +1,62 @@
package me.konsolas.aac.analysis;
import java.util.Map;
import java.util.Map.Entry;
public class FeatureResult {
public static final double IGNORED_SCORE = 1000.0;
private final RiskLevel riskLevel;
private final String description;
private final Map details;
private final double score;
public FeatureResult(RiskLevel riskLevel, String description, Map details, double score) {
for (Entry entry : (Iterable<Entry>) (Iterable<?>) (details.entrySet())) {
description = description.replace("{" + (String) entry.getKey() + "}", (CharSequence) entry.getValue());
}
this.riskLevel = riskLevel;
this.description = description;
this.details = details;
this.score = score;
}
public static FeatureResult create(String text, Map entries, double value) {
if (value >= 10.0) {
RiskLevel riskLevel = value > 25.0 ? (value > 100.0 ? RiskLevel.HIGH : RiskLevel.SUSPICIOUS) : RiskLevel.NEUTRAL;
double value2 = Math.min(value, 250.0);
RiskLevel riskLevel2 = riskLevel;
return new FeatureResult(riskLevel2, text, entries, value2);
} else {
return null;
}
}
public FeatureResult scaledBy(double value) {
double value2 = this.score * value;
Map entries = this.details;
String text = this.description;
RiskLevel riskLevel2 = this.riskLevel;
return new FeatureResult(riskLevel2, text, entries, value2);
}
public RiskLevel getRiskLevel() {
return this.riskLevel;
}
public Map getDetails() {
return this.details;
}
public String getDescription() {
return this.description;
}
public double getScore() {
return this.score;
}
}
@@ -0,0 +1,21 @@
package me.konsolas.aac.analysis;
class FeatureWeight {
private final String featureName;
private final double weight;
public FeatureWeight(String featureName, double weight) {
this.featureName = featureName;
this.weight = weight;
}
static String findString(FeatureWeight featureWeight) {
return featureWeight.featureName;
}
static double calculateValue(FeatureWeight featureWeight) {
return featureWeight.weight;
}
}
@@ -0,0 +1,95 @@
package me.konsolas.aac.analysis;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.UUID;
import me.konsolas.aac.AAC;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.HoverEvent.Action;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.OfflinePlayer;
public class PlayerAnalysisReport {
public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT).withZone(ZoneId.systemDefault()).withLocale(Locale.UK);
private static final String PLUGIN_VERSION = "AAC " + AAC.class.getPackage().getImplementationVersion();
private final String playerName;
private final UUID playerId;
private final RiskLevel riskLevel;
private final Instant generatedAt;
private final double score;
private final List<FeatureResult> features;
public PlayerAnalysisReport(OfflinePlayer offlinePlayer, RiskLevel riskLevel, Instant generatedAt, double score, List features) {
this.playerName = offlinePlayer.getName();
this.playerId = offlinePlayer.getUniqueId();
this.riskLevel = riskLevel;
this.generatedAt = generatedAt;
this.score = score;
this.features = features;
}
public RiskLevel getRiskLevel() {
return this.riskLevel;
}
public Instant getGeneratedAt() {
return this.generatedAt;
}
public double getScore() {
return this.score;
}
public List<FeatureResult> getFeatures() {
return this.features;
}
public List<BaseComponent> toChatComponents() {
ArrayList values = new ArrayList();
TextComponent textComponent = new TextComponent(" AAC Player Analysis of " + this.playerName + " at ");
TextComponent textComponent2 = new TextComponent(DATE_FORMAT.format(this.generatedAt));
textComponent2.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new TextComponent[] { new TextComponent(DATE_FORMAT.getZone().getId()) }));
textComponent.addExtra(textComponent2);
TextComponent textComponent3 = new TextComponent(" Scoring (" + Math.round(this.score) + ") [" + this.features.size() + " features]");
textComponent3.setColor(ChatColor.DARK_AQUA);
values.add(textComponent);
values.add(textComponent3);
for (FeatureResult result : this.features) {
TextComponent textComponent4 = new TextComponent(" - ");
TextComponent textComponent5 = new TextComponent(result.getDescription());
result.getRiskLevel().updateBaseComponent(textComponent5);
TextComponent[] textComponents = new TextComponent[result.getDetails().size()];
int value = 0;
for (Entry entry : (Iterable<Entry>) (Iterable<?>) (result.getDetails().entrySet())) {
TextComponent textComponent6 = new TextComponent((String) entry.getKey() + ": ");
TextComponent textComponent7 = new TextComponent((String) entry.getValue() + "\n");
textComponent7.setColor(ChatColor.GRAY);
textComponent6.addExtra(textComponent7);
textComponents[value++] = textComponent6;
}
textComponent5.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, textComponents));
textComponent4.addExtra(textComponent5);
values.add(textComponent4);
}
TextComponent textComponent8 = new TextComponent("Generated by " + PLUGIN_VERSION);
textComponent8.setColor(ChatColor.DARK_GRAY);
values.add(textComponent8);
return values;
}
}
@@ -0,0 +1,35 @@
package me.konsolas.aac.analysis;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.ChatColor;
public enum RiskLevel {
IGNORED(ChatColor.STRIKETHROUGH), NEUTRAL(ChatColor.GRAY), SUSPICIOUS(ChatColor.GOLD), HIGH(ChatColor.RED);
private final ChatColor color;
private RiskLevel(ChatColor color) {
this.color = color;
}
public ChatColor getColor() {
return this.color;
}
public void updateBaseComponent(BaseComponent baseComponent) {
switch(this) {
case IGNORED:
baseComponent.setStrikethrough(true);
break;
case NEUTRAL:
baseComponent.setColor(net.md_5.bungee.api.ChatColor.GRAY);
break;
case SUSPICIOUS:
baseComponent.setColor(net.md_5.bungee.api.ChatColor.GOLD);
break;
case HIGH:
baseComponent.setColor(net.md_5.bungee.api.ChatColor.RED);
}
}
}
@@ -0,0 +1,46 @@
package me.konsolas.aac.analysis.analyzer;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.ToLongFunction;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.PlayerAnalysisReport;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.player.PlayerLoginInfo;
public class AccountFeatureAnalyzer extends FeatureAnalyzer {
private final double threshold;
private final ToLongFunction<PlayerLoginInfo> timestampExtractor;
public AccountFeatureAnalyzer(String text, double threshold, ToLongFunction<PlayerLoginInfo> timestampExtractor) {
super(text);
this.threshold = threshold;
this.timestampExtractor = timestampExtractor;
}
private static double calculateValue(double value) {
return 2.0 / (Math.exp(value) + Math.exp(-value));
}
@Override
public Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text) {
long value = this.timestampExtractor.applyAsLong(playerLoginInfo);
long value2 = System.currentTimeMillis() - value;
double value3 = value2 / 8.64E7;
double value4 = value3;
double value5 = Math.min(this.threshold * calculateValue(value4), 1000.0);
LinkedHashMap entries = new LinkedHashMap();
entries.put("id", this.getConfigurationPath());
entries.put("score", String.format(Locale.UK, "%.1f", value5));
entries.put("timestamp", PlayerAnalysisReport.DATE_FORMAT.format(Instant.ofEpochMilli(value)));
entries.put("timezone", PlayerAnalysisReport.DATE_FORMAT.getZone().getId());
entries.put("address", playerLoginInfo.getAddress());
return Optional.ofNullable(FeatureResult.create(text, entries, value5));
}
}
@@ -0,0 +1,49 @@
package me.konsolas.aac.analysis.analyzer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.DoubleUnaryOperator;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.player.PlayerLoginInfo;
public class AverageFeatureAnalyzer extends FeatureAnalyzer {
private final FeatureType feature;
private final DoubleUnaryOperator scoringFunction;
public AverageFeatureAnalyzer(String text, FeatureType feature, DoubleUnaryOperator scoringFunction) {
super(text);
this.feature = feature;
this.scoringFunction = scoringFunction;
}
@Override
public Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text) {
double value = 0.0;
int value2 = 0;
for (FeatureEvent event : values) {
if (event.getType() == this.feature) {
double value3 = event.getValue() - value;
value2++;
value += value3 / value2;
}
}
if (value2 < 2) {
return Optional.empty();
} else {
double value4 = Math.min(this.scoringFunction.applyAsDouble(value), 1000.0);
LinkedHashMap entries = new LinkedHashMap();
entries.put("id", this.getConfigurationPath());
entries.put("score", String.format(Locale.UK, "%.1f", value4));
entries.put("mean", String.format(Locale.UK, "%.4f", value));
entries.put("count", Integer.toString(value2));
return Optional.ofNullable(FeatureResult.create(text, entries, value4));
}
}
}
@@ -0,0 +1,37 @@
package me.konsolas.aac.analysis.analyzer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.DoubleUnaryOperator;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.player.PlayerLoginInfo;
public class CountFeatureAnalyzer extends FeatureAnalyzer {
private final FeatureType feature;
private final DoubleUnaryOperator scoringFunction;
public CountFeatureAnalyzer(String text, FeatureType feature, DoubleUnaryOperator scoringFunction) {
super(text);
this.feature = feature;
this.scoringFunction = scoringFunction;
}
@Override
public Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text) {
LinkedHashMap entries = new LinkedHashMap();
FeatureType feature2 = this.feature;
int count = featureAccumulator.getCount(feature2);
double value = Math.min(this.scoringFunction.applyAsDouble(count), 1000.0);
entries.put("id", this.getConfigurationPath());
entries.put("score", String.format(Locale.UK, "%.1f", value));
entries.put("count", Integer.toString(count));
return Optional.ofNullable(FeatureResult.create(text, entries, value));
}
}
@@ -0,0 +1,25 @@
package me.konsolas.aac.analysis.analyzer;
import java.util.List;
import java.util.Optional;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.player.PlayerLoginInfo;
public abstract class FeatureAnalyzer {
public static final double weight = 0.5;
private final String configurationPath;
public FeatureAnalyzer(String configurationPath) {
this.configurationPath = configurationPath;
}
public abstract Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text);
public String getConfigurationPath() {
return this.configurationPath;
}
}
@@ -0,0 +1,45 @@
package me.konsolas.aac.analysis.analyzer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.DoubleUnaryOperator;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.player.PlayerLoginInfo;
public class FrequencyFeatureAnalyzer extends FeatureAnalyzer {
private final FeatureType countFeature;
private final FeatureType totalFeature;
private final DoubleUnaryOperator scoringFunction;
public FrequencyFeatureAnalyzer(String text, FeatureType countFeature, FeatureType totalFeature, DoubleUnaryOperator scoringFunction) {
super(text);
this.countFeature = countFeature;
this.totalFeature = totalFeature;
this.scoringFunction = scoringFunction;
}
@Override
public Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text) {
LinkedHashMap entries = new LinkedHashMap();
FeatureType feature = this.totalFeature;
double total = featureAccumulator.getTotal(feature);
FeatureType feature2 = this.countFeature;
int count = featureAccumulator.getCount(feature2);
double value = count / Math.max(total, 0.5);
double value2 = Math.min(this.scoringFunction.applyAsDouble(value), 1000.0);
entries.put("id", this.getConfigurationPath());
entries.put("score", String.format(Locale.UK, "%.1f", value2));
entries.put("count", Integer.toString(count));
entries.put("time", String.format(Locale.UK, "%.1f", total));
entries.put("rate", String.format(Locale.UK, "%.1f", value));
return Optional.ofNullable(FeatureResult.create(text, entries, value2));
}
}
@@ -0,0 +1,63 @@
package me.konsolas.aac.analysis.analyzer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.DoubleUnaryOperator;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.player.PlayerLoginInfo;
import org.hipparchus.stat.descriptive.rank.Percentile;
public class PercentileFeatureAnalyzer extends FeatureAnalyzer {
private static final Percentile PERCENTILE = new Percentile();
private final FeatureType valueFeature;
private final FeatureType totalFeature;
private final double percentile;
private final DoubleUnaryOperator scoringFunction;
public PercentileFeatureAnalyzer(String text, FeatureType valueFeature, FeatureType totalFeature, double percentile, DoubleUnaryOperator scoringFunction) {
super(text);
this.valueFeature = valueFeature;
this.totalFeature = totalFeature;
this.percentile = percentile;
this.scoringFunction = scoringFunction;
}
@Override
public Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text) {
FeatureType feature = this.totalFeature;
double total = featureAccumulator.getTotal(feature);
FeatureType feature2 = this.valueFeature;
double[] values2 = new double[featureAccumulator.getCount(feature2)];
int value = 0;
for (FeatureEvent event : values) {
if (event.getType() == this.valueFeature) {
values2[value++] = event.getValue();
}
}
if (values2.length > 10) {
double value2 = this.percentile;
double value3 = PERCENTILE.evaluate(values2, value2);
double value4 = Math.min(this.scoringFunction.applyAsDouble(value3) * Math.min(Math.cbrt(total / 0.5), 1.0), 1000.0);
LinkedHashMap entries = new LinkedHashMap();
entries.put("id", this.getConfigurationPath());
entries.put("score", String.format(Locale.UK, "%.1f", value4));
entries.put("percentile", String.format(Locale.UK, "%.1f", this.percentile));
entries.put("value", String.format(Locale.UK, "%.4f", value3));
entries.put("count", Integer.toString(values2.length));
entries.put("time", String.format(Locale.UK, "%.1f", total));
return Optional.ofNullable(FeatureResult.create(text, entries, value4));
} else {
return Optional.empty();
}
}
}
@@ -0,0 +1,45 @@
package me.konsolas.aac.analysis.analyzer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.DoubleUnaryOperator;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.player.PlayerLoginInfo;
public class RateFeatureAnalyzer extends FeatureAnalyzer {
private final FeatureType countFeature;
private final FeatureType totalFeature;
private final DoubleUnaryOperator scoringFunction;
public RateFeatureAnalyzer(String text, FeatureType countFeature, FeatureType totalFeature, DoubleUnaryOperator scoringFunction) {
super(text);
this.countFeature = countFeature;
this.totalFeature = totalFeature;
this.scoringFunction = scoringFunction;
}
@Override
public Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text) {
LinkedHashMap entries = new LinkedHashMap();
FeatureType feature = this.totalFeature;
double total = featureAccumulator.getTotal(feature);
FeatureType feature2 = this.countFeature;
double total2 = featureAccumulator.getTotal(feature2);
double value2 = total2 / Math.max(total, 0.5);
double value3 = Math.min(this.scoringFunction.applyAsDouble(value2), 1000.0);
entries.put("id", this.getConfigurationPath());
entries.put("score", String.format(Locale.UK, "%.1f", value3));
entries.put("total", String.format(Locale.UK, "%.1f", total2));
entries.put("time", String.format(Locale.UK, "%.1f", total));
entries.put("rate", String.format(Locale.UK, "%.1f", value2));
return Optional.ofNullable(FeatureResult.create(text, entries, value3));
}
}
@@ -0,0 +1,51 @@
package me.konsolas.aac.analysis.analyzer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.analysis.statistics.StatisticalAnalysis;
import me.konsolas.aac.analysis.statistics.StatisticalTestResult;
import me.konsolas.aac.player.PlayerLoginInfo;
public class TTestFeatureAnalyzer extends FeatureAnalyzer {
private final FeatureType feature;
private final double expectedMean;
private final boolean upperTail;
public TTestFeatureAnalyzer(String text, FeatureType feature, double expectedMean, boolean upperTail) {
super(text);
this.feature = feature;
this.expectedMean = expectedMean;
this.upperTail = upperTail;
}
@Override
public Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text) {
boolean matches = this.upperTail;
double value = this.expectedMean;
FeatureType feature2 = this.feature;
Optional optional = StatisticalAnalysis.testMean(feature2, values, value, matches);
if (optional.isPresent()) {
double value2 = Math.min(1.0 / ((StatisticalTestResult) optional.get()).getPValue(), 1000.0);
LinkedHashMap entries = new LinkedHashMap();
entries.put("id", this.getConfigurationPath());
entries.put("score", String.format(Locale.UK, "%.1f", value2));
entries.put("count", Integer.toString(((StatisticalTestResult) optional.get()).getSampleCount()));
entries.put("outliers", Integer.toString(((StatisticalTestResult) optional.get()).getOutlierCount()));
entries.put("mean", String.format(Locale.UK, "%.5f", ((StatisticalTestResult) optional.get()).getMean()));
entries.put("p", String.format(Locale.UK, "%.5f", ((StatisticalTestResult) optional.get()).getPValue()));
entries.put("test", "Student's t-test");
return Optional.ofNullable(FeatureResult.create(text, entries, value2));
} else {
return Optional.empty();
}
}
}
@@ -0,0 +1,40 @@
package me.konsolas.aac.analysis.analyzer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import me.konsolas.aac.analysis.FeatureResult;
import me.konsolas.aac.analysis.feature.FeatureAccumulator;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.player.PlayerLoginInfo;
public class ThresholdFeatureAnalyzer extends FeatureAnalyzer {
private final double threshold;
private final FeatureType feature;
public ThresholdFeatureAnalyzer(String text, double threshold, FeatureType feature) {
super(text);
this.threshold = threshold;
this.feature = feature;
}
@Override
public Optional<FeatureResult> analyze(List<FeatureEvent> values, FeatureAccumulator featureAccumulator, PlayerLoginInfo playerLoginInfo, String text) {
FeatureType feature2 = this.feature;
double total = featureAccumulator.getTotal(feature2);
if (total <= 0.5) {
LinkedHashMap entries = new LinkedHashMap();
entries.put("id", this.getConfigurationPath());
entries.put("score", String.format(Locale.UK, "%.1f", this.threshold));
entries.put("time", String.format(Locale.UK, "%.1f", total));
double value = this.threshold;
return Optional.ofNullable(FeatureResult.create(text, entries, value));
} else {
return Optional.empty();
}
}
}
@@ -0,0 +1,23 @@
package me.konsolas.aac.analysis.feature;
public class FeatureAccumulator {
private static final int FEATURE_COUNT = FeatureType.values().length;
private final int[] counts = new int[FEATURE_COUNT];
private final double[] totals = new double[FEATURE_COUNT];
public void record(FeatureType feature, float value) {
this.counts[feature.ordinal()]++;
this.totals[feature.ordinal()] += value;
}
public int getCount(FeatureType feature) {
return this.counts[feature.ordinal()];
}
public double getTotal(FeatureType feature) {
return this.totals[feature.ordinal()];
}
}
@@ -0,0 +1,37 @@
package me.konsolas.aac.analysis.feature;
import java.util.UUID;
public class FeatureEvent {
private final long timestamp;
private final UUID playerId;
private final FeatureType type;
private final float value;
public FeatureEvent(long timestamp, UUID playerId, FeatureType type, float value) {
this.timestamp = timestamp;
this.playerId = playerId;
this.type = type;
this.value = value;
}
public long getTimestamp() {
return this.timestamp;
}
public UUID getPlayerId() {
return this.playerId;
}
public FeatureType getType() {
return this.type;
}
public float getValue() {
return this.value;
}
}
@@ -0,0 +1,76 @@
package me.konsolas.aac.analysis.feature;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public enum FeatureType {
AAC_NORM_MOVE(2),
AAC_NORM_ATTACK(1),
AAC_NORM_INTERACT(3),
AAC_DELAYS_BREAK(100),
AAC_DELAYS_PLACE(101),
AAC_DELAYS_CONSUME(102),
AAC_DELAYS_BOW(103),
AAC_DELAYS_REGEN(104),
AAC_DELAYS_UNSNEAK(105),
AAC_DELAYS_RELEASE(106),
AAC_DELAYS_BREAKDELAY(108),
AAC_MOVE_NOFALL(300),
AAC_MOVE_VEL(301),
AAC_MOVE_VEHICLE(302),
AAC_MOVE_ELYTRA(303),
AAC_MOVE_WATER(304),
AAC_MOVE_LAVA(305),
AAC_MOVE_NOSLOW(306),
AAC_MOVE_GENERIC(307),
AAC_MOVE_TIMER(308),
AAC_MOVE_INF(309),
AAC_AIMBOT_PITCH_SPREAD(401),
AAC_AIMBOT_SENS_MISMATCH(402),
AAC_AIMBOT_SENS_X_OOR(403),
AAC_AIMBOT_SENS_Y_OOR(404),
AAC_AIMBOT_BAD_DELTA_X(405),
AAC_AIMBOT_BAD_DELTA_Y(406),
AAC_AIMBOT_HEAD_SNAP(407),
AAC_AIMBOT_ZERO_POINT(408),
AAC_CLICK_CPS(500),
AAC_CLICK_VAR(501),
AAC_CLICK_TICK_DELAY(502),
AAC_CLICK_NOSWING(503),
AAC_CLICK_TIMING(504),
AAC_HITBOX_COUNT(601),
AAC_HITBOX_MISS(602),
AAC_HITBOX_WALLS(603),
AAC_HITBOX_REACH(604),
AAC_INTERACT_GEN(700),
AAC_INTERACT_BREAK(701),
AAC_INTERACT_PLACE(702),
AAC_MISC_ABILITIES(801),
AAC_MISC_PITCH(802),
AAC_MISC_ROTATION(803);
private final int id;
private static final Int2ObjectMap BY_ID = new Int2ObjectOpenHashMap();
private FeatureType(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public static FeatureType fromId(int value) {
return (FeatureType) BY_ID.get(value);
}
static {
for (FeatureType feature : values()) {
if (BY_ID.put(feature.getId(), feature) != null) {
throw new IllegalStateException("duplicate mapping for id " + feature);
}
}
}
}
@@ -0,0 +1,56 @@
package me.konsolas.aac.analysis.statistics;
import java.util.List;
import org.hipparchus.distribution.continuous.TDistribution;
public class DistributionAnalysis {
public static int calculateCount(List values, double value) {
int value2 = 0;
while (checkDistributionAnalysis(values, value)) {
value2++;
}
return value2;
}
private static boolean checkDistributionAnalysis(List<Double> values, double value) {
double value2 = 0.0;
double value3 = 0.0;
int size2 = values.size();
if (size2 <= 6) {
return false;
} else {
for (double value4 : values) {
value2 += value4;
value3 += value4 * value4;
}
double value5 = value2 / size2;
double value6 = value3 / size2 - value5 * value5;
double value7 = Math.sqrt(value6);
double value8 = 0.0;
int value9 = -1;
for (int index = 0; index < values.size(); index++) {
double value10 = (Double) values.get(index);
double value11 = Math.abs(value5 - value10);
if (value11 > value8) {
value8 = value11;
value9 = index;
}
}
double value12 = value8 / value7;
double value13 = size2 - 2.0;
double value14 = value13;
TDistribution tDistribution = new TDistribution(value14);
double value15 = value / (2 * size2);
double value16 = tDistribution.inverseCumulativeProbability(value15);
double value17 = value16 * value16;
double value18 = (size2 - 1) / Math.sqrt(size2) * Math.sqrt(value17 / (size2 - 2 + value17));
if (value12 > value18) {
values.remove(value9);
return true;
} else {
return false;
}
}
}
}
@@ -0,0 +1,39 @@
package me.konsolas.aac.analysis.statistics;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import org.hipparchus.stat.StatUtils;
import org.hipparchus.stat.inference.TTest;
public class StatisticalAnalysis {
private static final TTest T_TEST = new TTest();
public static Optional<StatisticalTestResult> testMean(FeatureType feature, List<FeatureEvent> values, double value, boolean matches) {
ArrayList<Double> values2 = new ArrayList();
for (FeatureEvent event : values) {
if (event.getType() == feature) {
values2.add((double) event.getValue());
}
}
int size2 = values2.size();
if (values2.size() <= 6) {
return Optional.empty();
} else {
int value2 = DistributionAnalysis.calculateCount(values2, (double) 0.05);
double[] values3 = values2.stream().mapToDouble(Double::doubleValue).toArray();
double value3 = StatUtils.mean(values3);
if (matches) {
if (value3 <= value) {
return Optional.empty();
}
} else if (value3 >= value) {
return Optional.empty();
}
return Optional.of(new StatisticalTestResult(T_TEST.tTest(value, values3) / 2.0, size2, value2, value3));
}
}
}
@@ -0,0 +1,35 @@
package me.konsolas.aac.analysis.statistics;
public class StatisticalTestResult {
private final double pValue;
private final int sampleCount;
private final int outlierCount;
private final double mean;
public StatisticalTestResult(double pValue, int sampleCount, int outlierCount, double mean) {
this.pValue = pValue;
this.sampleCount = sampleCount;
this.outlierCount = outlierCount;
this.mean = mean;
}
public double getPValue() {
return this.pValue;
}
public int getSampleCount() {
return this.sampleCount;
}
public int getOutlierCount() {
return this.outlierCount;
}
public double getMean() {
return this.mean;
}
}
@@ -0,0 +1,15 @@
package me.konsolas.aac.api;
import java.util.Set;
import org.bukkit.entity.Player;
public interface AACAPI {
void addExemption(Player player, AACExemption aACExemption);
void removeExemption(Player player, AACExemption aACExemption);
Set getExemptions(Player player);
void registerCustomFeatureProvider(AACCustomFeatureProvider aACCustomFeatureProvider);
}
@@ -0,0 +1,33 @@
package me.konsolas.aac.api;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
public class AACCustomFeature {
private final String info;
private final double score;
private final Map tooltip = new LinkedHashMap();
public AACCustomFeature(String text, String info, double score, Map entries) {
this.info = info;
this.score = score;
this.tooltip.put("id", text);
this.tooltip.putAll(entries);
}
public String getInfo() {
return this.info;
}
public Map getTooltip() {
return Collections.unmodifiableMap(this.tooltip);
}
public double getScore() {
return this.score;
}
}
@@ -0,0 +1,9 @@
package me.konsolas.aac.api;
import java.util.Collection;
import org.bukkit.OfflinePlayer;
public interface AACCustomFeatureProvider {
Collection getFeaturesAsync(OfflinePlayer offlinePlayer);
}
@@ -0,0 +1,14 @@
package me.konsolas.aac.api;
public class AACExemption {
private final String reason;
public AACExemption(String reason) {
this.reason = reason;
}
public String getReason() {
return this.reason;
}
}
@@ -0,0 +1,37 @@
package me.konsolas.aac.api.internal;
import java.util.Set;
import me.konsolas.aac.AAC;
import me.konsolas.aac.api.AACAPI;
import me.konsolas.aac.api.AACCustomFeatureProvider;
import me.konsolas.aac.api.AACExemption;
import org.bukkit.entity.Player;
public class AACApiImplementation implements AACAPI {
private final AAC plugin;
public AACApiImplementation(AAC plugin) {
this.plugin = plugin;
}
@Override
public void addExemption(Player player, AACExemption aACExemption) {
this.plugin.getPacketDispatcher().addExemption(player, aACExemption);
}
@Override
public void removeExemption(Player player, AACExemption aACExemption) {
this.plugin.getPacketDispatcher().removeExemption(player, aACExemption);
}
@Override
public Set getExemptions(Player player) {
return this.plugin.getPacketDispatcher().getExemptions(player);
}
@Override
public void registerCustomFeatureProvider(AACCustomFeatureProvider aACCustomFeatureProvider) {
this.plugin.getAnalysisManager().registerFeatureProvider(aACCustomFeatureProvider);
}
}
@@ -0,0 +1,43 @@
package me.konsolas.aac.checks;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.database.PlayerDatabase;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
public abstract class BaseCheck {
private final AAC plugin;
private final Player player;
private final ConfigurationSection configuration;
public BaseCheck(AAC plugin, Player player, String text) {
this.plugin = plugin;
this.player = player;
this.configuration = text == null ? plugin.getConfig().getConfigurationSection("checks") : plugin.getConfig().getConfigurationSection("checks." + text);
if (this.configuration == null) {
throw new IllegalArgumentException("Missing configuration section for checks." + text);
}
}
protected ConfigurationSection getConfiguration() {
return this.configuration;
}
public AAC getPlugin() {
return this.plugin;
}
public Player getPlayer() {
return this.player;
}
protected void recordFeature(FeatureType feature, float value) {
PlayerDatabase database = this.getPlugin().getDatabase();
Player player = this.getPlayer();
database.recordFeature(player, feature, value);
}
}
@@ -0,0 +1,244 @@
package me.konsolas.aac.checks;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Play.Client;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerAction;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerDigType;
import me.konsolas.aac.AAC;
import me.konsolas.aac.checks.combat.AimbotCheck;
import me.konsolas.aac.checks.combat.AutoClickerCheck;
import me.konsolas.aac.checks.combat.HitboxCheck;
import me.konsolas.aac.checks.interaction.InteractCheck;
import me.konsolas.aac.checks.movement.MovementCheck;
import me.konsolas.aac.checks.player.ActionDelayCheck;
import me.konsolas.aac.checks.player.ActionStateTracker;
import me.konsolas.aac.checks.player.MiscellaneousCheck;
import me.konsolas.aac.protocol.EntityVelocityPacket;
import me.konsolas.aac.protocol.PacketReader;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerMoveEvent;
public class PlayerChecks extends BaseCheck {
private long lastTick;
private final ActionDelayCheck delayCheck;
private final MovementCheck movementCheck;
private final AimbotCheck aimbotCheck;
private final AutoClickerCheck autoClickerCheck;
private final HitboxCheck hitboxCheck;
private final InteractCheck interactCheck;
private final MiscellaneousCheck miscellaneousCheck;
private final ActionStateTracker actionStateCheck;
public PlayerChecks(AAC aacPlugin, Player player) {
super(aacPlugin, player, (String) (null));
this.lastTick = 0L;
this.delayCheck = this.getConfiguration().getBoolean("delays.enabled") ? new ActionDelayCheck(aacPlugin, player) : null;
this.movementCheck = this.getConfiguration().getBoolean("move.enabled") ? new MovementCheck(aacPlugin, player) : null;
this.aimbotCheck = this.getConfiguration().getBoolean("aimbot.enabled") ? new AimbotCheck(aacPlugin, player) : null;
this.autoClickerCheck = this.getConfiguration().getBoolean("autoclicker.enabled") ? new AutoClickerCheck(aacPlugin, player) : null;
this.hitboxCheck = this.getConfiguration().getBoolean("hitbox.enabled") ? new HitboxCheck(aacPlugin, player) : null;
this.interactCheck = this.getConfiguration().getBoolean("interact.enabled") ? new InteractCheck(aacPlugin, player) : null;
this.miscellaneousCheck = this.getConfiguration().getBoolean("misc.enabled") ? new MiscellaneousCheck(aacPlugin, player) : null;
this.actionStateCheck = new ActionStateTracker(aacPlugin, player);
}
public void updateLocation(Location location) {
if (this.movementCheck != null) {
this.movementCheck.updateLocation(location);
}
}
public void updateLocationWithMovementCheck(Location location) {
if (this.movementCheck != null) {
this.movementCheck.updateLocationWithFallDistance(location);
}
if (this.aimbotCheck != null) {
this.aimbotCheck.updateLocation(location);
}
}
public void onEvent(Event event) {
if (event instanceof PlayerMoveEvent) {
this.actionStateCheck.recordMovement();
}
if (event instanceof BlockPlaceEvent) {
BlockPlaceEvent blockPlaceEvent = (BlockPlaceEvent) event;
if (this.delayCheck != null && this.delayCheck.isActionDelay()) {
blockPlaceEvent.setCancelled(true);
}
} else if (event instanceof BlockDamageEvent) {
BlockDamageEvent blockDamageEvent = (BlockDamageEvent) event;
if (this.delayCheck != null) {
ActionDelayCheck actionDelayCheck = this.delayCheck;
boolean instaBreak = blockDamageEvent.getInstaBreak();
boolean matches = instaBreak;
if (actionDelayCheck.checkActionDelay(matches)) {
blockDamageEvent.setCancelled(true);
}
}
} else if (event instanceof BlockBreakEvent) {
BlockBreakEvent blockBreakEvent = (BlockBreakEvent) event;
if (this.delayCheck != null) {
ActionDelayCheck actionDelayCheck2 = this.delayCheck;
Block block = blockBreakEvent.getBlock();
if (actionDelayCheck2.checkActionDelay(block)) {
blockBreakEvent.setCancelled(true);
}
}
if (this.interactCheck != null) {
InteractCheck interactCheck2 = this.interactCheck;
Block block2 = blockBreakEvent.getBlock();
if (interactCheck2.checkInteract(block2)) {
blockBreakEvent.setCancelled(true);
}
}
} else if (event instanceof PlayerInteractEvent) {
PlayerInteractEvent playerInteractEvent = (PlayerInteractEvent) event;
if (this.delayCheck != null) {
ActionDelayCheck actionDelayCheck3 = this.delayCheck;
Action action = playerInteractEvent.getAction();
Action action2 = action;
actionDelayCheck3.onAction(action2);
}
if (this.interactCheck != null && this.interactCheck.onPlayerInteractEvent(playerInteractEvent)) {
playerInteractEvent.setCancelled(true);
}
this.actionStateCheck.recordInteraction();
} else if (event instanceof PlayerItemConsumeEvent) {
PlayerItemConsumeEvent playerItemConsumeEvent = (PlayerItemConsumeEvent) event;
if (this.delayCheck != null) {
ActionDelayCheck actionDelayCheck4 = this.delayCheck;
Material type = playerItemConsumeEvent.getItem().getType();
Material material = type;
if (actionDelayCheck4.checkActionDelay(material)) {
playerItemConsumeEvent.setCancelled(true);
}
}
} else if (event instanceof EntityShootBowEvent) {
EntityShootBowEvent entityShootBowEvent = (EntityShootBowEvent) event;
if (this.delayCheck != null && entityShootBowEvent.getBow() != null && entityShootBowEvent.getBow().getType() == Material.BOW) {
ActionDelayCheck actionDelayCheck5 = this.delayCheck;
float force = entityShootBowEvent.getForce();
if (actionDelayCheck5.checkActionDelay(force)) {
entityShootBowEvent.setCancelled(true);
}
}
} else if (event instanceof EntityRegainHealthEvent) {
EntityRegainHealthEvent entityRegainHealthEvent = (EntityRegainHealthEvent) event;
if (this.delayCheck != null) {
ActionDelayCheck actionDelayCheck6 = this.delayCheck;
RegainReason regainReason = entityRegainHealthEvent.getRegainReason();
if (actionDelayCheck6.onEntityRegainHealthEventRegainReason(regainReason)) {
entityRegainHealthEvent.setCancelled(true);
}
}
}
}
public void handlePacket(PacketEvent event) {
if (this.movementCheck != null) {
this.movementCheck.handlePacket(event);
}
if (this.hitboxCheck != null) {
this.hitboxCheck.handlePacket(event);
}
if (event.getPacketType() == Client.ENTITY_ACTION) {
if (event.getPacket().getPlayerActions().read(0) == PlayerAction.STOP_SNEAKING && this.delayCheck != null) {
this.delayCheck.tickWithCheckFastSneak();
}
} else if (event.getPacketType() == Client.BLOCK_DIG) {
if (event.getPacket().getPlayerDigTypes().read(0) == PlayerDigType.RELEASE_USE_ITEM && this.delayCheck != null) {
this.delayCheck.tick();
}
if (this.autoClickerCheck != null) {
AutoClickerCheck autoClickerCheck2 = this.autoClickerCheck;
BlockPosition blockPosition = (BlockPosition) event.getPacket().getBlockPositionModifier().read(0);
PlayerDigType playerDigType = (PlayerDigType) event.getPacket().getPlayerDigTypes().read(0);
BlockPosition blockPosition2 = blockPosition;
autoClickerCheck2.updateBlockPosition(blockPosition2, playerDigType);
}
} else {
PacketType packetType = event.getPacketType();
if (PacketReader.checkPacketReader(packetType)) {
if (this.autoClickerCheck != null) {
this.autoClickerCheck.tickWithTickDelayCheck();
}
if (this.interactCheck != null) {
InteractCheck interactCheck2 = this.interactCheck;
PacketContainer packet = event.getPacket();
PacketContainer packet2 = packet;
interactCheck2.handlePacket(packet2);
}
} else if (event.getPacketType() == Client.BLOCK_PLACE || event.getPacketType() == PacketReader.USE_ITEM) {
PacketContainer packet3 = event.getPacket();
EntityVelocityPacket entityVelocityPacket = EntityVelocityPacket.create(packet3);
if (entityVelocityPacket != null && this.autoClickerCheck != null) {
this.autoClickerCheck.tickWithCheckTiming();
}
} else if (event.getPacketType() == Client.ABILITIES && this.miscellaneousCheck != null) {
long value = this.lastTick;
this.miscellaneousCheck.updateTime(value);
}
}
if (event.getPacketType() == Client.LOOK || event.getPacketType() == Client.POSITION_LOOK) {
float value2 = (Float) event.getPacket().getFloat().read(0);
float value3 = (Float) event.getPacket().getFloat().read(1);
if (this.aimbotCheck != null) {
this.aimbotCheck.analyzeRotation(value3, value2);
}
if (this.miscellaneousCheck != null) {
long value4 = this.lastTick;
this.miscellaneousCheck.updateTime(value4, value3, value2);
}
}
PacketContainer packet4 = event.getPacket();
if (PacketReader.checkPacketReader(packet4)) {
if (this.aimbotCheck != null) {
this.aimbotCheck.tick();
}
if (this.autoClickerCheck != null) {
this.autoClickerCheck.updateCount();
}
this.actionStateCheck.recordAttack();
}
if (event.getPacketType() == Client.ARM_ANIMATION && this.autoClickerCheck != null) {
this.autoClickerCheck.tick();
}
}
public void updateTime(long value) {
this.lastTick++;
if (this.movementCheck != null) {
this.movementCheck.tick();
}
if (this.hitboxCheck != null) {
this.hitboxCheck.tick();
}
this.actionStateCheck.updateTime(value);
}
}
@@ -0,0 +1,48 @@
package me.konsolas.aac.checks;
import java.util.Map;
import java.util.Objects;
import org.bukkit.configuration.ConfigurationSection;
public class ViolationBuffer {
private float level;
private long lastUpdate;
private final boolean mitigate;
private final float threshold;
private final float maximum;
private final float decay;
public ViolationBuffer(boolean mitigate, float threshold, float value2, float decay) {
this.mitigate = mitigate;
this.threshold = threshold;
this.maximum = Math.max(value2, 1.0F);
this.decay = decay;
}
public boolean checkViolationBuffer(float value) {
long now = System.currentTimeMillis();
this.level = Math.min(Math.max(Math.max(this.level - this.decay * (float) (now - this.lastUpdate) / 1000.0F, 0.0F) + value, 0.0F), this.maximum);
this.lastUpdate = now;
return this.mitigate && this.level >= this.threshold;
}
public float getLevel() {
return this.level;
}
public static ViolationBuffer create(Map entries) {
return new ViolationBuffer((Boolean) entries.get("mitigate"), ((Number) entries.get("threshold")).floatValue(), ((Number) entries.get("max")).floatValue(), ((Number) entries.get("decay")).floatValue());
}
public static ViolationBuffer create(ConfigurationSection section, String text) {
Map values = ((ConfigurationSection) Objects.requireNonNull(section.get(text))).getValues(false);
Map entries = values;
return create(entries);
}
}
@@ -0,0 +1,150 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import me.konsolas.aac.util.math.MouseSensitivityMath;
import me.konsolas.aac.util.math.MouseStepEstimator;
import me.konsolas.aac.util.time.ExpiringCounter;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class AimbotCheck extends BaseCheck {
private long lastAttack;
private final ExpiringCounter sampleTimer;
private float lastPitch;
private float lastYaw;
private float previousPitch;
private float previousYaw;
private final double[] yawSamples;
private final double[] pitchSamples;
private int sampleIndex;
private boolean checkMouseDelta;
private boolean checkSensitivity;
private double yawSensitivity;
private double pitchSensitivity;
private float lastSensitivity;
private final SensitivityCheck sensitivityCheck;
private final MouseDeltaCheck mouseDeltaCheck;
private final HeadSnapCheck headSnapCheck;
private final PitchSpreadCheck pitchSpreadCheck;
private final boolean checkZeroPoint;
public AimbotCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("aimbot"));
this.sampleTimer = new ExpiringCounter();
this.yawSamples = new double[50];
this.pitchSamples = new double[50];
this.sampleIndex = 0;
this.checkMouseDelta = false;
this.sensitivityCheck = this.getConfiguration().getBoolean("check_sensitivity") ? new SensitivityCheck(aacPlugin, player) : null;
this.mouseDeltaCheck = this.getConfiguration().getBoolean("check_mouse_delta") ? new MouseDeltaCheck(aacPlugin, player) : null;
this.headSnapCheck = this.getConfiguration().getBoolean("check_head_snap") ? new HeadSnapCheck(aacPlugin, player) : null;
this.pitchSpreadCheck = this.getConfiguration().getBoolean("check_pitch_spread") ? new PitchSpreadCheck(aacPlugin, player) : null;
this.checkZeroPoint = this.getConfiguration().getBoolean("check_zero_point");
Location location = player.getLocation();
Location location2 = location;
this.updateLocation(location2);
}
public void updateLocation(Location location) {
this.previousYaw = this.lastYaw = location.getYaw();
this.previousPitch = this.lastPitch = location.getPitch();
}
public void analyzeRotation(float value, float value2) {
if (this.getPlayer().getVehicle() != null) {
this.previousYaw = this.lastYaw = value;
this.previousPitch = this.lastPitch = value2;
} else {
float value3 = Math.abs(value2 - this.previousYaw);
float value4 = Math.abs(value - this.previousPitch);
if (value3 > 0.1 && value4 > 0.1 && value3 < 180.0F && Math.abs(value) < 89.0F && Math.abs(this.previousPitch) < 89.0F) {
this.yawSamples[this.sampleIndex] = value3;
this.pitchSamples[this.sampleIndex] = value4;
if (++this.sampleIndex == 50) {
this.sampleIndex = 0;
this.checkMouseDelta = true;
this.checkSensitivity = true;
}
}
this.previousPitch = value;
this.previousYaw = value2;
if (System.currentTimeMillis() - this.lastAttack <= 500L) {
if (this.pitchSpreadCheck != null) {
this.pitchSpreadCheck.updateValue(value4, value3);
}
if (this.headSnapCheck != null) {
this.headSnapCheck.updateValue(value4, value3);
}
if (this.checkMouseDelta && this.sensitivityCheck != null) {
this.updateRotation(value3, value4);
}
if (this.checkMouseDelta && this.checkZeroPoint) {
float value5 = (float) Math.abs(this.lastYaw - Math.round(this.lastYaw / this.yawSensitivity) * this.yawSensitivity);
float value6 = (float) Math.abs(value - Math.round(value2 / this.yawSensitivity) * this.yawSensitivity);
if (value6 < 1.0E-5 && value5 > 0.001 && this.sampleTimer.tryAcquire()) {
float value7 = (float) this.yawSensitivity;
FeatureType feature = FeatureType.AAC_AIMBOT_ZERO_POINT;
this.recordFeature(feature, value7);
}
}
}
}
}
private void updateRotation(float value, float value2) {
if (this.checkSensitivity) {
this.checkSensitivity = false;
double[] values = this.yawSamples;
this.yawSensitivity = MouseStepEstimator.estimateStep(values);
double[] values2 = this.pitchSamples;
this.pitchSensitivity = MouseStepEstimator.estimateStep(values2);
double value6 = this.yawSensitivity;
double value7 = MouseSensitivityMath.estimateSensitivity(value6);
double value8 = this.pitchSensitivity;
double value9 = MouseSensitivityMath.estimateAbsoluteSensitivity(value8);
int value10 = MouseSensitivityMath.sensitivityPercent(value7);
int value11 = MouseSensitivityMath.sensitivityPercent(value9);
if (!this.sensitivityCheck.checkHeadSnap(value10, value11)) {
this.sampleIndex = 0;
this.checkMouseDelta = false;
return;
}
this.lastSensitivity = (float) value7;
}
double value12 = value;
double value13 = this.yawSensitivity;
double value14 = value12;
int value15 = MouseSensitivityMath.mouseCounts(value14, value13);
double value16 = value2;
double value17 = this.pitchSensitivity;
double value18 = value16;
int value19 = MouseSensitivityMath.absoluteMouseCounts(value18, value17);
float value20 = this.lastSensitivity;
this.mouseDeltaCheck.updateCount(value15, value19, value, value2, value20);
}
public void tick() {
this.lastAttack = System.currentTimeMillis();
}
}
@@ -0,0 +1,100 @@
package me.konsolas.aac.checks.combat;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerDigType;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
import org.hipparchus.stat.StatUtils;
public class AutoClickerCheck extends BaseCheck {
private boolean checkTiming;
private long lastClick;
private long lastSwing;
private long lastTick;
private final double[] clickSamples;
private int sampleIndex;
private final ClickTickDelayCheck tickDelayCheck;
private final ClickTimingCheck timingCheck;
private final NoSwingCheck noSwingCheck;
public AutoClickerCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("autoclicker"));
this.checkTiming = false;
this.sampleIndex = 0;
this.tickDelayCheck = this.getConfiguration().getBoolean("check_tick_delay") ? new ClickTickDelayCheck(aacPlugin, player) : null;
this.timingCheck = this.getConfiguration().getBoolean("check_no_swing") ? new ClickTimingCheck(aacPlugin, player) : null;
this.noSwingCheck = this.getConfiguration().getBoolean("check_timing") ? new NoSwingCheck(aacPlugin, player) : null;
this.clickSamples = new double[this.getConfiguration().getInt("sample_size")];
}
public void updateCount() {
if (this.tickDelayCheck != null) {
this.tickDelayCheck.tickWithClicksThisTick();
}
if (this.timingCheck != null) {
this.timingCheck.tick();
}
if (this.noSwingCheck != null) {
this.noSwingCheck.tick();
}
this.lastTick = System.currentTimeMillis();
}
public void tickWithTickDelayCheck() {
if (this.tickDelayCheck != null) {
this.tickDelayCheck.tick();
}
if (this.noSwingCheck != null) {
this.noSwingCheck.tickWithLastSwing();
}
}
public void tick() {
long now = System.currentTimeMillis();
if (this.timingCheck != null) {
this.timingCheck.tickWithPreviousAttack();
}
if (!this.checkTiming && now - this.lastClick >= 100L && System.currentTimeMillis() - this.lastTick <= 1000L) {
if (this.lastSwing != 0L) {
double value = (now - this.lastSwing) / 1000.0;
this.clickSamples[this.sampleIndex++] = value;
if (this.sampleIndex >= this.clickSamples.length) {
this.sampleIndex = 0;
double[] values = this.clickSamples;
double value2 = StatUtils.mean(values);
double[] values2 = this.clickSamples;
double value3 = StatUtils.variance(values2);
float value4 = (float) (1.0 / value2);
FeatureType feature = FeatureType.AAC_CLICK_CPS;
this.recordFeature(feature, value4);
float value5 = (float) value3;
FeatureType feature2 = FeatureType.AAC_CLICK_VAR;
this.recordFeature(feature2, value5);
}
}
this.lastSwing = now;
} else {
this.lastSwing = 0L;
}
}
public void updateBlockPosition(BlockPosition blockPosition, PlayerDigType playerDigType) {
this.checkTiming = playerDigType == PlayerDigType.START_DESTROY_BLOCK;
}
public void tickWithCheckTiming() {
this.checkTiming = false;
this.lastClick = System.currentTimeMillis();
}
}
@@ -0,0 +1,42 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
public class ClickTickDelayCheck extends BaseCheck {
private int previousClicks;
private int clicksThisTick;
private int previousDelta;
private int violations;
public ClickTickDelayCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("autoclicker"));
}
public void tickWithClicksThisTick() {
int value = this.clicksThisTick - this.previousClicks;
if (value == this.previousDelta) {
this.violations++;
if (this.violations >= 16) {
float value2 = this.violations;
FeatureType feature = FeatureType.AAC_CLICK_TICK_DELAY;
this.recordFeature(feature, value2);
}
} else {
this.violations = 0;
}
this.previousDelta = value;
this.previousClicks = this.clicksThisTick;
this.clicksThisTick = 0;
}
public void tick() {
this.clicksThisTick++;
}
}
@@ -0,0 +1,29 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
public class ClickTimingCheck extends BaseCheck {
boolean previousAttack;
public ClickTimingCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("autoclicker"));
this.previousAttack = false;
}
public void tick() {
if (this.previousAttack) {
FeatureType feature = FeatureType.AAC_CLICK_NOSWING;
this.recordFeature(feature, (float) 0.0F);
} else {
this.previousAttack = true;
}
}
public void tickWithPreviousAttack() {
this.previousAttack = false;
}
}
@@ -0,0 +1,71 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
public class HeadSnapCheck extends BaseCheck {
private float lastYaw;
private float lastPitch;
private final float[] yawSamples;
private final float[] pitchSamples;
private int sampleIndex;
private float previousDelta;
public HeadSnapCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("aimbot"));
this.yawSamples = new float[20];
this.pitchSamples = new float[20];
this.sampleIndex = 0;
this.previousDelta = 0.0F;
}
public void updateValue(float value, float value2) {
if (value2 > 0.0 && value > 0.0) {
float value3 = Math.abs(value2 - this.lastPitch);
float value4 = Math.abs(value - this.lastYaw);
this.lastPitch = value2;
this.lastYaw = value;
float value5 = Math.abs(value3 - value2);
float value6 = Math.abs(value4 - value);
this.pitchSamples[this.sampleIndex] = value5;
this.yawSamples[this.sampleIndex] = value6;
if (++this.sampleIndex == 20) {
this.sampleIndex = 0;
for (int index = 0; index < 20; index++) {
if (this.yawSamples[index] == 0.0F || this.pitchSamples[index] == 0.0F) {
return;
}
}
float value7 = 0.0F;
float value8 = 0.0F;
float value9 = 0.0F;
float value10 = 0.0F;
for (int index2 = 0; index2 < 20; index2++) {
value7 += this.pitchSamples[index2];
value8 += this.pitchSamples[index2] * this.pitchSamples[index2];
value9 += this.yawSamples[index2];
value10 += this.yawSamples[index2] * this.yawSamples[index2];
}
float value11 = (float) (value8 / 20.0F - Math.pow(value7 / 20.0F, 2.0));
float value12 = (float) (value10 / 20.0F - Math.pow(value9 / 20.0F, 2.0));
if (value11 > 50.0F && value12 > 3.0F) {
if (++this.previousDelta > 3.0F) {
float value13 = value11 + value12;
FeatureType feature = FeatureType.AAC_AIMBOT_HEAD_SNAP;
this.recordFeature(feature, value13);
} else {
this.previousDelta = Math.max(this.previousDelta - 0.1F, 0.0F);
}
}
}
}
}
}
@@ -0,0 +1,231 @@
package me.konsolas.aac.checks.combat;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import me.konsolas.aac.checks.ViolationBuffer;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.NativeAccessProvider;
import me.konsolas.aac.debug.DebugManager;
import me.konsolas.aac.movement.PlayerPose;
import me.konsolas.aac.protocol.PacketReader;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.timings.EntityTracker;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.util.time.ExpiringCounter;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
public class HitboxCheck extends BaseCheck {
private static final Vector previousEyePosition = new Vector(0.1, 0.1, 0.1);
private static final Vector eyePosition = new Vector(0.13, 0.13, 0.13);
private static final Vector lookDirection = new Vector(0.5, 0.5, 0.5);
private final BlockingQueue<TeleportState> pendingAttacks;
private Location lastLocation;
private final ExpiringCounter attackTimer;
private final ViolationBuffer hitboxBuffer;
private final boolean checkBlocks;
public HitboxCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("hitbox"));
this.pendingAttacks = new ArrayBlockingQueue(10);
this.attackTimer = new ExpiringCounter(100L);
this.checkBlocks = this.getConfiguration().getBoolean("check_blocks");
ConfigurationSection configuration = this.getConfiguration();
ConfigurationSection section = configuration;
this.hitboxBuffer = ViolationBuffer.create(section, (String) "vl");
}
public void handlePacket(PacketEvent event) {
PacketContainer packet = event.getPacket();
PacketType type = packet.getType();
if (PacketReader.checkPacketReader(type)) {
if (this.lastLocation == null || this.lastLocation.getWorld() != this.getPlayer().getWorld()) {
this.lastLocation = this.getPlayer().getLocation();
}
Location location = this.lastLocation;
this.lastLocation = PacketReader.findLocation(packet, location);
if (this.getPlayer().getVehicle() != null) {
Location location2 = this.getPlayer().getLocation();
this.lastLocation.setX(location2.getX());
this.lastLocation.setY(location2.getY());
this.lastLocation.setZ(location2.getZ());
}
for (TeleportState teleportState : this.pendingAttacks) {
Location location3 = this.lastLocation;
TeleportState.updateTeleportState(teleportState, location3);
}
} else if (PacketReader.checkPacketReader(packet)) {
int value2 = (Integer) packet.getIntegers().read(0);
if (value2 < 0) {
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "hitbox: ignoring invalid eid " + value2);
}
return;
}
if (!this.pendingAttacks.offer(new TeleportState(value2, this.lastLocation))) {
this.hitboxBuffer.checkViolationBuffer((float) 1.0F);
FeatureType feature = FeatureType.AAC_HITBOX_COUNT;
this.recordFeature(feature, (float) 1.0F);
}
if (this.hitboxBuffer.checkViolationBuffer((float) 0.0F)) {
event.setCancelled(true);
}
}
}
private RayTraceCandidate findRayTraceCandidate(Location location, Iterable<AxisAlignedBoundingBox> iterable, Vector vector) {
Vector direction = location.getDirection();
Vector vector2 = location.toVector();
double value;
BlockRayTraceResult blockRayTraceResult;
if (this.checkBlocks) {
NativeAccess instance = NativeAccessProvider.getInstance();
Player player = this.getPlayer();
blockRayTraceResult = instance.rayTrace(player, vector2, direction, 4.5);
value = blockRayTraceResult.isBlockRayTraceResult() ? blockRayTraceResult.getVector().distance(vector2) : Double.POSITIVE_INFINITY;
} else {
blockRayTraceResult = null;
value = Double.POSITIVE_INFINITY;
}
double value2 = Double.POSITIVE_INFINITY;
for (AxisAlignedBoundingBox box : iterable) {
if (box != null) {
double value3 = box.expand(vector).rayIntersectionDistance(vector2, direction);
if (value3 < value2) {
value2 = value3;
if (value3 < Math.min(3.0, value)) {
break;
}
}
}
}
return new RayTraceCandidate(value2, value, blockRayTraceResult);
}
public void tick() {
if (!this.pendingAttacks.isEmpty()) {
ArrayList<TeleportState> values = new ArrayList();
while (!this.pendingAttacks.isEmpty() && (TeleportState.findLocation((TeleportState) this.pendingAttacks.element()) != null || TeleportState.checkTeleportState((TeleportState) this.pendingAttacks.element()))) {
values.add((TeleportState) this.pendingAttacks.poll());
}
for (TeleportState teleportState : this.pendingAttacks) {
TeleportState.checkTeleportState(teleportState, true);
}
AAC plugin = this.getPlugin();
Player player = this.getPlayer();
Player player2 = player;
ProtocolVersion version = plugin.getProtocolVersion(player2);
ArrayList<Location> values2 = new ArrayList();
for (TeleportState teleportState2 : values) {
if (TeleportState.findLocationWithOrigin(teleportState2) != null) {
Vector vector = this.getPlayer().getVehicle() != null ? lookDirection : (TeleportState.findLocation(teleportState2) == null ? eyePosition : previousEyePosition);
Entity entityFromID = ProtocolLibrary.getProtocolManager().getEntityFromID(this.getPlayer().getWorld(), TeleportState.calculateCount(teleportState2));
if (entityFromID instanceof LivingEntity && !(entityFromID instanceof Enderman)) {
EntityTracker entityTracker = this.getPlugin().getEntityTracker();
LivingEntity livingEntity = (LivingEntity) entityFromID;
entityTracker.updateLivingEntity(livingEntity);
EntityTracker entityTracker2 = this.getPlugin().getEntityTracker();
LivingEntity livingEntity2 = (LivingEntity) entityFromID;
List values3 = entityTracker2.findList(livingEntity2);
if (values3 != null) {
values2.clear();
values2.add(TeleportState.findLocationWithOrigin(teleportState2));
if (TeleportState.findLocation(teleportState2) != null) {
values2.add(TeleportState.findLocation(teleportState2));
values2.add(TeleportState.findLocation(teleportState2).clone().setDirection(TeleportState.findLocationWithOrigin(teleportState2).getDirection()));
values2.add(TeleportState.findLocationWithOrigin(teleportState2).clone().setDirection(TeleportState.findLocation(teleportState2).getDirection()));
}
RayTraceCandidate rayTraceCandidate = null;
for (PlayerPose playerPose : PlayerPose.POSES) {
double value = playerPose.calculateValue(version);
for (Location location : values2) {
location = location.clone().add(0.0, value, 0.0);
RayTraceCandidate rayTraceCandidate2 = this.findRayTraceCandidate(location, values3, vector);
if (RayTraceCandidate.checkRayTraceCandidate(rayTraceCandidate2, rayTraceCandidate)) {
rayTraceCandidate = rayTraceCandidate2;
}
}
}
assert rayTraceCandidate != null;
if (!Double.isFinite(RayTraceCandidate.calculateValueWithDistance(rayTraceCandidate))) {
float value2 = RayTraceCandidate.calculateValue(rayTraceCandidate);
DebugManager debugManager = this.getPlugin().getDebugManager();
player = this.getPlayer();
Player player3 = player;
if (debugManager.isDebugging(player3)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "hitbox: no intersection: %.3f%+.3f", new Object[] { this.hitboxBuffer.getLevel(), value2 });
}
this.hitboxBuffer.checkViolationBuffer(value2);
if (this.attackTimer.tryAcquire()) {
FeatureType feature = FeatureType.AAC_HITBOX_MISS;
this.recordFeature(feature, value2);
}
} else if (RayTraceCandidate.calculateValueWithDistance(rayTraceCandidate) > RayTraceCandidate.calculateValueWithTolerance(rayTraceCandidate)) {
float value3 = RayTraceCandidate.calculateValue(rayTraceCandidate);
DebugManager debugManager2 = this.getPlugin().getDebugManager();
player = this.getPlayer();
Player player4 = player;
if (debugManager2.isDebugging(player4)) {
assert RayTraceCandidate.findBlockRayTraceResult(rayTraceCandidate) != null;
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "hitbox: through block: %s (%.3f > %.3f): %.3f%+.3f", new Object[] { RayTraceCandidate.findBlockRayTraceResult(rayTraceCandidate).getBlockVector().toLocation(this.getPlayer().getWorld()).getBlock().getType(), RayTraceCandidate.calculateValueWithDistance(rayTraceCandidate), RayTraceCandidate.calculateValueWithTolerance(rayTraceCandidate), this.hitboxBuffer.getLevel(), value3 });
}
this.hitboxBuffer.checkViolationBuffer(value3);
if (this.attackTimer.tryAcquire()) {
FeatureType feature2 = FeatureType.AAC_HITBOX_WALLS;
this.recordFeature(feature2, value3);
}
} else {
float value4 = RayTraceCandidate.calculateValue(rayTraceCandidate);
DebugManager debugManager3 = this.getPlugin().getDebugManager();
player = this.getPlayer();
Player player5 = player;
if (debugManager3.isDebugging(player5)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "hitbox: normal: %.3f: %.3f%+.3f", new Object[] { RayTraceCandidate.calculateValueWithDistance(rayTraceCandidate), this.hitboxBuffer.getLevel(), value4 });
}
this.hitboxBuffer.checkViolationBuffer(value4);
if (this.attackTimer.tryAcquire()) {
FeatureType feature3 = FeatureType.AAC_HITBOX_REACH;
this.recordFeature(feature3, value4);
}
}
} else {
DebugManager debugManager4 = this.getPlugin().getDebugManager();
player = this.getPlayer();
Player player6 = player;
if (debugManager4.isDebugging(player6)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "hitbox: no data for eid " + TeleportState.calculateCount(teleportState2) + " in " + Objects.requireNonNull(TeleportState.findLocationWithOrigin(teleportState2).getWorld()).getName());
}
}
}
}
}
}
}
}
@@ -0,0 +1,34 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import me.konsolas.aac.util.time.ExpiringCounter;
import org.bukkit.entity.Player;
public class MouseDeltaCheck extends BaseCheck {
private final ExpiringCounter sampleTimer;
public MouseDeltaCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("aimbot"));
this.sampleTimer = new ExpiringCounter();
}
public void updateCount(int value, int value2, float value3, float value4, float value5) {
float value6 = value5 * 0.6F + 0.2F;
float value7 = value6 * value6 * value6 * 8.0F;
float value8 = value * value7 * 0.15F;
float value9 = value2 * value7 * 0.15F;
float value10 = Math.abs(value3 - value8);
float value11 = Math.abs(value4 - value9);
if (value10 > 0.01 && this.sampleTimer.tryAcquire()) {
FeatureType feature = FeatureType.AAC_AIMBOT_BAD_DELTA_X;
this.recordFeature(feature, value10);
}
if (value11 > 0.01 && this.sampleTimer.tryAcquire()) {
FeatureType feature2 = FeatureType.AAC_AIMBOT_BAD_DELTA_Y;
this.recordFeature(feature2, value11);
}
}
}
@@ -0,0 +1,37 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
public class NoSwingCheck extends BaseCheck {
private long lastSwing;
private long lastAttack;
public NoSwingCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("autoclicker"));
}
public void tickWithLastSwing() {
long now = System.currentTimeMillis();
long value = now - this.lastSwing;
this.lastSwing = System.currentTimeMillis();
if (value < 25L) {
this.lastAttack = now;
}
}
public void tick() {
long now = System.currentTimeMillis();
long value = now - this.lastSwing;
long value2 = now - this.lastAttack;
if (value < 5L && value2 > 50L) {
float value3 = (float) value / 1000.0F;
FeatureType feature = FeatureType.AAC_CLICK_TIMING;
this.recordFeature(feature, value3);
}
}
}
@@ -0,0 +1,49 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
public class PitchSpreadCheck extends BaseCheck {
private final float[] pitchSamples;
private int sampleIndex;
private float lastPitch;
private int sampleCount;
public PitchSpreadCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("aimbot"));
this.pitchSamples = new float[20];
this.sampleIndex = 0;
this.lastPitch = 0.0F;
}
public void updateValue(float value, float value2) {
if (value2 > 0.0 && value > 0.0) {
this.pitchSamples[this.sampleIndex++] = value;
if (this.sampleIndex == this.pitchSamples.length) {
float value3 = 0.0F;
float value4 = 0.0F;
for (float value5 : this.pitchSamples) {
value3 += value5;
value4 += value5 * value5;
}
float value6 = value3 / this.pitchSamples.length;
float value7 = value4 / this.pitchSamples.length - value6 * value6;
double value8 = Math.abs(value6 - this.lastPitch);
if (!(value8 > 1.0) || !(value7 > 36.0)) {
this.sampleCount = Math.max(this.sampleCount - 1, 0);
} else if ((this.sampleCount += 4) > 20) {
FeatureType feature = FeatureType.AAC_AIMBOT_PITCH_SPREAD;
this.recordFeature(feature, value7);
}
this.sampleIndex = 0;
this.lastPitch = value6;
}
}
}
}
@@ -0,0 +1,56 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.world.BlockRayTraceResult;
class RayTraceCandidate {
private final double distance;
private final double tolerance;
private final BlockRayTraceResult result;
RayTraceCandidate(double distance, double tolerance, BlockRayTraceResult result) {
this.distance = distance;
this.tolerance = tolerance;
this.result = result;
}
private float calculateValue() {
if (!Double.isFinite(this.distance)) {
return 1.0F;
} else {
return this.distance > this.tolerance ? (float) (this.distance - this.tolerance) + 1.0F : (float) this.distance - 3.0F;
}
}
private boolean checkRayTraceCandidate(RayTraceCandidate rayTraceCandidate) {
if (rayTraceCandidate == null) {
return true;
} else if (Double.isFinite(this.distance) && !Double.isFinite(rayTraceCandidate.distance)) {
return true;
} else {
return this.distance <= this.tolerance && rayTraceCandidate.distance > rayTraceCandidate.tolerance ? true : this.calculateValue() < rayTraceCandidate.calculateValue();
}
}
static boolean checkRayTraceCandidate(RayTraceCandidate rayTraceCandidate, RayTraceCandidate rayTraceCandidate2) {
return rayTraceCandidate.checkRayTraceCandidate(rayTraceCandidate2);
}
static double calculateValueWithDistance(RayTraceCandidate rayTraceCandidate) {
return rayTraceCandidate.distance;
}
static float calculateValue(RayTraceCandidate rayTraceCandidate) {
return rayTraceCandidate.calculateValue();
}
static double calculateValueWithTolerance(RayTraceCandidate rayTraceCandidate) {
return rayTraceCandidate.tolerance;
}
static BlockRayTraceResult findBlockRayTraceResult(RayTraceCandidate rayTraceCandidate) {
return rayTraceCandidate.result;
}
}
@@ -0,0 +1,51 @@
package me.konsolas.aac.checks.combat;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
public class SensitivityCheck extends BaseCheck {
private boolean previousSnap;
public SensitivityCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("aimbot"));
}
public boolean checkHeadSnap(int value, int value2) {
if (value >= 0 && value <= 200) {
if (value2 >= 0 && value2 <= 200) {
if (value != value2) {
if (this.previousSnap) {
FeatureType feature = FeatureType.AAC_AIMBOT_SENS_MISMATCH;
float value3 = Math.abs(value - value2);
FeatureType feature2 = feature;
this.recordFeature(feature2, value3);
}
this.previousSnap = true;
return false;
} else {
this.previousSnap = false;
return true;
}
} else {
if (this.previousSnap) {
float value4 = value2;
FeatureType feature3 = FeatureType.AAC_AIMBOT_SENS_Y_OOR;
this.recordFeature(feature3, value4);
}
this.previousSnap = true;
return false;
}
} else {
if (this.previousSnap) {
float value5 = value;
FeatureType feature4 = FeatureType.AAC_AIMBOT_SENS_X_OOR;
this.recordFeature(feature4, value5);
}
this.previousSnap = true;
return false;
}
}
}
@@ -0,0 +1,49 @@
package me.konsolas.aac.checks.combat;
import org.bukkit.Location;
class TeleportState {
private final int teleportId;
private final Location origin;
private Location destination;
private boolean confirmed;
TeleportState(int teleportId, Location origin) {
this.teleportId = teleportId;
this.origin = origin;
}
private void updateLocation(Location location) {
if (this.destination == null) {
this.destination = location;
}
}
static void updateTeleportState(TeleportState teleportState, Location location) {
teleportState.updateLocation(location);
}
static Location findLocation(TeleportState teleportState) {
return teleportState.destination;
}
static boolean checkTeleportState(TeleportState teleportState) {
return teleportState.confirmed;
}
static boolean checkTeleportState(TeleportState teleportState, boolean matches) {
return teleportState.confirmed = matches;
}
static Location findLocationWithOrigin(TeleportState teleportState) {
return teleportState.origin;
}
static int calculateCount(TeleportState teleportState) {
return teleportState.teleportId;
}
}
@@ -0,0 +1,256 @@
package me.konsolas.aac.checks.interaction;
import com.comphenix.protocol.events.PacketContainer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Set;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import me.konsolas.aac.checks.ViolationBuffer;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.NativeAccessProvider;
import me.konsolas.aac.debug.DebugManager;
import me.konsolas.aac.movement.PlayerPose;
import me.konsolas.aac.protocol.PacketReader;
import me.konsolas.aac.util.collection.FixedSizeList;
import me.konsolas.aac.world.BlockRayTraceResult;
import me.konsolas.aac.world.MaterialAlias;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
public class InteractCheck extends BaseCheck {
private final ViolationBuffer interactionBuffer;
private final double maximumAngleDifference;
private final Set exemptMaterials;
private final FixedSizeList interactionHistory;
private static final double[] angleSamples = new double[] { 0.0, 0.5, 1.0 };
private static final Vector[] lookDirections;
private static final Set interactedBlocks;
public InteractCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("interact"));
this.exemptMaterials = EnumSet.noneOf(Material.class);
this.interactionHistory = new FixedSizeList(5);
ConfigurationSection configuration = this.getConfiguration();
ConfigurationSection section = configuration;
this.interactionBuffer = ViolationBuffer.create(section, (String) "vl");
this.maximumAngleDifference = this.getConfiguration().getDouble("max_angle_diff");
for (String text : this.getConfiguration().getStringList("exempt")) {
Material material = Material.matchMaterial(text);
this.exemptMaterials.add(material);
}
}
public void handlePacket(PacketContainer packet) {
Location location = (Location) this.interactionHistory.latest();
if (location == null || location.getWorld() != this.getPlayer().getWorld()) {
if (location != null) {
this.interactionHistory.advance();
}
location = this.getPlayer().getLocation();
}
Location location2 = PacketReader.findLocation(packet, location);
if (this.getPlayer().getVehicle() != null) {
Location location3 = this.getPlayer().getLocation();
location2.setX(location3.getX());
location2.setY(location3.getY());
location2.setZ(location3.getZ());
}
this.interactionHistory.add(location2);
}
public boolean checkInteract(Block block) {
if (!this.exemptMaterials.contains(block.getType())) {
if (this.checkInteract(block, (BlockFace) (Object) null)) {
if (this.interactionBuffer.checkViolationBuffer((float) 1.0F)) {
FeatureType feature = FeatureType.AAC_INTERACT_BREAK;
this.recordFeature(feature, (float) 1.0F);
return true;
}
}
}
return false;
}
public boolean onPlayerInteractEvent(PlayerInteractEvent playerInteractEvent) {
if (playerInteractEvent.getAction() == Action.RIGHT_CLICK_BLOCK && playerInteractEvent.getClickedBlock() != null && !this.exemptMaterials.contains(playerInteractEvent.getClickedBlock().getType())) {
if (playerInteractEvent.getClickedBlock().isLiquid() && playerInteractEvent.getItem() != null && interactedBlocks.contains(playerInteractEvent.getItem().getType())) {
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "interact: " + playerInteractEvent.getItem().getType() + " on " + playerInteractEvent.getClickedBlock().getType() + ": allowed");
}
return false;
}
BlockFace blockFace = playerInteractEvent.getBlockFace();
Block clickedBlock = playerInteractEvent.getClickedBlock();
if (this.checkInteract(clickedBlock, blockFace)) {
if (this.interactionBuffer.checkViolationBuffer((float) 1.0F)) {
FeatureType feature = playerInteractEvent.isBlockInHand() ? FeatureType.AAC_INTERACT_PLACE : FeatureType.AAC_INTERACT_GEN;
this.recordFeature(feature, (float) 1.0F);
return true;
}
}
}
return false;
}
private static float calculateValue(Vector vector, Vector vector2) {
Vector vector3 = vector.clone().setY(0);
Vector vector4 = vector2.clone().setY(0);
double value = vector3.dot(vector4) / (vector3.length() * vector4.length());
value = Math.min(Math.max(value, -1.0), 1.0);
double value2 = Math.acos(value);
value = Math.sqrt(vector.getX() * vector.getX() + vector.getZ() * vector.getZ());
double value3 = Math.sqrt(vector2.getX() * vector2.getX() + vector2.getZ() * vector2.getZ());
double value4 = Math.abs(Math.atan(-vector.getY() / value) - Math.atan(-vector2.getY() / value3));
return (float) Math.sqrt(value2 * value2 + value4 * value4);
}
private boolean checkInteract(Block block, BlockFace blockFace) {
Location location = block.getLocation();
BlockVector blockVector = location.toVector().toBlockVector();
for (PlayerPose playerPose : PlayerPose.POSES) {
AAC plugin = this.getPlugin();
Player player = this.getPlayer();
Player player2 = player;
Vector vector = new Vector(0.0F, playerPose.calculateValue(plugin.getProtocolVersion(player2)), 0.0F);
if (!this.checkInteract(block, blockFace, blockVector, vector)) {
return false;
}
}
return true;
}
private boolean checkInteract(Block block, BlockFace blockFace, BlockVector blockVector, Vector vector) {
if (this.interactionHistory.isEmpty()) {
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "interact: warn: no pos history: " + block.getType() + ":" + blockFace + " at " + blockVector);
}
return false;
} else {
Collection<Vector> values = this.findCollection(blockFace, blockVector, vector);
if (values.isEmpty()) {
DebugManager debugManager2 = this.getPlugin().getDebugManager();
Player player3 = this.getPlayer();
Player player4 = player3;
if (debugManager2.isDebugging(player4)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "interact: occluded:" + block.getType() + ":" + blockFace + " at " + blockVector);
}
return true;
} else {
float value = Float.POSITIVE_INFINITY;
for (Vector vector2 : values) {
for (Location location : (Iterable<Location>) (Iterable<?>) (this.interactionHistory)) {
if (location != null) {
float value2 = calculateValue(location.getDirection(), vector2);
if (value2 < value) {
value = value2;
}
}
}
}
DebugManager debugManager3 = this.getPlugin().getDebugManager();
Player player5 = this.getPlayer();
Player player6 = player5;
if (debugManager3.isDebugging(player6)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "interact: angle: %.3f rad " + block.getType() + ":" + blockFace + " at " + blockVector, new Object[] { value });
}
return value > this.maximumAngleDifference;
}
}
}
private Collection findCollection(BlockFace blockFace, BlockVector blockVector, Vector vector) {
ArrayList values = new ArrayList();
for (Location location : (Iterable<Location>) (Iterable<?>) (this.interactionHistory)) {
if (location != null) {
Vector vector2 = location.toVector().add(vector);
for (Location location2 : (Iterable<Location>) (Iterable<?>) (this.interactionHistory)) {
if (location2 != null) {
Vector direction = location2.getDirection();
NativeAccess instance = NativeAccessProvider.getInstance();
Player player = this.getPlayer();
BlockRayTraceResult blockRayTraceResult = instance.rayTrace(player, vector2, direction, 5.0);
if (blockRayTraceResult.isBlockRayTraceResult() && blockRayTraceResult.getBlockVector().equals(blockVector) && (blockFace == null || blockRayTraceResult.getFace() == blockFace)) {
values.add(direction);
break;
}
}
}
}
}
if (!values.isEmpty()) {
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player2 = this.getPlayer();
Player player3 = player2;
if (debugManager.isDebugging(player3)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "interact: exact: " + values.iterator().next());
}
return values;
} else {
for (Location location3 : (Iterable<Location>) (Iterable<?>) (this.interactionHistory)) {
if (location3 != null) {
Vector vector3 = location3.toVector().add(vector);
for (Vector vector4 : lookDirections) {
Vector vector5 = vector4.clone().add(blockVector).subtract(vector3);
if (vector5.lengthSquared() > 0.0) {
NativeAccess instance2 = NativeAccessProvider.getInstance();
Player player4 = this.getPlayer();
BlockRayTraceResult blockRayTraceResult2 = instance2.rayTrace(player4, vector3, vector5, 5.0);
if (blockRayTraceResult2.isBlockRayTraceResult() && blockRayTraceResult2.getBlockVector().equals(blockVector) && (blockFace == null || blockRayTraceResult2.getFace() == blockFace)) {
values.add(vector5);
}
}
}
}
}
DebugManager debugManager2 = this.getPlugin().getDebugManager();
Player player5 = this.getPlayer();
Player player6 = player5;
if (debugManager2.isDebugging(player6)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "interact: approx: " + values.size());
}
return values;
}
}
static {
ArrayList<Vector> values2 = new ArrayList();
for (double value : angleSamples) {
for (double value2 : angleSamples) {
for (double value3 : angleSamples) {
values2.add(new Vector(value, value2, value3));
}
}
}
lookDirections = values2.toArray(new Vector[0]);
interactedBlocks = EnumSet.of(MaterialAlias.LILY_PAD.getMaterial());
for (Material material : Material.values()) {
if (material.name().contains("BOAT")) {
interactedBlocks.add(material);
}
}
}
}
@@ -0,0 +1,73 @@
package me.konsolas.aac.checks.interaction;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerDigType;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.block.Action;
import org.bukkit.util.Vector;
public interface InteractionTracker {
default void updatePlayer(Player player, Location location) {
}
default void computeTick() {
}
default void tick() {
}
default void updateEnumWrappersPlayerDigType(PlayerDigType playerDigType, BlockPosition blockPosition) {
}
default void findTick() {
}
default void updateBlockPosition(BlockPosition blockPosition, BlockPosition blockPosition2, Hand hand) {
}
default void processTick() {
}
default void collectTick() {
}
default void inspectTick() {
}
default void updateVector(Vector vector) {
}
default void updateAxisAlignedBoundingBox(AxisAlignedBoundingBox box) {
}
default void readTick() {
}
default void measureTick() {
}
default void evaluateTick() {
}
default void updateBlock(Block block) {
}
default void updateAction(Action action, Block block, BlockFace blockFace) {
}
default void resolveTick() {
}
default void updateMaterial(Material material, double value) {
}
default void deriveTick() {
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,313 @@
package me.konsolas.aac.checks.player;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import me.konsolas.aac.checks.ViolationBuffer;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.NativeAccessProvider;
import me.konsolas.aac.debug.DebugManager;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.world.MaterialAlias;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.block.Action;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.inventory.ItemStack;
public class ActionDelayCheck extends BaseCheck {
private static final ItemStack lastItem = MaterialAlias.BONE_MEAL.getItemStack();
private final ViolationBuffer delayBuffer;
private final boolean checkFastUse;
private final boolean checkFastBow;
private final boolean checkFastPlace;
private final boolean checkFastBreak;
private final boolean checkRegeneration;
private final boolean checkFastSneak;
private final boolean checkRelease;
private final boolean usingItem;
private long lastPlace;
private long lastBreak;
private long lastUse;
private long lastBow;
private long lastHeal;
private long lastSneak;
private long lastRelease;
public ActionDelayCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("delays"));
ConfigurationSection configuration = this.getConfiguration();
ConfigurationSection section = configuration;
this.delayBuffer = ViolationBuffer.create(section, (String) "vl");
this.checkFastUse = this.getConfiguration().getBoolean("fast_break");
this.checkFastBow = this.getConfiguration().getBoolean("fast_place");
this.checkFastPlace = this.getConfiguration().getBoolean("fast_use");
this.checkFastBreak = this.getConfiguration().getBoolean("fast_bow");
this.checkRegeneration = this.getConfiguration().getBoolean("regen");
this.checkFastSneak = this.getConfiguration().getBoolean("fast_sneak");
this.checkRelease = this.getConfiguration().getBoolean("fast_release");
this.usingItem = this.getConfiguration().getBoolean("break_delay");
}
public boolean checkActionDelay(boolean matches) {
if (!matches) {
this.lastPlace = System.currentTimeMillis();
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "delays: damaged block");
}
} else {
this.lastPlace = 0L;
DebugManager debugManager2 = this.getPlugin().getDebugManager();
Player player3 = this.getPlayer();
Player player4 = player3;
if (debugManager2.isDebugging(player4)) {
this.getPlugin().getDebugManager().log(this.getPlayer(), "delays: damaged block (instabreak)");
}
}
if (this.usingItem) {
long value = System.currentTimeMillis() - this.lastBreak;
if (value < 500L) {
float value2 = matches ? 0.05F : 0.1F;
float value3 = value2 - (float) value / 1000.0F;
if (this.delayBuffer.getLevel() > 0.5F) {
float value4 = value3 / value2;
FeatureType feature = FeatureType.AAC_DELAYS_BREAKDELAY;
this.recordFeature(feature, value4);
}
DebugManager debugManager3 = this.getPlugin().getDebugManager();
Player player5 = this.getPlayer();
Player player6 = player5;
if (debugManager3.isDebugging(player6)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "delays: breakdelay: %.3f%+.3f", new Object[] { this.delayBuffer.getLevel(), value3 });
}
return this.delayBuffer.checkViolationBuffer(value3);
}
}
return false;
}
public boolean checkActionDelay(Block block) {
if (this.checkFastUse && this.lastPlace != 0L) {
this.lastBreak = System.currentTimeMillis();
long value = this.lastBreak - this.lastPlace;
NativeAccess instance = NativeAccessProvider.getInstance();
Player player = this.getPlayer();
Player player2 = player;
double blockDamage = instance.getBlockDamage(player2, block);
if (blockDamage >= 1.0) {
return false;
} else {
float value2 = (float) (1.0 / blockDamage * 0.05F);
float value3 = value2 - (float) value / 1000.0F;
if (this.delayBuffer.getLevel() > 0.5F) {
float value4 = value3 / value2;
FeatureType feature = FeatureType.AAC_DELAYS_BREAK;
this.recordFeature(feature, value4);
}
DebugManager debugManager = this.getPlugin().getDebugManager();
player = this.getPlayer();
Player player3 = player;
if (debugManager.isDebugging(player3)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "delays: fastbreak: %.3f%+.3f", new Object[] { this.delayBuffer.getLevel(), value3 });
}
return this.delayBuffer.checkViolationBuffer(value3);
}
} else {
return false;
}
}
public boolean isActionDelay() {
if (!this.checkFastBow) {
return false;
} else {
for (ItemStack itemStack : NativeAccessProvider.getInstance().getHandItems(this.getPlayer())) {
if (itemStack != null && (itemStack.getType() == Material.FLINT_AND_STEEL || itemStack.isSimilar(lastItem))) {
return false;
}
}
long now = System.currentTimeMillis();
long value = this.lastUse;
long value2 = now - value;
this.lastUse = now;
if (value == 0L) {
return false;
} else {
float value3 = 0.05F - (float) value2 / 1000.0F;
if (this.delayBuffer.getLevel() > 0.5F) {
float value4 = value3 / 0.05F;
FeatureType feature = FeatureType.AAC_DELAYS_PLACE;
this.recordFeature(feature, value4);
}
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "delays: fastplace: %.3f%+.3f", new Object[] { this.delayBuffer.getLevel(), value3 });
}
return this.delayBuffer.checkViolationBuffer(value3);
}
}
}
public void onAction(Action action) {
if (action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK) {
this.lastBow = System.currentTimeMillis();
}
}
public boolean checkActionDelay(Material material) {
if (!this.checkFastPlace) {
return false;
} else {
long value = System.currentTimeMillis() - this.lastBow;
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_13;
float value2 = serverVersion.isAtLeast(version) && material == Material.DRIED_KELP ? 0.75F : 1.5F;
float value3 = value2 - (float) value / 1000.0F;
if (this.delayBuffer.getLevel() > 0.5F) {
float value4 = value3 / value2;
FeatureType feature = FeatureType.AAC_DELAYS_CONSUME;
this.recordFeature(feature, value4);
}
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "delays: fastuse: %.3f%+.3f", new Object[] { this.delayBuffer.getLevel(), value3 });
}
return this.delayBuffer.checkViolationBuffer(value3);
}
}
public boolean checkActionDelay(float value) {
if (this.checkFastBreak) {
long value2 = System.currentTimeMillis() - this.lastBow;
float value3 = calculateValue(value);
float value4 = value3 - (float) value2 / 1000.0F;
if (this.delayBuffer.getLevel() > 0.5F) {
float value5 = value4 / value3;
FeatureType feature = FeatureType.AAC_DELAYS_BOW;
this.recordFeature(feature, value5);
}
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "delays: fastbow: %.3f%+.3f", new Object[] { this.delayBuffer.getLevel(), value4 });
}
return this.delayBuffer.checkViolationBuffer(value4);
} else {
return false;
}
}
private static float calculateValue(float value) {
return 0.1F + 0.95F * value;
}
public boolean onEntityRegainHealthEventRegainReason(RegainReason regainReason) {
if (this.checkRegeneration && regainReason == RegainReason.SATIATED) {
long now = System.currentTimeMillis();
long value = this.lastHeal;
long value2 = now - value;
this.lastHeal = now;
if (value == 0L) {
return false;
} else {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_9;
float value3 = serverVersion.isAtLeast(version) && this.getPlayer().getFoodLevel() == 20 ? 0.5F : 4.0F;
float value4 = value3 - (float) value2 / 1000.0F;
if (this.delayBuffer.getLevel() > 0.5F) {
float value5 = value4 / value3;
FeatureType feature = FeatureType.AAC_DELAYS_REGEN;
this.recordFeature(feature, value5);
}
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "delays: regen: %.3f%+.3f", new Object[] { this.delayBuffer.getLevel(), value4 });
}
return this.delayBuffer.checkViolationBuffer(value4);
}
} else {
return false;
}
}
public void tickWithCheckFastSneak() {
if (this.checkFastSneak) {
long now = System.currentTimeMillis();
long value = this.lastSneak;
long value2 = now - value;
this.lastSneak = now;
if (value == 0L) {
return;
}
float value3 = 0.1F;
float value4 = value3 - (float) value2 / 1000.0F;
if (this.delayBuffer.getLevel() > 0.5F) {
float value5 = value4 / value3;
FeatureType feature = FeatureType.AAC_DELAYS_UNSNEAK;
this.recordFeature(feature, value5);
}
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "delays: sneak: %.3f%+.3f", new Object[] { this.delayBuffer.getLevel(), value4 });
}
this.delayBuffer.checkViolationBuffer(value4);
}
}
public void tick() {
if (this.checkRelease) {
long now = System.currentTimeMillis();
long value = this.lastRelease;
long value2 = now - value;
this.lastRelease = now;
if (value == 0L) {
return;
}
float value3 = 0.1F;
float value4 = value3 - (float) value2 / 1000.0F;
if (this.delayBuffer.getLevel() > 0.5F) {
float value5 = value4 / value3;
FeatureType feature = FeatureType.AAC_DELAYS_RELEASE;
this.recordFeature(feature, value5);
}
DebugManager debugManager = this.getPlugin().getDebugManager();
Player player = this.getPlayer();
Player player2 = player;
if (debugManager.isDebugging(player2)) {
this.getPlugin().getDebugManager().updatePlayer(this.getPlayer(), "delays: block: %.3f%+.3f", new Object[] { this.delayBuffer.getLevel(), value4 });
}
this.delayBuffer.checkViolationBuffer(value4);
}
}
}
@@ -0,0 +1,77 @@
package me.konsolas.aac.checks.player;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
public class ActionStateTracker extends BaseCheck {
private boolean movedThisSecond;
private boolean attackedThisSecond;
private boolean interactedThisSecond;
private int movementSamples;
private int attackSamples;
private int interactionSamples;
public ActionStateTracker(AAC aacPlugin, Player player) {
super(aacPlugin, player, (String) (null));
this.movedThisSecond = false;
this.attackedThisSecond = false;
this.interactedThisSecond = false;
}
public void updateTime(long value) {
if (value % 20L == 0L) {
if (this.movedThisSecond) {
this.movementSamples++;
}
if (this.attackedThisSecond) {
this.attackSamples++;
}
if (this.interactedThisSecond) {
this.interactionSamples++;
}
this.movedThisSecond = false;
this.attackedThisSecond = false;
this.interactedThisSecond = false;
}
if (value % 200L == 0L) {
if (this.movementSamples > 0) {
float value2 = this.movementSamples * 20.0F / 1200.0F;
FeatureType feature = FeatureType.AAC_NORM_MOVE;
this.recordFeature(feature, value2);
this.movementSamples = 0;
}
if (this.attackSamples > 0) {
float value3 = this.attackSamples * 20.0F / 1200.0F;
FeatureType feature2 = FeatureType.AAC_NORM_ATTACK;
this.recordFeature(feature2, value3);
this.attackSamples = 0;
}
if (this.interactionSamples > 0) {
float value4 = this.interactionSamples * 20.0F / 1200.0F;
FeatureType feature3 = FeatureType.AAC_NORM_INTERACT;
this.recordFeature(feature3, value4);
this.interactionSamples = 0;
}
}
}
public void recordMovement() {
this.movedThisSecond = true;
}
public void recordAttack() {
this.attackedThisSecond = true;
}
public void recordInteraction() {
this.interactedThisSecond = true;
}
}
@@ -0,0 +1,54 @@
package me.konsolas.aac.checks.player;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.checks.BaseCheck;
import org.bukkit.entity.Player;
public class MiscellaneousCheck extends BaseCheck {
private long lastRotation;
private float previousYaw;
private float previousPitch;
private final boolean checkAbilities;
private final boolean checkPitch;
private final boolean checkRotationRate;
public MiscellaneousCheck(AAC aacPlugin, Player player) {
super(aacPlugin, player, ("misc"));
this.checkAbilities = this.getConfiguration().getBoolean("invalid_pitch");
this.checkPitch = this.getConfiguration().getBoolean("player_abilities");
this.checkRotationRate = this.getConfiguration().getBoolean("rotation_rate");
}
public void updateTime(long value) {
if (this.getPlayer().getAllowFlight()) {
this.lastRotation = value;
} else if (this.checkPitch && value > 100L && value - this.lastRotation > 100L) {
FeatureType feature = FeatureType.AAC_MISC_ABILITIES;
this.recordFeature(feature, (float) 1.0F);
}
}
public void updateTime(long value, float value2, float value3) {
float value4 = value2 - this.previousYaw;
float value5 = value3 - this.previousPitch;
this.previousYaw = value2;
this.previousPitch = value3;
if (this.checkRotationRate && (value4 > 1.0E8F || value5 > 1.0E8F)) {
FeatureType feature = FeatureType.AAC_MISC_ROTATION;
float value6 = Math.max(value4, value5);
FeatureType feature2 = feature;
this.recordFeature(feature2, value6);
}
if (this.checkAbilities && value > 100L && (value2 > 90.1F || value2 < -90.1F)) {
FeatureType feature3 = FeatureType.AAC_MISC_PITCH;
this.recordFeature(feature3, value2);
}
}
}
@@ -0,0 +1,504 @@
package me.konsolas.aac.command;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.PlayerAnalysisReport;
import me.konsolas.aac.analysis.RiskLevel;
import me.konsolas.aac.api.AACExemption;
import me.konsolas.aac.util.chat.ChatMessages;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ClickEvent.Action;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.StringUtil;
public class AACCommandExecutor implements TabExecutor {
private final AAC plugin;
private final ChatColor ACCENT_COLOR;
private final Map<CommandSender, MitigationMode> alertModes = new WeakHashMap();
private final Map spectateLocations = new WeakHashMap();
private static final List SUBCOMMANDS = Arrays.asList("help", "status", "exempt", "spec", "spectate", "check", "reset", "debug", "reload");
private static final List ALERT_MODES = Arrays.asList("normal", "reduced", "off");
public AACCommandExecutor(AAC plugin) {
this.plugin = plugin;
String string = plugin.getConfig().getString("aac_prefix_colour");
if (string != null && string.length() == 1 && "0123456789abcdef".contains(string)) {
this.ACCENT_COLOR = ChatColor.getByChar(string.charAt(0));
} else {
plugin.getLogger().warning("Invalid colour code " + string + ", defaulting to 'a'");
this.ACCENT_COLOR = ChatColor.GREEN;
}
}
public boolean onCommand(CommandSender sender, Command command, String text, String[] texts) {
if (texts.length == 0) {
BaseComponent baseComponent = this.getBaseComponent();
baseComponent.addExtra("AAC " + AAC.class.getPackage().getImplementationVersion() + " - ");
TextComponent textComponent = new TextComponent("https://www.spigotmc.org/resources/6442/");
textComponent.setClickEvent(new ClickEvent(Action.OPEN_URL, "https://www.spigotmc.org/resources/6442/"));
baseComponent.addExtra(textComponent);
ChatMessages.send(sender, baseComponent);
return false;
} else {
String text2 = texts[0].toLowerCase();
switch(text2) {
case "help":
if (sender.hasPermission("aac.status")) {
BaseComponent baseComponent2 = this.getBaseComponent();
baseComponent2.addExtra("/aac status - list online players");
ChatMessages.send(sender, baseComponent2);
BaseComponent baseComponent3 = this.getBaseComponent();
baseComponent3.addExtra("/aac status <player> - view latest analysis for <player>");
ChatMessages.send(sender, baseComponent3);
}
if (sender.hasPermission("aac.exempt")) {
BaseComponent baseComponent4 = this.getBaseComponent();
baseComponent4.addExtra("/aac exempt <player> - exempt/unexempt <player> from AAC checking");
ChatMessages.send(sender, baseComponent4);
}
if (sender.hasPermission("aac.spectate")) {
BaseComponent baseComponent5 = this.getBaseComponent();
baseComponent5.addExtra("/aac spectate <player> - switch modes and teleport to <player>");
ChatMessages.send(sender, baseComponent5);
BaseComponent baseComponent6 = this.getBaseComponent();
baseComponent6.addExtra("/aac spectate - teleport back after spectating a player");
ChatMessages.send(sender, baseComponent6);
}
if (sender.hasPermission("aac.sudo")) {
BaseComponent baseComponent7 = this.getBaseComponent();
baseComponent7.addExtra("/aac sudo <player> <command> - force <player> to execute <command>");
ChatMessages.send(sender, baseComponent7);
}
if (sender.hasPermission("aac.check")) {
BaseComponent baseComponent8 = this.getBaseComponent();
baseComponent8.addExtra("/aac check <player> - force AAC to analyse <player>");
ChatMessages.send(sender, baseComponent8);
}
if (sender.hasPermission("aac.reset")) {
BaseComponent baseComponent9 = this.getBaseComponent();
baseComponent9.addExtra("/aac reset <player> - clear AAC's database entries for <player>");
ChatMessages.send(sender, baseComponent9);
}
if (sender.hasPermission("aac.alert")) {
BaseComponent baseComponent10 = this.getBaseComponent();
baseComponent10.addExtra("/aac alerts <off/normal/reduced> - set your alert level (reduced = only severe alerts)");
ChatMessages.send(sender, baseComponent10);
BaseComponent baseComponent11 = this.getBaseComponent();
baseComponent11.addExtra("/aac alerts - check your current alert level");
ChatMessages.send(sender, baseComponent11);
}
if (sender.hasPermission("aac.debug")) {
BaseComponent baseComponent12 = this.getBaseComponent();
baseComponent12.addExtra("/aac debug [players...] - toggle your debug output for [players...]");
ChatMessages.send(sender, baseComponent12);
}
if (sender.hasPermission("aac.reload")) {
BaseComponent baseComponent13 = this.getBaseComponent();
baseComponent13.addExtra("/aac reload - reload AAC's checks, API hooks, and configuration file");
ChatMessages.send(sender, baseComponent13);
}
return true;
case "status":
if (!sender.hasPermission("aac.status")) {
sender.sendMessage("/aac status missing permission node aac.status");
return false;
}
if (texts.length > 1) {
for (int index = 1; index < texts.length; index++) {
OfflinePlayer offlinePlayer = this.plugin.getServer().getOfflinePlayer(texts[index]);
CompletableFuture<PlayerAnalysisReport> completableFuture;
if (this.plugin.getAnalysisManager().getReport(offlinePlayer) == null) {
completableFuture = this.plugin.getAnalysisManager().analyzeAsync(offlinePlayer);
} else {
completableFuture = CompletableFuture.completedFuture(this.plugin.getAnalysisManager().getReport(offlinePlayer));
}
completableFuture.whenComplete((result, result2) -> {
this.updateCommandSender(sender, offlinePlayer);
if (!offlinePlayer.isOnline() || !this.plugin.getPacketDispatcher().getExemptions((Player) offlinePlayer).isEmpty()) {
TextComponent textComponent2 = new TextComponent(" This player is currently exempt from AAC checking");
textComponent2.setColor(ChatColor.DARK_AQUA);
ChatMessages.send(sender, textComponent2);
if (offlinePlayer.isOnline()) {
for (AACExemption aACExemption : this.plugin.getPacketDispatcher().getExemptions((Player) offlinePlayer)) {
TextComponent textComponent3 = new TextComponent(" - ");
TextComponent textComponent4 = new TextComponent(aACExemption.getReason());
textComponent4.setColor(ChatColor.GRAY);
textComponent3.addExtra(textComponent4);
ChatMessages.send(sender, textComponent3);
}
} else {
TextComponent textComponent5 = new TextComponent(" - ");
TextComponent textComponent6 = new TextComponent("The player is currently offline");
textComponent6.setColor(ChatColor.GRAY);
textComponent5.addExtra(textComponent6);
ChatMessages.send(sender, textComponent5);
}
}
for (BaseComponent baseComponent16 : this.plugin.getAnalysisManager().getReport(offlinePlayer).toChatComponents()) {
ChatMessages.send(sender, baseComponent16);
}
});
}
} else {
BaseComponent baseComponent17 = this.getBaseComponent();
ArrayList<Player> values = new ArrayList(Bukkit.getOnlinePlayers());
values.sort(Comparator.<Player>comparingDouble(result3 -> this.plugin.getAnalysisManager().getReport(result3).getScore()).reversed());
for (Player player : values) {
baseComponent17.addExtra(this.findBaseComponent(player));
baseComponent17.addExtra(" ");
}
ChatMessages.send(sender, baseComponent17);
}
return true;
case "exempt":
if (!sender.hasPermission("aac.exempt")) {
sender.sendMessage("/aac exempt missing permission node aac.exempt");
return false;
} else if (texts.length <= 1) {
sender.sendMessage("/aac exempt <player> [players...] missing player argument");
return false;
} else {
for (int index2 = 1; index2 < texts.length; index2++) {
Player player2 = this.plugin.getServer().getPlayer(texts[index2]);
if (player2 == null) {
sender.sendMessage("/aac exempt unknown player " + texts[index2]);
} else {
BaseComponent baseComponent18 = this.getBaseComponent();
if (this.plugin.toggleExemption(player2)) {
baseComponent18.addExtra("Added command exemption to ");
} else {
baseComponent18.addExtra("Removed command exemption from ");
}
baseComponent18.addExtra(this.findBaseComponent(player2));
ChatMessages.send(sender, baseComponent18);
}
}
return true;
}
case "spectate":
case "spec":
if (!sender.hasPermission("aac.spectate")) {
sender.sendMessage("/aac spectate missing permission node aac.spectate");
return false;
} else if (!(sender instanceof Player)) {
sender.sendMessage("/aac spectate sender must be a player");
return false;
} else if (texts.length > 2) {
sender.sendMessage("/aac spectate <player> too many arguments");
return false;
} else {
Player player3 = (Player) sender;
if (texts.length >= 2) {
Player player4 = this.plugin.getServer().getPlayer(texts[1]);
if (player4 == null) {
sender.sendMessage("/aac spectate unknown player " + texts[1]);
return false;
}
for (String text3 : this.plugin.getConfig().getStringList("pre_spectate")) {
this.plugin.getServer().dispatchCommand(Bukkit.getConsoleSender(), this.plugin.resolvePlaceholders(player3, text3));
}
this.spectateLocations.putIfAbsent(player3, player3.getLocation());
player3.teleport(player4, TeleportCause.COMMAND);
BaseComponent baseComponent19 = this.getBaseComponent();
baseComponent19.addExtra("Teleported to ");
baseComponent19.addExtra(this.findBaseComponent(player4));
baseComponent19.addExtra(" - ");
baseComponent19.addExtra(this.findBaseComponent(player3));
ChatMessages.send(sender, baseComponent19);
return true;
} else {
Location location = (Location) this.spectateLocations.get(player3);
if (location == null) {
sender.sendMessage("/aac spectate missing location to go back to");
return false;
}
for (String text4 : this.plugin.getConfig().getStringList("post_spectate")) {
this.plugin.getServer().dispatchCommand(Bukkit.getConsoleSender(), this.plugin.resolvePlaceholders(player3, text4));
}
player3.teleport(location, TeleportCause.COMMAND);
this.spectateLocations.remove(player3);
BaseComponent baseComponent20 = this.getBaseComponent();
baseComponent20.addExtra("Teleported back");
ChatMessages.send(sender, baseComponent20);
return true;
}
}
case "sudo":
if (!sender.hasPermission("aac.sudo")) {
sender.sendMessage("/aac sudo missing permission node aac.sudo");
return false;
} else if (texts.length <= 1) {
sender.sendMessage("/aac sudo <player> <command> [args...] missing player");
return false;
} else if (texts.length <= 2) {
sender.sendMessage("/aac sudo <player> <command> [args...] missing command");
return false;
} else {
Player player5 = this.plugin.getServer().getPlayer(texts[1]);
if (player5 == null) {
sender.sendMessage("/aac sudo unknown player " + texts[1]);
return false;
}
String text5 = Arrays.stream(texts).skip(2L).collect(Collectors.joining(" "));
BaseComponent baseComponent21 = this.getBaseComponent();
baseComponent21.addExtra("/" + text5);
ChatMessages.send(player5, baseComponent21);
BaseComponent baseComponent22 = this.getBaseComponent();
baseComponent22.addExtra(this.findBaseComponent(player5));
baseComponent22.addExtra(" - /" + text5);
ChatMessages.send(sender, baseComponent22);
this.plugin.getServer().dispatchCommand(player5, text5);
return true;
}
case "reset":
if (!sender.hasPermission("aac.reset")) {
sender.sendMessage("/aac reset missing permission node aac.reset");
return false;
} else {
if (texts.length <= 1) {
sender.sendMessage("/aac reset <player> [players...] missing player argument");
return false;
}
for (int index3 = 1; index3 < texts.length; index3++) {
OfflinePlayer offlinePlayer2 = this.plugin.getServer().getOfflinePlayer(texts[index3]);
this.plugin.getDatabase().resetPlayerAsync(offlinePlayer2).thenCompose(result4 -> this.plugin.getAnalysisManager().analyzeAsync(offlinePlayer2).thenApply(result5 -> result4)).whenComplete((result, result2) -> {
BaseComponent baseComponent23 = this.getBaseComponent();
if (result2 == null) {
TextComponent textComponent7 = new TextComponent(Integer.toString(result));
textComponent7.setColor(ChatColor.GRAY);
baseComponent23.addExtra("Cleared ");
baseComponent23.addExtra(textComponent7);
baseComponent23.addExtra(" entries for ");
baseComponent23.addExtra(this.findBaseComponent(offlinePlayer2));
baseComponent23.addExtra(" from database");
ChatMessages.send(sender, baseComponent23);
} else {
baseComponent23.addExtra("Failed to reset ");
baseComponent23.addExtra(this.findBaseComponent(offlinePlayer2));
result2.printStackTrace();
}
});
}
return true;
}
case "check":
if (!sender.hasPermission("aac.check")) {
sender.sendMessage("/aac check missing permission node aac.check");
return false;
} else {
if (texts.length <= 1) {
sender.sendMessage("/aac check <player> [players...] missing player argument");
return false;
}
for (int index4 = 1; index4 < texts.length; index4++) {
OfflinePlayer offlinePlayer3 = this.plugin.getServer().getOfflinePlayer(texts[index4]);
this.plugin.getAnalysisManager().analyzeAsync(offlinePlayer3).whenComplete((result, result2) -> {
BaseComponent baseComponent23 = this.getBaseComponent();
if (result2 == null) {
baseComponent23.addExtra("Report ready for ");
baseComponent23.addExtra(this.findBaseComponent(offlinePlayer3));
ChatMessages.send(sender, baseComponent23);
} else {
baseComponent23.addExtra("Failed to generate report for ");
baseComponent23.addExtra(this.findBaseComponent(offlinePlayer3));
result2.printStackTrace();
}
});
}
return true;
}
case "alerts":
if (!sender.hasPermission("aac.alerts")) {
sender.sendMessage("/aac alerts missing permission node aac.alerts");
return false;
} else if (texts.length > 2) {
sender.sendMessage("/aac alerts <off/normal/reduced> too many arguments");
return false;
} else {
if (texts.length == 1) {
BaseComponent baseComponent24 = this.getBaseComponent();
baseComponent24.addExtra("Your alert level is " + this.alertModes.getOrDefault(sender, MitigationMode.NORMAL));
ChatMessages.send(sender, baseComponent24);
} else {
String text6 = texts[1].toLowerCase();
switch(text6) {
case "off":
this.alertModes.put(sender, MitigationMode.OFF);
break;
case "normal":
this.alertModes.remove(sender);
break;
case "reduced":
this.alertModes.put(sender, MitigationMode.REDUCED);
break;
default:
sender.sendMessage("/aac alerts <off/normal/reduced> invalid alert level");
return false;
}
BaseComponent baseComponent25 = this.getBaseComponent();
baseComponent25.addExtra("Alert level updated to " + this.alertModes.getOrDefault(sender, MitigationMode.NORMAL));
ChatMessages.send(sender, baseComponent25);
}
return true;
}
case "debug":
if (!sender.hasPermission("aac.debug")) {
sender.sendMessage("/aac debug missing permission node aac.debug");
return false;
}
if (texts.length == 1) {
this.plugin.getDebugManager().updateCommandSender(sender);
} else {
for (int index5 = 1; index5 < texts.length; index5++) {
OfflinePlayer offlinePlayer4 = this.plugin.getServer().getOfflinePlayer(texts[index5]);
this.plugin.getDebugManager().updateCommandSender(sender, offlinePlayer4);
}
}
BaseComponent baseComponent26 = this.getBaseComponent();
baseComponent26.addExtra("Currently debugging:");
if (this.plugin.getDebugManager().checkDebugManager(sender)) {
baseComponent26.addExtra(" ");
TextComponent textComponent8 = new TextComponent("[global]");
textComponent8.setColor(ChatColor.GRAY);
baseComponent26.addExtra(textComponent8);
} else if (!this.plugin.getDebugManager().findSet(sender).isEmpty()) {
for (OfflinePlayer offlinePlayer5 : this.plugin.getDebugManager().findSet(sender)) {
baseComponent26.addExtra(" ");
baseComponent26.addExtra(this.findBaseComponent(offlinePlayer5));
}
} else {
baseComponent26.addExtra(" ");
TextComponent textComponent9 = new TextComponent("[none]");
textComponent9.setColor(ChatColor.GRAY);
baseComponent26.addExtra(textComponent9);
}
ChatMessages.send(sender, baseComponent26);
return true;
case "reload":
if (!sender.hasPermission("aac.reload")) {
sender.sendMessage("/aac reload missing permission node aac.reload");
return false;
}
this.plugin.getLogger().info("Reload requested by " + sender.getName());
Bukkit.getServer().getPluginManager().disablePlugin(this.plugin);
Bukkit.getServer().getPluginManager().enablePlugin(this.plugin);
BaseComponent baseComponent27 = this.getBaseComponent();
baseComponent27.addExtra("Reload complete");
ChatMessages.send(sender, baseComponent27);
return true;
default:
return false;
}
}
}
public void updatePlayer(OfflinePlayer offlinePlayer) {
RiskLevel riskLevel = this.plugin.getAnalysisManager().getReport(offlinePlayer).getRiskLevel();
for (Player player : Bukkit.getOnlinePlayers()) {
if (player.hasPermission("aac.alerts") && this.alertModes.getOrDefault(player, MitigationMode.NORMAL).checkMitigationMode(riskLevel)) {
this.updateCommandSender(player, offlinePlayer);
}
}
if (Bukkit.getConsoleSender().hasPermission("aac.alerts") && this.alertModes.getOrDefault(Bukkit.getConsoleSender(), MitigationMode.NORMAL).checkMitigationMode(riskLevel)) {
ConsoleCommandSender consoleSender = Bukkit.getConsoleSender();
this.updateCommandSender(consoleSender, offlinePlayer);
}
}
private void updateCommandSender(CommandSender sender, OfflinePlayer offlinePlayer) {
BaseComponent baseComponent = this.getBaseComponent();
baseComponent.addExtra(this.findBaseComponent(offlinePlayer));
if (offlinePlayer.isOnline()) {
baseComponent.addExtra(" - ");
Player player = (Player) offlinePlayer;
baseComponent.addExtra(this.findBaseComponent(player, sender));
}
ChatMessages.send(sender, baseComponent);
}
private BaseComponent getBaseComponent() {
TextComponent textComponent = new TextComponent(" ");
TextComponent textComponent2 = new TextComponent("AAC ");
textComponent2.setColor(this.ACCENT_COLOR);
textComponent2.setBold(true);
textComponent.addExtra(textComponent2);
return textComponent;
}
private BaseComponent findBaseComponent(OfflinePlayer offlinePlayer) {
TextComponent textComponent = new TextComponent(offlinePlayer.getName());
textComponent.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/aac status " + offlinePlayer.getName()));
textComponent.setHoverEvent(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, new BaseComponent[] { new TextComponent("/aac status " + offlinePlayer.getName()) }));
textComponent.setBold(false);
PlayerAnalysisReport report = this.plugin.getAnalysisManager().getReport(offlinePlayer);
if (report != null) {
report.getRiskLevel().updateBaseComponent(textComponent);
} else {
RiskLevel.NEUTRAL.updateBaseComponent(textComponent);
}
if (!offlinePlayer.isOnline() || !this.plugin.getPacketDispatcher().getExemptions((Player) offlinePlayer).isEmpty()) {
RiskLevel.IGNORED.updateBaseComponent(textComponent);
}
return textComponent;
}
private BaseComponent findBaseComponent(Player player, CommandSender sender) {
TextComponent textComponent = new TextComponent("Spectate");
textComponent.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/aac spec " + player.getName()));
textComponent.setHoverEvent(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, new BaseComponent[] { new TextComponent("/aac spec " + player.getName()) }));
if (!(sender instanceof Player) || !sender.hasPermission("aac.spectate")) {
textComponent.setStrikethrough(true);
}
return textComponent;
}
private BaseComponent createBackLink(CommandSender sender) {
TextComponent textComponent = new TextComponent("Go Back");
textComponent.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/aac spec"));
textComponent.setHoverEvent(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, new BaseComponent[] { new TextComponent("/aac spec") }));
if (!(sender instanceof Player) || !sender.hasPermission("aac.spectate")) {
textComponent.setStrikethrough(true);
}
return textComponent;
}
public List onTabComplete(CommandSender sender, Command command, String text, String[] texts) {
ArrayList values = new ArrayList();
if (texts.length == 0) {
return SUBCOMMANDS;
} else if (texts.length == 1) {
StringUtil.copyPartialMatches(texts[0], SUBCOMMANDS, values);
return values;
} else if ("alerts".equals(texts[0])) {
StringUtil.copyPartialMatches(texts[0], ALERT_MODES, values);
return values;
} else {
return null;
}
}
}
@@ -0,0 +1,21 @@
package me.konsolas.aac.command;
import me.konsolas.aac.analysis.RiskLevel;
enum MitigationMode {
OFF, NORMAL, REDUCED;
boolean checkMitigationMode(RiskLevel riskLevel) {
switch(this) {
case OFF:
return false;
case NORMAL:
return riskLevel == RiskLevel.SUSPICIOUS || riskLevel == RiskLevel.HIGH;
case REDUCED:
return riskLevel == RiskLevel.HIGH;
default:
throw new AssertionError();
}
}
}
@@ -0,0 +1,30 @@
package me.konsolas.aac.compat;
import java.util.Collection;
import java.util.List;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public interface NativeAccess {
ItemStack getActiveItem(Player player);
Collection<ItemStack> getHandItems(Player player);
boolean isGliding(Player player);
float getBlockFriction(Block block);
AxisAlignedBoundingBox getBoundingBox(Entity entity);
List getBlockCollisionBoxes(Block block, Entity entity);
BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value);
float getBlockDamage(Player player, Block block);
}
@@ -0,0 +1,51 @@
package me.konsolas.aac.compat;
import me.konsolas.aac.compat.v1_11.Minecraft111Access;
import me.konsolas.aac.compat.v1_13.Minecraft113Access;
import me.konsolas.aac.compat.v1_14.Minecraft114Access;
import me.konsolas.aac.compat.v1_16.Minecraft116Access;
import me.konsolas.aac.compat.v1_17.Minecraft117Access;
import me.konsolas.aac.compat.v1_8.Minecraft18Access;
import me.konsolas.aac.compat.v1_9.Minecraft19Access;
import me.konsolas.aac.protocol.ProtocolVersion;
public final class NativeAccessProvider {
private static final NativeAccess INSTANCE;
public static NativeAccess getInstance() {
return INSTANCE;
}
static {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
switch(serverVersion) {
case V1_8:
INSTANCE = new Minecraft18Access();
break;
case V1_9:
case V1_10:
INSTANCE = new Minecraft19Access(serverVersion);
break;
case V1_11:
case V1_12:
INSTANCE = new Minecraft111Access(serverVersion);
break;
case V1_13:
INSTANCE = new Minecraft113Access(serverVersion);
break;
case V1_14:
case V1_15:
INSTANCE = new Minecraft114Access(serverVersion);
break;
case V1_16:
INSTANCE = new Minecraft116Access(serverVersion);
break;
case V1_17:
INSTANCE = new Minecraft117Access();
break;
default:
throw new AssertionError();
}
}
}
@@ -0,0 +1,55 @@
package me.konsolas.aac.compat.integration;
import java.lang.reflect.Method;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public final class OptionalIntegrations {
private OptionalIntegrations() {
}
private static Class<?> apiClass(String pluginName, String className) throws ClassNotFoundException {
Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName);
return Class.forName(className, true, plugin.getClass().getClassLoader());
}
public static int viaVersion(Player player) {
try {
Class<?> via = apiClass("ViaVersion", "com.viaversion.viaversion.api.Via");
Object api = via.getMethod("getAPI").invoke(null);
for (Method method : api.getClass().getMethods()) if (method.getName().equals("getPlayerVersion") && method.getParameterTypes().length == 1) {
Class<?> parameter = method.getParameterTypes()[0];
if (parameter == UUID.class)
return ((Number) method.invoke(api, player.getUniqueId())).intValue();
if (parameter.isInstance(player))
return ((Number) method.invoke(api, player)).intValue();
}
throw new NoSuchMethodException("ViaAPI.getPlayerVersion");
} catch (ReflectiveOperationException exception) {
throw new IllegalStateException("Failed to query ViaVersion", exception);
}
}
public static int protocolSupportVersion(Player player) {
try {
Class<?> api = apiClass("ProtocolSupport", "protocolsupport.api.ProtocolSupportAPI");
Object version = api.getMethod("getProtocolVersion", Player.class).invoke(null, player);
return ((Number) version.getClass().getMethod("getId").invoke(version)).intValue();
} catch (ReflectiveOperationException exception) {
throw new IllegalStateException("Failed to query ProtocolSupport", exception);
}
}
public static boolean isFloodgatePlayer(UUID playerId) {
try {
Class<?> api = apiClass("floodgate", "org.geysermc.floodgate.api.FloodgateApi");
Object instance = api.getMethod("getInstance").invoke(null);
return (Boolean) api.getMethod("isFloodgatePlayer", UUID.class).invoke(instance, playerId);
} catch (ReflectiveOperationException exception) {
throw new IllegalStateException("Failed to query Floodgate", exception);
}
}
}
@@ -0,0 +1,111 @@
package me.konsolas.aac.compat.nms;
import it.unimi.dsi.fastutil.objects.AbstractObjectCollection;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import me.konsolas.aac.protocol.ProtocolVersion;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class BlockBreakingHelper {
private static final Method GET_HANDLE_METHOD;
private static final Method GET_HANDLE_METHOD2;
private static final Constructor CONSTRUCTOR;
private static final Method GET_TYPE_METHOD;
private static Method GET_BLOCK_METHOD;
private static Method GET_DAMAGE_METHOD;
private static Method A_METHOD;
private static Method GET_DAMAGE_METHOD2;
public static long calculateTime(Block block, Player player) {
return (long) (1.0F / getWorld(block, player));
}
public static float getWorld(Block block, Player player) {
if (ProtocolVersion.getServerVersion() == ProtocolVersion.V1_8) {
try {
Object result = CONSTRUCTOR.newInstance(block.getX(), block.getY(), block.getZ());
Object result2 = GET_HANDLE_METHOD2.invoke(block.getWorld());
Object result3 = GET_TYPE_METHOD.invoke(result2, result);
Object result4 = GET_BLOCK_METHOD.invoke(result3);
return (Float) GET_DAMAGE_METHOD.invoke(result4, GET_HANDLE_METHOD.invoke(player), result2, result);
} catch (InstantiationException | InvocationTargetException | IllegalAccessException exception) {
throw new RuntimeException(exception);
}
} else {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_13;
if (serverVersion.isAtLeast(version)) {
try {
Object result5 = CONSTRUCTOR.newInstance(block.getX(), block.getY(), block.getZ());
Object result6 = GET_HANDLE_METHOD2.invoke(block.getWorld());
Object result7 = GET_TYPE_METHOD.invoke(result6, result5);
return (Float) GET_DAMAGE_METHOD2.invoke(result7, GET_HANDLE_METHOD.invoke(player), result6, result5);
} catch (InstantiationException | InvocationTargetException | IllegalAccessException exception2) {
throw new RuntimeException(exception2);
}
} else {
try {
Object result8 = CONSTRUCTOR.newInstance(block.getX(), block.getY(), block.getZ());
Object result9 = GET_HANDLE_METHOD2.invoke(block.getWorld());
Object result10 = GET_TYPE_METHOD.invoke(result9, result8);
return (Float) A_METHOD.invoke(result10, GET_HANDLE_METHOD.invoke(player), result9, result8);
} catch (InstantiationException | InvocationTargetException | IllegalAccessException exception3) {
throw new RuntimeException(exception3);
}
}
}
}
public static int getAmplifier(Player player) {
for (PotionEffect potionEffect : player.getActivePotionEffects()) {
if (potionEffect.getType().equals(PotionEffectType.FAST_DIGGING)) {
return potionEffect.getAmplifier() + 1;
}
}
return 0;
}
static {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_17;
if (serverVersion.isAtLeast(version)) {
GET_HANDLE_METHOD = null;
GET_HANDLE_METHOD2 = null;
CONSTRUCTOR = null;
GET_TYPE_METHOD = null;
} else {
try {
GET_HANDLE_METHOD2 = MinecraftReflection.getCraftWorldClass().getMethod("getHandle");
GET_HANDLE_METHOD = MinecraftReflection.getCraftPlayerClass().getMethod("getHandle");
CONSTRUCTOR = MinecraftReflection.getBlockPositionClass().getConstructor(int.class, int.class, int.class);
GET_TYPE_METHOD = MinecraftReflection.getWorldClass().getMethod("getType", MinecraftReflection.getBlockPositionClass());
if (ProtocolVersion.getServerVersion() == ProtocolVersion.V1_8) {
GET_BLOCK_METHOD = MinecraftReflection.getIBlockDataClass().getMethod("getBlock");
GET_DAMAGE_METHOD = MinecraftReflection.getBlockClass().getMethod("getDamage", MinecraftReflection.getEntityHumanClass(), MinecraftReflection.getWorldClass(), MinecraftReflection.getBlockPositionClass());
} else {
serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version2 = ProtocolVersion.V1_13;
if (serverVersion.isAtLeast(version2)) {
GET_DAMAGE_METHOD2 = MinecraftReflection.getIBlockDataClass().getMethod("getDamage", MinecraftReflection.getEntityHumanClass(), MinecraftReflection.getIBlockAccessClass(), MinecraftReflection.getBlockPositionClass());
} else {
A_METHOD = MinecraftReflection.getIBlockDataClass().getMethod("a", MinecraftReflection.getEntityHumanClass(), MinecraftReflection.getWorldClass(), MinecraftReflection.getBlockPositionClass());
}
}
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
}
}
@@ -0,0 +1,117 @@
package me.konsolas.aac.compat.nms;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.Arrays;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
public class EntityRayTracer {
private static final MethodHandle entityHandle;
private static final MethodHandle vectorConstructor;
private static final MethodHandle hitBlockPosition;
private static final MethodHandle hitDirection;
private static final MethodHandle directionToBlockFace;
private static final MethodHandle hitPosition;
private static final MethodHandle vectorX;
private static final MethodHandle vectorY;
private static final MethodHandle vectorZ;
private static final MethodHandle blockX;
private static final MethodHandle blockY;
private static final MethodHandle blockZ;
private static final MethodHandle rayTrace;
public static BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value) {
Vector vector3 = vector.clone().add(vector2.clone().normalize().multiply(value));
try {
Object result = (Object) entityHandle.invoke((World) entity.getWorld());
Object result2 = (Object) vectorConstructor.invoke((double) vector.getX(), (double) vector.getY(), (double) vector.getZ());
Object result3 = (Object) vectorConstructor.invoke((double) vector3.getX(), (double) vector3.getY(), (double) vector3.getZ());
Object result4 = (Object) rayTrace.invoke((Object) result, (Object) result2, (Object) result3);
if (result4 == null) {
return new BlockRayTraceResult();
} else {
Object result5 = (Object) hitPosition.invoke((Object) result4);
Object result6 = (Object) hitBlockPosition.invoke((Object) result4);
Vector vector4 = new Vector((double) vectorX.invoke((Object) result5), (double) vectorY.invoke((Object) result5), (double) vectorZ.invoke((Object) result5));
BlockVector blockVector = new BlockVector((int) blockX.invoke((Object) result6), (int) blockY.invoke((Object) result6), (int) blockZ.invoke((Object) result6));
BlockFace blockFace = (BlockFace) directionToBlockFace.invoke((Object) (Object) hitDirection.invoke((Object) result4));
return new BlockRayTraceResult(vector4, blockVector, blockFace);
}
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
static {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_13;
if (serverVersion.isAtLeast(version)) {
entityHandle = null;
vectorConstructor = null;
hitBlockPosition = null;
hitDirection = null;
directionToBlockFace = null;
hitPosition = null;
vectorX = null;
vectorY = null;
vectorZ = null;
blockX = null;
blockY = null;
blockZ = null;
rayTrace = null;
} else {
try {
Class vec3DClass = MinecraftReflection.getVec3DClass();
Class movingObjectPositionClass = MinecraftReflection.getMovingObjectPositionClass();
Class blockPositionClass = MinecraftReflection.getBlockPositionClass();
Class minecraftClassWithMinecraftPackage = MinecraftReflection.getNmsClass((String) "EnumDirection");
Class minecraftClass = MinecraftReflection.getCraftBlockClass();
entityHandle = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getCraftWorldClass().getMethod("getHandle")));
vectorConstructor = ReflectionAccess.LOOKUP.findConstructor(vec3DClass, MethodType.methodType(void.class, double.class, double.class, double.class));
hitPosition = ReflectionAccess.LOOKUP.findGetter(movingObjectPositionClass, "pos", vec3DClass);
hitBlockPosition = ReflectionAccess.LOOKUP.unreflect(Arrays.stream(movingObjectPositionClass.getMethods()).filter(result -> result.getReturnType().equals(blockPositionClass)).findFirst().orElseThrow(NoSuchMethodException::new));
serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version2 = ProtocolVersion.V1_14;
hitDirection = serverVersion.isAtLeast(version2) ? ReflectionAccess.LOOKUP.findVirtual(movingObjectPositionClass, "getDirection", MethodType.methodType(minecraftClassWithMinecraftPackage)) : ReflectionAccess.LOOKUP.findGetter(movingObjectPositionClass, "direction", minecraftClassWithMinecraftPackage);
directionToBlockFace = ReflectionAccess.LOOKUP.findStatic(minecraftClass, "notchToBlockFace", MethodType.methodType(BlockFace.class, minecraftClassWithMinecraftPackage));
serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version3 = ProtocolVersion.V1_9;
if (serverVersion.isAtLeast(version3)) {
vectorX = ReflectionAccess.LOOKUP.findGetter(MinecraftReflection.getVec3DClass(), "x", double.class);
vectorY = ReflectionAccess.LOOKUP.findGetter(MinecraftReflection.getVec3DClass(), "y", double.class);
vectorZ = ReflectionAccess.LOOKUP.findGetter(MinecraftReflection.getVec3DClass(), "z", double.class);
} else {
vectorX = ReflectionAccess.LOOKUP.findGetter(MinecraftReflection.getVec3DClass(), "a", double.class);
vectorY = ReflectionAccess.LOOKUP.findGetter(MinecraftReflection.getVec3DClass(), "b", double.class);
vectorZ = ReflectionAccess.LOOKUP.findGetter(MinecraftReflection.getVec3DClass(), "c", double.class);
}
blockX = ReflectionAccess.LOOKUP.unreflect(blockPositionClass.getMethod("getX"));
blockY = ReflectionAccess.LOOKUP.unreflect(blockPositionClass.getMethod("getY"));
blockZ = ReflectionAccess.LOOKUP.unreflect(blockPositionClass.getMethod("getZ"));
rayTrace = ReflectionAccess.LOOKUP.findVirtual(MinecraftReflection.getWorldClass(), "rayTrace", MethodType.methodType(movingObjectPositionClass, vec3DClass, vec3DClass));
} catch (IllegalAccessException | NoSuchFieldException | NoSuchMethodException exception) {
throw new RuntimeException("LegacyRaytracer: <clinit>", exception);
}
}
}
}
@@ -0,0 +1,89 @@
package me.konsolas.aac.compat.nms;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import org.bukkit.Bukkit;
public class LegacyBoundingBoxHelper {
private static final MethodHandle constructor;
private static final MethodHandle minXGetter;
private static final MethodHandle minYGetter;
private static final MethodHandle minZGetter;
private static final MethodHandle maxXGetter;
private static final MethodHandle maxYGetter;
private static final MethodHandle maxZGetter;
public static AxisAlignedBoundingBox findAxisAlignedBoundingBox(Object result) {
try {
return new AxisAlignedBoundingBox((double) minXGetter.invoke((Object) result), (double) minYGetter.invoke((Object) result), (double) minZGetter.invoke((Object) result), (double) maxXGetter.invoke((Object) result), (double) maxYGetter.invoke((Object) result), (double) maxZGetter.invoke((Object) result));
} catch (Throwable throwable) {
throw new RuntimeException("LegacyBoundingBoxHelper: fromNMS", throwable);
}
}
public static AxisAlignedBoundingBox findAxisAlignedBoundingBox(Object result, double value, double value2, double value3) {
try {
return new AxisAlignedBoundingBox((double) minXGetter.invoke((Object) result) + value, (double) minYGetter.invoke((Object) result) + value2, (double) minZGetter.invoke((Object) result) + value3, (double) maxXGetter.invoke((Object) result) + value, (double) maxYGetter.invoke((Object) result) + value2, (double) maxZGetter.invoke((Object) result) + value3);
} catch (Throwable throwable) {
throw new RuntimeException("LegacyBoundingBoxHelper: fromNMS_offset", throwable);
}
}
public static Object findObject(double value, double value2, double value3, double value4, double value5, double value6) {
try {
return (Object) constructor.invoke((double) value, (double) value2, (double) value3, (double) value4, (double) value5, (double) value6);
} catch (Throwable throwable) {
throw new RuntimeException("LegacyBoundingBoxHelper: cons", throwable);
}
}
static {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_13;
if (serverVersion.isAtLeast(version)) {
constructor = null;
minXGetter = null;
minYGetter = null;
minZGetter = null;
maxXGetter = null;
maxYGetter = null;
maxZGetter = null;
} else {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String text = name.replace("org.bukkit.craftbukkit", "net.minecraft.server");
Class classValue = Class.forName(text + ".AxisAlignedBB");
constructor = ReflectionAccess.LOOKUP.unreflectConstructor((Constructor<?>) ReflectionAccess.makeAccessible(classValue.getConstructor(double.class, double.class, double.class, double.class, double.class, double.class)));
serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version2 = ProtocolVersion.V1_13;
if (serverVersion.isAtLeast(version2)) {
minXGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("minX")));
minYGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("minY")));
minZGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("minZ")));
maxXGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("maxX")));
maxYGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("maxY")));
maxZGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("maxZ")));
} else {
minXGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("a")));
minYGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("b")));
minZGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("c")));
maxXGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("d")));
maxYGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("e")));
maxZGetter = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue.getDeclaredField("f")));
}
} catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException | NoSuchFieldException exception) {
throw new RuntimeException("LegacyBoundingBoxHelper: <clinit>", exception);
}
}
}
}
@@ -0,0 +1,109 @@
package me.konsolas.aac.compat.nms;
import java.util.HashMap;
import java.util.Map;
import me.konsolas.aac.protocol.ProtocolVersion;
import org.bukkit.Bukkit;
public final class MinecraftReflection {
public static String craftBukkitPackage = Bukkit.getServer().getClass().getPackage().getName();
public static String minecraftPackage = craftBukkitPackage.replace("org.bukkit.craftbukkit", "net.minecraft.server");
private static final Map classCache = new HashMap();
private MinecraftReflection() {
throw new AssertionError();
}
private static Class resolveClass(String text) {
try {
if (classCache.containsKey(text)) {
return (Class) classCache.get(text);
} else {
Class classValue = Class.forName(text);
classCache.put(text, classValue);
return classValue;
}
} catch (ClassNotFoundException classNotFoundException) {
throw new IllegalArgumentException("Class not found: " + text, classNotFoundException);
}
}
public static Class getNmsClass(String text) {
String text2 = minecraftPackage + '.' + text;
String text3 = text2;
return resolveClass(text3);
}
public static Class getCraftClass(String text) {
String text2 = craftBukkitPackage + '.' + text;
String text3 = text2;
return resolveClass(text3);
}
public static Class getCraftPlayerClass() {
return getCraftClass((String) "entity.CraftPlayer");
}
public static Class getCraftWorldClass() {
return getCraftClass((String) "CraftWorld");
}
public static Class getCraftBlockClass() {
return getCraftClass((String) "block.CraftBlock");
}
public static Class getEntityClass() {
return getNmsClass((String) "Entity");
}
public static Class getEntityPlayerClass() {
return getNmsClass((String) "EntityPlayer");
}
public static Class getEntityHumanClass() {
return getNmsClass((String) "EntityHuman");
}
public static Class getWorldClass() {
return getNmsClass((String) "World");
}
public static Class getBlockClass() {
return getNmsClass((String) "Block");
}
public static Class getMovingObjectPositionClass() {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_14;
Class classValue;
if (serverVersion.isAtLeast(version)) {
classValue = getNmsClass((String) "MovingObjectPositionBlock");
} else {
classValue = getNmsClass((String) "MovingObjectPosition");
}
return classValue;
}
public static Class getBlockPositionClass() {
return getNmsClass((String) "BlockPosition");
}
public static Class getIBlockDataClass() {
return getNmsClass((String) "IBlockData");
}
public static Class getIBlockAccessClass() {
return getNmsClass((String) "IBlockAccess");
}
public static Class getVec3DClass() {
return getNmsClass((String) "Vec3D");
}
public static Class getVoxelShapeCollisionClass() {
return getNmsClass((String) "VoxelShapeCollision");
}
}
@@ -0,0 +1,15 @@
package me.konsolas.aac.compat.nms;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.AccessibleObject;
public class ReflectionAccess {
public static Lookup LOOKUP = MethodHandles.lookup();
public static AccessibleObject makeAccessible(AccessibleObject accessibleObject) {
accessibleObject.setAccessible(true);
return accessibleObject;
}
}
@@ -0,0 +1,170 @@
package me.konsolas.aac.compat.v1_11;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.nms.BlockBreakingHelper;
import me.konsolas.aac.compat.nms.EntityRayTracer;
import me.konsolas.aac.compat.nms.LegacyBoundingBoxHelper;
import me.konsolas.aac.compat.nms.MinecraftReflection;
import me.konsolas.aac.compat.nms.ReflectionAccess;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class Minecraft111Access implements NativeAccess {
private final MethodHandle declaredField;
private final Object field;
private final MethodHandle method;
private final MethodHandle declaredMethod;
private final MethodHandle declaredField2;
private final MethodHandle method2;
private final MethodHandle method3;
private final MethodHandle method4;
private final MethodHandle constructor;
private final MethodHandle method5;
private final MethodHandle method6;
public Minecraft111Access(ProtocolVersion version) {
if (version != ProtocolVersion.V1_11 && version != ProtocolVersion.V1_12) {
throw new IllegalArgumentException("Invalid version for SALImplV1_9_10: " + version);
} else {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String text = name.replace("org.bukkit.craftbukkit", "net.minecraft.server");
Class classValue = Class.forName(name + ".entity.CraftEntity");
Class classValue2 = Class.forName(name + ".CraftWorld");
Class classValue3 = Class.forName(name + ".inventory.ItemStack");
Class classValue4 = Class.forName(text + ".World");
Class classValue5 = Class.forName(text + ".Entity");
Class classValue6 = Class.forName(text + ".EntityPlayer");
Class classValue7 = Class.forName(text + ".ItemStack");
Class classValue8 = Class.forName(text + ".AxisAlignedBB");
Class classValue9 = Class.forName(text + ".BlockPosition");
Class classValue10 = Class.forName(text + ".IBlockData");
this.declaredField = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue6.getSuperclass().getSuperclass().getDeclaredField("activeItem")));
this.field = classValue7.getField("a").get(null);
this.method = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue3.getMethod("asCraftMirror", classValue7)));
this.declaredMethod = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getCraftBlockClass().getDeclaredMethod("getNMSBlock")));
this.declaredField2 = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(MinecraftReflection.getBlockClass().getDeclaredField("frictionFactor")));
this.method2 = ReflectionAccess.LOOKUP.unreflect(classValue.getMethod("getHandle"));
this.method3 = ReflectionAccess.LOOKUP.unreflect(classValue2.getMethod("getHandle"));
this.method4 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getEntityClass().getMethod("getBoundingBox")));
this.constructor = ReflectionAccess.LOOKUP.unreflectConstructor(classValue9.getConstructor(int.class, int.class, int.class));
this.method5 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue4.getMethod("getType", classValue9)));
this.method6 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue10.getMethod("a", classValue4, classValue9, classValue8, List.class, classValue5, boolean.class)));
} catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException | IllegalAccessException exception) {
throw new RuntimeException("SALImplV1_11_12: <clinit>", exception);
}
}
}
@Override
public ItemStack getActiveItem(Player player) {
try {
Object result = (Object) this.declaredField.invoke((Object) (Object) this.method2.invoke((Player) player));
return Objects.equals(result, this.field) ? null : (ItemStack) this.method.invoke((Object) result);
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_11_12: getItemInUse", throwable);
}
}
@Override
public Collection getHandItems(Player player) {
return Arrays.asList(player.getInventory().getItemInMainHand(), player.getInventory().getItemInOffHand());
}
@Override
public boolean isGliding(Player player) {
return player.isGliding();
}
@Override
public float getBlockFriction(Block block) {
try {
return (float) this.declaredField2.invoke((Object) (Object) this.declaredMethod.invoke((Block) block));
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_11_12: getFrictionFactor", throwable);
}
}
@Override
public AxisAlignedBoundingBox getBoundingBox(Entity entity) {
try {
Object result = (Object) this.method4.invoke((Object) (Object) this.method2.invoke((Entity) entity));
return LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result);
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_11_12: getBoundingBox", throwable);
}
}
@Override
public List getBlockCollisionBoxes(Block block, Entity entity) {
ArrayList values;
try {
Object result = (Object) this.method3.invoke((World) block.getWorld());
Object result2 = (Object) this.constructor.invoke((int) block.getX(), (int) block.getY(), (int) block.getZ());
double x = block.getX();
double y = block.getY();
double z = block.getZ();
double value = block.getX() + 1.0;
double value2 = block.getZ() + 1.0;
double value3 = block.getY() + 1.0;
double value4 = value;
double value5 = z;
double value6 = y;
double value7 = x;
Object result3 = LegacyBoundingBoxHelper.findObject(value7, value6, value5, value4, value3, value2);
ArrayList values2 = new ArrayList();
this.method6.invoke((Object) (Object) this.method5.invoke((Object) result, (Object) result2), (Object) result, (Object) result2, (Object) result3, (List) values2, (Object) (Object) this.method2.invoke((Entity) entity), (boolean) false);
ArrayList values3 = new ArrayList(values2.size());
for (Object result4 : values2) {
z = -block.getX();
double value8 = -block.getZ();
double value9 = -block.getY();
double value10 = z;
values3.add(LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result4, value10, value9, value8));
}
values = values3;
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_11_12: getCollisionShape", throwable);
}
if (null != null) {
}
return values;
}
@Override
public BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value) {
return EntityRayTracer.rayTrace(entity, vector, vector2, value);
}
@Override
public float getBlockDamage(Player player, Block block) {
return BlockBreakingHelper.getWorld(block, player);
}
}
@@ -0,0 +1,149 @@
package me.konsolas.aac.compat.v1_13;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.nms.BlockBreakingHelper;
import me.konsolas.aac.compat.nms.LegacyBoundingBoxHelper;
import me.konsolas.aac.compat.nms.MinecraftReflection;
import me.konsolas.aac.compat.nms.ReflectionAccess;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
public class Minecraft113Access implements NativeAccess {
private final MethodHandle declaredField;
private final Object field;
private final MethodHandle method;
private final MethodHandle declaredMethod;
private final MethodHandle declaredField2;
private final MethodHandle method2;
private final MethodHandle method3;
private final MethodHandle constructor;
private final MethodHandle method4;
private final MethodHandle method5;
private final MethodHandle method6;
public Minecraft113Access(ProtocolVersion version) {
if (version != ProtocolVersion.V1_13) {
throw new IllegalArgumentException("Invalid version for SALImplV1_13: " + version);
} else {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String text = name.replace("org.bukkit.craftbukkit", "net.minecraft.server");
Class classValue = Class.forName(name + ".entity.CraftEntity");
Class classValue2 = Class.forName(name + ".CraftWorld");
Class classValue3 = Class.forName(name + ".inventory.ItemStack");
Class classValue4 = Class.forName(text + ".World");
Class.forName(text + ".Entity");
Class classValue5 = Class.forName(text + ".EntityPlayer");
Class classValue6 = Class.forName(text + ".ItemStack");
Class.forName(text + ".AxisAlignedBB");
Class classValue7 = Class.forName(text + ".BlockPosition");
Class.forName(text + ".IBlockData");
this.declaredField = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue5.getSuperclass().getSuperclass().getDeclaredField("activeItem")));
this.field = classValue6.getField("a").get(null);
this.method = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue3.getMethod("asCraftMirror", classValue6)));
this.declaredMethod = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getCraftBlockClass().getDeclaredMethod("getNMSBlock")));
this.declaredField2 = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(MinecraftReflection.getBlockClass().getDeclaredField("frictionFactor")));
this.method2 = ReflectionAccess.LOOKUP.unreflect(classValue.getMethod("getHandle"));
this.method3 = ReflectionAccess.LOOKUP.unreflect(classValue2.getMethod("getHandle"));
this.constructor = ReflectionAccess.LOOKUP.unreflectConstructor(classValue7.getConstructor(int.class, int.class, int.class));
this.method4 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue4.getMethod("getType", classValue7)));
this.method5 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getIBlockDataClass().getMethod("getCollisionShape", MinecraftReflection.getIBlockAccessClass(), MinecraftReflection.getBlockPositionClass())));
this.method6 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getNmsClass((String) "VoxelShape").getMethod("d")));
} catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException | IllegalAccessException exception) {
throw new RuntimeException("SALImplV1_13: <clinit>", exception);
}
}
}
@Override
public ItemStack getActiveItem(Player player) {
try {
Object result = (Object) this.declaredField.invoke((Object) (Object) this.method2.invoke((Player) player));
return Objects.equals(result, this.field) ? null : (ItemStack) this.method.invoke((Object) result);
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_13: getItemInUse", throwable);
}
}
@Override
public Collection getHandItems(Player player) {
return Arrays.asList(player.getInventory().getItemInMainHand(), player.getInventory().getItemInOffHand());
}
@Override
public boolean isGliding(Player player) {
return player.isGliding();
}
@Override
public float getBlockFriction(Block block) {
try {
return (float) this.declaredField2.invoke((Object) (Object) this.declaredMethod.invoke((Block) block));
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_13: getFrictionFactor", throwable);
}
}
@Override
public AxisAlignedBoundingBox getBoundingBox(Entity entity) {
BoundingBox boundingBox = entity.getBoundingBox();
return new AxisAlignedBoundingBox(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ());
}
@Override
public List getBlockCollisionBoxes(Block block, Entity entity) {
try {
Object result = (Object) this.method3.invoke((World) block.getWorld());
Object result2 = (Object) this.constructor.invoke((int) block.getX(), (int) block.getY(), (int) block.getZ());
Object result3 = (Object) this.method5.invoke((Object) (Object) this.method4.invoke((Object) result, (Object) result2), (Object) result, (Object) result2);
List values = (List) this.method6.invoke((Object) result3);
ArrayList values2 = new ArrayList(values.size());
for (Object result4 : values) {
values2.add(LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result4));
}
return values2;
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_13: getCollisionShape", throwable);
}
}
@Override
public BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value) {
RayTraceResult rayTraceResult = entity.getWorld().rayTraceBlocks(vector.toLocation(entity.getWorld()), vector2.clone().normalize(), value);
return BlockRayTraceResult.create(rayTraceResult);
}
@Override
public float getBlockDamage(Player player, Block block) {
return BlockBreakingHelper.getWorld(block, player);
}
}
@@ -0,0 +1,153 @@
package me.konsolas.aac.compat.v1_14;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.nms.BlockBreakingHelper;
import me.konsolas.aac.compat.nms.LegacyBoundingBoxHelper;
import me.konsolas.aac.compat.nms.MinecraftReflection;
import me.konsolas.aac.compat.nms.ReflectionAccess;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
public class Minecraft114Access implements NativeAccess {
private final MethodHandle declaredField;
private final Object field;
private final MethodHandle method;
private final MethodHandle declaredMethod;
private final MethodHandle declaredField2;
private final MethodHandle method2;
private final MethodHandle method3;
private final MethodHandle constructor;
private final MethodHandle method4;
private final MethodHandle method5;
private final Object method6;
private final MethodHandle method7;
public Minecraft114Access(ProtocolVersion version) {
if (version != ProtocolVersion.V1_14 && version != ProtocolVersion.V1_15) {
throw new IllegalArgumentException("Invalid version for SALImplV1_14_15: " + version);
} else {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String text = name.replace("org.bukkit.craftbukkit", "net.minecraft.server");
Class classValue = Class.forName(name + ".entity.CraftEntity");
Class classValue2 = Class.forName(name + ".CraftWorld");
Class classValue3 = Class.forName(name + ".inventory.ItemStack");
Class classValue4 = Class.forName(text + ".World");
Class.forName(text + ".Entity");
Class classValue5 = Class.forName(text + ".EntityPlayer");
Class classValue6 = Class.forName(text + ".ItemStack");
Class.forName(text + ".AxisAlignedBB");
Class classValue7 = Class.forName(text + ".BlockPosition");
Class.forName(text + ".IBlockData");
this.declaredField = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue5.getSuperclass().getSuperclass().getDeclaredField("activeItem")));
this.field = classValue6.getField("a").get(null);
this.method = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue3.getMethod("asCraftMirror", classValue6)));
this.declaredMethod = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getCraftBlockClass().getDeclaredMethod("getNMSBlock")));
this.declaredField2 = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(MinecraftReflection.getBlockClass().getDeclaredField("frictionFactor")));
this.method2 = ReflectionAccess.LOOKUP.unreflect(classValue.getMethod("getHandle"));
this.method3 = ReflectionAccess.LOOKUP.unreflect(classValue2.getMethod("getHandle"));
this.constructor = ReflectionAccess.LOOKUP.unreflectConstructor(classValue7.getConstructor(int.class, int.class, int.class));
this.method4 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue4.getMethod("getType", classValue7)));
this.method5 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getIBlockDataClass().getMethod("b", MinecraftReflection.getIBlockAccessClass(), MinecraftReflection.getBlockPositionClass(), MinecraftReflection.getVoxelShapeCollisionClass())));
this.method6 = MinecraftReflection.getVoxelShapeCollisionClass().getMethod("a").invoke(null);
this.method7 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getNmsClass((String) "VoxelShape").getMethod("d")));
} catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException | InvocationTargetException | IllegalAccessException exception) {
throw new RuntimeException("SALImplV1_14_15: <clinit>", exception);
}
}
}
@Override
public ItemStack getActiveItem(Player player) {
try {
Object result = (Object) this.declaredField.invoke((Object) (Object) this.method2.invoke((Player) player));
return Objects.equals(result, this.field) ? null : (ItemStack) this.method.invoke((Object) result);
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_14_15: getItemInUse", throwable);
}
}
@Override
public Collection getHandItems(Player player) {
return Arrays.asList(player.getInventory().getItemInMainHand(), player.getInventory().getItemInOffHand());
}
@Override
public boolean isGliding(Player player) {
return player.isGliding();
}
@Override
public float getBlockFriction(Block block) {
try {
return (float) this.declaredField2.invoke((Object) (Object) this.declaredMethod.invoke((Block) block));
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_14_15: getFrictionFactor", throwable);
}
}
@Override
public AxisAlignedBoundingBox getBoundingBox(Entity entity) {
BoundingBox boundingBox = entity.getBoundingBox();
return new AxisAlignedBoundingBox(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ());
}
@Override
public List getBlockCollisionBoxes(Block block, Entity entity) {
try {
Object result = (Object) this.method3.invoke((World) block.getWorld());
Object result2 = (Object) this.constructor.invoke((int) block.getX(), (int) block.getY(), (int) block.getZ());
Object result3 = (Object) this.method5.invoke((Object) (Object) this.method4.invoke((Object) result, (Object) result2), (Object) result, (Object) result2, (Object) this.method6);
List values = (List) this.method7.invoke((Object) result3);
ArrayList values2 = new ArrayList(values.size());
for (Object result4 : values) {
values2.add(LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result4));
}
return values2;
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_14_15: getCollisionShape", throwable);
}
}
@Override
public BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value) {
RayTraceResult rayTraceResult = entity.getWorld().rayTraceBlocks(vector.toLocation(entity.getWorld()), vector2.clone().normalize(), value);
return BlockRayTraceResult.create(rayTraceResult);
}
@Override
public float getBlockDamage(Player player, Block block) {
return BlockBreakingHelper.getWorld(block, player);
}
}
@@ -0,0 +1,153 @@
package me.konsolas.aac.compat.v1_16;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.nms.BlockBreakingHelper;
import me.konsolas.aac.compat.nms.LegacyBoundingBoxHelper;
import me.konsolas.aac.compat.nms.MinecraftReflection;
import me.konsolas.aac.compat.nms.ReflectionAccess;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
public class Minecraft116Access implements NativeAccess {
private final MethodHandle declaredField;
private final Object field;
private final MethodHandle method;
private final MethodHandle declaredMethod;
private final MethodHandle declaredField2;
private final MethodHandle method2;
private final MethodHandle method3;
private final MethodHandle constructor;
private final MethodHandle method4;
private final MethodHandle method5;
private final Object method6;
private final MethodHandle method7;
public Minecraft116Access(ProtocolVersion version) {
if (version != ProtocolVersion.V1_16) {
throw new IllegalArgumentException("Invalid version for SALImplV1_16: " + version);
} else {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String text = name.replace("org.bukkit.craftbukkit", "net.minecraft.server");
Class classValue = Class.forName(name + ".entity.CraftEntity");
Class classValue2 = Class.forName(name + ".CraftWorld");
Class classValue3 = Class.forName(name + ".inventory.ItemStack");
Class classValue4 = Class.forName(text + ".World");
Class.forName(text + ".Entity");
Class classValue5 = Class.forName(text + ".EntityPlayer");
Class classValue6 = Class.forName(text + ".ItemStack");
Class.forName(text + ".AxisAlignedBB");
Class classValue7 = Class.forName(text + ".BlockPosition");
Class.forName(text + ".IBlockData");
this.declaredField = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue5.getSuperclass().getSuperclass().getDeclaredField("activeItem")));
this.field = classValue6.getField("a").get(null);
this.method = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue3.getMethod("asCraftMirror", classValue6)));
this.declaredMethod = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getCraftBlockClass().getDeclaredMethod("getNMSBlock")));
this.declaredField2 = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(MinecraftReflection.getBlockClass().getDeclaredField("frictionFactor")));
this.method2 = ReflectionAccess.LOOKUP.unreflect(classValue.getMethod("getHandle"));
this.method3 = ReflectionAccess.LOOKUP.unreflect(classValue2.getMethod("getHandle"));
this.constructor = ReflectionAccess.LOOKUP.unreflectConstructor(classValue7.getConstructor(int.class, int.class, int.class));
this.method4 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue4.getMethod("getType", classValue7)));
this.method5 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getIBlockDataClass().getMethod("b", MinecraftReflection.getIBlockAccessClass(), MinecraftReflection.getBlockPositionClass(), MinecraftReflection.getVoxelShapeCollisionClass())));
this.method6 = MinecraftReflection.getVoxelShapeCollisionClass().getMethod("b").invoke(null);
this.method7 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getNmsClass((String) "VoxelShape").getMethod("d")));
} catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException | InvocationTargetException | IllegalAccessException exception) {
throw new RuntimeException("SALImplV1_16: <clinit>", exception);
}
}
}
@Override
public ItemStack getActiveItem(Player player) {
try {
Object result = (Object) this.declaredField.invoke((Object) (Object) this.method2.invoke((Player) player));
return Objects.equals(result, this.field) ? null : (ItemStack) this.method.invoke((Object) result);
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_16: getItemInUse", throwable);
}
}
@Override
public Collection getHandItems(Player player) {
return Arrays.asList(player.getInventory().getItemInMainHand(), player.getInventory().getItemInOffHand());
}
@Override
public boolean isGliding(Player player) {
return player.isGliding();
}
@Override
public float getBlockFriction(Block block) {
try {
return (float) this.declaredField2.invoke((Object) (Object) this.declaredMethod.invoke((Block) block));
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_16: getFrictionFactor", throwable);
}
}
@Override
public AxisAlignedBoundingBox getBoundingBox(Entity entity) {
BoundingBox boundingBox = entity.getBoundingBox();
return new AxisAlignedBoundingBox(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ());
}
@Override
public List getBlockCollisionBoxes(Block block, Entity entity) {
try {
Object result = (Object) this.method3.invoke((World) block.getWorld());
Object result2 = (Object) this.constructor.invoke((int) block.getX(), (int) block.getY(), (int) block.getZ());
Object result3 = (Object) this.method5.invoke((Object) (Object) this.method4.invoke((Object) result, (Object) result2), (Object) result, (Object) result2, (Object) this.method6);
List values = (List) this.method7.invoke((Object) result3);
ArrayList values2 = new ArrayList(values.size());
for (Object result4 : values) {
values2.add(LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result4));
}
return values2;
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_16: getCollisionShape", throwable);
}
}
@Override
public BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value) {
RayTraceResult rayTraceResult = entity.getWorld().rayTraceBlocks(vector.toLocation(entity.getWorld()), vector2.clone().normalize(), value);
return BlockRayTraceResult.create(rayTraceResult);
}
@Override
public float getBlockDamage(Player player, Block block) {
return BlockBreakingHelper.getWorld(block, player);
}
}
@@ -0,0 +1,65 @@
package me.konsolas.aac.compat.v1_17;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
public class Minecraft117Access implements NativeAccess {
@Override
public ItemStack getActiveItem(Player player) {
return player.getItemInUse();
}
@Override
public Collection getHandItems(Player player) {
return Arrays.asList(player.getInventory().getItemInMainHand(), player.getInventory().getItemInOffHand());
}
@Override
public boolean isGliding(Player player) {
return player.isGliding();
}
@Override
public float getBlockFriction(Block block) {
return block.getType().getSlipperiness();
}
@Override
public AxisAlignedBoundingBox getBoundingBox(Entity entity) {
return AxisAlignedBoundingBox.fromBukkit(entity.getBoundingBox());
}
@Override
public List getBlockCollisionBoxes(Block block, Entity entity) {
Collection<BoundingBox> boundingBoxes = block.getCollisionShape().getBoundingBoxes();
ArrayList values = new ArrayList(boundingBoxes.size());
for (BoundingBox box : boundingBoxes) {
values.add(AxisAlignedBoundingBox.fromBukkit(box));
}
return values;
}
@Override
public BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value) {
RayTraceResult rayTraceResult = entity.getWorld().rayTraceBlocks(vector.toLocation(entity.getWorld()), vector2.clone().normalize(), value);
return BlockRayTraceResult.create(rayTraceResult);
}
@Override
public float getBlockDamage(Player player, Block block) {
return block.getBreakSpeed(player);
}
}
@@ -0,0 +1,157 @@
package me.konsolas.aac.compat.v1_8;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.nms.BlockBreakingHelper;
import me.konsolas.aac.compat.nms.EntityRayTracer;
import me.konsolas.aac.compat.nms.LegacyBoundingBoxHelper;
import me.konsolas.aac.compat.nms.MinecraftReflection;
import me.konsolas.aac.compat.nms.ReflectionAccess;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class Minecraft18Access implements NativeAccess {
private final MethodHandle declaredMethod;
private final MethodHandle declaredMethod2;
private final MethodHandle declaredField;
private final MethodHandle method;
private final MethodHandle method2;
private final MethodHandle method3;
private final MethodHandle constructor;
private final MethodHandle method4;
private final MethodHandle method5;
private final MethodHandle method6;
public Minecraft18Access() {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String text = name.replace("org.bukkit.craftbukkit", "net.minecraft.server");
Class classValue = Class.forName(name + ".entity.CraftEntity");
Class classValue2 = Class.forName(name + ".CraftWorld");
Class classValue3 = Class.forName(text + ".World");
Class classValue4 = Class.forName(text + ".Entity");
Class.forName(text + ".EntityHuman");
Class classValue5 = Class.forName(text + ".Block");
Class classValue6 = Class.forName(text + ".AxisAlignedBB");
Class classValue7 = Class.forName(text + ".BlockPosition");
Class classValue8 = Class.forName(text + ".IBlockData");
this.declaredMethod = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getEntityPlayerClass().getSuperclass().getDeclaredMethod("bS")));
this.declaredMethod2 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getCraftBlockClass().getDeclaredMethod("getNMSBlock")));
this.declaredField = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(MinecraftReflection.getBlockClass().getDeclaredField("frictionFactor")));
this.method = ReflectionAccess.LOOKUP.unreflect(classValue.getMethod("getHandle"));
this.method2 = ReflectionAccess.LOOKUP.unreflect(classValue2.getMethod("getHandle"));
this.method3 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getEntityClass().getMethod("getBoundingBox")));
this.constructor = ReflectionAccess.LOOKUP.unreflectConstructor(classValue7.getConstructor(int.class, int.class, int.class));
this.method4 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue3.getMethod("getType", classValue7)));
this.method5 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue8.getMethod("getBlock")));
this.method6 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue5.getMethod("a", classValue3, classValue7, classValue8, classValue6, List.class, classValue4)));
} catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException | IllegalAccessException exception) {
throw new RuntimeException("SALImplV1_8: <clinit>", exception);
}
}
@Override
public ItemStack getActiveItem(Player player) {
try {
return (boolean) this.declaredMethod.invoke((Object) (Object) this.method.invoke((Player) player)) ? player.getItemInHand() : null;
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_8: getItemInUse", throwable);
}
}
@Override
public Collection getHandItems(Player player) {
return Collections.singleton(player.getItemInHand());
}
@Override
public boolean isGliding(Player player) {
return false;
}
@Override
public float getBlockFriction(Block block) {
try {
return (float) this.declaredField.invoke((Object) (Object) this.declaredMethod2.invoke((Block) block));
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_8: getFrictionFactor", throwable);
}
}
@Override
public AxisAlignedBoundingBox getBoundingBox(Entity entity) {
try {
Object result = (Object) this.method3.invoke((Object) (Object) this.method.invoke((Entity) entity));
return LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result);
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_8: getBoundingBox", throwable);
}
}
@Override
public List getBlockCollisionBoxes(Block block, Entity entity) {
try {
Object result = (Object) this.method2.invoke((World) block.getWorld());
Object result2 = (Object) this.constructor.invoke((int) block.getX(), (int) block.getY(), (int) block.getZ());
Object result3 = (Object) this.method4.invoke((Object) result, (Object) result2);
double x = block.getX();
double y = block.getY();
double z = block.getZ();
double value = block.getX() + 1.0;
double value2 = block.getZ() + 1.0;
double value3 = block.getY() + 1.0;
double value4 = value;
double value5 = z;
double value6 = y;
double value7 = x;
Object result4 = LegacyBoundingBoxHelper.findObject(value7, value6, value5, value4, value3, value2);
ArrayList values = new ArrayList();
Object result5 = (Object) this.method5.invoke((Object) result3);
this.method6.invoke((Object) result5, (Object) result, (Object) result2, (Object) result3, (Object) result4, (List) values, (Object) (Object) this.method.invoke((Entity) entity));
ArrayList values2 = new ArrayList(values.size());
for (Object result6 : values) {
z = -block.getX();
double value8 = -block.getZ();
double value9 = -block.getY();
double value10 = z;
values2.add(LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result6, value10, value9, value8));
}
return values2;
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_8: getCollisionShape", throwable);
}
}
@Override
public BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value) {
return EntityRayTracer.rayTrace(entity, vector, vector2, value);
}
@Override
public float getBlockDamage(Player player, Block block) {
return BlockBreakingHelper.getWorld(block, player);
}
}
@@ -0,0 +1,162 @@
package me.konsolas.aac.compat.v1_9;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import me.konsolas.aac.compat.NativeAccess;
import me.konsolas.aac.compat.nms.BlockBreakingHelper;
import me.konsolas.aac.compat.nms.EntityRayTracer;
import me.konsolas.aac.compat.nms.LegacyBoundingBoxHelper;
import me.konsolas.aac.compat.nms.MinecraftReflection;
import me.konsolas.aac.compat.nms.ReflectionAccess;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockRayTraceResult;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class Minecraft19Access implements NativeAccess {
private final MethodHandle declaredField;
private final MethodHandle method;
private final MethodHandle declaredMethod;
private final MethodHandle declaredField2;
private final MethodHandle method2;
private final MethodHandle method3;
private final MethodHandle method4;
private final MethodHandle constructor;
private final MethodHandle method5;
private final MethodHandle method6;
public Minecraft19Access(ProtocolVersion version) {
if (version != ProtocolVersion.V1_9 && version != ProtocolVersion.V1_10) {
throw new IllegalArgumentException("Invalid version for SALImplV1_9_10: " + version);
} else {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String text = name.replace("org.bukkit.craftbukkit", "net.minecraft.server");
Class classValue = Class.forName(name + ".entity.CraftEntity");
Class classValue2 = Class.forName(name + ".CraftWorld");
Class classValue3 = Class.forName(name + ".inventory.ItemStack");
Class classValue4 = Class.forName(text + ".World");
Class classValue5 = Class.forName(text + ".Entity");
Class classValue6 = Class.forName(text + ".EntityPlayer");
Class classValue7 = Class.forName(text + ".ItemStack");
Class classValue8 = Class.forName(text + ".AxisAlignedBB");
Class classValue9 = Class.forName(text + ".BlockPosition");
Class classValue10 = Class.forName(text + ".IBlockData");
this.declaredField = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(classValue6.getSuperclass().getSuperclass().getDeclaredField(version == ProtocolVersion.V1_9 ? "bn" : "bo")));
this.method = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue3.getMethod("asCraftMirror", classValue7)));
this.declaredMethod = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getCraftBlockClass().getDeclaredMethod("getNMSBlock")));
this.declaredField2 = ReflectionAccess.LOOKUP.unreflectGetter((Field) ReflectionAccess.makeAccessible(MinecraftReflection.getBlockClass().getDeclaredField("frictionFactor")));
this.method2 = ReflectionAccess.LOOKUP.unreflect(classValue.getMethod("getHandle"));
this.method3 = ReflectionAccess.LOOKUP.unreflect(classValue2.getMethod("getHandle"));
this.method4 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(MinecraftReflection.getEntityClass().getMethod("getBoundingBox")));
this.constructor = ReflectionAccess.LOOKUP.unreflectConstructor(classValue9.getConstructor(int.class, int.class, int.class));
this.method5 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue4.getMethod("getType", classValue9)));
this.method6 = ReflectionAccess.LOOKUP.unreflect((Method) ReflectionAccess.makeAccessible(classValue10.getMethod("a", classValue4, classValue9, classValue8, List.class, classValue5)));
} catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException | IllegalAccessException exception) {
throw new RuntimeException("SALImplV1_9_10: <clinit>", exception);
}
}
}
@Override
public ItemStack getActiveItem(Player player) {
try {
Object result = (Object) this.declaredField.invoke((Object) (Object) this.method2.invoke((Player) player));
return result == null ? null : (ItemStack) this.method.invoke((Object) result);
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_9_10: getItemInUse", throwable);
}
}
@Override
public Collection getHandItems(Player player) {
return Arrays.asList(player.getInventory().getItemInMainHand(), player.getInventory().getItemInOffHand());
}
@Override
public boolean isGliding(Player player) {
return player.isGliding();
}
@Override
public float getBlockFriction(Block block) {
try {
return (float) this.declaredField2.invoke((Object) (Object) this.declaredMethod.invoke((Block) block));
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_9_10: getFrictionFactor", throwable);
}
}
@Override
public AxisAlignedBoundingBox getBoundingBox(Entity entity) {
try {
Object result = (Object) this.method4.invoke((Object) (Object) this.method2.invoke((Entity) entity));
return LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result);
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_9_10: getBoundingBox", throwable);
}
}
@Override
public List getBlockCollisionBoxes(Block block, Entity entity) {
try {
Object result = (Object) this.method3.invoke((World) block.getWorld());
Object result2 = (Object) this.constructor.invoke((int) block.getX(), (int) block.getY(), (int) block.getZ());
double x = block.getX();
double y = block.getY();
double z = block.getZ();
double value = block.getX() + 1.0;
double value2 = block.getZ() + 1.0;
double value3 = block.getY() + 1.0;
double value4 = value;
double value5 = z;
double value6 = y;
double value7 = x;
Object result3 = LegacyBoundingBoxHelper.findObject(value7, value6, value5, value4, value3, value2);
ArrayList values = new ArrayList();
this.method6.invoke((Object) (Object) this.method5.invoke((Object) result, (Object) result2), (Object) result, (Object) result2, (Object) result3, (List) values, (Object) (Object) this.method2.invoke((Entity) entity));
ArrayList values2 = new ArrayList(values.size());
for (Object result4 : values) {
z = -block.getX();
double value8 = -block.getZ();
double value9 = -block.getY();
double value10 = z;
values2.add(LegacyBoundingBoxHelper.findAxisAlignedBoundingBox(result4, value10, value9, value8));
}
return values2;
} catch (Throwable throwable) {
throw new RuntimeException("SALImplV1_9_10: getCollisionShape", throwable);
}
}
@Override
public BlockRayTraceResult rayTrace(Entity entity, Vector vector, Vector vector2, double value) {
return EntityRayTracer.rayTrace(entity, vector, vector2, value);
}
@Override
public float getBlockDamage(Player player, Block block) {
return BlockBreakingHelper.getWorld(block, player);
}
}
@@ -0,0 +1,298 @@
package me.konsolas.aac.database;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
class ConnectionDelegate implements Connection {
private final Connection delegate;
ConnectionDelegate(Connection delegate) {
this.delegate = delegate;
}
@Override
public Statement createStatement() throws SQLException {
return this.delegate.createStatement();
}
@Override
public PreparedStatement prepareStatement(String text) throws SQLException {
return this.delegate.prepareStatement(text);
}
@Override
public CallableStatement prepareCall(String text) throws SQLException {
return this.delegate.prepareCall(text);
}
@Override
public String nativeSQL(String text) throws SQLException {
return this.delegate.nativeSQL(text);
}
@Override
public void setAutoCommit(boolean matches) throws SQLException {
this.delegate.setAutoCommit(matches);
}
@Override
public boolean getAutoCommit() throws SQLException {
return this.delegate.getAutoCommit();
}
@Override
public void commit() throws SQLException {
this.delegate.commit();
}
@Override
public void rollback() throws SQLException {
this.delegate.rollback();
}
@Override
public void close() {
}
@Override
public boolean isClosed() throws SQLException {
return this.delegate.isClosed();
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return this.delegate.getMetaData();
}
@Override
public void setReadOnly(boolean matches) throws SQLException {
this.delegate.setReadOnly(matches);
}
@Override
public boolean isReadOnly() throws SQLException {
return this.delegate.isReadOnly();
}
@Override
public void setCatalog(String text) throws SQLException {
this.delegate.setCatalog(text);
}
@Override
public String getCatalog() throws SQLException {
return this.delegate.getCatalog();
}
@Override
public void setTransactionIsolation(int value) throws SQLException {
this.delegate.setTransactionIsolation(value);
}
@Override
public int getTransactionIsolation() throws SQLException {
return this.delegate.getTransactionIsolation();
}
@Override
public SQLWarning getWarnings() throws SQLException {
return this.delegate.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
this.delegate.clearWarnings();
}
@Override
public Statement createStatement(int value, int value2) throws SQLException {
return this.delegate.createStatement(value, value2);
}
@Override
public PreparedStatement prepareStatement(String text, int value, int value2) throws SQLException {
return this.delegate.prepareStatement(text, value, value2);
}
@Override
public CallableStatement prepareCall(String text, int value, int value2) throws SQLException {
return this.delegate.prepareCall(text, value, value2);
}
@Override
public Map getTypeMap() throws SQLException {
return this.delegate.getTypeMap();
}
@Override
public void setTypeMap(Map entries) throws SQLException {
this.delegate.setTypeMap(entries);
}
@Override
public void setHoldability(int value) throws SQLException {
this.delegate.setHoldability(value);
}
@Override
public int getHoldability() throws SQLException {
return this.delegate.getHoldability();
}
@Override
public Savepoint setSavepoint() throws SQLException {
return this.delegate.setSavepoint();
}
@Override
public Savepoint setSavepoint(String text) throws SQLException {
return this.delegate.setSavepoint(text);
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
this.delegate.rollback(savepoint);
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
this.delegate.releaseSavepoint(savepoint);
}
@Override
public Statement createStatement(int value, int value2, int value3) throws SQLException {
return this.delegate.createStatement(value, value2, value3);
}
@Override
public PreparedStatement prepareStatement(String text, int value, int value2, int value3) throws SQLException {
return this.delegate.prepareStatement(text, value, value2, value3);
}
@Override
public CallableStatement prepareCall(String text, int value, int value2, int value3) throws SQLException {
return this.delegate.prepareCall(text, value, value2, value3);
}
@Override
public PreparedStatement prepareStatement(String text, int value) throws SQLException {
return this.delegate.prepareStatement(text, value);
}
@Override
public PreparedStatement prepareStatement(String text, int[] values) throws SQLException {
return this.delegate.prepareStatement(text, values);
}
@Override
public PreparedStatement prepareStatement(String text, String[] texts) throws SQLException {
return this.delegate.prepareStatement(text, texts);
}
@Override
public Clob createClob() throws SQLException {
return this.delegate.createClob();
}
@Override
public Blob createBlob() throws SQLException {
return this.delegate.createBlob();
}
@Override
public NClob createNClob() throws SQLException {
return this.delegate.createNClob();
}
@Override
public SQLXML createSQLXML() throws SQLException {
return this.delegate.createSQLXML();
}
@Override
public boolean isValid(int value) throws SQLException {
return this.delegate.isValid(value);
}
@Override
public void setClientInfo(String text, String text2) throws SQLClientInfoException {
this.delegate.setClientInfo(text, text2);
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
this.delegate.setClientInfo(properties);
}
@Override
public String getClientInfo(String text) throws SQLException {
return this.delegate.getClientInfo(text);
}
@Override
public Properties getClientInfo() throws SQLException {
return this.delegate.getClientInfo();
}
@Override
public Array createArrayOf(String text, Object[] results) throws SQLException {
return this.delegate.createArrayOf(text, results);
}
@Override
public Struct createStruct(String text, Object[] results) throws SQLException {
return this.delegate.createStruct(text, results);
}
@Override
public void setSchema(String text) throws SQLException {
this.delegate.setSchema(text);
}
@Override
public String getSchema() throws SQLException {
return this.delegate.getSchema();
}
@Override
public void abort(Executor executor) throws SQLException {
this.delegate.abort(executor);
}
@Override
public void setNetworkTimeout(Executor executor, int value) throws SQLException {
this.delegate.setNetworkTimeout(executor, value);
}
@Override
public int getNetworkTimeout() throws SQLException {
return this.delegate.getNetworkTimeout();
}
@Override
public Object unwrap(Class classValue) throws SQLException {
return this.delegate.unwrap(classValue);
}
@Override
public boolean isWrapperFor(Class classValue) throws SQLException {
return this.delegate.isWrapperFor(classValue);
}
}
@@ -0,0 +1,38 @@
package me.konsolas.aac.database;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.function.Supplier;
import org.bukkit.Bukkit;
class ConnectionProvider implements AutoCloseable {
private final Supplier connectionFactory;
private final DatabaseDialect dialect;
private Connection connection;
ConnectionProvider(Supplier connectionFactory, DatabaseDialect dialect) {
this.connectionFactory = connectionFactory;
this.dialect = dialect;
this.connection = (Connection) connectionFactory.get();
}
public Connection getConnection() throws SQLException {
if (this.connection == null || !this.connection.isValid(30)) {
Bukkit.getLogger().info("[AAC5] Reconnecting to database...");
this.connection = (Connection) this.connectionFactory.get();
}
return new ConnectionDelegate(this.connection);
}
public DatabaseDialect getDialect() {
return this.dialect;
}
@Override
public void close() throws SQLException {
this.connection.close();
}
}
@@ -0,0 +1,6 @@
package me.konsolas.aac.database;
public enum DatabaseDialect {
SQLITE, MYSQL
}
@@ -0,0 +1,40 @@
package me.konsolas.aac.database;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureEvent;
class DatabaseWriter implements Runnable {
final AAC plugin;
final PlayerDatabase database;
DatabaseWriter(PlayerDatabase database, AAC plugin) {
this.database = database;
this.plugin = plugin;
}
@Override
public void run() {
try {
ArrayList values = new ArrayList();
while (PlayerDatabase.checkPlayerDatabase(this.database)) {
values.add((FeatureEvent) PlayerDatabase.findBlockingQueue(this.database).take());
PlayerDatabase.findBlockingQueue(this.database).drainTo(values);
try {
PlayerDatabase playerDatabase = this.database;
PlayerDatabase.updatePlayerDatabase(playerDatabase, values);
} catch (SQLException sQLException) {
this.plugin.getLogger().log(Level.SEVERE, "Failed to save events to database", (Throwable) sQLException);
}
values.clear();
Thread.sleep(1000L);
}
} catch (InterruptedException interruptedException) {
this.plugin.getLogger().info(PlayerDatabase.findThread(this.database).getName() + " exiting");
}
}
}
@@ -0,0 +1,547 @@
package me.konsolas.aac.database;
import java.io.Closeable;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Supplier;
import java.util.logging.Level;
import me.konsolas.aac.AAC;
import me.konsolas.aac.analysis.feature.FeatureEvent;
import me.konsolas.aac.analysis.feature.FeatureType;
import me.konsolas.aac.player.PlayerLoginInfo;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
public class PlayerDatabase implements Closeable {
private final AAC plugin;
private final ConnectionProvider connectionProvider;
private final BlockingQueue eventQueue = new LinkedBlockingQueue();
private final Thread writerThread;
private volatile boolean closed = true;
private PlayerDatabase(AAC plugin, ConnectionProvider connectionProvider) throws SQLException {
this.plugin = plugin;
this.connectionProvider = connectionProvider;
this.tick();
this.writerThread = new Thread(new DatabaseWriter(this, plugin), "AAC Database Thread");
this.writerThread.start();
}
public static PlayerDatabase create(AAC aacPlugin, String text) throws SQLException {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException classNotFoundException) {
throw new RuntimeException(classNotFoundException);
}
Supplier supplier = () -> {
try {
return DriverManager.getConnection("jdbc:sqlite:" + text);
} catch (SQLException sQLException) {
aacPlugin.getLogger().log(Level.SEVERE, "Could not connect to SQLite database", (Throwable) sQLException);
throw new RuntimeException(sQLException);
}
};
DatabaseDialect databaseDialect = DatabaseDialect.SQLITE;
Supplier supplier2 = supplier;
ConnectionProvider connectionProvider = new ConnectionProvider(supplier2, databaseDialect);
ConnectionProvider connectionProvider2 = connectionProvider;
return new PlayerDatabase(aacPlugin, connectionProvider2);
}
public static PlayerDatabase create(AAC aacPlugin, String text, int value, String text2, String text3, String text4) throws SQLException {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException classNotFoundException) {
throw new RuntimeException(classNotFoundException);
}
String text5 = "jdbc:mysql://" + text + ":" + value + "/" + text2;
Supplier supplier = () -> {
try {
return DriverManager.getConnection(text5, text3, text4);
} catch (SQLException sQLException) {
aacPlugin.getLogger().log(Level.SEVERE, "Could not connect to MySQL database", (Throwable) sQLException);
throw new RuntimeException(sQLException);
}
};
DatabaseDialect databaseDialect = DatabaseDialect.MYSQL;
Supplier supplier2 = supplier;
ConnectionProvider connectionProvider = new ConnectionProvider(supplier2, databaseDialect);
ConnectionProvider connectionProvider2 = connectionProvider;
return new PlayerDatabase(aacPlugin, connectionProvider2);
}
private void tick() throws SQLException {
Connection connection = this.connectionProvider.getConnection();
try {
Statement statement = connection.createStatement();
try {
statement.execute("CREATE TABLE IF NOT EXISTS `aac_events` ( `time` DATETIME NOT NULL, `uuid` BINARY(16) NOT NULL, `type` INT NOT NULL, `data` FLOAT NOT NULL);");
statement.execute("CREATE TABLE IF NOT EXISTS `aac_players` ( `uuid` BINARY(16) PRIMARY KEY, `join` DATETIME NOT NULL, `addr` VARCHAR(45) NOT NULL, `addr_time` DATETIME NOT NULL, `exempt` BOOLEAN NOT NULL);");
} catch (Throwable throwable) {
if (statement != null) {
try {
statement.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
}
throw throwable;
}
if (statement != null) {
statement.close();
}
} catch (Throwable throwable3) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
}
throw throwable3;
}
if (connection != null) {
connection.close();
}
try {
connection = this.connectionProvider.getConnection();
try {
Statement statement2 = connection.createStatement();
try {
statement2.execute("CREATE INDEX `time_uuid_idx` ON `aac_events` (`time`, `uuid`)");
} catch (Throwable throwable5) {
if (statement2 != null) {
try {
statement2.close();
} catch (Throwable throwable6) {
throwable5.addSuppressed(throwable6);
}
}
throw throwable5;
}
if (statement2 != null) {
statement2.close();
}
} catch (Throwable throwable7) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable8) {
throwable7.addSuppressed(throwable8);
}
}
throw throwable7;
}
if (connection != null) {
connection.close();
}
} catch (SQLException sQLException) {
}
}
public int deleteEventsBefore(long value) throws SQLException {
Connection connection = this.connectionProvider.getConnection();
int value2;
try {
PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM `aac_events` WHERE `time` < ?");
try {
preparedStatement.setTimestamp(1, new Timestamp(value));
value2 = preparedStatement.executeUpdate();
} catch (Throwable throwable) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
}
throw throwable;
}
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (Throwable throwable3) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
}
throw throwable3;
}
if (connection != null) {
connection.close();
}
return value2;
}
public void recordFeature(Player player, FeatureType feature, float value) {
FeatureEvent event = new FeatureEvent(System.currentTimeMillis(), player.getUniqueId(), feature, value);
this.eventQueue.add(event);
this.plugin.getAnalysisManager().updatePlayerWithAlertRecipients(player);
}
public CompletableFuture<Integer> resetPlayerAsync(OfflinePlayer offlinePlayer) {
UUID uniqueId = offlinePlayer.getUniqueId();
return CompletableFuture.supplyAsync(() -> {
try {
Connection connection = this.connectionProvider.getConnection();
Integer value;
try {
PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM `aac_events` WHERE `uuid` = ?");
try {
preparedStatement.setBytes(1, encodeUuid(uniqueId));
value = preparedStatement.executeUpdate();
} catch (Throwable throwable) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
}
throw throwable;
}
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (Throwable throwable3) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
}
throw throwable3;
}
if (connection != null) {
connection.close();
}
return value;
} catch (SQLException sQLException) {
throw new CompletionException(sQLException);
}
});
}
private void updateList(List<FeatureEvent> values) throws SQLException {
Connection connection = this.connectionProvider.getConnection();
try {
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `aac_events`(`time`, `uuid`, `type`, `data`) VALUES (?, ?, ?, ?);");
try {
for (FeatureEvent event : values) {
preparedStatement.setObject(1, new Timestamp(event.getTimestamp()));
UUID playerId = event.getPlayerId();
UUID uUID = playerId;
preparedStatement.setBytes(2, encodeUuid(uUID));
preparedStatement.setInt(3, event.getType().getId());
preparedStatement.setFloat(4, event.getValue());
preparedStatement.addBatch();
}
connection.setAutoCommit(false);
preparedStatement.executeBatch();
connection.setAutoCommit(true);
} catch (Throwable throwable) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
}
throw throwable;
}
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (Throwable throwable3) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
}
throw throwable3;
}
if (connection != null) {
connection.close();
}
}
public PlayerLoginInfo findPlayerLoginInfo(UUID uUID) throws SQLException {
Connection connection = this.connectionProvider.getConnection();
PlayerLoginInfo playerLoginInfo;
decision: {
try {
PreparedStatement preparedStatement = connection.prepareStatement("SELECT `join`, `addr`, `addr_time`, `exempt` FROM `aac_players` WHERE `uuid` = ?");
decision2: {
try {
preparedStatement.setBytes(1, encodeUuid(uUID));
ResultSet resultSet = preparedStatement.executeQuery();
if (!resultSet.next()) {
playerLoginInfo = null;
break decision2;
}
playerLoginInfo = new PlayerLoginInfo(uUID, resultSet.getTimestamp(1).getTime(), resultSet.getString(2), resultSet.getTimestamp(3).getTime(), resultSet.getBoolean(4));
} catch (Throwable throwable) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
}
throw throwable;
}
if (preparedStatement != null) {
preparedStatement.close();
}
break decision;
}
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (Throwable throwable3) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
}
throw throwable3;
}
if (connection != null) {
connection.close();
}
return playerLoginInfo;
}
if (connection != null) {
connection.close();
}
return playerLoginInfo;
}
public PlayerLoginInfo findPlayerLoginInfo(UUID uUID, InetAddress inetAddress) throws SQLException {
long now = System.currentTimeMillis();
String hostAddress = inetAddress.getHostAddress();
PlayerLoginInfo playerLoginInfo = this.findPlayerLoginInfo(uUID);
if (playerLoginInfo == null) {
playerLoginInfo = new PlayerLoginInfo(uUID, now, hostAddress, now, false);
Connection connection = this.connectionProvider.getConnection();
try {
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `aac_players`(`uuid`, `join`, `addr`, `addr_time`, `exempt`) VALUES (?, ?, ?, ?, ?)");
try {
preparedStatement.setBytes(1, encodeUuid(uUID));
preparedStatement.setTimestamp(2, new Timestamp(playerLoginInfo.getFirstSeen()));
preparedStatement.setString(3, playerLoginInfo.getAddress());
preparedStatement.setTimestamp(4, new Timestamp(playerLoginInfo.getLastSeen()));
preparedStatement.setBoolean(5, playerLoginInfo.isExempt());
preparedStatement.executeUpdate();
} catch (Throwable throwable) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
}
throw throwable;
}
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (Throwable throwable3) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
}
throw throwable3;
}
if (connection != null) {
connection.close();
}
} else if (!playerLoginInfo.getAddress().equals(hostAddress)) {
playerLoginInfo = new PlayerLoginInfo(uUID, playerLoginInfo.getFirstSeen(), hostAddress, now, playerLoginInfo.isExempt());
Connection connection2 = this.connectionProvider.getConnection();
try {
PreparedStatement preparedStatement2 = connection2.prepareStatement("UPDATE `aac_players` SET `addr` = ?, `addr_time` = ? WHERE `uuid` = ?");
try {
preparedStatement2.setString(1, playerLoginInfo.getAddress());
preparedStatement2.setTimestamp(2, new Timestamp(playerLoginInfo.getLastSeen()));
preparedStatement2.setBytes(3, encodeUuid(uUID));
preparedStatement2.executeUpdate();
} catch (Throwable throwable5) {
if (preparedStatement2 != null) {
try {
preparedStatement2.close();
} catch (Throwable throwable6) {
throwable5.addSuppressed(throwable6);
}
}
throw throwable5;
}
if (preparedStatement2 != null) {
preparedStatement2.close();
}
} catch (Throwable throwable7) {
if (connection2 != null) {
try {
connection2.close();
} catch (Throwable throwable8) {
throwable7.addSuppressed(throwable8);
}
}
throw throwable7;
}
if (connection2 != null) {
connection2.close();
}
}
return playerLoginInfo;
}
public void setExempt(UUID uUID, boolean matches) throws SQLException {
Connection connection = this.connectionProvider.getConnection();
try {
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `aac_players` SET `exempt` = ? WHERE `uuid` = ?");
try {
preparedStatement.setBoolean(1, matches);
preparedStatement.setBytes(2, encodeUuid(uUID));
preparedStatement.executeUpdate();
} catch (Throwable throwable) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
}
throw throwable;
}
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (Throwable throwable3) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
}
throw throwable3;
}
if (connection != null) {
connection.close();
}
}
public List getEventsSince(long value, UUID uUID) throws SQLException {
Connection connection = this.connectionProvider.getConnection();
ArrayList values;
try {
PreparedStatement preparedStatement = connection.prepareStatement("SELECT `time`, `type`, `data` FROM `aac_events` WHERE `time` > ? AND `uuid` = ?");
try {
preparedStatement.setObject(1, new Timestamp(value));
preparedStatement.setBytes(2, encodeUuid(uUID));
ResultSet resultSet = preparedStatement.executeQuery();
ArrayList values2 = new ArrayList();
while (resultSet.next()) {
long time = resultSet.getTimestamp(1).getTime();
int intValue = resultSet.getInt(2);
values2.add(new FeatureEvent(time, uUID, FeatureType.fromId(intValue), resultSet.getFloat(3)));
}
values = values2;
} catch (Throwable throwable) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
}
throw throwable;
}
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (Throwable throwable3) {
if (connection != null) {
try {
connection.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
}
throw throwable3;
}
if (connection != null) {
connection.close();
}
return values;
}
private static byte[] encodeUuid(UUID uUID) {
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
byteBuffer.putLong(uUID.getMostSignificantBits());
byteBuffer.putLong(uUID.getLeastSignificantBits());
return byteBuffer.array();
}
@Override
public void close() {
try {
this.closed = false;
this.writerThread.join();
} catch (InterruptedException interruptedException) {
this.plugin.getLogger().warning("Interrupted while closing database connection");
}
try {
this.connectionProvider.close();
} catch (Exception exception) {
this.plugin.getLogger().log(Level.WARNING, "Could not close connection", (Throwable) exception);
}
}
static boolean checkPlayerDatabase(PlayerDatabase playerDatabase) {
return playerDatabase.closed;
}
static BlockingQueue findBlockingQueue(PlayerDatabase playerDatabase) {
return playerDatabase.eventQueue;
}
static void updatePlayerDatabase(PlayerDatabase playerDatabase, List values) throws SQLException {
playerDatabase.updateList(values);
}
static Thread findThread(PlayerDatabase playerDatabase) {
return playerDatabase.writerThread;
}
}
@@ -0,0 +1,102 @@
package me.konsolas.aac.debug;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import me.konsolas.aac.AAC;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class DebugManager {
private final AAC plugin;
private final Executor executor = Executors.newSingleThreadExecutor();
private final Map<UUID, Set<CommandSender>> debugSubscriptions = new ConcurrentHashMap();
private CommandSender consoleSubscriber = null;
public DebugManager(AAC plugin) {
this.plugin = plugin;
}
public boolean isDebugging(Player player) {
if (this.consoleSubscriber != null) {
return true;
} else {
Set values = (Set) this.debugSubscriptions.get(player.getUniqueId());
return values != null && !values.isEmpty();
}
}
public void log(Player player, String text) {
long now = System.currentTimeMillis();
this.executor.execute(() -> this.writeLog(player, text, now));
}
private void writeLog(Player player, String text, long value) {
Set<CommandSender> values = (Set) this.debugSubscriptions.get(player.getUniqueId());
if (this.consoleSubscriber != null) {
if (values == null) {
values = Collections.singleton(this.consoleSubscriber);
} else {
values.add(this.consoleSubscriber);
}
}
if (values != null) {
String text2 = Long.toString(value);
text = "" + ChatColor.DARK_GRAY + text2.substring(text2.length() - 4) + " " + ChatColor.DARK_GREEN + player.getName() + " " + ChatColor.GRAY + text;
for (CommandSender sender : values) {
sender.sendMessage(text);
}
}
}
public void updatePlayer(Player player, String text, Object[] results) {
this.log(player, String.format(Locale.UK, text, results));
}
public void updateCommandSender(CommandSender sender) {
if (this.consoleSubscriber == sender) {
this.consoleSubscriber = null;
} else {
this.consoleSubscriber = sender;
}
}
public boolean checkDebugManager(CommandSender sender) {
return sender == this.consoleSubscriber;
}
public void updateCommandSender(CommandSender sender, OfflinePlayer offlinePlayer) {
Set values = this.debugSubscriptions.computeIfAbsent(offlinePlayer.getUniqueId(), result -> new HashSet());
if (values.remove(sender)) {
if (values.isEmpty()) {
this.debugSubscriptions.remove(offlinePlayer.getUniqueId());
}
} else {
values.add(sender);
}
}
public Set<OfflinePlayer> findSet(CommandSender sender) {
HashSet values = new HashSet();
for (Entry entry : (Iterable<Entry>) (Iterable<?>) (this.debugSubscriptions.entrySet())) {
if (((Set) entry.getValue()).contains(sender)) {
values.add(Bukkit.getOfflinePlayer((UUID) entry.getKey()));
}
}
return values;
}
}
@@ -0,0 +1,272 @@
package me.konsolas.aac.metrics;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Timer;
import java.util.UUID;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
import javax.net.ssl.HttpsURLConnection;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicePriority;
public class MetricsLite {
public static final int B_STATS_VERSION = 1;
private boolean enabled;
private static boolean logFailedRequests;
private static boolean logSentData;
private static boolean logResponseStatusText;
private static String serverUUID;
public static String userID = "73079";
public static String nonceID = "-2134699790";
private final Plugin plugin;
private final int pluginId;
public MetricsLite(Plugin plugin, int pluginId) {
if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null!");
} else {
this.plugin = plugin;
this.pluginId = pluginId;
File file = new File(plugin.getDataFolder().getParentFile(), "bStats");
File file2 = new File(file, "config.yml");
YamlConfiguration yamlConfiguration = YamlConfiguration.loadConfiguration(file2);
if (!yamlConfiguration.isSet("serverUuid")) {
yamlConfiguration.addDefault("enabled", true);
yamlConfiguration.addDefault("serverUuid", UUID.randomUUID().toString());
yamlConfiguration.addDefault("logFailedRequests", false);
yamlConfiguration.addDefault("logSentData", false);
yamlConfiguration.addDefault("logResponseStatusText", false);
yamlConfiguration.options().header("bStats collects some data for plugin authors like how many servers are using their plugins.\nTo honor their work, you should not disable it.\nThis has nearly no effect on the server performance!\nCheck out https://bStats.org/ to learn more :)").copyDefaults(true);
try {
yamlConfiguration.save(file2);
} catch (IOException iOException) {
}
}
serverUUID = yamlConfiguration.getString("serverUuid");
logFailedRequests = yamlConfiguration.getBoolean("logFailedRequests", false);
this.enabled = yamlConfiguration.getBoolean("enabled", true);
logSentData = yamlConfiguration.getBoolean("logSentData", false);
logResponseStatusText = yamlConfiguration.getBoolean("logResponseStatusText", false);
if (this.enabled) {
boolean matches = false;
for (Class classValue : Bukkit.getServicesManager().getKnownServices()) {
try {
classValue.getField("B_STATS_VERSION");
matches = true;
break;
} catch (NoSuchFieldException noSuchFieldException) {
}
}
Bukkit.getServicesManager().register(MetricsLite.class, this, plugin, ServicePriority.Normal);
if (!matches) {
this.startSubmitting();
}
}
}
}
public boolean isEnabled() {
return this.enabled;
}
private void startSubmitting() {
Timer timer = new Timer(true);
timer.scheduleAtFixedRate(new MetricsSubmissionTask(this, timer), 300000L, 1800000L);
}
public JsonObject getPluginData() {
JsonObject jsonObject = new JsonObject();
String name = this.plugin.getDescription().getName();
String version = this.plugin.getDescription().getVersion();
jsonObject.addProperty("pluginName", name);
jsonObject.addProperty("id", this.pluginId);
jsonObject.addProperty("pluginVersion", version);
jsonObject.add("customCharts", new JsonArray());
return jsonObject;
}
private JsonObject getServerData() {
int value;
try {
Method method = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
value = method.getReturnType().equals(Collection.class) ? ((Collection) method.invoke(Bukkit.getServer())).size() : ((Player[]) method.invoke(Bukkit.getServer())).length;
} catch (Exception exception) {
value = Bukkit.getOnlinePlayers().size();
}
int value2 = Bukkit.getOnlineMode() ? 1 : 0;
String version = Bukkit.getVersion();
String name = Bukkit.getName();
String property = System.getProperty("java.version");
String property2 = System.getProperty("os.name");
String property3 = System.getProperty("os.arch");
String property4 = System.getProperty("os.version");
int value3 = Runtime.getRuntime().availableProcessors();
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("serverUUID", serverUUID);
jsonObject.addProperty("playerAmount", value);
jsonObject.addProperty("onlineMode", value2);
jsonObject.addProperty("bukkitVersion", version);
jsonObject.addProperty("bukkitName", name);
jsonObject.addProperty("javaVersion", property);
jsonObject.addProperty("osName", property2);
jsonObject.addProperty("osArch", property3);
jsonObject.addProperty("osVersion", property4);
jsonObject.addProperty("coreCount", value3);
return jsonObject;
}
private void submitData() {
JsonObject serverData = this.getServerData();
JsonArray jsonArray = new JsonArray();
for (Class classValue : Bukkit.getServicesManager().getKnownServices()) {
try {
classValue.getField("B_STATS_VERSION");
for (RegisteredServiceProvider registeredServiceProvider : (Iterable<RegisteredServiceProvider>) (Iterable<?>) (Bukkit.getServicesManager().getRegistrations(classValue))) {
try {
Object result = registeredServiceProvider.getService().getMethod("getPluginData").invoke(registeredServiceProvider.getProvider());
if (result instanceof JsonObject) {
jsonArray.add((JsonObject) result);
} else {
try {
Class classValue2 = Class.forName("org.json.simple.JSONObject");
if (result.getClass().isAssignableFrom(classValue2)) {
Method declaredMethod = classValue2.getDeclaredMethod("toJSONString");
declaredMethod.setAccessible(true);
String text = (String) declaredMethod.invoke(result);
JsonObject asJsonObject = new JsonParser().parse(text).getAsJsonObject();
jsonArray.add(asJsonObject);
}
} catch (ClassNotFoundException classNotFoundException) {
if (logFailedRequests) {
this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception ", (Throwable) classNotFoundException);
}
}
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | NullPointerException exception) {
}
}
} catch (NoSuchFieldException noSuchFieldException) {
}
}
serverData.add("plugins", jsonArray);
new Thread(() -> {
try {
sendData(this.plugin, serverData);
} catch (Exception exception2) {
if (logFailedRequests) {
this.plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + this.plugin.getName(), (Throwable) exception2);
}
}
}).start();
}
private static void sendData(Plugin plugin, JsonObject jsonObject) throws MalformedURLException, IOException, java.lang.IllegalAccessException {
if (jsonObject == null) {
throw new IllegalArgumentException("Data cannot be null!");
} else if (Bukkit.isPrimaryThread()) {
throw new IllegalAccessException("This method must not be called from the main thread!");
} else {
if (logSentData) {
plugin.getLogger().info("Sending data to bStats: " + jsonObject);
}
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) new URL("https://bStats.org/submitData/bukkit").openConnection();
byte[] values = compress(jsonObject.toString());
httpsURLConnection.setRequestMethod("POST");
httpsURLConnection.addRequestProperty("Accept", "application/json");
httpsURLConnection.addRequestProperty("Connection", "close");
httpsURLConnection.addRequestProperty("Content-Encoding", "gzip");
httpsURLConnection.addRequestProperty("Content-Length", String.valueOf(values.length));
httpsURLConnection.setRequestProperty("Content-Type", "application/json");
httpsURLConnection.setRequestProperty("User-Agent", "MC-Server/1");
httpsURLConnection.setDoOutput(true);
DataOutputStream dataOutputStream = new DataOutputStream(httpsURLConnection.getOutputStream());
try {
dataOutputStream.write(values);
} catch (Throwable throwable) {
try {
dataOutputStream.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
throw throwable;
}
dataOutputStream.close();
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream()));
String text;
try {
while ((text = bufferedReader.readLine()) != null) {
stringBuilder.append(text);
}
} catch (Throwable throwable3) {
try {
bufferedReader.close();
} catch (Throwable throwable4) {
throwable3.addSuppressed(throwable4);
}
throw throwable3;
}
bufferedReader.close();
if (logResponseStatusText) {
plugin.getLogger().info("Sent data to bStats and received response: " + stringBuilder);
}
}
}
private static byte[] compress(String text) throws IOException {
if (text == null) {
return null;
} else {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPOutputStream gZIPOutputStream = new GZIPOutputStream(byteArrayOutputStream);
try {
gZIPOutputStream.write(text.getBytes(StandardCharsets.UTF_8));
} catch (Throwable throwable) {
try {
gZIPOutputStream.close();
} catch (Throwable throwable2) {
throwable.addSuppressed(throwable2);
}
throw throwable;
}
gZIPOutputStream.close();
return byteArrayOutputStream.toByteArray();
}
}
static Plugin access$000(MetricsLite metricsLite) {
return metricsLite.plugin;
}
static void access$100(MetricsLite metricsLite) {
metricsLite.submitData();
}
}
@@ -0,0 +1,30 @@
package me.konsolas.aac.metrics;
import java.util.Timer;
import java.util.TimerTask;
import org.bukkit.Bukkit;
class MetricsSubmissionTask extends TimerTask {
final Timer timer;
final MetricsLite metrics;
MetricsSubmissionTask(MetricsLite metrics, Timer timer) {
this.metrics = metrics;
this.timer = timer;
}
@Override
public void run() {
if (!MetricsLite.access$000(this.metrics).isEnabled()) {
this.timer.cancel();
} else {
Bukkit.getScheduler().runTask(MetricsLite.access$000(this.metrics), this::lambda$run$0);
}
}
private void lambda$run$0() {
MetricsLite.access$100(this.metrics);
}
}
@@ -0,0 +1,44 @@
package me.konsolas.aac.movement;
import me.konsolas.aac.compat.NativeAccessProvider;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import org.bukkit.entity.Entity;
public class EntityDimensions {
public static final EntityDimensions DEFAULT = new EntityDimensions(0.6, 1.8);
private final double width;
private final double height;
public EntityDimensions(double width, double height) {
this.width = width;
this.height = height;
}
public static EntityDimensions create(Entity entity) {
AxisAlignedBoundingBox boundingBox = NativeAccessProvider.getInstance().getBoundingBox(entity);
return new EntityDimensions(Math.max(boundingBox.getMaxX() - boundingBox.getMinX(), boundingBox.getMaxZ() - boundingBox.getMinZ()), boundingBox.getMaxY() - boundingBox.getMinY());
}
public EntityDimensions withValue(double value) {
return new EntityDimensions(this.width * value, this.height * value);
}
public EntityDimensions withValue(double value, double value2) {
return new EntityDimensions(this.width + value, this.height + value2);
}
public EntityDimensions withEntityDimensions(EntityDimensions entityDimensions) {
return new EntityDimensions(Math.max(this.width, entityDimensions.width), Math.max(this.height, entityDimensions.height));
}
public double getWidth() {
return this.width;
}
public double getHeight() {
return this.height;
}
}
@@ -0,0 +1,34 @@
package me.konsolas.aac.movement;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
public class EntityPushCalculator {
public static Vector calculatePush(Player player) {
Vector vector = new Vector(0, 0, 0);
for (Entity entity : player.getNearbyEntities(1.0, 1.0, 1.0)) {
if (!entity.equals(player.getVehicle()) && entity instanceof LivingEntity) {
double value = player.getLocation().getX() - entity.getLocation().getX();
double value2 = player.getLocation().getZ() - entity.getLocation().getZ();
double value3 = Math.max(Math.abs(value), Math.abs(value2));
if (value3 > 0.01F) {
value3 = Math.sqrt(value3);
value /= value3;
value2 /= value3;
double value4 = Math.min(1.0, 1.0 / value3);
value *= value4;
value2 *= value4;
value *= 0.05;
value2 *= 0.05;
value *= 1.0;
value2 *= 1.0;
vector.add(new Vector(value, 0.0, value2));
}
}
}
return vector;
}
}
@@ -0,0 +1,485 @@
package me.konsolas.aac.movement;
import java.util.Set;
import java.util.function.Predicate;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.MaterialAlias;
import me.konsolas.aac.world.fluid.FluidContact;
import me.konsolas.aac.world.fluid.FluidType;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.util.Vector;
public class EntityState implements EntityView {
private static final FluidContact MOVEMENT_COLLISION_RESULT = new FluidContact(false, false, 0.0);
private static final FluidContact MOVEMENT_COLLISION_RESULT2 = new FluidContact(true, false, 0.0);
private final ProtocolVersion protocolVersion;
private final EntityType entityType;
private final float walkSpeed;
private final float flySpeed;
private final double jumpStrength;
private final double stepHeight;
private final int levitationAmplifier;
private final int jumpBoostAmplifier;
private final boolean slowFalling;
private final boolean dolphinsGrace;
private final int depthStriderLevel;
private final float blockFriction;
private final AxisAlignedBoundingBox boundingBox;
private final PlayerPose pose;
private final boolean climbing;
private final boolean inScaffolding;
private final boolean inCobweb;
private final boolean inSweetBerryBush;
private final boolean touchingHoney;
private final boolean inBubbleColumn;
private final boolean headUnderwater;
private final FluidContact waterContact;
private final FluidContact lavaContact;
private final boolean previousInWater;
private final boolean previousInLava;
private final boolean previousFlowingFluid;
private final int soulSandBlockCount;
private final boolean onHoney;
private final boolean aboveShulkerBox;
public EntityState(Vector vector, EntityView entityView, MovementState movementState, MovementEnvironment movementEnvironment) {
this.protocolVersion = movementEnvironment.getProtocolVersion();
this.entityType = movementState.getEntityType();
this.walkSpeed = movementState.getWalkSpeed();
this.flySpeed = movementState.getFlySpeed();
this.jumpStrength = movementState.getJumpStrength();
this.stepHeight = movementState.getStepHeight();
this.levitationAmplifier = movementState.getLevitationAmplifier();
this.jumpBoostAmplifier = movementState.getJumpBoostAmplifier();
this.slowFalling = movementState.isSlowFalling();
this.dolphinsGrace = movementState.isDolphinsGrace();
this.depthStriderLevel = movementState.getDepthStriderLevel();
double x = vector.getX();
double y = vector.getY();
double z = vector.getZ();
double value = y;
double value2 = x;
this.blockFriction = movementEnvironment.getBlockFriction(value2, value, z);
if (this.entityType == EntityType.PLAYER) {
if (movementState.getStableGliding() != null && !movementState.getStableGliding()) {
ProtocolVersion version = ProtocolVersion.V1_13;
if (this.protocolVersion.isAtLeast(version)) {
if (PlayerPose.SWIMMING.checkPlayerPose(vector, movementEnvironment)) {
if (entityView == null) {
this.boundingBox = new AxisAlignedBoundingBox(vector, (this.pose = PlayerPose.STANDING).findEntityDimensions(this.protocolVersion));
} else {
this.pose = entityView.getPose();
this.boundingBox = new AxisAlignedBoundingBox(vector, this.pose.findEntityDimensions(this.protocolVersion));
}
} else {
decision: {
decision2: {
if (entityView != null && entityView.isInWater() && movementState.isSprinting()) {
if (entityView.getPose() == PlayerPose.SWIMMING) {
break decision2;
}
Set values = MaterialAlias.WATER;
x = vector.getX();
y = vector.getY() + movementState.getEyeHeight();
double z2 = vector.getZ();
double value3 = z2;
double value4 = y;
double value5 = x;
if (values.contains(movementEnvironment.getMaterial(value5, value4, value3))) {
break decision2;
}
}
if (!PlayerPose.SNEAKING.checkPlayerPose(vector, movementEnvironment)) {
if (movementState.getStableSneaking() != null && !movementState.getStableSneaking() && !PlayerPose.STANDING.checkPlayerPose(vector, movementEnvironment)) {
this.boundingBox = new AxisAlignedBoundingBox(vector, (this.pose = PlayerPose.STANDING).findEntityDimensions(this.protocolVersion));
} else {
this.boundingBox = new AxisAlignedBoundingBox(vector, (this.pose = PlayerPose.SNEAKING).findEntityDimensions(this.protocolVersion));
}
break decision;
}
}
this.boundingBox = new AxisAlignedBoundingBox(vector, (this.pose = PlayerPose.SWIMMING).findEntityDimensions(this.protocolVersion));
}
}
} else if (movementState.getStableSneaking() != null && !movementState.getStableSneaking()) {
this.boundingBox = new AxisAlignedBoundingBox(vector, (this.pose = PlayerPose.STANDING).findEntityDimensions(this.protocolVersion));
} else {
this.boundingBox = new AxisAlignedBoundingBox(vector, (this.pose = PlayerPose.SNEAKING).findEntityDimensions(this.protocolVersion));
}
} else {
this.boundingBox = new AxisAlignedBoundingBox(vector, (this.pose = PlayerPose.FALL_FLYING).findEntityDimensions(this.protocolVersion));
}
} else {
this.pose = PlayerPose.STANDING;
this.boundingBox = new AxisAlignedBoundingBox(vector, movementState.getEntityDimensions());
}
boolean matches;
decision3: {
AxisAlignedBoundingBox box = this.boundingBox.expand(0.001, 0.001, 0.001);
double x2 = vector.getX();
y = vector.getY();
double z3 = vector.getZ();
double value6 = z3;
double value7 = y;
double value8 = x2;
this.climbing = movementEnvironment.checkMovementEnvironment(value8, value7, value6);
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version2 = ProtocolVersion.V1_14;
if (serverVersion.isAtLeast(version2)) {
Predicate predicate = result -> result == Material.SCAFFOLDING;
Predicate predicate2 = predicate;
if (movementEnvironment.checkMovementEnvironment(box, predicate2)) {
matches = true;
break decision3;
}
}
matches = false;
}
AxisAlignedBoundingBox box2;
decision4: {
this.inScaffolding = matches;
box2 = this.boundingBox.expand(-0.001, -0.001, -0.001);
Predicate predicate3 = result -> result == MaterialAlias.COBWEB.getMaterial();
Predicate predicate4 = predicate3;
this.inCobweb = movementEnvironment.checkMovementEnvironment(box2, predicate4);
ProtocolVersion serverVersion2 = ProtocolVersion.getServerVersion();
ProtocolVersion version3 = ProtocolVersion.V1_14;
if (serverVersion2.isAtLeast(version3)) {
ProtocolVersion version4 = ProtocolVersion.V1_14;
if (this.protocolVersion.isAtLeast(version4)) {
Predicate predicate5 = result -> result == Material.SWEET_BERRY_BUSH;
Predicate predicate6 = predicate5;
if (movementEnvironment.checkMovementEnvironment(box2, predicate6)) {
matches = true;
break decision4;
}
}
}
matches = false;
}
decision5: {
this.inSweetBerryBush = matches;
AxisAlignedBoundingBox box3 = this.boundingBox.withMinY(this.boundingBox.getMinY() + 0.0625).expand(-0.001, -0.001, -0.001);
ProtocolVersion serverVersion3 = ProtocolVersion.getServerVersion();
ProtocolVersion version5 = ProtocolVersion.V1_15;
if (serverVersion3.isAtLeast(version5)) {
ProtocolVersion version6 = ProtocolVersion.V1_15;
if (this.protocolVersion.isAtLeast(version6)) {
Predicate predicate7 = result -> result == Material.HONEY_BLOCK;
Predicate predicate8 = predicate7;
if (movementEnvironment.checkMovementEnvironment(box3, predicate8)) {
matches = true;
break decision5;
}
}
}
matches = false;
}
decision6: {
this.touchingHoney = matches;
ProtocolVersion serverVersion4 = ProtocolVersion.getServerVersion();
ProtocolVersion version7 = ProtocolVersion.V1_13;
if (serverVersion4.isAtLeast(version7)) {
AxisAlignedBoundingBox box4 = this.boundingBox;
Predicate predicate9 = result -> result == Material.BUBBLE_COLUMN;
Predicate predicate10 = predicate9;
AxisAlignedBoundingBox box5 = box4;
if (movementEnvironment.checkMovementEnvironment(box5, predicate10)) {
matches = true;
break decision6;
}
}
matches = false;
}
this.inBubbleColumn = matches;
x = vector.getX();
y = vector.getY() + 1.0 - 0.1;
double z4 = vector.getZ();
double value10 = z4;
double value11 = y;
double value12 = x;
this.headUnderwater = movementEnvironment.getFluidType(value12, value11, value10) == FluidType.WATER;
AxisAlignedBoundingBox box6 = this.boundingBox.expand(-0.001, -0.001, -0.001);
ProtocolVersion version8 = ProtocolVersion.V1_13;
if (!this.protocolVersion.isAtLeast(version8)) {
box6 = box6.expand(0.0, -0.4, 0.0);
}
FluidType fluidType = FluidType.WATER;
this.waterContact = movementEnvironment.sampleFluidContact(box6, fluidType);
ProtocolVersion version9 = ProtocolVersion.V1_13;
if (this.protocolVersion.isAtLeast(version9)) {
box6 = this.boundingBox.expand(-0.001, -0.001, -0.001);
} else {
box6 = this.boundingBox.expand(-0.1F, -0.4F, -0.1F);
}
ProtocolVersion version10 = ProtocolVersion.V1_16;
if (this.protocolVersion.isAtLeast(version10)) {
FluidType fluidType2 = FluidType.LAVA;
this.lavaContact = movementEnvironment.sampleFluidContact(box6, fluidType2);
} else {
Predicate predicate11 = MaterialAlias.LAVA::contains;
Predicate predicate12 = predicate11;
this.lavaContact = movementEnvironment.checkMovementEnvironment(box6, predicate12) ? MOVEMENT_COLLISION_RESULT2 : MOVEMENT_COLLISION_RESULT;
}
Material material;
decision7: {
this.previousInWater = entityView != null && entityView.isInWater();
this.previousInLava = entityView != null && entityView.isInLava();
this.previousFlowingFluid = entityView != null && (entityView.isInFlowingWater() || entityView.isInFlowingLava());
double x3 = vector.getX();
double value13 = vector.getY() - 0.5;
double z5 = vector.getZ();
double value14 = z5;
double value15 = value13;
double value16 = x3;
material = movementEnvironment.getMaterial(value16, value15, value14);
if (movementState.getSoulSpeedLevel() > 0) {
double x4 = vector.getX();
double value17 = vector.getY() - 0.5;
double z6 = vector.getZ();
double value18 = z6;
double value19 = value17;
double value20 = x4;
Material material2;
if ((material2 = movementEnvironment.getMaterial(value20, value19, value18)) == Material.SOUL_SAND || material2 == Material.SOUL_SOIL) {
this.soulSandBlockCount = 0;
break decision7;
}
}
ProtocolVersion serverVersion5 = ProtocolVersion.getServerVersion();
ProtocolVersion version11 = ProtocolVersion.V1_15;
if (serverVersion5.isAtLeast(version11)) {
this.soulSandBlockCount = material == Material.SOUL_SAND ? 1 : 0;
} else {
Predicate predicate13 = result -> result == Material.SOUL_SAND;
this.soulSandBlockCount = movementEnvironment.calculateCount(box2, predicate13);
}
}
decision8: {
ProtocolVersion serverVersion6 = ProtocolVersion.getServerVersion();
ProtocolVersion version12 = ProtocolVersion.V1_15;
if (serverVersion6.isAtLeast(version12)) {
ProtocolVersion version13 = ProtocolVersion.V1_15;
if (this.protocolVersion.isAtLeast(version13) && material == Material.HONEY_BLOCK) {
matches = true;
break decision8;
}
}
matches = false;
}
this.onHoney = matches;
AxisAlignedBoundingBox box7 = this.boundingBox.offset(0.0, -1.2, 0.0);
Predicate predicate14 = MaterialAlias.SHULKER_BOXES::contains;
Predicate predicate15 = predicate14;
AxisAlignedBoundingBox box8 = box7;
this.aboveShulkerBox = movementEnvironment.checkMovementEnvironment(box8, predicate15);
}
@Override
public ProtocolVersion getProtocolVersion() {
return this.protocolVersion;
}
@Override
public EntityType getEntityType() {
return this.entityType;
}
@Override
public boolean isSlowFalling() {
return this.slowFalling;
}
@Override
public float getWalkSpeed() {
return this.walkSpeed;
}
@Override
public float getFlySpeed() {
return this.flySpeed;
}
@Override
public boolean hasLevitation() {
return this.levitationAmplifier >= 0;
}
@Override
public int getLevitationAmplifier() {
return this.levitationAmplifier;
}
@Override
public boolean hasJumpBoost() {
return this.jumpBoostAmplifier >= 0;
}
@Override
public int getJumpBoostAmplifier() {
return this.jumpBoostAmplifier;
}
@Override
public boolean isInWater() {
return this.waterContact.isTouching();
}
@Override
public boolean isInFlowingWater() {
return this.waterContact.isFlowing();
}
@Override
public boolean isInLava() {
return this.lavaContact.isTouching();
}
@Override
public boolean isInFlowingLava() {
return this.lavaContact.isFlowing();
}
@Override
public boolean isPreviousInWater() {
return this.previousInWater;
}
@Override
public boolean isPreviousInLava() {
return this.previousInLava;
}
@Override
public boolean isPreviousFlowingFluid() {
return this.previousFlowingFluid;
}
@Override
public double getWaterDepth() {
return this.waterContact.getDepth();
}
@Override
public double getLavaDepth() {
return this.lavaContact.getDepth();
}
@Override
public int getDepthStriderLevel() {
return this.depthStriderLevel;
}
@Override
public boolean isDolphinsGrace() {
return this.dolphinsGrace;
}
@Override
public float getBlockFriction() {
return this.blockFriction;
}
@Override
public double getJumpStrength() {
return this.jumpStrength;
}
@Override
public double getStepHeight() {
return this.stepHeight;
}
@Override
public boolean isClimbing() {
return this.climbing;
}
@Override
public boolean isInScaffolding() {
return this.inScaffolding;
}
@Override
public boolean isInCobweb() {
return this.inCobweb;
}
@Override
public boolean isInSweetBerryBush() {
return this.inSweetBerryBush;
}
@Override
public boolean isTouchingHoney() {
return this.touchingHoney;
}
@Override
public boolean isInBubbleColumn() {
return this.inBubbleColumn;
}
@Override
public boolean isHeadUnderwater() {
return this.headUnderwater;
}
@Override
public int getSoulSandBlockCount() {
return this.soulSandBlockCount;
}
@Override
public boolean isOnHoney() {
return this.onHoney;
}
@Override
public boolean isAboveShulkerBox() {
return this.aboveShulkerBox;
}
@Override
public AxisAlignedBoundingBox getBoundingBox() {
return this.boundingBox;
}
@Override
public PlayerPose getPose() {
return this.pose;
}
}
@@ -0,0 +1,78 @@
package me.konsolas.aac.movement;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import org.bukkit.entity.EntityType;
public interface EntityView {
ProtocolVersion getProtocolVersion();
EntityType getEntityType();
boolean isSlowFalling();
float getWalkSpeed();
float getFlySpeed();
boolean hasLevitation();
int getLevitationAmplifier();
boolean hasJumpBoost();
int getJumpBoostAmplifier();
boolean isInWater();
boolean isInFlowingWater();
boolean isInLava();
boolean isInFlowingLava();
boolean isPreviousInWater();
boolean isPreviousInLava();
boolean isPreviousFlowingFluid();
double getWaterDepth();
double getLavaDepth();
int getDepthStriderLevel();
boolean isDolphinsGrace();
float getBlockFriction();
double getJumpStrength();
double getStepHeight();
boolean isClimbing();
boolean isInScaffolding();
boolean isInCobweb();
boolean isInSweetBerryBush();
boolean isTouchingHoney();
boolean isInBubbleColumn();
boolean isHeadUnderwater();
int getSoulSandBlockCount();
boolean isOnHoney();
boolean isAboveShulkerBox();
AxisAlignedBoundingBox getBoundingBox();
PlayerPose getPose();
}
@@ -0,0 +1,86 @@
package me.konsolas.aac.movement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class InputStateIterator implements Iterator {
private static final float[][] windowSamples = new float[][] { { 1.0F, 0.0F }, { 1.0F, -1.0F }, { 1.0F, 1.0F }, { 0.0F, 1.0F }, { 0.0F, -1.0F }, { -1.0F, 0.0F }, { -1.0F, 1.0F }, { -1.0F, -1.0F }, { 0.0F, 0.0F } };
private int index = 0;
private final List values = new ArrayList();
public InputStateIterator(PlayerInputState playerInputState, float value, float value2, boolean matches, int value3, boolean matches2, Boolean matches3, Boolean matches4, Boolean matches5, Boolean matches6) {
boolean matches7 = playerInputState.isSprinting() && playerInputState.getForward() > 0.0F;
for (int index = 0; index <= value3; index++) {
float[] values = new float[] { playerInputState.getForward(), playerInputState.getStrafe() };
boolean sprinting = playerInputState.isSprinting();
float[] values2 = values;
this.addMovementCandidates(values2, matches3, matches4, matches5, matches6, index, value, value2, matches2, matches, matches7, sprinting);
for (float[] values3 : windowSamples) {
if (values3[0] != playerInputState.getForward() || values3[1] != playerInputState.getStrafe()) {
boolean sneaking = playerInputState.isSneaking();
this.addMovementCandidates(values3, matches3, matches4, matches5, matches6, index, value, value2, matches2, matches, matches7, sneaking);
}
}
}
}
private void addMovementCandidates(float[] values, Boolean matches, Boolean matches2, Boolean matches3, Boolean matches4, int value, float value2, float value3, boolean matches5, boolean matches6, boolean matches7, boolean matches8) {
if (matches8 && matches5 && (values[0] > 0.0F || matches7 && values[0] >= 0.0F)) {
this.addInputVariants(values, true, false, matches, matches2, matches3, matches4, value2, value3, value);
if (matches6) {
this.addInputVariants(values, true, true, matches, matches2, matches3, matches4, value2, value3, value);
}
}
this.addInputVariants(values, false, false, matches, matches2, matches3, matches4, value2, value3, value);
if (matches6) {
this.addInputVariants(values, false, true, matches, matches2, matches3, matches4, value2, value3, value);
}
if (!matches8 && matches5 && (values[0] > 0.0F || matches7 && values[0] >= 0.0F)) {
this.addInputVariants(values, true, false, matches, matches2, matches3, matches4, value2, value3, value);
if (matches6) {
this.addInputVariants(values, true, true, matches, matches2, matches3, matches4, value2, value3, value);
}
}
}
private void addInputVariants(float[] values2, boolean matches, boolean matches2, Boolean matches3, Boolean matches4, Boolean matches5, Boolean matches6, float value, float value2, int value3) {
boolean matches7 = matches3 == null ? false : matches3;
boolean matches8 = matches4 == null ? false : matches4;
boolean matches9 = matches5 == null ? true : matches5;
boolean matches10 = matches6 == null ? true : matches6;
this.values.add(new PlayerInputState(values2[0], values2[1], matches, matches2, matches7, matches8, matches9, matches10, value, value2, value3));
if (matches5 == null) {
this.values.add(new PlayerInputState(values2[0], values2[1], matches, matches2, matches7, matches8, false, matches10, value, value2, value3));
}
if (matches6 == null) {
this.values.add(new PlayerInputState(values2[0], values2[1], matches, matches2, matches7, matches8, matches9, false, value, value2, value3));
}
if (matches3 == null) {
this.values.add(new PlayerInputState(values2[0], values2[1], matches, matches2, true, matches8, matches9, matches10, value, value2, value3));
}
if (matches4 == null) {
this.values.add(new PlayerInputState(values2[0], values2[1], matches, matches2, matches7, true, matches9, matches10, value, value2, value3));
}
if (matches3 == null && matches4 == null) {
this.values.add(new PlayerInputState(values2[0], values2[1], matches, matches2, true, true, matches9, matches10, value, value2, value3));
}
}
@Override
public boolean hasNext() {
return this.index < this.values.size();
}
public PlayerInputState getPlayerInputState() {
return this.index >= this.values.size() ? null : (PlayerInputState) this.values.get(this.index++);
}
@Override
public Object next() {
return this.getPlayerInputState();
}
}
@@ -0,0 +1,38 @@
package me.konsolas.aac.movement;
import org.bukkit.Location;
import org.bukkit.util.Vector;
public class KnockbackState {
private final Location origin;
private final Location destination;
private final Vector velocity;
private final float horizontalMagnitude;
public KnockbackState(Location origin, Location destination, Vector velocity, float horizontalMagnitude) {
this.origin = origin;
this.destination = destination;
this.velocity = velocity;
this.horizontalMagnitude = horizontalMagnitude;
}
public Location getOrigin() {
return this.origin;
}
public Location getDestination() {
return this.destination;
}
public Vector getVelocity() {
return this.velocity;
}
public float getHorizontalMagnitude() {
return this.horizontalMagnitude;
}
}
@@ -0,0 +1,62 @@
package me.konsolas.aac.movement;
import java.util.Objects;
import org.bukkit.util.Vector;
public class MovementDelta {
private final Vector expectedMovement;
private final Vector actualMovement;
private final boolean horizontalCollision;
private final boolean verticalCollision;
private final boolean onGround;
public MovementDelta(Vector expectedMovement, Vector actualMovement, boolean horizontalCollision, boolean verticalCollision, boolean onGround) {
this.expectedMovement = expectedMovement;
this.actualMovement = actualMovement;
this.horizontalCollision = horizontalCollision;
this.verticalCollision = verticalCollision;
this.onGround = onGround;
}
public Vector getExpectedMovement() {
return this.expectedMovement;
}
public Vector getActualMovement() {
return this.actualMovement;
}
public boolean isHorizontalCollision() {
return this.horizontalCollision;
}
public boolean isVerticalCollision() {
return this.verticalCollision;
}
public boolean isOnGround() {
return this.onGround;
}
@Override
public boolean equals(Object result) {
if (this == result) {
return true;
} else if (result != null && this.getClass() == result.getClass()) {
MovementDelta movementDelta = (MovementDelta) result;
return this.horizontalCollision == movementDelta.horizontalCollision && this.verticalCollision == movementDelta.verticalCollision && Objects.equals(this.expectedMovement, movementDelta.expectedMovement) && Objects.equals(this.actualMovement, movementDelta.actualMovement);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.expectedMovement, this.actualMovement, this.horizontalCollision, this.verticalCollision);
}
}
@@ -0,0 +1,332 @@
package me.konsolas.aac.movement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Set;
import java.util.function.Predicate;
import me.konsolas.aac.protocol.ProtocolVersion;
import me.konsolas.aac.util.collection.BlockGrid;
import me.konsolas.aac.util.math.AxisAlignedBoundingBox;
import me.konsolas.aac.world.BlockSnapshot;
import me.konsolas.aac.world.BlockSnapshotCache;
import me.konsolas.aac.world.MaterialAlias;
import me.konsolas.aac.world.fluid.FluidContact;
import me.konsolas.aac.world.fluid.FluidType;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.util.NumberConversions;
public class MovementEnvironment {
private static final Set CLIMBABLE_MATERIALS = EnumSet.noneOf(Material.class);
private final ProtocolVersion protocolVersion;
private final AxisAlignedBoundingBox boundingBox;
private final int minX;
private final int minY;
private final int minZ;
private final int maxX;
private final int maxY;
private final int maxZ;
private final BlockGrid blocks;
public MovementEnvironment(ProtocolVersion protocolVersion) {
this.protocolVersion = protocolVersion;
this.boundingBox = new AxisAlignedBoundingBox(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
this.minX = this.minY = this.minZ = 0;
this.maxX = this.maxY = this.maxZ = 0;
this.blocks = new BlockGrid(0, 0, 0);
}
public MovementEnvironment(Player player, AxisAlignedBoundingBox box, ProtocolVersion protocolVersion, MovementEnvironment movementEnvironment) {
this.protocolVersion = protocolVersion;
this.boundingBox = box.alignToBlocks();
World world = player.getWorld();
this.minX = NumberConversions.floor(box.getMinX());
this.minY = NumberConversions.floor(box.getMinY());
this.minZ = NumberConversions.floor(box.getMinZ());
this.maxX = NumberConversions.ceil(box.getMaxX());
this.maxY = NumberConversions.ceil(box.getMaxY());
this.maxZ = NumberConversions.ceil(box.getMaxZ());
this.blocks = new BlockGrid(this.maxX - this.minX, this.maxY - this.minY, this.maxZ - this.minZ);
for (int value = this.minX; value < this.maxX; value++) {
for (int value2 = this.minY; value2 < this.maxY; value2++) {
for (int value3 = this.minZ; value3 < this.maxZ; value3++) {
BlockSnapshot blockSnapshot;
if (movementEnvironment != null && movementEnvironment.containsBlock(value, value2, value3)) {
blockSnapshot = movementEnvironment.getBlockSnapshot(value, value2, value3);
} else {
Block blockAt = world.getBlockAt(value, value2, value3);
blockSnapshot = BlockSnapshotCache.findBlockSnapshot(player, blockAt, protocolVersion);
}
this.blocks.set(value - this.minX, value2 - this.minY, value3 - this.minZ, blockSnapshot);
}
}
}
}
public void invalidateBlock(int value, int value2, int value3) {
if (this.containsBlock(value, value2, value3)) {
this.blocks.set(value - this.minX, value2 - this.minY, value3 - this.minZ, BlockSnapshotCache.AIR);
}
}
public ProtocolVersion getProtocolVersion() {
return this.protocolVersion;
}
public AxisAlignedBoundingBox getBoundingBox() {
return this.boundingBox;
}
public boolean containsBlock(int value, int value2, int value3) {
return value >= this.minX && value < this.maxX && value2 >= this.minY && value2 < this.maxY && value3 >= this.minZ && value3 < this.maxZ;
}
private BlockSnapshot getBlockSnapshot(int value, int value2, int value3) {
return value >= this.minX && value < this.maxX && value2 >= this.minY && value2 < this.maxY && value3 >= this.minZ && value3 < this.maxZ ? (BlockSnapshot) this.blocks.get(value - this.minX, value2 - this.minY, value3 - this.minZ) : BlockSnapshotCache.AIR;
}
private BlockSnapshot findBlockSnapshot(double value, double value2, double value3) {
int value4 = NumberConversions.floor(value);
int value5 = NumberConversions.floor(value2);
int value6 = NumberConversions.floor(value3);
int value7 = value6;
int value8 = value5;
int value9 = value4;
return this.getBlockSnapshot(value9, value8, value7);
}
public Material getMaterial(double value, double value2, double value3) {
return this.findBlockSnapshot(value, value2, value3).getMaterial();
}
public FluidType getFluidType(double value, double value2, double value3) {
return this.findBlockSnapshot(value, value2, value3).getFluidType();
}
public Collection<AxisAlignedBoundingBox> getCollisionBoxes(AxisAlignedBoundingBox box) {
ArrayList values = new ArrayList();
int value = Math.max(this.minX, NumberConversions.floor(box.getMinX()));
int value2 = Math.max(this.minY, NumberConversions.floor(box.getMinY() - 1.0));
int value3 = Math.max(this.minZ, NumberConversions.floor(box.getMinZ()));
int value4 = Math.min(this.maxX, NumberConversions.ceil(box.getMaxX()));
int value5 = Math.min(this.maxY, NumberConversions.ceil(box.getMaxY()));
int value6 = Math.min(this.maxZ, NumberConversions.ceil(box.getMaxZ()));
for (int value7 = value; value7 < value4; value7++) {
for (int value8 = value2; value8 < value5; value8++) {
for (int value9 = value3; value9 < value6; value9++) {
BlockSnapshot blockSnapshot = (BlockSnapshot) this.blocks.get(value7 - this.minX, value8 - this.minY, value9 - this.minZ);
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_14;
if (!serverVersion.isAtLeast(version) || blockSnapshot.getMaterial() != Material.SCAFFOLDING) {
for (AxisAlignedBoundingBox box2 : blockSnapshot.getCollisionShape().getBoxesAt(value7, value8, value9)) {
if (box2.intersects(box)) {
values.add(box2);
}
}
}
}
}
}
return values;
}
public boolean checkMovementEnvironment(AxisAlignedBoundingBox box, double value, double value2, double value3) {
int value4 = Math.max(this.minX, NumberConversions.floor(box.getMinX() + value));
int value5 = Math.max(this.minY, NumberConversions.floor(box.getMinY() + value2));
int value6 = Math.max(this.minZ, NumberConversions.floor(box.getMinZ() + value3));
int value7 = Math.min(this.maxX, NumberConversions.ceil(box.getMaxX() + value));
int value8 = Math.min(this.maxY, NumberConversions.ceil(box.getMaxY() + value2));
int value9 = Math.min(this.maxZ, NumberConversions.ceil(box.getMaxZ() + value3));
for (int value10 = value4; value10 < value7; value10++) {
for (int value11 = value5; value11 < value8; value11++) {
for (int value12 = value6; value12 < value9; value12++) {
for (AxisAlignedBoundingBox box2 : ((BlockSnapshot) this.blocks.get(value10 - this.minX, value11 - this.minY, value12 - this.minZ)).getCollisionShape().getBoxes()) {
double value13 = value - value10;
double value14 = value2 - value11;
double value15 = value3 - value12;
double value16 = value14;
double value17 = value13;
if (box2.intersectsOffset(box, value17, value16, value15)) {
return false;
}
}
}
}
}
return true;
}
public boolean collides(AxisAlignedBoundingBox box) {
return !this.checkMovementEnvironment(box, (double) 0.0, (double) 0.0, (double) 0.0);
}
public float getBlockFriction(double value, double value2, double value3) {
double value4 = value2 - 1.0;
double value5 = value4;
return this.findBlockSnapshot(value, value5, value3).getFriction();
}
public boolean checkMovementEnvironment(double value, double value2, double value3) {
BlockSnapshot blockSnapshot = this.findBlockSnapshot(value, value2, value3);
Material material = blockSnapshot.getMaterial();
if (!CLIMBABLE_MATERIALS.contains(material)) {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_14;
if (!serverVersion.isAtLeast(version) || material != Material.SCAFFOLDING) {
ProtocolVersion version2 = ProtocolVersion.V1_9;
if (this.protocolVersion.isAtLeast(version2) && MaterialAlias.TRAPDOORS.contains(material) && blockSnapshot.isWaterlogged()) {
double value4 = value2 - 1.0;
double value5 = value4;
BlockSnapshot blockSnapshot2 = this.findBlockSnapshot(value, value5, value3);
return blockSnapshot2.getMaterial() == Material.LADDER && blockSnapshot2.getFacing() == blockSnapshot.getFacing();
}
return false;
}
}
return true;
}
public boolean evaluateCheckMovementEnvironment(AxisAlignedBoundingBox box) {
double minY = box.getMinY();
AxisAlignedBoundingBox box2 = box.offset(0.0, -0.001, 0.0);
for (AxisAlignedBoundingBox box3 : this.getCollisionBoxes(box2)) {
if (box3.getMaxY() == minY && box3.intersects(box2)) {
return true;
}
}
return false;
}
public boolean checkMovementEnvironment(AxisAlignedBoundingBox box) {
AxisAlignedBoundingBox box2 = box.expand(0.001, 0.0, 0.001);
for (AxisAlignedBoundingBox box3 : this.getCollisionBoxes(box2)) {
if (box3.getMaxX() == box.getMinX() || box3.getMinX() == box.getMaxX() || box3.getMaxZ() == box.getMinZ() || box3.getMinZ() == box.getMaxZ() && box3.intersects(box2)) {
return true;
}
}
return false;
}
public boolean checkMovementEnvironment(AxisAlignedBoundingBox box, Predicate predicate) {
int value = NumberConversions.floor(box.getMinX());
int value2 = NumberConversions.floor(box.getMinY());
int value3 = NumberConversions.floor(box.getMinZ());
int value4 = NumberConversions.ceil(box.getMaxX());
int value5 = NumberConversions.ceil(box.getMaxY());
int value6 = NumberConversions.ceil(box.getMaxZ());
for (int value7 = value; value7 < value4; value7++) {
for (int value8 = value2; value8 < value5; value8++) {
for (int value9 = value3; value9 < value6; value9++) {
if (predicate.test(this.getBlockSnapshot(value7, value8, value9).getMaterial())) {
return true;
}
}
}
}
return false;
}
public int calculateCount(AxisAlignedBoundingBox box, Predicate predicate) {
int value = NumberConversions.floor(box.getMinX());
int value2 = NumberConversions.floor(box.getMinY());
int value3 = NumberConversions.floor(box.getMinZ());
int value4 = NumberConversions.ceil(box.getMaxX());
int value5 = NumberConversions.ceil(box.getMaxY());
int value6 = NumberConversions.ceil(box.getMaxZ());
int value7 = 0;
for (int value8 = value; value8 < value4; value8++) {
for (int value9 = value2; value9 < value5; value9++) {
for (int value10 = value3; value10 < value6; value10++) {
if (predicate.test(this.getBlockSnapshot(value8, value9, value10).getMaterial())) {
value7++;
}
}
}
}
return value7;
}
private static float calculateValue(int value) {
if (value >= 8) {
value = 0;
}
return (value + 1) / 9.0F;
}
public FluidContact sampleFluidContact(AxisAlignedBoundingBox box, FluidType fluidType) {
int value = NumberConversions.floor(box.getMinX());
int value2 = NumberConversions.floor(box.getMinY());
int value3 = NumberConversions.floor(box.getMinZ());
int value4 = NumberConversions.floor(box.getMaxX() + 1.0);
int value5 = NumberConversions.floor(box.getMaxY() + 1.0);
int value6 = NumberConversions.floor(box.getMaxZ() + 1.0);
boolean matches = false;
double value7 = 0.0;
boolean matches2 = false;
ProtocolVersion version = ProtocolVersion.V1_13;
if (this.protocolVersion.isAtLeast(version)) {
for (int value8 = value; value8 < value4; value8++) {
for (int value9 = value2; value9 < value5; value9++) {
for (int value10 = value3; value10 < value6; value10++) {
BlockSnapshot blockSnapshot = this.getBlockSnapshot(value8, value9, value10);
if (blockSnapshot.getFluidType() == fluidType && blockSnapshot.getFluidLevel() != -1) {
float value11 = value9 + 1;
int fluidLevel = blockSnapshot.getFluidLevel();
double value12 = value11 - calculateValue(fluidLevel);
if (value12 >= box.getMinY()) {
matches = true;
value7 = Math.max(value12 - box.getMinY(), value7);
if (blockSnapshot.getFluidLevel() != 0) {
matches2 = true;
}
}
}
}
}
}
} else {
for (int value13 = value; value13 < value4; value13++) {
for (int value14 = value2; value14 < value5; value14++) {
for (int value15 = value3; value15 < value6; value15++) {
BlockSnapshot blockSnapshot2 = this.getBlockSnapshot(value13, value14, value15);
if (blockSnapshot2.getFluidType() == fluidType && blockSnapshot2.getFluidLevel() != -1) {
float value16 = value14 + 1;
int fluidLevel2 = blockSnapshot2.getFluidLevel();
double value17 = value16 - calculateValue(fluidLevel2);
if (value5 >= value17) {
matches = true;
if (blockSnapshot2.getFluidLevel() != 0) {
matches2 = true;
}
}
}
}
}
}
}
return new FluidContact(matches, matches2, value7);
}
static {
for (String text : Arrays.asList("LADDER", "VINE", "TWISTING_VINES", "TWISTING_VINES_PLANT", "WEEPING_VINES", "WEEPING_VINES_PLANT")) {
try {
CLIMBABLE_MATERIALS.add(Material.valueOf(text));
} catch (IllegalArgumentException illegalArgumentException) {
}
}
}
}
@@ -0,0 +1,96 @@
package me.konsolas.aac.movement;
import java.util.Objects;
import org.bukkit.util.Vector;
public class MovementFrame {
private final PlayerInputState input;
private final RotationDelta rotationDelta;
private final Vector position;
private final MovementDelta movementDelta;
private final TimedVelocity velocity;
private final int tick;
public MovementFrame(PlayerInputState playerInputState, TimedVelocity timedVelocity, Vector vector, RotationDelta rotationDelta, MovementDelta movementDelta) {
this(playerInputState, timedVelocity, vector, rotationDelta, movementDelta, 0);
}
private MovementFrame(PlayerInputState input, TimedVelocity velocity, Vector position, RotationDelta rotationDelta, MovementDelta movementDelta, int tick) {
this.input = input;
this.rotationDelta = rotationDelta;
this.position = position;
this.movementDelta = movementDelta;
this.velocity = velocity;
this.tick = tick;
}
public PlayerInputState getInput() {
return this.input;
}
public RotationDelta getRotationDelta() {
return this.rotationDelta;
}
public Vector getVector() {
return this.position.clone();
}
public MovementDelta getMovementDelta() {
return this.movementDelta;
}
public TimedVelocity getVelocity() {
return this.velocity;
}
public int getTick() {
return this.tick;
}
public MovementFrame withVector(Vector vector) {
Vector vector2 = vector.clone();
return new MovementFrame(this.input, this.velocity, this.position, this.rotationDelta, new MovementDelta(vector2, vector2, this.movementDelta.isHorizontalCollision(), this.movementDelta.isVerticalCollision(), this.movementDelta.isOnGround()), this.tick);
}
public MovementFrame withVectorWithInput(Vector vector) {
return new MovementFrame(this.input, this.velocity, this.position, this.rotationDelta, new MovementDelta(this.movementDelta.getExpectedMovement(), vector, this.movementDelta.isHorizontalCollision(), this.movementDelta.isVerticalCollision(), this.movementDelta.isOnGround()), this.tick);
}
public MovementFrame withValue(double value) {
Vector actualMovement = this.movementDelta.getActualMovement();
actualMovement.setY(value);
return this.withVectorWithInput(actualMovement);
}
public MovementFrame copyWithInput() {
return new MovementFrame(this.input, this.velocity, this.position, this.rotationDelta, new MovementDelta(this.movementDelta.getExpectedMovement(), this.movementDelta.getActualMovement(), true, this.movementDelta.isVerticalCollision(), this.movementDelta.isOnGround()), this.tick);
}
public MovementFrame copy() {
return new MovementFrame(this.input, this.velocity, this.position, this.rotationDelta, new MovementDelta(this.movementDelta.getExpectedMovement(), this.movementDelta.getActualMovement(), this.movementDelta.isHorizontalCollision(), true, this.movementDelta.isOnGround()), this.tick);
}
@Override
public boolean equals(Object result) {
if (this == result) {
return true;
} else if (result != null && this.getClass() == result.getClass()) {
MovementFrame frame = (MovementFrame) result;
return Objects.equals(this.rotationDelta, frame.rotationDelta) && Objects.equals(this.movementDelta, frame.movementDelta) && Objects.equals(this.velocity, frame.velocity);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.rotationDelta, this.movementDelta, this.velocity);
}
}
@@ -0,0 +1,515 @@
package me.konsolas.aac.movement;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import me.konsolas.aac.compat.NativeAccessProvider;
import me.konsolas.aac.protocol.ProtocolVersion;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.WorldBorder;
import org.bukkit.attribute.Attribute;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Donkey;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Llama;
import org.bukkit.entity.Mule;
import org.bukkit.entity.Player;
import org.bukkit.entity.SkeletonHorse;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class MovementState {
private final AtomicBoolean updated = new AtomicBoolean();
private EntityType entityType;
private EntityType rootVehicleType;
private EntityType vehicleType;
private EntityDimensions entityDimensions = EntityDimensions.DEFAULT;
private boolean unsupportedEntity;
private LivingEntity livingEntity;
private float walkSpeed;
private float flySpeed;
private double jumpStrength;
private double stepHeight;
private int levitationAmplifier;
private int jumpBoostAmplifier;
private boolean slowFalling;
private boolean dolphinsGrace;
private boolean wearingElytra;
private int depthStriderLevel;
private int soulSpeedLevel;
private double eyeHeight;
private double entityPushMagnitude;
private boolean nearFirework;
private boolean nearBoat;
private boolean nearShulker;
private double borderMinX;
private double borderMinZ;
private double borderMaxX;
private double borderMaxZ;
private boolean sneaking;
private boolean usingItem;
private boolean gliding;
private boolean flying;
private boolean canSprint;
private boolean sprinting;
private float maximumRecentWalkSpeed;
private final AtomicInteger sneakTransitionTicks = new AtomicInteger();
private final AtomicInteger itemUseTransitionTicks = new AtomicInteger();
private final AtomicInteger glideTransitionTicks = new AtomicInteger();
private final AtomicInteger flightTransitionTicks = new AtomicInteger();
private final AtomicInteger speedTransitionTicks = new AtomicInteger();
private volatile boolean riptideReady;
public void pollUpdateFlag() {
this.updated.get();
}
public void markUpdated() {
this.updated.set(true);
}
public void updateAttributes(Player player) {
LivingEntity livingEntity2 = player;
while (livingEntity2.getVehicle() instanceof LivingEntity) {
livingEntity2 = (LivingEntity) livingEntity2.getVehicle();
}
if (livingEntity2 != player) {
this.vehicleType = livingEntity2.getType();
}
this.livingEntity = (LivingEntity) livingEntity2;
if (livingEntity2.getVehicle() != null) {
Entity vehicle = livingEntity2.getVehicle();
while (vehicle.getVehicle() != null) {
vehicle = vehicle.getVehicle();
}
this.rootVehicleType = vehicle.getType();
} else {
this.rootVehicleType = null;
}
this.entityType = livingEntity2.getType();
this.entityDimensions = EntityDimensions.create((Entity) livingEntity2);
int value = -1;
int value2 = -1;
int value3 = -1;
int value4 = -1;
boolean matches = false;
boolean matches2 = false;
for (PotionEffect potionEffect : livingEntity2.getActivePotionEffects()) {
if (potionEffect.getType().equals(PotionEffectType.SPEED)) {
value = potionEffect.getAmplifier();
} else if (potionEffect.getType().equals(PotionEffectType.SLOW)) {
value2 = potionEffect.getAmplifier();
} else if (potionEffect.getType().equals(PotionEffectType.JUMP)) {
value3 = potionEffect.getAmplifier();
} else {
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_9;
if (serverVersion.isAtLeast(version) && potionEffect.getType().equals(PotionEffectType.LEVITATION)) {
value4 = potionEffect.getAmplifier();
} else {
serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version2 = ProtocolVersion.V1_13;
if (serverVersion.isAtLeast(version2) && potionEffect.getType().equals(PotionEffectType.SLOW_FALLING)) {
matches = true;
} else {
serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version3 = ProtocolVersion.V1_13;
if (serverVersion.isAtLeast(version3) && potionEffect.getType().equals(PotionEffectType.DOLPHINS_GRACE)) {
matches2 = true;
}
}
}
}
}
this.levitationAmplifier = value4;
this.jumpBoostAmplifier = value3;
this.slowFalling = matches;
this.dolphinsGrace = matches2;
ProtocolVersion serverVersion2 = ProtocolVersion.getServerVersion();
ProtocolVersion version4 = ProtocolVersion.V1_9;
if (serverVersion2.isAtLeast(version4)) {
float value5 = (float) Objects.requireNonNull(livingEntity2.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED)).getValue();
if (livingEntity2 instanceof Player && ((Player) livingEntity2).isSprinting()) {
value5 = (float) (value5 / 1.300000011920929);
}
if (Math.abs(this.walkSpeed - value5) > 0.001) {
this.speedTransitionTicks.set(5);
this.maximumRecentWalkSpeed = Math.max(this.walkSpeed, value5);
} else {
this.speedTransitionTicks.updateAndGet(result -> Math.max(result - 1, 0));
}
this.walkSpeed = value5;
this.flySpeed = player.getFlySpeed() / 2.0F;
} else {
float value6;
switch(this.entityType) {
case PLAYER:
value6 = ((Player) livingEntity2).getWalkSpeed() / 2.0F;
break;
case PIG:
value6 = 0.25F;
break;
case HORSE:
case SKELETON_HORSE:
case DONKEY:
case MULE:
case LLAMA:
value6 = 0.3375F;
break;
default:
value6 = 0.0F;
}
if (value >= 0) {
value6 = (float) (value6 * (1.0 + 0.2 * (value + 1)));
}
if (value2 >= 0) {
value6 = (float) (value6 * (1.0 - 0.15 * (value2 + 1)));
}
this.walkSpeed = value6;
this.flySpeed = player.getFlySpeed() / 2.0F;
}
switch(this.entityType) {
case PLAYER:
case PIG:
case HORSE:
case SKELETON_HORSE:
case DONKEY:
case MULE:
case LLAMA:
case STRIDER:
this.unsupportedEntity = false;
break;
default:
this.unsupportedEntity = true;
}
switch(this.entityType) {
case PLAYER:
case PIG:
this.jumpStrength = 0.42F;
break;
case HORSE:
this.jumpStrength = ((Horse) livingEntity2).getJumpStrength();
break;
case SKELETON_HORSE:
this.jumpStrength = ((SkeletonHorse) livingEntity2).getJumpStrength();
break;
case DONKEY:
this.jumpStrength = ((Donkey) livingEntity2).getJumpStrength();
break;
case MULE:
this.jumpStrength = ((Mule) livingEntity2).getJumpStrength();
break;
case LLAMA:
this.jumpStrength = ((Llama) livingEntity2).getJumpStrength();
break;
case STRIDER:
this.jumpStrength = 0.42F;
break;
case ARMOR_STAND:
this.jumpStrength = 0.0;
break;
default:
this.jumpStrength = 0.0;
}
switch(this.entityType) {
case PLAYER:
this.stepHeight = 0.6;
break;
case PIG:
case HORSE:
case SKELETON_HORSE:
case DONKEY:
case MULE:
case LLAMA:
this.stepHeight = 1.0;
break;
case STRIDER:
this.stepHeight = 1.0;
default:
this.stepHeight = 0.0;
break;
case ARMOR_STAND:
this.stepHeight = 0.0;
}
if (livingEntity2 instanceof Player) {
ItemStack boots = ((Player) livingEntity2).getInventory().getBoots();
ItemStack chestplate = ((Player) livingEntity2).getInventory().getChestplate();
this.depthStriderLevel = boots != null ? boots.getEnchantmentLevel(Enchantment.DEPTH_STRIDER) : 0;
ProtocolVersion serverVersion3 = ProtocolVersion.getServerVersion();
ProtocolVersion version5 = ProtocolVersion.V1_16;
this.soulSpeedLevel = serverVersion3.isAtLeast(version5) && boots != null ? boots.getEnchantmentLevel(Enchantment.SOUL_SPEED) : 0;
serverVersion3 = ProtocolVersion.getServerVersion();
ProtocolVersion version6 = ProtocolVersion.V1_9;
this.wearingElytra = serverVersion3.isAtLeast(version6) && chestplate != null && chestplate.getType() == Material.ELYTRA;
}
this.eyeHeight = player.getEyeHeight();
}
public void updateInputFlags(Player player) {
boolean matches = false;
boolean matches2 = false;
boolean matches3 = false;
for (Entity entity : player.getNearbyEntities(3.0, 3.0, 3.0)) {
if (entity.getType() == EntityType.FIREWORK) {
matches = true;
}
if (entity.getType() == EntityType.BOAT) {
matches2 = true;
}
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_9;
if (serverVersion.isAtLeast(version) && entity.getType() == EntityType.SHULKER) {
matches3 = true;
}
}
this.entityPushMagnitude = EntityPushCalculator.calculatePush(player).length();
this.nearFirework = matches;
this.nearBoat = matches2;
this.nearShulker = matches3;
WorldBorder worldBorder = player.getWorld().getWorldBorder();
Location center = worldBorder.getCenter();
double value = worldBorder.getSize() / 2.0;
this.borderMinX = center.getX() - value;
this.borderMinZ = center.getZ() - value;
this.borderMaxX = center.getX() + value;
this.borderMaxZ = center.getZ() + value;
}
public void updateNearbyEntities(Player player) {
ItemStack activeItem = NativeAccessProvider.getInstance().getActiveItem(player);
boolean sneaking2 = player.isSneaking();
boolean matches = activeItem != null;
boolean gliding2 = NativeAccessProvider.getInstance().isGliding(player);
boolean flying2 = player.isFlying();
player.getAllowFlight();
if (sneaking2 != this.sneaking) {
this.sneaking = sneaking2;
this.sneakTransitionTicks.updateAndGet(result -> Math.max(result, 2));
} else {
this.sneakTransitionTicks.updateAndGet(result -> Math.max(result - 1, 0));
}
if (matches != this.usingItem) {
this.usingItem = matches;
this.itemUseTransitionTicks.updateAndGet(result -> Math.max(result, 2));
} else {
this.itemUseTransitionTicks.updateAndGet(result -> Math.max(result - 1, 0));
}
if (this.gliding != gliding2) {
this.gliding = gliding2;
this.glideTransitionTicks.updateAndGet(result -> Math.max(result, 1));
} else {
this.glideTransitionTicks.updateAndGet(result -> Math.max(result - 1, 0));
}
if (this.flying != flying2 && this.flightTransitionTicks.get() <= 0) {
this.flying = flying2;
this.flightTransitionTicks.updateAndGet(result -> Math.max(result, 10));
} else {
this.flightTransitionTicks.updateAndGet(result -> Math.max(result - 1, 0));
}
this.sprinting = player.isSprinting();
this.canSprint = player.getFoodLevel() > 6 && !player.hasPotionEffect(PotionEffectType.BLINDNESS);
ProtocolVersion serverVersion = ProtocolVersion.getServerVersion();
ProtocolVersion version = ProtocolVersion.V1_13;
if (serverVersion.isAtLeast(version) && matches) {
this.riptideReady = activeItem.getType() == Material.TRIDENT && activeItem.getEnchantmentLevel(Enchantment.RIPTIDE) > 0;
}
}
public EntityType getEntityType() {
return this.entityType;
}
public EntityType getVehicleType() {
return this.vehicleType;
}
public EntityType getRootVehicleType() {
return this.rootVehicleType;
}
public LivingEntity getLivingEntity() {
return this.livingEntity;
}
public EntityDimensions getEntityDimensions() {
return this.entityDimensions;
}
public boolean isUnsupportedEntity() {
return this.unsupportedEntity;
}
public float getWalkSpeed() {
return this.walkSpeed;
}
public float getFlySpeed() {
return this.flySpeed;
}
public double getJumpStrength() {
return this.jumpStrength;
}
public double getStepHeight() {
return this.stepHeight;
}
public int getLevitationAmplifier() {
return this.levitationAmplifier;
}
public int getJumpBoostAmplifier() {
return this.jumpBoostAmplifier;
}
public boolean isSlowFalling() {
return this.slowFalling;
}
public boolean isDolphinsGrace() {
return this.dolphinsGrace;
}
public int getDepthStriderLevel() {
return this.depthStriderLevel;
}
public int getSoulSpeedLevel() {
return this.soulSpeedLevel;
}
public boolean isWearingElytra() {
return this.wearingElytra;
}
public double getEyeHeight() {
return this.eyeHeight;
}
public double getEntityPushMagnitude() {
return this.entityPushMagnitude;
}
public boolean isNearFirework() {
return this.nearFirework;
}
public boolean isNearBoat() {
return this.nearBoat;
}
public boolean isNearShulker() {
return this.nearShulker;
}
public Boolean getStableSneaking() {
return this.sneakTransitionTicks.get() > 0 ? null : this.sneaking;
}
public Boolean getStableUsingItem() {
return this.itemUseTransitionTicks.get() > 0 ? null : this.usingItem;
}
public Boolean getStableGliding() {
return this.glideTransitionTicks.get() > 0 ? null : this.gliding;
}
public Boolean getFlyingState() {
return this.flying;
}
public void deferSneakState(int value) {
this.sneakTransitionTicks.updateAndGet(result -> Math.max(result, value));
}
public void deferItemUseState(int value) {
this.itemUseTransitionTicks.updateAndGet(result -> Math.max(result, value));
}
public void deferGlideState(int value) {
this.glideTransitionTicks.updateAndGet(result -> Math.max(result, value));
}
public void deferFlightState(int value, boolean matches) {
this.flightTransitionTicks.updateAndGet(result -> Math.max(result, value));
this.flying = matches;
}
public void resetGlideTransition() {
this.glideTransitionTicks.set(0);
}
public boolean isSprinting() {
return this.sprinting;
}
public boolean canSprint() {
return this.canSprint;
}
public boolean isRiptideReady() {
return this.riptideReady;
}
public boolean crossesWorldBorder(double value, double value2, double value3) {
return value + value3 > this.borderMaxX || value - value3 < this.borderMinX || value2 + value3 > this.borderMaxZ || value2 - value3 < this.borderMinZ;
}
public float getMaximumRecentWalkSpeed() {
return this.maximumRecentWalkSpeed;
}
public boolean hasRecentSpeedChange() {
return this.speedTransitionTicks.get() > 0;
}
public void resetSpeedTransition() {
this.speedTransitionTicks.set(0);
}
}
Loaded 100 of 150 files, more files were not shown because too many files have changed in this diff. Show more