Compare commits
157
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf115fd9c5 | ||
|
|
999f083363 | ||
|
|
96657b399f | ||
|
|
2cdca3ed72 | ||
|
|
196d4f592b | ||
|
|
588ba8def2 | ||
|
|
55cf328063 | ||
|
|
ddab7562fd | ||
|
|
804e34f20d | ||
|
|
fa65721116 | ||
|
|
0c81517639 | ||
|
|
b71c44c2e1 | ||
|
|
d7437bce97 | ||
|
|
888f209994 | ||
|
|
f6397c978b | ||
|
|
d612a522cc | ||
|
|
661010805f | ||
|
|
6848c03e47 | ||
|
|
0b168e2d60 | ||
|
|
a1d0a6a73d | ||
|
|
a88c506518 | ||
|
|
04f4bd7d21 | ||
|
|
cae28699a3 | ||
|
|
ee689d1503 | ||
|
|
695e1ad5a3 | ||
|
|
bc766b51dd | ||
|
|
fb1f3cda72 | ||
|
|
554d6d62db | ||
|
|
b9f71bce4e | ||
|
|
f4f9092bd7 | ||
|
|
ff461cf041 | ||
|
|
9b5264f0f3 | ||
|
|
5cb5ce634d | ||
|
|
0403565830 | ||
|
|
4d0a3696c9 | ||
|
|
f1440bad93 | ||
|
|
a92e1e3892 | ||
|
|
c60355536e | ||
|
|
2aeafe14cc | ||
|
|
e5d011b681 | ||
|
|
5b59392817 | ||
|
|
656e73a07d | ||
|
|
7d9836ca50 | ||
|
|
7e91c739b2 | ||
|
|
9aaf8b9491 | ||
|
|
3869a2077d | ||
|
|
525c380560 | ||
|
|
ca7326cbd7 | ||
|
|
e9f2d29fd5 | ||
|
|
dfdab62763 | ||
|
|
e339626ce1 | ||
|
|
b0df122cb9 | ||
|
|
ae284e2886 | ||
|
|
586f4bde69 | ||
|
|
c3d1b14dc1 | ||
|
|
b71c11882a | ||
|
|
990efdd6d2 | ||
|
|
3c89193fff | ||
|
|
aff9dc3c25 | ||
|
|
6b17d5fd0e | ||
|
|
319dca27ae | ||
|
|
5d20372645 | ||
|
|
74108a2088 | ||
|
|
aab710dd8b | ||
|
|
1fb1a73060 | ||
|
|
6811bc71fc | ||
|
|
6205a23edd | ||
|
|
2f844bc56e | ||
|
|
5ca4082675 | ||
|
|
078bc139f7 | ||
|
|
37d07d3b03 | ||
|
|
5bccfe831d | ||
|
|
3fbaa0a0e6 | ||
|
|
931d26569c | ||
|
|
b207fe233e | ||
|
|
0cc0910455 | ||
|
|
b5acee4911 | ||
|
|
ccada109b1 | ||
|
|
16c0d37b54 | ||
|
|
f6c16ea567 | ||
|
|
b9934f5130 | ||
|
|
3c48b6edab | ||
|
|
fdf8bc26a5 | ||
|
|
900cbed5fa | ||
|
|
233cd2a7d7 | ||
|
|
0c8b60018a | ||
|
|
a54787152d | ||
|
|
2932f0a40c | ||
|
|
94d47391af | ||
|
|
9964478ce1 | ||
|
|
d3667e1add | ||
|
|
04e1459d9e | ||
|
|
e99855bdc5 | ||
|
|
028a526c51 | ||
|
|
9650cdb4f2 | ||
|
|
5326845c7a | ||
|
|
7646df0563 | ||
|
|
23369cf1d6 | ||
|
|
864e9de3e8 | ||
|
|
68b4fa7805 | ||
|
|
c7e1fda7bb | ||
|
|
6c42bdcd4e | ||
|
|
439cbc6db3 | ||
|
|
652b66202d | ||
|
|
9f031e638a | ||
|
|
45da02e7c0 | ||
|
|
68a04d05f8 | ||
|
|
e329171b11 | ||
|
|
b8121543ee | ||
|
|
70cf56fad6 | ||
|
|
f88a114e0e | ||
|
|
ff888f8c73 | ||
|
|
66a250eb9e | ||
|
|
3c56ba9880 | ||
|
|
514a48e508 | ||
|
|
32b66cb4ff | ||
|
|
057de4d4e2 | ||
|
|
081e2d3b2b | ||
|
|
856a51e574 | ||
|
|
a4786a16c0 | ||
|
|
c904f14c7b | ||
|
|
896cf12b71 | ||
|
|
1506c97ffc | ||
|
|
9107586fc1 | ||
|
|
bc96460eb3 | ||
|
|
94705fcd09 | ||
|
|
7ae935f5e3 | ||
|
|
6d06b9b559 | ||
|
|
bae421ff27 | ||
|
|
f81743e07f | ||
|
|
b0e4693f2b | ||
|
|
e569483f63 | ||
|
|
164d16dce9 | ||
|
|
a504b8f595 | ||
|
|
0a9ea97aa6 | ||
|
|
91e281514b | ||
|
|
a03c8bbdbd | ||
|
|
22074dc228 | ||
|
|
3a40ba8b29 | ||
|
|
0d84b4e958 | ||
|
|
098399f754 | ||
|
|
334a356446 | ||
|
|
acac69e750 | ||
|
|
f8aa54855d | ||
|
|
7d928d581f | ||
|
|
31394f472f | ||
|
|
f721b1850c | ||
|
|
4419646f11 | ||
|
|
40bbd2eb2e | ||
|
|
6cfe71da9b | ||
|
|
393357d9f6 | ||
|
|
dcf0c73005 | ||
|
|
856ec6c655 | ||
|
|
54a10f77db | ||
|
|
0f50bde4db | ||
|
|
d7368ceba6 | ||
|
|
1e8fc587af |
No files matched your search
+1
-1
@@ -5,4 +5,4 @@ name = "java"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
runtime_version = "16"
|
||||
runtime_version = "17"
|
||||
@@ -0,0 +1,17 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 100
|
||||
tab_width = 4
|
||||
|
||||
# intellij specific configuration
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = false
|
||||
ij_smart_tabs = false
|
||||
ij_wrap_on_typing = false
|
||||
@@ -20,19 +20,51 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
|
||||
# Temporary tasks so built jar works because PacketEvents won't merge my fixes for their broken fabric support
|
||||
- name: Clone Axionize's PacketEvents Repository
|
||||
run: |
|
||||
git clone -b fix/fabric-events https://github.com/Axionize/packetevents.git packetevents
|
||||
cd packetevents
|
||||
echo "Cloned PacketEvents repository"
|
||||
|
||||
- name: Build and Publish PacketEvents to Maven Local
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
build-root-directory: packetevents
|
||||
arguments: publishToMavenLocal
|
||||
|
||||
- name: Extract Version from build.gradle.kts
|
||||
id: extract-version
|
||||
run: |
|
||||
# Extract the version from build.gradle.kts using grep and sed
|
||||
VERSION=$(grep "^version\s*=" build.gradle.kts | sed 's/version\s*=\s*"\(.*\)"/\1/')
|
||||
echo "VERSION: $VERSION"
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build with Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
arguments: build
|
||||
- name: Upload a Build Artifact
|
||||
|
||||
- name: Upload Bukkit Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: /home/runner/work/Grim/Grim/build/libs/**.jar
|
||||
name: grimac-bukkit
|
||||
path: ${{ github.workspace }}/bukkit/build/libs/grimac-bukkit-${{ env.VERSION }}.jar
|
||||
|
||||
- name: Upload Fabric Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: grimac-fabric
|
||||
path: ${{ github.workspace }}/fabric/build/libs/grimac-fabric-${{ env.VERSION }}.jar
|
||||
|
||||
+7
-1
@@ -65,4 +65,10 @@ nb-configuration.xml
|
||||
##############################
|
||||
## OS X
|
||||
##############################
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
|
||||
##############################
|
||||
## Fabric
|
||||
##############################
|
||||
run/
|
||||
fabric/run/
|
||||
@@ -41,8 +41,8 @@ What makes Grim stand out against other anticheats?
|
||||
### Movement Simulation Engine
|
||||
|
||||
* We have a 1:1 replication of the player's possible movements
|
||||
* This covers everything from basic walking, swimming, knockback, cobwebs, to bubble columns
|
||||
* It even covers riding entities from boats to pigs to striders
|
||||
* This covers everything from basic walking, swimming, knockback, cobwebs, to bubble columns
|
||||
* It even covers riding entities from boats to pigs to striders
|
||||
* Built upon covering edge cases to confirm accuracy
|
||||
* 1.13+ clients on 1.13+ servers, 1.12- clients on 1.13+ servers, 1.13+ clients on 1.12- servers, and 1.12- clients on 1.12- servers are all supported regardless of the large technical changes between these versions.
|
||||
* The order of collisions depends on the client version and is correct
|
||||
|
||||
+9
-197
@@ -1,206 +1,18 @@
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission
|
||||
|
||||
plugins {
|
||||
id("java")
|
||||
id("maven-publish")
|
||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
|
||||
id("com.diffplug.spotless") version "6.25.0"
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
endWithNewline()
|
||||
indentWithSpaces(4)
|
||||
removeUnusedImports()
|
||||
trimTrailingWhitespace()
|
||||
targetExclude("build/generated/**/*")
|
||||
}
|
||||
|
||||
kotlinGradle {
|
||||
endWithNewline()
|
||||
indentWithSpaces(4)
|
||||
trimTrailingWhitespace()
|
||||
}
|
||||
}
|
||||
|
||||
group = "ac.grim.grimac"
|
||||
version = "2.3.69"
|
||||
version = "2.3.71"
|
||||
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
|
||||
// Set to false for debug builds
|
||||
// You cannot live reload classes if the jar relocates dependencies
|
||||
// Checks Project properties -> environment variable -> defaults true
|
||||
val relocate: Boolean = project.findProperty("relocate")?.toString()?.toBoolean()
|
||||
extra["relocate"] = project.findProperty("relocate")?.toString()?.toBoolean()
|
||||
?: System.getenv("RELOCATE_JAR")?.toBoolean()
|
||||
?: true
|
||||
?: true
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
|
||||
maven("https://jitpack.io/") { // Grim API
|
||||
content {
|
||||
includeGroup("com.github.grimanticheat")
|
||||
}
|
||||
}
|
||||
maven("https://repo.viaversion.com") // ViaVersion
|
||||
maven("https://repo.aikar.co/content/groups/aikar/") // ACF
|
||||
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
|
||||
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
|
||||
maven("https://repo.codemc.io/repository/maven-releases/") // PacketEvents
|
||||
maven("https://repo.codemc.io/repository/maven-snapshots/")
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // placeholderapi
|
||||
mavenCentral()
|
||||
// FastUtil, Discord-Webhooks
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.7.1-SNAPSHOT")
|
||||
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
|
||||
implementation("club.minnced:discord-webhooks:0.8.0") // Newer versions include kotlin-stdlib, which leads to incompatibility with plugins that use Kotlin
|
||||
implementation("it.unimi.dsi:fastutil:8.5.15")
|
||||
implementation("github.scarsz:configuralize:1.4.0")
|
||||
|
||||
|
||||
// Used for local testing:
|
||||
//implementation("ac.grim.grimac:GrimAPI:1.0")
|
||||
implementation("com.github.grimanticheat:grimapi:ed1ec7b4a1")
|
||||
|
||||
implementation("net.kyori:adventure-text-minimessage:4.17.0")
|
||||
implementation("net.kyori:adventure-platform-bukkit:4.3.4")
|
||||
|
||||
implementation("org.jetbrains:annotations:24.1.0")
|
||||
compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT")
|
||||
compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
|
||||
compileOnly("com.viaversion:viaversion-api:5.0.4-SNAPSHOT")
|
||||
compileOnly("me.clip:placeholderapi:2.11.6")
|
||||
compileOnly("io.netty:netty-all:4.1.85.Final")
|
||||
}
|
||||
|
||||
bukkit {
|
||||
name = "GrimAC"
|
||||
author = "GrimAC"
|
||||
main = "ac.grim.grimac.GrimAC"
|
||||
website = "https://grim.ac/"
|
||||
apiVersion = "1.13"
|
||||
foliaSupported = true
|
||||
|
||||
softDepend = listOf(
|
||||
"ProtocolLib",
|
||||
"ProtocolSupport",
|
||||
"Essentials",
|
||||
"ViaVersion",
|
||||
"ViaBackwards",
|
||||
"ViaRewind",
|
||||
"Geyser-Spigot",
|
||||
"floodgate",
|
||||
"FastLogin",
|
||||
"PlaceholderAPI",
|
||||
)
|
||||
|
||||
permissions {
|
||||
register("grim.alerts") {
|
||||
description = "Receive alerts for violations"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.alerts.enable-on-join") {
|
||||
description = "Enable alerts on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.performance") {
|
||||
description = "Check performance metrics"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.profile") {
|
||||
description = "Check user profile"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.brand") {
|
||||
description = "Show client brands on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.brand.enable-on-join") {
|
||||
description = "Enable showing client brands on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.sendalert") {
|
||||
description = "Send cheater alert"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.nosetback") {
|
||||
description = "Disable setback"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.nomodifypacket") {
|
||||
description = "Disable modifying packets"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.exempt") {
|
||||
description = "Exempt from all checks"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.verbose") {
|
||||
description = "Receive verbose alerts for violations. Requires grim.alerts"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.verbose.enable-on-join") {
|
||||
description = "Enable verbose alerts on join. Requires grim.alerts and grim.alerts.enable-on-join"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
dependsOn(tasks.spotlessApply)
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
artifact(tasks["shadowJar"])
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
minimize()
|
||||
archiveFileName.set("${project.name}-${project.version}.jar")
|
||||
if (relocate) {
|
||||
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
|
||||
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
|
||||
relocate("co.aikar.commands", "ac.grim.grimac.shaded.acf")
|
||||
relocate("co.aikar.locale", "ac.grim.grimac.shaded.locale")
|
||||
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
|
||||
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
|
||||
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
|
||||
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
|
||||
relocate("alexh", "ac.grim.grimac.shaded.maps")
|
||||
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
|
||||
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
|
||||
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
|
||||
relocate("okio", "ac.grim.grimac.shaded.okio")
|
||||
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
|
||||
relocate("org.json", "ac.grim.grimac.shaded.json")
|
||||
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
|
||||
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
|
||||
}
|
||||
// Build Optimization:
|
||||
// - Add parallel build support
|
||||
// - Add build caching
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.isFork = true
|
||||
options.isIncremental = true
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
kotlin("plugin.serialization") version "1.9.0" // Use the same Kotlin version as your main project
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.spotless)
|
||||
implementation(libs.lombok)
|
||||
implementation(libs.shadow)
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
id("io.freefair.lombok")
|
||||
id("com.diffplug.spotless")
|
||||
}
|
||||
|
||||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
description = rootProject.description
|
||||
|
||||
// Java compilation settings
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
disableAutoTargetJvm()
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
options.release.set(17)
|
||||
}
|
||||
|
||||
// Lombok configuration
|
||||
//lombok {
|
||||
// version.set("1.18.30") // Use the version from your version catalog if available
|
||||
//}
|
||||
|
||||
// Spotless configuration
|
||||
spotless {
|
||||
java {
|
||||
endWithNewline()
|
||||
indentWithSpaces(4)
|
||||
removeUnusedImports()
|
||||
trimTrailingWhitespace()
|
||||
targetExclude("build/generated/**/*")
|
||||
}
|
||||
|
||||
kotlinGradle {
|
||||
endWithNewline()
|
||||
indentWithSpaces(4)
|
||||
trimTrailingWhitespace()
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure spotlessApply runs before build
|
||||
tasks.build {
|
||||
dependsOn(tasks.named("spotlessApply"))
|
||||
}
|
||||
|
||||
// Process resources (e.g., for plugin metadata files)
|
||||
//tasks.processResources {
|
||||
// inputs.property("version", project.version)
|
||||
// filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json")) {
|
||||
// expand("version" to project.version)
|
||||
// }
|
||||
//}
|
||||
|
||||
// Javadoc configuration
|
||||
tasks.javadoc {
|
||||
title = "${rootProject.name}-${project.name} v${rootProject.version}"
|
||||
options.encoding = "UTF-8"
|
||||
options.overview =
|
||||
rootProject.file("buildSrc/src/main/resources/javadoc-overview.html").toString()
|
||||
setDestinationDir(file("${project.layout.buildDirectory.asFile.get()}/docs/javadoc"))
|
||||
options {
|
||||
(this as CoreJavadocOptions).addBooleanOption("Xdoclint:none", true)
|
||||
}
|
||||
}
|
||||
|
||||
// Default tasks
|
||||
defaultTasks("build")
|
||||
@@ -0,0 +1,391 @@
|
||||
import kotlinx.serialization.json.*
|
||||
import java.util.jar.JarFile
|
||||
import java.util.zip.ZipEntry
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
val jijDependencies: Configuration by project.configurations.creating {
|
||||
isCanBeResolved = true
|
||||
isCanBeConsumed = false
|
||||
extendsFrom(project.configurations.getByName("implementation"))
|
||||
project.configurations.findByName("modImplementation")?.let { extendsFrom(it) }
|
||||
}
|
||||
|
||||
data class DependencyIdentifier(
|
||||
val group: String,
|
||||
val name: String,
|
||||
val version: String,
|
||||
val classifier: String = "" // Add classifier field, default to empty string
|
||||
) {
|
||||
override fun toString() = "$group:$name:$version${if (classifier.isNotEmpty()) ":$classifier" else ""}"
|
||||
}
|
||||
|
||||
// Does not support extracting classifiers but while the fabric standard is ambiguous on whether they can be included
|
||||
// It does not appear dependency classifiers are in use by any mod I am aware of or can find
|
||||
fun parseFabricModJson(jarFile: File, project: Project): Set<DependencyIdentifier> {
|
||||
val nestedJars = mutableSetOf<DependencyIdentifier>()
|
||||
try {
|
||||
JarFile(jarFile).use { jar ->
|
||||
val fabricModJsonEntry: ZipEntry? = jar.getEntry("fabric.mod.json")
|
||||
if (fabricModJsonEntry != null) {
|
||||
jar.getInputStream(fabricModJsonEntry).bufferedReader().use { reader ->
|
||||
val jsonContent = reader.readText()
|
||||
val jsonElement = Json.parseToJsonElement(jsonContent)
|
||||
val jsonObject = jsonElement.jsonObject
|
||||
val jarsArray = jsonObject["jars"]?.jsonArray ?: return@use
|
||||
jarsArray.forEach { jarEntry: JsonElement ->
|
||||
val filePath =
|
||||
jarEntry.jsonObject["file"]?.jsonPrimitive?.content ?: return@forEach
|
||||
project.logger.debug(
|
||||
"Found nested JAR in fabric.mod.json: {} in {}",
|
||||
filePath,
|
||||
jarFile
|
||||
)
|
||||
val jarName = filePath.substringAfterLast("/")
|
||||
val parts = jarName.removeSuffix(".jar").split("-")
|
||||
if (parts.size >= 2) {
|
||||
val inferredName = parts.dropLast(1).joinToString("-")
|
||||
val inferredVersion = parts.last()
|
||||
nestedJars.add(DependencyIdentifier("", inferredName, inferredVersion))
|
||||
project.logger.debug("Inferred nested dependency from fabric.mod.json: :$inferredName:$inferredVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
project.logger.error("Failed to parse fabric.mod.json in $jarFile: ${e.message}")
|
||||
}
|
||||
return nestedJars
|
||||
}
|
||||
|
||||
fun extractEmbeddedJars(jarFile: File, project: Project): Set<DependencyIdentifier> {
|
||||
val embeddedJars = mutableSetOf<DependencyIdentifier>()
|
||||
embeddedJars.addAll(parseFabricModJson(jarFile, project))
|
||||
try {
|
||||
JarFile(jarFile).use { jar ->
|
||||
val entries = jar.entries()
|
||||
while (entries.hasMoreElements()) {
|
||||
val entry = entries.nextElement()
|
||||
val entryName = entry.name
|
||||
if (entryName.endsWith(".jar") && (entryName.startsWith("META-INF/jarjar/") || entryName.startsWith(
|
||||
"libs/"
|
||||
) || entryName.startsWith("META-INF/jars/"))
|
||||
) {
|
||||
project.logger.debug("Found embedded JAR: {} in {}", entryName, jarFile)
|
||||
val tempFile = File.createTempFile("embedded-", ".jar")
|
||||
tempFile.deleteOnExit()
|
||||
jar.getInputStream(entry).use { input ->
|
||||
tempFile.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
JarFile(tempFile).use { embeddedJar ->
|
||||
val manifest = embeddedJar.manifest
|
||||
if (manifest != null) {
|
||||
val group =
|
||||
manifest.mainAttributes.getValue("Implementation-Vendor") ?: ""
|
||||
val name = manifest.mainAttributes.getValue("Implementation-Title")
|
||||
?: embeddedJar.name
|
||||
val version =
|
||||
manifest.mainAttributes.getValue("Implementation-Version") ?: ""
|
||||
if (group.isNotEmpty() && name.isNotEmpty() && version.isNotEmpty()) {
|
||||
embeddedJars.add(DependencyIdentifier(group, name, version))
|
||||
project.logger.debug("Identified embedded dependency: $group:$name:$version")
|
||||
} else {
|
||||
val jarName = entryName.substringAfterLast("/")
|
||||
val parts = jarName.removeSuffix(".jar").split("-")
|
||||
if (parts.size >= 2) {
|
||||
val inferredName = parts.dropLast(1).joinToString("-")
|
||||
val inferredVersion = parts.last()
|
||||
embeddedJars.add(
|
||||
DependencyIdentifier(
|
||||
"",
|
||||
inferredName,
|
||||
inferredVersion
|
||||
)
|
||||
)
|
||||
project.logger.debug("Inferred embedded dependency from filename: :$inferredName:$inferredVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
project.logger.error("Failed to analyze JAR file $jarFile for embedded JARs: ${e.message}")
|
||||
}
|
||||
return embeddedJars
|
||||
}
|
||||
|
||||
fun shouldExcludeDependency(
|
||||
dependency: ResolvedDependency,
|
||||
allEmbeddedDependencies: Set<DependencyIdentifier>,
|
||||
actuallyIncludedDependencies: Set<DependencyIdentifier>,
|
||||
project: Project
|
||||
): Boolean {
|
||||
val group = dependency.moduleGroup
|
||||
val name = dependency.moduleName
|
||||
val version = dependency.moduleVersion
|
||||
// Extract classifier from resolved dependency (if available)
|
||||
val classifier = dependency.moduleArtifacts.firstOrNull()?.classifier ?: ""
|
||||
val depId = DependencyIdentifier(group, name, version, classifier)
|
||||
|
||||
if (group.startsWith("net.minecraft") ||
|
||||
group.startsWith("net.fabricmc") ||
|
||||
name == "minecraft" ||
|
||||
name == "fabric-loader" ||
|
||||
name == "fastutil" ||
|
||||
name.startsWith("fabric_") ||
|
||||
name.startsWith("fabric-api")
|
||||
) {
|
||||
project.logger.debug("Excluding platform dependency: {}", depId)
|
||||
return true
|
||||
}
|
||||
|
||||
if (name.endsWith("-bom") || name.contains("_bom")) {
|
||||
project.logger.debug("Excluding BOM file: {}", depId)
|
||||
return true
|
||||
}
|
||||
|
||||
if (allEmbeddedDependencies.any { it.name == name && it.version == version && it.classifier == classifier }) {
|
||||
project.logger.debug("Excluding dependency already embedded in another JAR: {}", depId)
|
||||
return true
|
||||
}
|
||||
|
||||
if (actuallyIncludedDependencies.any { it.name == name && it.version == version && it.classifier == classifier }) {
|
||||
project.logger.debug("Excluding duplicate dependency: {}", depId)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun isJijTarget(
|
||||
dependency: ResolvedDependency,
|
||||
allEmbeddedDependencies: Set<DependencyIdentifier>,
|
||||
actuallyIncludedDependencies: Set<DependencyIdentifier>,
|
||||
project: Project
|
||||
): Boolean {
|
||||
val classifier = dependency.moduleArtifacts.firstOrNull()?.classifier ?: ""
|
||||
project.logger.debug(
|
||||
"Checking JIJ target: {}",
|
||||
DependencyIdentifier(
|
||||
dependency.moduleGroup,
|
||||
dependency.moduleName,
|
||||
dependency.moduleVersion,
|
||||
classifier
|
||||
)
|
||||
)
|
||||
return !shouldExcludeDependency(
|
||||
dependency,
|
||||
allEmbeddedDependencies,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
}
|
||||
|
||||
fun includeDependencyWithExclusions(
|
||||
depId: DependencyIdentifier,
|
||||
project: Project,
|
||||
actuallyIncludedDependencies: MutableSet<DependencyIdentifier>,
|
||||
allEmbeddedDependencies: Set<DependencyIdentifier>
|
||||
) {
|
||||
project.logger.debug("Including external dependency as JIJ with dynamic exclusions: {}", depId)
|
||||
project.dependencies {
|
||||
// Include dependency with classifier (if present)
|
||||
"include"("${depId.group}:${depId.name}:${depId.version}${if (depId.classifier.isNotEmpty()) ":${depId.classifier}" else ""}") {
|
||||
allEmbeddedDependencies.forEach { embeddedDep ->
|
||||
if (embeddedDep.group.isNotEmpty()) {
|
||||
exclude(group = embeddedDep.group, module = embeddedDep.name)
|
||||
} else {
|
||||
exclude(module = embeddedDep.name)
|
||||
}
|
||||
project.logger.debug("Excluding embedded transitive dependency: ${embeddedDep.name}:${embeddedDep.version}${if (embeddedDep.classifier.isNotEmpty()) ":${embeddedDep.classifier}" else ""}")
|
||||
}
|
||||
}
|
||||
}
|
||||
actuallyIncludedDependencies.add(depId)
|
||||
}
|
||||
|
||||
fun processDependencies(
|
||||
dependencies: Set<ResolvedDependency>,
|
||||
processed: MutableSet<String>,
|
||||
allEmbeddedDependencies: MutableMap<DependencyIdentifier, File>,
|
||||
actuallyIncludedDependencies: MutableSet<DependencyIdentifier>,
|
||||
project: Project
|
||||
) {
|
||||
dependencies.forEach { dep: ResolvedDependency ->
|
||||
val classifier = dep.moduleArtifacts.firstOrNull()?.classifier ?: ""
|
||||
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}${if (classifier.isNotEmpty()) ":$classifier" else ""}"
|
||||
val depId = DependencyIdentifier(dep.moduleGroup, dep.moduleName, dep.moduleVersion, classifier)
|
||||
if (!processed.contains(depKey)) {
|
||||
processed.add(depKey)
|
||||
project.logger.debug("Resolved dependency: {}", depId)
|
||||
|
||||
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
|
||||
if (jarFile != null && jarFile.exists()) {
|
||||
val embeddedJars = extractEmbeddedJars(jarFile, project)
|
||||
embeddedJars.forEach { embeddedDep ->
|
||||
allEmbeddedDependencies[embeddedDep] = jarFile
|
||||
}
|
||||
}
|
||||
|
||||
if (isJijTarget(
|
||||
dep,
|
||||
allEmbeddedDependencies.keys,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
) {
|
||||
project.logger.debug("Processing JIJ dependency: {}", depId)
|
||||
val isProjectDependency = project.rootProject.allprojects.any { subproject ->
|
||||
subproject.name == dep.moduleName && (subproject.group == dep.moduleGroup || dep.moduleGroup.isEmpty())
|
||||
}
|
||||
if (isProjectDependency) {
|
||||
val projectPath = project.rootProject.allprojects.find { subproject ->
|
||||
subproject.name == dep.moduleName && (subproject.group == dep.moduleGroup || dep.moduleGroup.isEmpty())
|
||||
}?.path
|
||||
?: throw IllegalStateException("Project dependency not found: ${dep.moduleName}")
|
||||
project.logger.debug("Including project dependency as JIJ: $projectPath")
|
||||
project.dependencies {
|
||||
"include"(project.project(projectPath))
|
||||
}
|
||||
actuallyIncludedDependencies.add(depId)
|
||||
} else {
|
||||
includeDependencyWithExclusions(
|
||||
depId,
|
||||
project,
|
||||
actuallyIncludedDependencies,
|
||||
allEmbeddedDependencies.keys
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
processDependencies(
|
||||
dep.children,
|
||||
processed,
|
||||
allEmbeddedDependencies,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
project.logger.debug("Resolving jijDependencies configuration")
|
||||
val resolvedDependencies = jijDependencies.resolvedConfiguration.firstLevelModuleDependencies
|
||||
|
||||
val processed = mutableSetOf<String>()
|
||||
val allEmbeddedDependencies = mutableMapOf<DependencyIdentifier, File>()
|
||||
val actuallyIncludedDependencies = mutableSetOf<DependencyIdentifier>()
|
||||
|
||||
fun collectAllEmbeddedDependencies(dependencies: Set<ResolvedDependency>) {
|
||||
dependencies.forEach { dep ->
|
||||
val classifier = dep.moduleArtifacts.firstOrNull()?.classifier ?: ""
|
||||
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}${if (classifier.isNotEmpty()) ":$classifier" else ""}"
|
||||
if (!processed.contains(depKey)) {
|
||||
processed.add(depKey)
|
||||
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
|
||||
if (jarFile != null && jarFile.exists()) {
|
||||
val embeddedJars = extractEmbeddedJars(jarFile, project)
|
||||
embeddedJars.forEach { embeddedDep ->
|
||||
allEmbeddedDependencies[embeddedDep] = jarFile
|
||||
project.logger.debug(
|
||||
"Collected embedded dependency: {} from {}",
|
||||
embeddedDep,
|
||||
jarFile
|
||||
)
|
||||
}
|
||||
}
|
||||
collectAllEmbeddedDependencies(dep.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processed.clear()
|
||||
collectAllEmbeddedDependencies(resolvedDependencies)
|
||||
|
||||
processed.clear()
|
||||
processDependencies(
|
||||
resolvedDependencies,
|
||||
processed,
|
||||
allEmbeddedDependencies,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
}
|
||||
|
||||
tasks.withType<Jar>().configureEach {
|
||||
doFirst {
|
||||
project.logger.debug("Resolving JIJ dependencies for JAR inclusion")
|
||||
val resolvedDependencies =
|
||||
jijDependencies.resolvedConfiguration.firstLevelModuleDependencies
|
||||
val processed = mutableSetOf<String>()
|
||||
val allEmbeddedDependencies = mutableMapOf<DependencyIdentifier, File>()
|
||||
val actuallyIncludedDependencies = mutableSetOf<DependencyIdentifier>()
|
||||
|
||||
fun collectAllEmbeddedDependencies(dependencies: Set<ResolvedDependency>) {
|
||||
dependencies.forEach { dep ->
|
||||
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}"
|
||||
if (!processed.contains(depKey)) {
|
||||
processed.add(depKey)
|
||||
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
|
||||
if (jarFile != null && jarFile.exists()) {
|
||||
val embeddedJars = extractEmbeddedJars(jarFile, project)
|
||||
embeddedJars.forEach { embeddedDep ->
|
||||
allEmbeddedDependencies[embeddedDep] = jarFile
|
||||
project.logger.debug(
|
||||
"Collected embedded dependency for JAR: {} from {}",
|
||||
embeddedDep,
|
||||
jarFile
|
||||
)
|
||||
}
|
||||
}
|
||||
collectAllEmbeddedDependencies(dep.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processed.clear()
|
||||
collectAllEmbeddedDependencies(resolvedDependencies)
|
||||
|
||||
processed.clear()
|
||||
|
||||
fun logDependencies(dependencies: Set<ResolvedDependency>) {
|
||||
dependencies.forEach { dep ->
|
||||
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}"
|
||||
val depId = DependencyIdentifier(dep.moduleGroup, dep.moduleName, dep.moduleVersion)
|
||||
if (!processed.contains(depKey)) {
|
||||
processed.add(depKey)
|
||||
project.logger.debug("Resolved JIJ dependency for JAR: {}", depId)
|
||||
|
||||
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
|
||||
if (jarFile != null && jarFile.exists()) {
|
||||
val embeddedJars = extractEmbeddedJars(jarFile, project)
|
||||
embeddedJars.forEach { embeddedDep ->
|
||||
allEmbeddedDependencies[embeddedDep] = jarFile
|
||||
}
|
||||
}
|
||||
|
||||
if (isJijTarget(
|
||||
dep,
|
||||
allEmbeddedDependencies.keys,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
) {
|
||||
project.logger.debug("Including JIJ dependency in JAR: {}", depId)
|
||||
actuallyIncludedDependencies.add(depId)
|
||||
}
|
||||
logDependencies(dep.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
logDependencies(resolvedDependencies)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
plugins {
|
||||
id("com.gradleup.shadow")
|
||||
}
|
||||
|
||||
val relocate: Boolean by rootProject.extra
|
||||
|
||||
// Create a configuration for shading dependencies from common
|
||||
val shadowCommon: Configuration by project.configurations.creating {
|
||||
isCanBeResolved = true
|
||||
isCanBeConsumed = false
|
||||
extendsFrom(project.configurations.getByName("implementation"))
|
||||
}
|
||||
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
minimize()
|
||||
archiveFileName.set("${rootProject.name}-${project.name}-${rootProject.version}.jar")
|
||||
from(shadowCommon) // Use from() instead of direct assignment
|
||||
|
||||
if (relocate) {
|
||||
relocate(
|
||||
"io.github.retrooper.packetevents",
|
||||
"ac.grim.grimac.shaded.io.github.retrooper.packetevents"
|
||||
)
|
||||
relocate(
|
||||
"com.github.retrooper.packetevents",
|
||||
"ac.grim.grimac.shaded.com.github.retrooper.packetevents"
|
||||
)
|
||||
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
|
||||
relocate("org.slf4j", "ac.grim.grimac.shaded.slf4j") // Required by discord-webhooks
|
||||
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
|
||||
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
|
||||
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
|
||||
relocate("alexh", "ac.grim.grimac.shaded.maps")
|
||||
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
|
||||
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
|
||||
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
|
||||
relocate("okio", "ac.grim.grimac.shaded.okio")
|
||||
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
|
||||
relocate("org.json", "ac.grim.grimac.shaded.json")
|
||||
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
|
||||
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
|
||||
relocate("org.incendo", "ac.grim.grimac.shaded.incendo")
|
||||
relocate("io.leangen.geantyref", "ac.grim.grimac.shaded.geantyref") // Required by cloud
|
||||
}
|
||||
mergeServiceFiles()
|
||||
}
|
||||
|
||||
tasks.named("assemble") {
|
||||
dependsOn(tasks.named("shadowJar"))
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission
|
||||
|
||||
plugins {
|
||||
`maven-publish`
|
||||
grim.`base-conventions`
|
||||
grim.`shadow-conventions`
|
||||
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven {
|
||||
name = "papermc"
|
||||
url = uri("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
|
||||
maven("https://jitpack.io/") { // Grim API
|
||||
content {
|
||||
includeGroup("com.github.grimanticheat")
|
||||
}
|
||||
}
|
||||
maven("https://repo.viaversion.com") // ViaVersion
|
||||
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
|
||||
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
|
||||
maven("https://repo.codemc.io/repository/maven-releases/") // PacketEvents
|
||||
maven("https://repo.codemc.io/repository/maven-snapshots/")
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // placeholderapi
|
||||
mavenCentral()
|
||||
// FastUtil, Discord-Webhooks
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.paper.api)
|
||||
compileOnly(libs.placeholderapi)
|
||||
|
||||
implementation(libs.packetevents.spigot)
|
||||
implementation(libs.cloud.paper)
|
||||
implementation(libs.adventure.platform.bukkit)
|
||||
|
||||
implementation(project(":common"))
|
||||
shadow(project(":common"))
|
||||
}
|
||||
|
||||
bukkit {
|
||||
name = "GrimAC"
|
||||
author = "GrimAC"
|
||||
main = "ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin"
|
||||
website = "https://grim.ac/"
|
||||
apiVersion = "1.13"
|
||||
foliaSupported = true
|
||||
|
||||
softDepend = listOf(
|
||||
"ProtocolLib",
|
||||
"ProtocolSupport",
|
||||
"Essentials",
|
||||
"ViaVersion",
|
||||
"ViaBackwards",
|
||||
"ViaRewind",
|
||||
"Geyser-Spigot",
|
||||
"floodgate",
|
||||
"FastLogin",
|
||||
"PlaceholderAPI",
|
||||
)
|
||||
|
||||
permissions {
|
||||
register("grim.alerts") {
|
||||
description = "Receive alerts for violations"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.alerts.enable-on-join") {
|
||||
description = "Enable alerts on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.performance") {
|
||||
description = "Check performance metrics"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.profile") {
|
||||
description = "Check user profile"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.brand") {
|
||||
description = "Show client brands on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.brand.enable-on-join") {
|
||||
description = "Enable showing client brands on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.sendalert") {
|
||||
description = "Send cheater alert"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.nosetback") {
|
||||
description = "Disable setback"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.nomodifypacket") {
|
||||
description = "Disable modifying packets"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.exempt") {
|
||||
description = "Exempt from all checks"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.verbose") {
|
||||
description = "Receive verbose alerts for violations. Requires grim.alerts"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.verbose.enable-on-join") {
|
||||
description =
|
||||
"Enable verbose alerts on join. Requires grim.alerts and grim.alerts.enable-on-join"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
artifact(tasks["shadowJar"])
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
manifest {
|
||||
attributes["paperweight-mappings-namespace"] = "mojang"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package ac.grim.grimac.platform.bukkit;
|
||||
|
||||
import ac.grim.grimac.platform.api.PlatformPlugin;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class BukkitPlatformPlugin implements PlatformPlugin {
|
||||
private final Plugin plugin;
|
||||
|
||||
public BukkitPlatformPlugin(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return plugin.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return plugin.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return plugin.getDescription().getVersion();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package ac.grim.grimac.platform.bukkit;
|
||||
|
||||
import ac.grim.grimac.platform.api.PlatformServer;
|
||||
import ac.grim.grimac.platform.api.sender.Sender;
|
||||
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
|
||||
public class BukkitPlatformServer implements PlatformServer {
|
||||
|
||||
@Override
|
||||
public String getPlatformImplementationString() {
|
||||
return Bukkit.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchCommand(Sender sender, String command) {
|
||||
CommandSender commandSender = GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().reverse(sender);
|
||||
Bukkit.dispatchCommand(commandSender, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sender getConsoleSender() {
|
||||
return GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().map(Bukkit.getConsoleSender());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOutgoingPluginChannel(String bungeeCord) {
|
||||
GrimACBukkitLoaderPlugin.LOADER.getServer().getMessenger().registerOutgoingPluginChannel(GrimACBukkitLoaderPlugin.LOADER, "BungeeCord");
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTPS() {
|
||||
return SpigotReflectionUtil.getTPS();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package ac.grim.grimac.platform.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.BasicGrimPlugin;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.GrimAPIProvider;
|
||||
import ac.grim.grimac.api.GrimAbstractAPI;
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import ac.grim.grimac.manager.init.start.ExemptOnlinePlayersOnReload;
|
||||
import ac.grim.grimac.manager.init.start.StartableInitable;
|
||||
import ac.grim.grimac.platform.api.Platform;
|
||||
import ac.grim.grimac.platform.api.PlatformLoader;
|
||||
import ac.grim.grimac.platform.api.PlatformServer;
|
||||
import ac.grim.grimac.platform.api.manager.ItemResetHandler;
|
||||
import ac.grim.grimac.platform.api.manager.MessagePlaceHolderManager;
|
||||
import ac.grim.grimac.platform.api.manager.ParserDescriptorFactory;
|
||||
import ac.grim.grimac.platform.api.manager.PermissionRegistrationManager;
|
||||
import ac.grim.grimac.platform.api.manager.PlatformPluginManager;
|
||||
import ac.grim.grimac.platform.api.player.PlatformPlayerFactory;
|
||||
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.platform.api.sender.Sender;
|
||||
import ac.grim.grimac.platform.api.sender.SenderFactory;
|
||||
import ac.grim.grimac.platform.bukkit.initables.BukkitBStats;
|
||||
import ac.grim.grimac.platform.bukkit.initables.BukkitEventManager;
|
||||
import ac.grim.grimac.platform.bukkit.initables.BukkitTickEndEvent;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitItemResetHandler;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitMessagePlaceHolderManager;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitParserDescriptorFactory;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitPermissionRegistrationManager;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitPlatformPluginManager;
|
||||
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayerFactory;
|
||||
import ac.grim.grimac.platform.bukkit.scheduler.bukkit.BukkitPlatformScheduler;
|
||||
import ac.grim.grimac.platform.bukkit.scheduler.folia.FoliaPlatformScheduler;
|
||||
import ac.grim.grimac.platform.bukkit.sender.BukkitSenderFactory;
|
||||
import ac.grim.grimac.platform.bukkit.utils.placeholder.PlaceholderAPIExpansion;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import ac.grim.grimac.utils.lazy.LazyHolder;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.paper.LegacyPaperCommandManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class GrimACBukkitLoaderPlugin extends JavaPlugin implements PlatformLoader {
|
||||
|
||||
public static GrimACBukkitLoaderPlugin LOADER;
|
||||
|
||||
private final LazyHolder<PlatformScheduler> scheduler = LazyHolder.simple(this::createScheduler);
|
||||
private final LazyHolder<PacketEventsAPI<?>> packetEvents = LazyHolder.simple(() -> SpigotPacketEventsBuilder.build(this));
|
||||
private final LazyHolder<BukkitSenderFactory> senderFactory = LazyHolder.simple(BukkitSenderFactory::new);
|
||||
private final LazyHolder<CommandManager<Sender>> commandManager = LazyHolder.simple(this::createCommandManager);
|
||||
private final LazyHolder<ItemResetHandler> itemResetHandler = LazyHolder.simple(BukkitItemResetHandler::new);
|
||||
|
||||
private final PlatformPlayerFactory playerFactory = new BukkitPlatformPlayerFactory();
|
||||
private final ParserDescriptorFactory parserFactory = new BukkitParserDescriptorFactory();
|
||||
private final PlatformPluginManager platformPluginManager = new BukkitPlatformPluginManager();
|
||||
private final GrimPlugin plugin;
|
||||
private final PlatformServer platformServer = new BukkitPlatformServer();
|
||||
private final MessagePlaceHolderManager messagePlaceHolderManager = new BukkitMessagePlaceHolderManager();
|
||||
private final BukkitPermissionRegistrationManager bukkitPermissionRegistrationManager = new BukkitPermissionRegistrationManager();
|
||||
|
||||
public GrimACBukkitLoaderPlugin() {
|
||||
this.plugin = new BasicGrimPlugin(
|
||||
this.getLogger(),
|
||||
this.getDataFolder(),
|
||||
this.getDescription().getVersion(),
|
||||
this.getDescription().getDescription(),
|
||||
this.getDescription().getAuthors()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
LOADER = this;
|
||||
GrimAPI.INSTANCE.load(this, this.getBukkitInitTasks());
|
||||
}
|
||||
|
||||
private Initable[] getBukkitInitTasks() {
|
||||
return new Initable[]{
|
||||
new ExemptOnlinePlayersOnReload(),
|
||||
new BukkitEventManager(),
|
||||
new BukkitTickEndEvent(),
|
||||
new BukkitBStats(),
|
||||
(StartableInitable) () -> {
|
||||
if (MessageUtil.hasPlaceholderAPI) {
|
||||
new PlaceholderAPIExpansion().register();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
GrimAPI.INSTANCE.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
GrimAPI.INSTANCE.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformScheduler getScheduler() {
|
||||
return scheduler.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformPlayerFactory getPlatformPlayerFactory() {
|
||||
return playerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParserDescriptorFactory getParserDescriptorFactory() {
|
||||
return parserFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketEventsAPI<?> getPacketEvents() {
|
||||
return packetEvents.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandManager<Sender> getCommandManager() {
|
||||
return commandManager.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemResetHandler getItemResetHandler() {
|
||||
return itemResetHandler.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SenderFactory<CommandSender> getSenderFactory() {
|
||||
return senderFactory.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GrimPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformPluginManager getPluginManager() {
|
||||
return platformPluginManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformServer getPlatformServer() {
|
||||
return platformServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAPIService() {
|
||||
GrimAPIProvider.init(GrimAPI.INSTANCE.getExternalAPI());
|
||||
Bukkit.getServicesManager().register(GrimAbstractAPI.class, GrimAPI.INSTANCE.getExternalAPI(), GrimACBukkitLoaderPlugin.LOADER, ServicePriority.Normal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull MessagePlaceHolderManager getMessagePlaceHolderManager() {
|
||||
return messagePlaceHolderManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionRegistrationManager getPermissionManager() {
|
||||
return bukkitPermissionRegistrationManager;
|
||||
}
|
||||
|
||||
private PlatformScheduler createScheduler() {
|
||||
return GrimAPI.INSTANCE.getPlatform() == Platform.FOLIA ? new FoliaPlatformScheduler() : new BukkitPlatformScheduler();
|
||||
}
|
||||
|
||||
private CommandManager<Sender> createCommandManager() {
|
||||
LegacyPaperCommandManager<Sender> manager = new LegacyPaperCommandManager<>(
|
||||
this,
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
senderFactory.get()
|
||||
);
|
||||
if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
|
||||
manager.registerBrigadier();
|
||||
} else if (manager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
|
||||
manager.registerAsynchronousCompletions();
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
public BukkitSenderFactory getBukkitSenderFactory() {
|
||||
return LOADER.senderFactory.get();
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package ac.grim.grimac.platform.bukkit.command;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.platform.api.command.PlayerSelector;
|
||||
import ac.grim.grimac.platform.api.sender.Sender;
|
||||
import ac.grim.grimac.platform.bukkit.sender.BukkitSenderFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class BukkitPlayerSelectorAdapter implements PlayerSelector {
|
||||
private final org.incendo.cloud.bukkit.data.SinglePlayerSelector bukkitSelector;
|
||||
|
||||
public BukkitPlayerSelectorAdapter(org.incendo.cloud.bukkit.data.SinglePlayerSelector bukkitSelector) {
|
||||
this.bukkitSelector = bukkitSelector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sender getSinglePlayer() {
|
||||
return ((BukkitSenderFactory) GrimAPI.INSTANCE.getSenderFactory()).map(bukkitSelector.single());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Sender> getPlayers() {
|
||||
return Collections.singletonList(((BukkitSenderFactory) GrimAPI.INSTANCE.getSenderFactory()).map(bukkitSelector.single()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inputString() {
|
||||
return bukkitSelector.inputString();
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package ac.grim.grimac.platform.bukkit.command;
|
||||
|
||||
import ac.grim.grimac.platform.api.command.AbstractPlayerSelectorParser;
|
||||
import ac.grim.grimac.platform.api.command.PlayerSelector;
|
||||
import org.incendo.cloud.bukkit.parser.selector.SinglePlayerSelectorParser;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.parser.ParserDescriptor;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BukkitPlayerSelectorParser<C> extends AbstractPlayerSelectorParser<C> {
|
||||
|
||||
@Override
|
||||
public ParserDescriptor<C, PlayerSelector> descriptor() {
|
||||
return super.createDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParserDescriptor<C, ?> getPlatformSpecificDescriptor() {
|
||||
return SinglePlayerSelectorParser.singlePlayerSelectorParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<PlayerSelector> adaptToCommonSelector(CommandContext<C> context, Object platformSpecificSelector) {
|
||||
return CompletableFuture.completedFuture(new BukkitPlayerSelectorAdapter((org.incendo.cloud.bukkit.data.SinglePlayerSelector) platformSpecificSelector));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package ac.grim.grimac.platform.bukkit.entity;
|
||||
|
||||
import ac.grim.grimac.platform.api.entity.GrimEntity;
|
||||
import ac.grim.grimac.platform.api.world.PlatformWorld;
|
||||
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
|
||||
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
|
||||
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
|
||||
import ac.grim.grimac.utils.math.Location;
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BukkitGrimEntity implements GrimEntity {
|
||||
|
||||
private final Entity entity;
|
||||
private BukkitPlatformWorld bukkitPlatformWorld;
|
||||
|
||||
public BukkitGrimEntity(Entity entity) {
|
||||
Preconditions.checkArgument(entity != null);
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public Entity getBukkitEntity() {
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return entity.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eject() {
|
||||
return entity.eject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> teleportAsync(Location location) {
|
||||
org.bukkit.Location bLoc = BukkitConversionUtils.toBukkitLocation(location);
|
||||
return PaperUtils.teleportAsync(this.entity, bLoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Entity getNative() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDead() {
|
||||
return this.entity.isDead();
|
||||
}
|
||||
|
||||
// TODO replace with PlayerWorldChangeEvent listener instead of checking for equality for better performance
|
||||
@Override
|
||||
public PlatformWorld getWorld() {
|
||||
if (bukkitPlatformWorld == null || !bukkitPlatformWorld.getBukkitWorld().equals(entity.getWorld())) {
|
||||
bukkitPlatformWorld = new BukkitPlatformWorld(entity.getWorld());
|
||||
}
|
||||
|
||||
return bukkitPlatformWorld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
org.bukkit.Location location = this.entity.getLocation();
|
||||
return new Location(
|
||||
this.getWorld(),
|
||||
location.getX(),
|
||||
location.getY(),
|
||||
location.getZ(),
|
||||
location.getYaw(),
|
||||
location.getPitch()
|
||||
);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,8 +1,8 @@
|
||||
package ac.grim.grimac.events.bukkit;
|
||||
package ac.grim.grimac.platform.bukkit.events;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.platform.bukkit.utils.blockstate.BukkitBlockFaceHelper;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.blockstate.helper.BlockFaceHelper;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.PistonData;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
@@ -57,7 +57,7 @@ public class PistonEvent implements Listener {
|
||||
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.compensatedWorld.isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
|
||||
PistonData data = new PistonData(BlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), true, hasSlimeBlock, hasHoneyBlock);
|
||||
PistonData data = new PistonData(BukkitBlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), true, hasSlimeBlock, hasHoneyBlock);
|
||||
player.latencyUtils.addRealTimeTaskAsync(player.lastTransactionSent.get(), () -> player.compensatedWorld.activePistons.add(data));
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class PistonEvent implements Listener {
|
||||
boolean hasHoneyBlock = false;
|
||||
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
BlockFace face = BlockFaceHelper.fromBukkitFace(event.getDirection());
|
||||
BlockFace face = BukkitBlockFaceHelper.fromBukkitFace(event.getDirection());
|
||||
|
||||
// The event was called without blocks and is therefore in the right direction
|
||||
if (event.getBlocks().isEmpty()) {
|
||||
@@ -110,7 +110,7 @@ public class PistonEvent implements Listener {
|
||||
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.compensatedWorld.isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
|
||||
PistonData data = new PistonData(BlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), false, hasSlimeBlock, hasHoneyBlock);
|
||||
PistonData data = new PistonData(BukkitBlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), false, hasSlimeBlock, hasHoneyBlock);
|
||||
player.latencyUtils.addRealTimeTaskAsync(player.lastTransactionSent.get(), () -> player.compensatedWorld.activePistons.add(data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package ac.grim.grimac.platform.bukkit.initables;
|
||||
|
||||
import ac.grim.grimac.manager.init.start.StartableInitable;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import io.github.retrooper.packetevents.bstats.bukkit.Metrics;
|
||||
|
||||
public class BukkitBStats implements StartableInitable {
|
||||
@Override
|
||||
public void start() {
|
||||
int pluginId = 12820; // <-- Replace with the id of your plugin!
|
||||
try {
|
||||
new Metrics(GrimACBukkitLoaderPlugin.LOADER, pluginId);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package ac.grim.grimac.platform.bukkit.initables;
|
||||
|
||||
import ac.grim.grimac.manager.init.start.StartableInitable;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.events.PistonEvent;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class BukkitEventManager implements StartableInitable {
|
||||
public void start() {
|
||||
LogUtil.info("Registering singular bukkit event... (PistonEvent)");
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new PistonEvent(), GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+42
-16
@@ -1,7 +1,10 @@
|
||||
package ac.grim.grimac.manager.init.start;
|
||||
package ac.grim.grimac.platform.bukkit.initables;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import ac.grim.grimac.manager.init.start.AbstractTickEndEvent;
|
||||
import ac.grim.grimac.platform.api.Platform;
|
||||
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
|
||||
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.lists.HookedListWrapper;
|
||||
@@ -9,6 +12,9 @@ import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.util.reflection.Reflection;
|
||||
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -17,26 +23,45 @@ import java.util.List;
|
||||
|
||||
// Copied from: https://github.com/ThomasOM/Pledge/blob/master/src/main/java/dev/thomazz/pledge/inject/ServerInjector.java
|
||||
@SuppressWarnings(value = {"unchecked", "deprecated"})
|
||||
public class TickEndEvent implements Initable {
|
||||
boolean hasTicked = true;
|
||||
|
||||
private static void tickRelMove() {
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.disableGrim) continue; // If we aren't active don't spam extra transactions
|
||||
player.checkManager.getEntityReplication().onEndOfTickEvent();
|
||||
}
|
||||
}
|
||||
public class BukkitTickEndEvent extends AbstractTickEndEvent implements Listener {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (!GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("Reach.enable-post-packet", false)) {
|
||||
if (!super.shouldInjectEndTick()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_11_2) && !Boolean.getBoolean("paper.explicit-flush")) {
|
||||
LogUtil.warn("Reach.enable-post-packet=true but paper.explicit-flush=false, add \"-Dpaper.explicit-flush=true\" to your server's startup flags for fully functional extra reach accuracy.");
|
||||
}
|
||||
// this is necessary for folia
|
||||
if (GrimAPI.INSTANCE.getPlatform() == Platform.FOLIA) {
|
||||
PaperUtils.registerTickEndEvent(this, this::tickAllFoliaPlayers);
|
||||
return;
|
||||
}
|
||||
// if it fails to inject, try to use paper's event
|
||||
if (!injectWithReflection() && !PaperUtils.registerTickEndEvent(this, this::tickAllPlayers)) {
|
||||
LogUtil.error("Failed to inject into the end of tick event!");
|
||||
}
|
||||
}
|
||||
|
||||
private void tickAllPlayers() {
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.disableGrim) continue;
|
||||
super.onEndOfTick(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickAllFoliaPlayers() {
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.disableGrim) continue;
|
||||
if (player.platformPlayer == null) continue;
|
||||
Player p = ((BukkitPlatformPlayer) player.platformPlayer).getNative();
|
||||
if (!Bukkit.isOwnedByCurrentRegion(p)) continue;
|
||||
super.onEndOfTick(player);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean injectWithReflection() {
|
||||
// Inject so we can add the final transaction pre-flush event
|
||||
try {
|
||||
Object connection = SpigotReflectionUtil.getMinecraftServerConnectionInstance();
|
||||
@@ -52,8 +77,7 @@ public class TickEndEvent implements Initable {
|
||||
List<?> wrapper = Collections.synchronizedList(new HookedListWrapper<>(endOfTickObject) {
|
||||
@Override
|
||||
public void onIterator() {
|
||||
hasTicked = true;
|
||||
tickRelMove();
|
||||
tickAllPlayers();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -62,7 +86,9 @@ public class TickEndEvent implements Initable {
|
||||
Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
unsafe.putObject(connection, unsafe.objectFieldOffset(connectionsList), wrapper);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.exception("Failed to inject into the end of tick event via reflection", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.platform.api.manager.ItemResetHandler;
|
||||
import ac.grim.grimac.platform.api.player.PlatformPlayer;
|
||||
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
|
||||
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import lombok.SneakyThrows;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitItemResetHandler implements ItemResetHandler {
|
||||
// resets item usage, then returns whether the player was using an item
|
||||
private final @NotNull ItemUsageReset resetItemUsage = createItemUsageResetFunction();
|
||||
|
||||
@SneakyThrows
|
||||
public void resetItemUsage(@Nullable PlatformPlayer player) {
|
||||
if (player != null) {
|
||||
resetItemUsage.accept(((BukkitPlatformPlayer) player).getNative());
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private @NotNull ItemUsageReset createItemUsageResetFunction() {
|
||||
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
|
||||
if (version.isNewerThan(ServerVersion.V_1_17) && PaperUtils.PAPER) {
|
||||
if (version.isOlderThan(ServerVersion.V_1_19)) {
|
||||
return LivingEntity::clearActiveItem;
|
||||
}
|
||||
Method setLivingEntityFlag = Class.forName(version.isOlderThan(ServerVersion.V_1_20_5) ? "net.minecraft.world.entity.EntityLiving" : "net.minecraft.world.entity.LivingEntity")
|
||||
.getDeclaredMethod(version.isOlderThan(ServerVersion.V_1_20_5) ? "c" : "setLivingEntityFlag", int.class, boolean.class);
|
||||
Method getHandle = (version.isOlderThan(ServerVersion.V_1_20_5)
|
||||
? Class.forName("org.bukkit.craftbukkit." + Bukkit.getServer().getClass().getPackageName().split("\\.")[3] + ".entity.CraftPlayer")
|
||||
: Class.forName("org.bukkit.craftbukkit.entity.CraftPlayer")
|
||||
).getMethod("getHandle");
|
||||
|
||||
setLivingEntityFlag.setAccessible(true);
|
||||
|
||||
return player -> {
|
||||
// don't trigger gameevents
|
||||
setLivingEntityFlag.invoke(getHandle.invoke(player), 1, false);
|
||||
player.clearActiveItem();
|
||||
};
|
||||
}
|
||||
|
||||
if (version == ServerVersion.V_1_8_8) {
|
||||
Class<?> EntityHuman = Class.forName("net.minecraft.server.v1_8_R3.EntityHuman");
|
||||
Method getHandle = Class.forName("org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer").getMethod("getHandle");
|
||||
Method clearActiveItem = EntityHuman.getMethod("bV");
|
||||
Method isUsingItem = EntityHuman.getMethod("bS");
|
||||
|
||||
return player -> {
|
||||
Object handle = getHandle.invoke(player);
|
||||
clearActiveItem.invoke(handle);
|
||||
|
||||
// in 1.8 we need to resync item usage manually,
|
||||
// only do so if the player was using an item
|
||||
if ((boolean) isUsingItem.invoke(handle)) {
|
||||
player.updateInventory();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
String nmsPackage = Bukkit.getServer().getClass().getPackageName().split("\\.")[3];
|
||||
String livingEntityPackage = version.isNewerThan(ServerVersion.V_1_16_5) ? "net.minecraft.world.entity.EntityLiving" : "net.minecraft.server." + nmsPackage + ".EntityLiving";
|
||||
|
||||
Method getHandle = Class.forName("org.bukkit.craftbukkit." + nmsPackage + ".entity.CraftPlayer").getMethod("getHandle");
|
||||
Method clearActiveItem = Class.forName(livingEntityPackage).getMethod(
|
||||
switch (nmsPackage) {
|
||||
case "v1_9_R1" -> "cz";
|
||||
case "v1_9_R2" -> "cA";
|
||||
case "v1_10_R1" -> "cE";
|
||||
case "v1_11_R1" -> "cF";
|
||||
case "v1_12_R1" -> "cN";
|
||||
case "v1_13_R1", "v1_13_R2" -> "da";
|
||||
case "v1_14_R1" -> "dp";
|
||||
case "v1_15_R1" -> "dH";
|
||||
case "v1_16_R1", "v1_16_R2", "v1_16_R3", "v1_17_R1" -> "clearActiveItem";
|
||||
case "v1_18_R1" -> "eR";
|
||||
case "v1_18_R2" -> "eS";
|
||||
default ->
|
||||
throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
|
||||
}
|
||||
);
|
||||
|
||||
return player -> clearActiveItem.invoke(getHandle.invoke(player));
|
||||
}
|
||||
|
||||
private interface ItemUsageReset {
|
||||
void accept(@NotNull Player player) throws Throwable;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.platform.api.manager.MessagePlaceHolderManager;
|
||||
import ac.grim.grimac.platform.api.player.PlatformPlayer;
|
||||
import ac.grim.grimac.platform.api.sender.Sender;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class BukkitMessagePlaceHolderManager implements MessagePlaceHolderManager {
|
||||
@Override
|
||||
public @NonNull String replacePlaceholders(@Nullable Sender sender, @NonNull String string) {
|
||||
if (!MessageUtil.hasPlaceholderAPI) return string;
|
||||
CommandSender commandSender = sender == null ? null : GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().unwrap(sender);
|
||||
return PlaceholderAPI.setPlaceholders(sender instanceof OfflinePlayer ? (OfflinePlayer) commandSender : null, string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String replacePlaceholders(@Nullable PlatformPlayer object, @NonNull String string) {
|
||||
if (!MessageUtil.hasPlaceholderAPI) return string;
|
||||
return PlaceholderAPI.setPlaceholders(((BukkitPlatformPlayer) object).getBukkitPlayer(), string);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.platform.api.command.PlayerSelector;
|
||||
import ac.grim.grimac.platform.api.manager.ParserDescriptorFactory;
|
||||
import ac.grim.grimac.platform.api.sender.Sender;
|
||||
import ac.grim.grimac.platform.bukkit.command.BukkitPlayerSelectorParser;
|
||||
import org.incendo.cloud.parser.ParserDescriptor;
|
||||
|
||||
public class BukkitParserDescriptorFactory implements ParserDescriptorFactory {
|
||||
|
||||
BukkitPlayerSelectorParser<Sender> bukkitPlayerSelectorParser = new BukkitPlayerSelectorParser<>();
|
||||
|
||||
@Override
|
||||
public ParserDescriptor<Sender, PlayerSelector> getSinglePlayer() {
|
||||
return bukkitPlayerSelectorParser.descriptor();
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.platform.api.manager.PermissionRegistrationManager;
|
||||
import ac.grim.grimac.platform.api.permissions.PermissionDefaultValue;
|
||||
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
|
||||
public class BukkitPermissionRegistrationManager implements PermissionRegistrationManager {
|
||||
/**
|
||||
* Registers a permission with the specified default value on Bukkit.
|
||||
* This method is only called for dynamic permissions (e.g., check-specific permissions
|
||||
* like "grim.exempt.checkname") that are generated at runtime. Most other static permissions
|
||||
* (e.g., "grim.exempt", "grim.alerts.enable-on-join") are registered with their defaults
|
||||
* in the `plugin.yml` file, which is defined in the Bukkit Gradle build script.
|
||||
*
|
||||
* <p>Dynamic permissions are registered here to ensure they are available for autocomplete
|
||||
* and permission checks immediately on startup. If the permission already exists, its default
|
||||
* value is updated to match the specified value.</p>
|
||||
*
|
||||
* @param s The permission node to register (e.g., "grim.exempt.checkname").
|
||||
* @param defaultValue The default value for the permission.
|
||||
*/
|
||||
@Override
|
||||
public void registerPermission(String s, PermissionDefaultValue defaultValue) {
|
||||
final Permission permission = Bukkit.getPluginManager().getPermission(s);
|
||||
if (permission == null) {
|
||||
Bukkit.getPluginManager().addPermission(new Permission(s, BukkitConversionUtils.toBukkitPermissionDefault(defaultValue)));
|
||||
} else {
|
||||
permission.setDefault(BukkitConversionUtils.toBukkitPermissionDefault(defaultValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.api.event.EventBus;
|
||||
import ac.grim.grimac.api.event.GrimEvent;
|
||||
import ac.grim.grimac.api.event.OptimizedEventBus;
|
||||
import ac.grim.grimac.platform.api.PlatformPlugin;
|
||||
import ac.grim.grimac.platform.api.manager.PlatformPluginManager;
|
||||
import ac.grim.grimac.platform.bukkit.BukkitPlatformPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class BukkitPlatformPluginManager implements PlatformPluginManager {
|
||||
|
||||
private final EventBus eventBus = new OptimizedEventBus();
|
||||
|
||||
@Override
|
||||
public void callEvent(GrimEvent event) {
|
||||
eventBus.post(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBus getEventBus() {
|
||||
return this.eventBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformPlugin[] getPlugins() {
|
||||
Plugin[] bukkitPlugins = Bukkit.getPluginManager().getPlugins();
|
||||
PlatformPlugin[] plugins = new PlatformPlugin[bukkitPlugins.length];
|
||||
|
||||
for (int i = 0; i < bukkitPlugins.length; i++) {
|
||||
plugins[i] = new BukkitPlatformPlugin(bukkitPlugins[i]);
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PlatformPlugin getPlugin(String pluginName) {
|
||||
Plugin bukkitPlugin = Bukkit.getPluginManager().getPlugin(pluginName);
|
||||
return bukkitPlugin == null ? null : new BukkitPlatformPlugin(bukkitPlugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPluginEnabled(String pluginName) {
|
||||
PlatformPlugin plugin = getPlugin(pluginName);
|
||||
return plugin != null && plugin.isEnabled();
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package ac.grim.grimac.platform.bukkit.player;
|
||||
|
||||
import ac.grim.grimac.platform.api.player.PlatformInventory;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BukkitPlatformInventory implements PlatformInventory {
|
||||
|
||||
private final Player bukkitPlayer;
|
||||
|
||||
public BukkitPlatformInventory(Player bukkitPlayer) {
|
||||
this.bukkitPlayer = bukkitPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemInHand() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItemInHand());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemInOffHand() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItemInOffHand());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStack(int bukkitSlot, int vanillaSlot) {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItem(bukkitSlot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getHelmet() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getHelmet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getChestplate() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getHelmet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getLeggings() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getLeggings());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getBoots() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getBoots());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getContents() {
|
||||
org.bukkit.inventory.ItemStack[] bukkitItems = bukkitPlayer.getInventory().getContents();
|
||||
ItemStack[] items = new ItemStack[bukkitItems.length];
|
||||
for (int i = 0; i < bukkitItems.length; i++) {
|
||||
if (bukkitItems[i] == null) continue;
|
||||
items[i] = SpigotConversionUtil.fromBukkitItemStack(bukkitItems[i]);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOpenInventoryKey() {
|
||||
return bukkitPlayer.getOpenInventory().getType().toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package ac.grim.grimac.platform.bukkit.player;
|
||||
|
||||
import ac.grim.grimac.platform.api.entity.GrimEntity;
|
||||
import ac.grim.grimac.platform.api.player.PlatformInventory;
|
||||
import ac.grim.grimac.platform.api.player.PlatformPlayer;
|
||||
import ac.grim.grimac.platform.api.sender.Sender;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.entity.BukkitGrimEntity;
|
||||
import ac.grim.grimac.platform.bukkit.utils.anticheat.MultiLibUtil;
|
||||
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
|
||||
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
|
||||
import ac.grim.grimac.utils.math.Location;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BukkitPlatformPlayer extends BukkitGrimEntity implements PlatformPlayer {
|
||||
private static final BukkitAudiences audiences = BukkitAudiences.create(GrimACBukkitLoaderPlugin.LOADER);
|
||||
|
||||
@Getter
|
||||
private final Player bukkitPlayer;
|
||||
private final PlatformInventory inventory;
|
||||
|
||||
public BukkitPlatformPlayer(Player bukkitPlayer) {
|
||||
super(bukkitPlayer);
|
||||
this.bukkitPlayer = bukkitPlayer;
|
||||
this.inventory = new BukkitPlatformInventory(bukkitPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kickPlayer(String textReason) {
|
||||
bukkitPlayer.kickPlayer(textReason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String s) {
|
||||
return bukkitPlayer.hasPermission(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String s, boolean defaultIfUnset) {
|
||||
return this.bukkitPlayer.hasPermission(new Permission(s, defaultIfUnset ? PermissionDefault.TRUE : PermissionDefault.FALSE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSneaking() {
|
||||
return bukkitPlayer.isSneaking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSneaking(boolean isSneaking) {
|
||||
bukkitPlayer.setSneaking(isSneaking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
bukkitPlayer.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component message) {
|
||||
audiences.player(bukkitPlayer).sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnline() {
|
||||
return bukkitPlayer.isOnline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return bukkitPlayer.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory() {
|
||||
bukkitPlayer.updateInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3d getPosition() {
|
||||
org.bukkit.Location location = this.bukkitPlayer.getLocation();
|
||||
return new Vector3d(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformInventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GrimEntity getVehicle() {
|
||||
return new BukkitGrimEntity(bukkitPlayer.getVehicle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameMode getGameMode() {
|
||||
return BukkitConversionUtils.fromBukkitGameMode(bukkitPlayer.getGameMode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameMode(GameMode gameMode) {
|
||||
bukkitPlayer.setGameMode(BukkitConversionUtils.toBukkitGameMode(gameMode));
|
||||
}
|
||||
|
||||
public World getBukkitWorld() {
|
||||
return bukkitPlayer.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return bukkitPlayer.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eject() {
|
||||
return bukkitPlayer.eject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> teleportAsync(Location location) {
|
||||
org.bukkit.Location bLoc = BukkitConversionUtils.toBukkitLocation(location);
|
||||
return PaperUtils.teleportAsync(this.bukkitPlayer, bLoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExternalPlayer() {
|
||||
return MultiLibUtil.isExternalPlayer(this.bukkitPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPluginMessage(String channelName, byte[] byteArray) {
|
||||
this.bukkitPlayer.sendPluginMessage(GrimACBukkitLoaderPlugin.LOADER, channelName, byteArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sender getSender() {
|
||||
return GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().map(this.bukkitPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Player getNative() {
|
||||
return this.bukkitPlayer;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package ac.grim.grimac.platform.bukkit.player;
|
||||
|
||||
import ac.grim.grimac.platform.api.player.AbstractPlatformPlayerFactory;
|
||||
import ac.grim.grimac.platform.api.player.PlatformPlayer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class BukkitPlatformPlayerFactory extends AbstractPlatformPlayerFactory<Player> {
|
||||
@Override
|
||||
protected Player getNativePlayer(@NotNull UUID uuid) {
|
||||
return Bukkit.getPlayer(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlatformPlayer createPlatformPlayer(@NotNull Player nativePlayer) {
|
||||
return new BukkitPlatformPlayer(nativePlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isNativePlayerType(@NotNull Object playerObject) {
|
||||
return playerObject instanceof Player;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getPlayerUUID(@NotNull Player nativePlayer) {
|
||||
return nativePlayer.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Player> getNativePlayerClass() {
|
||||
return Player.class;
|
||||
}
|
||||
|
||||
// The cast is safe because Bukkit.getOnlinePlayers() is guaranteed to contain Player or its subtypes,
|
||||
// and we're only reading from it.
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Collection<Player> getNativeOnlinePlayers() {
|
||||
// Cast Collection<? extends Player> to Collection<Player>
|
||||
return (Collection<Player>) Bukkit.getOnlinePlayers();
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BukkitAsyncScheduler implements AsyncScheduler {
|
||||
|
||||
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
@Override
|
||||
public TaskHandle runNow(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskAsynchronously(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, @NotNull TimeUnit timeUnit) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLaterAsynchronously(GrimACBukkitLoaderPlugin.LOADER,
|
||||
task,
|
||||
PlatformScheduler.convertTimeToTicks(delay, timeUnit))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, long period, @NotNull TimeUnit timeUnit) {
|
||||
return new BukkitTaskHandle(
|
||||
bukkitScheduler.runTaskTimerAsynchronously(
|
||||
GrimACBukkitLoaderPlugin.LOADER,
|
||||
task,
|
||||
PlatformScheduler.convertTimeToTicks(delay, timeUnit),
|
||||
PlatformScheduler.convertTimeToTicks(period, timeUnit)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(
|
||||
bukkitScheduler.runTaskTimerAsynchronously(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NotNull GrimPlugin plugin) {
|
||||
bukkitScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.platform.api.entity.GrimEntity;
|
||||
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class BukkitEntityScheduler implements EntityScheduler {
|
||||
|
||||
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable run, @Nullable Runnable retired, long delay) {
|
||||
bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, run, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long delayTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitGlobalRegionScheduler implements GlobalRegionScheduler {
|
||||
|
||||
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull Runnable run) {
|
||||
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delay));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NotNull GrimPlugin plugin) {
|
||||
bukkitScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitPlatformScheduler implements PlatformScheduler {
|
||||
|
||||
private final BukkitAsyncScheduler bukkitAsyncScheduler = new BukkitAsyncScheduler();
|
||||
private final BukkitGlobalRegionScheduler bukkitGlobalRegionScheduler = new BukkitGlobalRegionScheduler();
|
||||
private final BukkitEntityScheduler bukkitEntityScheduler = new BukkitEntityScheduler();
|
||||
private final BukkitRegionScheduler bukkitRegionScheduler = new BukkitRegionScheduler();
|
||||
|
||||
@Override
|
||||
public @NonNull @NotNull AsyncScheduler getAsyncScheduler() {
|
||||
return bukkitAsyncScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull @NotNull GlobalRegionScheduler getGlobalRegionScheduler() {
|
||||
return bukkitGlobalRegionScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull @NotNull EntityScheduler getEntityScheduler() {
|
||||
return bukkitEntityScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull @NotNull RegionScheduler getRegionScheduler() {
|
||||
return bukkitRegionScheduler;
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.api.world.PlatformWorld;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.utils.math.Location;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitRegionScheduler implements RegionScheduler {
|
||||
|
||||
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable run) {
|
||||
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable run) {
|
||||
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long delayTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long delayTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
public class BukkitTaskHandle implements TaskHandle {
|
||||
|
||||
private final BukkitTask bukkitTask;
|
||||
|
||||
public BukkitTaskHandle(BukkitTask bukkitTask) {
|
||||
this.bukkitTask = bukkitTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSync() {
|
||||
return bukkitTask.isSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCancelled() {
|
||||
return bukkitTask.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
bukkitTask.cancel();
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FoliaAsyncScheduler implements AsyncScheduler {
|
||||
|
||||
private final io.papermc.paper.threadedregions.scheduler.AsyncScheduler asyncScheduler = Bukkit.getAsyncScheduler();
|
||||
|
||||
@Override
|
||||
public TaskHandle runNow(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
|
||||
return new FoliaTaskHandle(asyncScheduler.runNow(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, @NotNull TimeUnit timeUnit) {
|
||||
return new FoliaTaskHandle(
|
||||
asyncScheduler.runDelayed(
|
||||
GrimACBukkitLoaderPlugin.LOADER,
|
||||
(ignored) -> task.run(),
|
||||
delay,
|
||||
timeUnit
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, long period, @NotNull TimeUnit timeUnit) {
|
||||
return new FoliaTaskHandle(
|
||||
asyncScheduler.runAtFixedRate(
|
||||
GrimACBukkitLoaderPlugin.LOADER,
|
||||
(ignored) -> task.run(),
|
||||
delay,
|
||||
period,
|
||||
timeUnit
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new FoliaTaskHandle(
|
||||
asyncScheduler.runAtFixedRate(
|
||||
GrimACBukkitLoaderPlugin.LOADER,
|
||||
(ignored) -> task.run(),
|
||||
initialDelayTicks * 50,
|
||||
periodTicks * 50,
|
||||
TimeUnit.MILLISECONDS
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NotNull GrimPlugin plugin) {
|
||||
asyncScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.platform.api.entity.GrimEntity;
|
||||
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.entity.BukkitGrimEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class FoliaEntityScheduler implements EntityScheduler {
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable run, @Nullable Runnable retired, long delay) {
|
||||
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().execute(GrimACBukkitLoaderPlugin.LOADER, run, () -> {
|
||||
}, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired) {
|
||||
return new FoliaTaskHandle(
|
||||
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().run(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), () -> {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long delayTicks) {
|
||||
return new FoliaTaskHandle(
|
||||
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runDelayed(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), () -> {
|
||||
}, delayTicks)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long initialDelayTicks, long periodTicks) {
|
||||
return new FoliaTaskHandle(
|
||||
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), () -> {
|
||||
}, initialDelayTicks, periodTicks)
|
||||
);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
|
||||
|
||||
private final io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler globalRegionScheduler = Bukkit.getGlobalRegionScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull Runnable run) {
|
||||
globalRegionScheduler.execute(GrimACBukkitLoaderPlugin.LOADER, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
|
||||
return new FoliaTaskHandle(globalRegionScheduler.run(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay) {
|
||||
return new FoliaTaskHandle(globalRegionScheduler.runDelayed(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), delay));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new FoliaTaskHandle(globalRegionScheduler.runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), initialDelayTicks, periodTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NotNull GrimPlugin plugin) {
|
||||
globalRegionScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public class FoliaPlatformScheduler implements PlatformScheduler {
|
||||
|
||||
private final FoliaAsyncScheduler foliaAsyncScheduler = new FoliaAsyncScheduler();
|
||||
private final FoliaGlobalRegionScheduler foliaGlobalRegionScheduler = new FoliaGlobalRegionScheduler();
|
||||
private final FoliaEntityScheduler foliaEntityScheduler = new FoliaEntityScheduler();
|
||||
private final FoliaRegionScheduler foliaRegionScheduler = new FoliaRegionScheduler();
|
||||
|
||||
@Override
|
||||
public @NonNull AsyncScheduler getAsyncScheduler() {
|
||||
return foliaAsyncScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GlobalRegionScheduler getGlobalRegionScheduler() {
|
||||
return foliaGlobalRegionScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull EntityScheduler getEntityScheduler() {
|
||||
return foliaEntityScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull RegionScheduler getRegionScheduler() {
|
||||
return foliaRegionScheduler;
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.api.world.PlatformWorld;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
|
||||
import ac.grim.grimac.utils.math.Location;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FoliaRegionScheduler implements RegionScheduler {
|
||||
|
||||
private final io.papermc.paper.threadedregions.scheduler.RegionScheduler regionScheduler = Bukkit.getRegionScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable run) {
|
||||
regionScheduler.execute(GrimACBukkitLoaderPlugin.LOADER, ((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable run) {
|
||||
execute(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, run);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task) {
|
||||
return new FoliaTaskHandle(regionScheduler.run(GrimACBukkitLoaderPlugin.LOADER, ((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task) {
|
||||
return run(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long delayTicks) {
|
||||
return new FoliaTaskHandle(regionScheduler.runDelayed(GrimACBukkitLoaderPlugin.LOADER,
|
||||
((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run(), delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long delayTicks) {
|
||||
return runDelayed(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new FoliaTaskHandle(regionScheduler.runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER,
|
||||
((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run(), initialDelayTicks, periodTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return runAtFixedRate(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, initialDelayTicks, periodTicks);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
|
||||
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
|
||||
|
||||
public class FoliaTaskHandle implements TaskHandle {
|
||||
|
||||
private final ScheduledTask task;
|
||||
|
||||
public FoliaTaskHandle(ScheduledTask task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSync() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCancelled() {
|
||||
return task.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package ac.grim.grimac.platform.bukkit.sender;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.platform.api.sender.Sender;
|
||||
import ac.grim.grimac.platform.api.sender.SenderFactory;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.command.RemoteConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitSenderFactory extends SenderFactory<CommandSender> implements SenderMapper<CommandSender, Sender> {
|
||||
private final BukkitAudiences audiences;
|
||||
|
||||
public BukkitSenderFactory() {
|
||||
this.audiences = BukkitAudiences.create(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(CommandSender sender) {
|
||||
return sender instanceof Player ? sender.getName() : Sender.CONSOLE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getUniqueId(CommandSender sender) {
|
||||
return sender instanceof Player ? ((Player) sender).getUniqueId() : Sender.CONSOLE_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, String message) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
// we can safely send async for players and the console - otherwise, send it sync
|
||||
if (sender instanceof Player || sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
|
||||
this.audiences.sender(sender).sendMessage(message);
|
||||
} else {
|
||||
GrimAPI.INSTANCE.getScheduler().getGlobalRegionScheduler().run(
|
||||
GrimAPI.INSTANCE.getGrimPlugin(),
|
||||
() -> this.audiences.sender(sender).sendMessage(message)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSender sender, String node) {
|
||||
return sender.hasPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSender sender, String node, boolean defaultIfUnset) {
|
||||
return sender.hasPermission(new Permission(node, defaultIfUnset ? PermissionDefault.TRUE : PermissionDefault.FALSE));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommand(CommandSender sender, String command) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConsole(CommandSender sender) {
|
||||
return sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPlayer(CommandSender sender) {
|
||||
return sender instanceof Player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Sender map(@NonNull CommandSender base) {
|
||||
return this.wrap(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CommandSender reverse(@NonNull Sender mapped) {
|
||||
return this.unwrap(mapped);
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -1,4 +1,4 @@
|
||||
package ac.grim.grimac.utils.anticheat;
|
||||
package ac.grim.grimac.platform.bukkit.utils.anticheat;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
@@ -9,6 +9,8 @@ import java.lang.reflect.Method;
|
||||
public class MultiLibUtil {
|
||||
|
||||
public final static Method externalPlayerMethod = getMethod(Player.class, "isExternalPlayer");
|
||||
private static final boolean
|
||||
IS_PRE_1_18 = PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_18);
|
||||
|
||||
public static Method getMethod(Class<?> clazz, String methodName) {
|
||||
try {
|
||||
@@ -20,7 +22,7 @@ public class MultiLibUtil {
|
||||
|
||||
// TODO: cache external players for better performance, but this only matters for people using multi-lib
|
||||
public static boolean isExternalPlayer(Player player) {
|
||||
if (externalPlayerMethod == null || (PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_18))) return false;
|
||||
if (externalPlayerMethod == null || IS_PRE_1_18) return false;
|
||||
try {
|
||||
return (boolean) externalPlayerMethod.invoke(player);
|
||||
} catch (Exception e) {
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package ac.grim.grimac.platform.bukkit.utils.blockstate;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
|
||||
public class BukkitBlockFaceHelper {
|
||||
/**
|
||||
* For use with bukkit events only
|
||||
* Grim is not meant to be restrained by bukkit!
|
||||
*/
|
||||
@Deprecated
|
||||
public static BlockFace fromBukkitFace(org.bukkit.block.BlockFace face) {
|
||||
return switch (face) {
|
||||
case NORTH -> BlockFace.NORTH;
|
||||
case SOUTH -> BlockFace.SOUTH;
|
||||
case WEST -> BlockFace.WEST;
|
||||
case EAST -> BlockFace.EAST;
|
||||
case UP -> BlockFace.UP;
|
||||
case DOWN -> BlockFace.DOWN;
|
||||
default -> BlockFace.OTHER;
|
||||
};
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package ac.grim.grimac.platform.bukkit.utils.convert;
|
||||
|
||||
import ac.grim.grimac.platform.api.permissions.PermissionDefaultValue;
|
||||
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
|
||||
import ac.grim.grimac.utils.math.Location;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
|
||||
public class BukkitConversionUtils {
|
||||
public static org.bukkit.Location toBukkitLocation(Location location) {
|
||||
return new org.bukkit.Location(((BukkitPlatformWorld) location.getWorld()).getBukkitWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
}
|
||||
|
||||
public static GameMode fromBukkitGameMode(org.bukkit.GameMode gameMode) {
|
||||
switch (gameMode) {
|
||||
case CREATIVE:
|
||||
return GameMode.CREATIVE;
|
||||
case SURVIVAL:
|
||||
return GameMode.SURVIVAL;
|
||||
case ADVENTURE:
|
||||
return GameMode.ADVENTURE;
|
||||
case SPECTATOR:
|
||||
return GameMode.SPECTATOR;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public static org.bukkit.GameMode toBukkitGameMode(GameMode gameMode) {
|
||||
switch (gameMode) {
|
||||
case CREATIVE:
|
||||
return org.bukkit.GameMode.CREATIVE;
|
||||
case SURVIVAL:
|
||||
return org.bukkit.GameMode.SURVIVAL;
|
||||
case ADVENTURE:
|
||||
return org.bukkit.GameMode.ADVENTURE;
|
||||
case SPECTATOR:
|
||||
return org.bukkit.GameMode.SPECTATOR;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this enum to a Bukkit PermissionDefault.
|
||||
*
|
||||
* @return The corresponding Bukkit PermissionDefault.
|
||||
*/
|
||||
public static org.bukkit.permissions.PermissionDefault toBukkitPermissionDefault(PermissionDefaultValue permissionDefaultValue) {
|
||||
switch (permissionDefaultValue) {
|
||||
case TRUE:
|
||||
return org.bukkit.permissions.PermissionDefault.TRUE;
|
||||
case FALSE:
|
||||
return org.bukkit.permissions.PermissionDefault.FALSE;
|
||||
case OP:
|
||||
return org.bukkit.permissions.PermissionDefault.OP;
|
||||
case NOT_OP:
|
||||
return org.bukkit.permissions.PermissionDefault.NOT_OP;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-3
@@ -1,4 +1,4 @@
|
||||
package ac.grim.grimac.manager.init.start;
|
||||
package ac.grim.grimac.platform.bukkit.utils.placeholder;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
@@ -14,13 +14,14 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class PlaceholderAPIExpansion extends PlaceholderExpansion {
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return "grim";
|
||||
}
|
||||
|
||||
public @NotNull String getAuthor() {
|
||||
return String.join(", ", GrimAPI.INSTANCE.getPlugin().getDescription().getAuthors());
|
||||
return String.join(", ", GrimAPI.INSTANCE.getGrimPlugin().getDescription().getAuthors());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -28,6 +29,11 @@ public class PlaceholderAPIExpansion extends PlaceholderExpansion {
|
||||
return GrimAPI.INSTANCE.getExternalAPI().getGrimVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persist() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<String> getPlaceholders() {
|
||||
Set<String> placeholders = GrimAPI.INSTANCE.getExternalAPI().getStaticReplacements().keySet();
|
||||
@@ -47,7 +53,7 @@ public class PlaceholderAPIExpansion extends PlaceholderExpansion {
|
||||
}
|
||||
|
||||
if (offlinePlayer instanceof Player player) {
|
||||
GrimPlayer grimPlayer = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(player);
|
||||
GrimPlayer grimPlayer = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(player.getUniqueId());
|
||||
if (grimPlayer == null) return null;
|
||||
|
||||
for (Map.Entry<String, Function<GrimUser, String>> entry : GrimAPI.INSTANCE.getExternalAPI().getVariableReplacements().entrySet()) {
|
||||
@@ -0,0 +1,52 @@
|
||||
package ac.grim.grimac.platform.bukkit.utils.reflection;
|
||||
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.reflection.ReflectionUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class PaperUtils {
|
||||
|
||||
public static final boolean PAPER;
|
||||
public static final boolean TICK_END_EVENT;
|
||||
public static final boolean ASYNC_TELEPORT;
|
||||
|
||||
static {
|
||||
PAPER = ReflectionUtils.hasClass("com.destroystokyo.paper.PaperConfig") || ReflectionUtils.hasClass("io.papermc.paper.configuration.Configuration");
|
||||
TICK_END_EVENT = ReflectionUtils.hasClass("com.destroystokyo.paper.event.server.ServerTickEndEvent");
|
||||
ASYNC_TELEPORT = ReflectionUtils.hasMethod(Entity.class, "teleportAsync", org.bukkit.Location.class);
|
||||
}
|
||||
|
||||
public static CompletableFuture<Boolean> teleportAsync(final Entity entity, final Location location) {
|
||||
if (PAPER) {
|
||||
return entity.teleportAsync(location);
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(entity.teleport(location));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean registerTickEndEvent(Listener listener, Runnable runnable) {
|
||||
if (TICK_END_EVENT) {
|
||||
try {
|
||||
Class<?> clazz = ReflectionUtils.getClass("com.destroystokyo.paper.event.server.ServerTickEndEvent");
|
||||
if (clazz == null) return false;
|
||||
GrimACBukkitLoaderPlugin.LOADER.getServer().getPluginManager().registerEvent((Class<? extends Event>) clazz,
|
||||
listener,
|
||||
EventPriority.NORMAL,
|
||||
(l, event) -> runnable.run(), GrimACBukkitLoaderPlugin.LOADER);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogUtil.exception("Failed to register tick end event", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package ac.grim.grimac.platform.bukkit.world;
|
||||
|
||||
import ac.grim.grimac.platform.api.world.PlatformChunk;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class BukkitPlatformChunk implements PlatformChunk {
|
||||
private static final HashMap<BlockData, Integer> blockDataToId = new HashMap<>();
|
||||
private static final boolean isFlat = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13);
|
||||
private final Chunk chunk;
|
||||
|
||||
public BukkitPlatformChunk(@NotNull Chunk chunkAt) {
|
||||
this.chunk = chunkAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockID(int x, int y, int z) {
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
|
||||
return isFlat // Cache blockDataToID because Strings are expensive
|
||||
? blockDataToId.computeIfAbsent(block.getBlockData(), data -> WrappedBlockState.getByString(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), data.getAsString(false)).getGlobalId())
|
||||
: (block.getType().getId() << 4) | block.getData();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package ac.grim.grimac.platform.bukkit.world;
|
||||
|
||||
import ac.grim.grimac.platform.api.world.PlatformChunk;
|
||||
import ac.grim.grimac.platform.api.world.PlatformWorld;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
public class BukkitPlatformWorld implements PlatformWorld {
|
||||
|
||||
private final World bukkitWorld;
|
||||
|
||||
public BukkitPlatformWorld(@NotNull World world) {
|
||||
this.bukkitWorld = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int chunkX, int chunkZ) {
|
||||
return bukkitWorld.isChunkLoaded(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedBlockState getBlockAt(int x, int y, int z) {
|
||||
return SpigotConversionUtil.fromBukkitBlockData(bukkitWorld.getBlockAt(x, y, z).getBlockData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return bukkitWorld.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable UUID getUID() {
|
||||
return this.bukkitWorld.getUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformChunk getChunkAt(int currChunkX, int currChunkZ) {
|
||||
return new BukkitPlatformChunk(bukkitWorld.getChunkAt(currChunkX, currChunkZ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return Bukkit.getWorld(bukkitWorld.getUID()) != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
plugins {
|
||||
`maven-publish`
|
||||
grim.`base-conventions`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven {
|
||||
name = "papermc"
|
||||
url = uri("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
|
||||
maven("https://jitpack.io/") { // Grim API
|
||||
content {
|
||||
includeGroup("com.github.grimanticheat")
|
||||
}
|
||||
}
|
||||
maven("https://repo.viaversion.com") // ViaVersion
|
||||
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
|
||||
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
|
||||
maven("https://repo.codemc.io/repository/maven-releases/") // PacketEvents
|
||||
maven("https://repo.codemc.io/repository/maven-snapshots/")
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
mavenCentral()
|
||||
// FastUtil, Discord-Webhooks
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(libs.packetevents.api)
|
||||
api(libs.cloud.core)
|
||||
api("org.incendo:cloud-processors-requirements:1.0.0-rc.1")
|
||||
api("github.scarsz:configuralize:1.4.1:slim") {
|
||||
exclude(group = "org.yaml", module = "snakeyaml")
|
||||
}
|
||||
// Bump snakeyaml (transitive dep of configuralize) 1.29 -> 2.2 for geyser-fabric
|
||||
api("org.yaml:snakeyaml:2.2")
|
||||
api(libs.discord.webhooks)
|
||||
api(libs.fastutil)
|
||||
api(libs.adventure.text.minimessage)
|
||||
api(libs.jetbrains.annotations)
|
||||
|
||||
// Used for local testing:
|
||||
// api("ac.grim.grimac:GrimAPI:1.0")
|
||||
api("com.github.grimanticheat:grimapi:8507e14a73")
|
||||
|
||||
compileOnly(libs.floodgate.api)
|
||||
compileOnly(libs.via.version.api)
|
||||
compileOnly(libs.netty)
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
from(components["java"])
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.manager.AlertManagerImpl;
|
||||
import ac.grim.grimac.manager.DiscordManager;
|
||||
import ac.grim.grimac.manager.InitManager;
|
||||
import ac.grim.grimac.manager.SpectateManager;
|
||||
import ac.grim.grimac.manager.TickManager;
|
||||
import ac.grim.grimac.manager.config.BaseConfigManager;
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import ac.grim.grimac.platform.api.Platform;
|
||||
import ac.grim.grimac.platform.api.PlatformLoader;
|
||||
import ac.grim.grimac.platform.api.PlatformServer;
|
||||
import ac.grim.grimac.platform.api.manager.ItemResetHandler;
|
||||
import ac.grim.grimac.platform.api.manager.MessagePlaceHolderManager;
|
||||
import ac.grim.grimac.platform.api.manager.ParserDescriptorFactory;
|
||||
import ac.grim.grimac.platform.api.manager.PermissionRegistrationManager;
|
||||
import ac.grim.grimac.platform.api.manager.PlatformPluginManager;
|
||||
import ac.grim.grimac.platform.api.player.PlatformPlayerFactory;
|
||||
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.platform.api.sender.SenderFactory;
|
||||
import ac.grim.grimac.utils.anticheat.PlayerDataManager;
|
||||
import ac.grim.grimac.utils.reflection.ReflectionUtils;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
public final class GrimAPI {
|
||||
public static final GrimAPI INSTANCE = new GrimAPI();
|
||||
|
||||
private final Platform platform = detectPlatform();
|
||||
private final BaseConfigManager configManager;
|
||||
private final AlertManagerImpl alertManager;
|
||||
private final SpectateManager spectateManager;
|
||||
private final DiscordManager discordManager;
|
||||
private final PlayerDataManager playerDataManager;
|
||||
private final TickManager tickManager;
|
||||
private final GrimExternalAPI externalAPI;
|
||||
private PlatformLoader loader;
|
||||
private InitManager initManager;
|
||||
private boolean initialized = false;
|
||||
|
||||
private GrimAPI() {
|
||||
this.configManager = new BaseConfigManager();
|
||||
this.alertManager = new AlertManagerImpl();
|
||||
this.spectateManager = new SpectateManager();
|
||||
this.discordManager = new DiscordManager();
|
||||
this.playerDataManager = new PlayerDataManager();
|
||||
this.tickManager = new TickManager();
|
||||
this.externalAPI = new GrimExternalAPI(this);
|
||||
}
|
||||
|
||||
private static Platform detectPlatform() {
|
||||
final Map<String, Platform> platforms = Collections.unmodifiableMap(new HashMap<>() {{
|
||||
put("io.papermc.paper.threadedregions.RegionizedServer", Platform.FOLIA);
|
||||
put("org.bukkit.Bukkit", Platform.BUKKIT);
|
||||
put("net.fabricmc.loader.api.FabricLoader", Platform.FABRIC);
|
||||
}});
|
||||
|
||||
return platforms.entrySet().stream()
|
||||
.filter(entry -> ReflectionUtils.hasClass(entry.getKey()))
|
||||
.map(Map.Entry::getValue)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Unknown platform!"));
|
||||
}
|
||||
|
||||
public void load(PlatformLoader platformLoader, Initable... platformSpecificInitables) {
|
||||
this.loader = platformLoader;
|
||||
this.initManager = new InitManager(loader.getPacketEvents(), loader::getCommandManager, platformSpecificInitables);
|
||||
this.initManager.load();
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
checkInitialized();
|
||||
initManager.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
checkInitialized();
|
||||
initManager.stop();
|
||||
}
|
||||
|
||||
public PlatformScheduler getScheduler() {
|
||||
return loader.getScheduler();
|
||||
}
|
||||
|
||||
public PlatformPlayerFactory getPlatformPlayerFactory() {
|
||||
return loader.getPlatformPlayerFactory();
|
||||
}
|
||||
|
||||
public ParserDescriptorFactory getParserDescriptors() {
|
||||
return loader.getParserDescriptorFactory();
|
||||
}
|
||||
|
||||
public InitManager getInitManager() {
|
||||
return initManager;
|
||||
}
|
||||
|
||||
public GrimPlugin getGrimPlugin() {
|
||||
return loader.getPlugin();
|
||||
}
|
||||
|
||||
public SenderFactory<?> getSenderFactory() {
|
||||
return loader.getSenderFactory();
|
||||
}
|
||||
|
||||
public ItemResetHandler getItemResetHandler() {
|
||||
return loader.getItemResetHandler();
|
||||
}
|
||||
|
||||
public PlatformPluginManager getPluginManager() {
|
||||
return loader.getPluginManager();
|
||||
}
|
||||
|
||||
public PlatformServer getPlatformServer() {
|
||||
return loader.getPlatformServer();
|
||||
}
|
||||
|
||||
public @NotNull MessagePlaceHolderManager getMessagePlaceHolderManager() {
|
||||
return loader.getMessagePlaceHolderManager();
|
||||
}
|
||||
|
||||
private void checkInitialized() {
|
||||
if (!initialized) {
|
||||
throw new IllegalStateException("GrimAPI has not been initialized!");
|
||||
}
|
||||
}
|
||||
|
||||
public PermissionRegistrationManager getPermissionManager() {
|
||||
return loader.getPermissionManager();
|
||||
}
|
||||
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
+34
-43
@@ -1,24 +1,21 @@
|
||||
package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.api.GrimAbstractAPI;
|
||||
import ac.grim.grimac.api.plugin.GrimPluginDescription;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
import ac.grim.grimac.api.alerts.AlertManager;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.events.GrimReloadEvent;
|
||||
import ac.grim.grimac.api.event.EventBus;
|
||||
import ac.grim.grimac.api.event.events.GrimReloadEvent;
|
||||
import ac.grim.grimac.manager.config.ConfigManagerFileImpl;
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import ac.grim.grimac.manager.init.start.StartableInitable;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.chat.ChatUtil;
|
||||
import ac.grim.grimac.utils.common.ConfigReloadObserver;
|
||||
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
|
||||
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -29,33 +26,32 @@ import java.util.function.Function;
|
||||
|
||||
//This is used for grim's external API. It has its own class just for organization.
|
||||
|
||||
public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, Initable {
|
||||
public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, StartableInitable {
|
||||
|
||||
private final GrimAPI api;
|
||||
@Getter
|
||||
private final Map<String, Function<GrimUser, String>> variableReplacements = new ConcurrentHashMap<>();
|
||||
@Getter
|
||||
private final Map<String, String> staticReplacements = new ConcurrentHashMap<>();
|
||||
private final Map<String, Function<Object, Object>> functions = new ConcurrentHashMap<>();
|
||||
private final ConfigManagerFileImpl configManagerFile = new ConfigManagerFileImpl();
|
||||
private ConfigManager configManager = null;
|
||||
private boolean started = false;
|
||||
|
||||
public GrimExternalAPI(GrimAPI api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public GrimUser getGrimUser(Player player) {
|
||||
return api.getPlayerDataManager().getPlayer(player);
|
||||
public @NonNull EventBus getEventBus() {
|
||||
return api.getPluginManager().getEventBus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GrimUser getGrimUser(UUID uuid) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player == null) return null;
|
||||
return getGrimUser(player);
|
||||
return api.getPlayerDataManager().getPlayer(uuid);
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final Map<String, Function<GrimUser, String>> variableReplacements = new ConcurrentHashMap<>();
|
||||
|
||||
@Getter
|
||||
private final Map<String, String> staticReplacements = new ConcurrentHashMap<>();
|
||||
|
||||
public String replaceVariables(GrimUser user, String content) {
|
||||
for (Map.Entry<String, String> entry : staticReplacements.entrySet()) {
|
||||
content = content.replace(entry.getKey(), entry.getValue());
|
||||
@@ -86,12 +82,10 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
|
||||
@Override
|
||||
public String getGrimVersion() {
|
||||
PluginDescriptionFile description = GrimAPI.INSTANCE.getPlugin().getDescription();
|
||||
GrimPluginDescription description = GrimAPI.INSTANCE.getGrimPlugin().getDescription();
|
||||
return description.getVersion();
|
||||
}
|
||||
|
||||
private final Map<String, Function<Object, Object>> functions = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void registerFunction(String key, Function<Object, Object> function) {
|
||||
if (function == null) {
|
||||
@@ -126,14 +120,10 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
return GrimAPI.INSTANCE.getTickManager().currentTick;
|
||||
}
|
||||
|
||||
private ConfigManager configManager = null;
|
||||
private final ConfigManagerFileImpl configManagerFile = new ConfigManagerFileImpl();
|
||||
private boolean started = false;
|
||||
|
||||
// on load, load the config & register the service
|
||||
public void load() {
|
||||
reload(configManagerFile);
|
||||
Bukkit.getServicesManager().register(GrimAbstractAPI.class, this, GrimAPI.INSTANCE.getPlugin(), ServicePriority.Normal);
|
||||
api.getLoader().registerAPIService();
|
||||
}
|
||||
|
||||
// handles any config loading that's needed to be done after load
|
||||
@@ -150,8 +140,8 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
@Override
|
||||
public void reload(ConfigManager config) {
|
||||
if (config.isLoadedAsync() && started) {
|
||||
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
|
||||
o -> successfulReload(config));
|
||||
GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(GrimAPI.INSTANCE.getGrimPlugin(),
|
||||
() -> successfulReload(config));
|
||||
} else {
|
||||
successfulReload(config);
|
||||
}
|
||||
@@ -161,8 +151,8 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
public CompletableFuture<Boolean> reloadAsync(ConfigManager config) {
|
||||
if (config.isLoadedAsync() && started) {
|
||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
|
||||
o -> future.complete(successfulReload(config)));
|
||||
GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(GrimAPI.INSTANCE.getGrimPlugin(),
|
||||
() -> future.complete(successfulReload(config)));
|
||||
return future;
|
||||
}
|
||||
return CompletableFuture.completedFuture(successfulReload(config));
|
||||
@@ -174,14 +164,16 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
GrimAPI.INSTANCE.getConfigManager().load(config);
|
||||
if (started) GrimAPI.INSTANCE.getConfigManager().start();
|
||||
onReload(config);
|
||||
if (started) FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
|
||||
o -> Bukkit.getPluginManager().callEvent(new GrimReloadEvent(true)));
|
||||
if (started)
|
||||
GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(GrimAPI.INSTANCE.getGrimPlugin(),
|
||||
() -> GrimAPI.INSTANCE.getPluginManager().callEvent(new GrimReloadEvent(true)));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (started) FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
|
||||
o -> Bukkit.getPluginManager().callEvent(new GrimReloadEvent(false)));
|
||||
if (started)
|
||||
GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(GrimAPI.INSTANCE.getGrimPlugin(),
|
||||
() -> GrimAPI.INSTANCE.getPluginManager().callEvent(new GrimReloadEvent(false)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -196,8 +188,8 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
// Update variables
|
||||
updateVariables();
|
||||
// Restart
|
||||
GrimAPI.INSTANCE.getDiscordManager().start();
|
||||
GrimAPI.INSTANCE.getSpectateManager().start();
|
||||
GrimAPI.INSTANCE.getDiscordManager().reload();
|
||||
GrimAPI.INSTANCE.getSpectateManager().reload();
|
||||
// Don't reload players if the plugin hasn't started yet
|
||||
if (!started) return;
|
||||
// Reload checks for all players
|
||||
@@ -217,11 +209,10 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
variableReplacements.putIfAbsent("%h_sensitivity%", user -> ((int) Math.round(user.getHorizontalSensitivity() * 200)) + "");
|
||||
variableReplacements.putIfAbsent("%v_sensitivity%", user -> ((int) Math.round(user.getVerticalSensitivity() * 200)) + "");
|
||||
variableReplacements.putIfAbsent("%fast_math%", user -> !user.isVanillaMath() + "");
|
||||
variableReplacements.putIfAbsent("%tps%", user -> String.format("%.2f", SpigotReflectionUtil.getTPS()));
|
||||
variableReplacements.putIfAbsent("%tps%", user -> String.format("%.2f", GrimAPI.INSTANCE.getPlatformServer().getTPS()));
|
||||
variableReplacements.putIfAbsent("%version%", GrimUser::getVersionName);
|
||||
// static variables
|
||||
staticReplacements.put("%prefix%", ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getPrefix()));
|
||||
staticReplacements.put("%prefix%", ChatUtil.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getPrefix()));
|
||||
staticReplacements.putIfAbsent("%grim_version%", getGrimVersion());
|
||||
}
|
||||
|
||||
}
|
||||
+31
-19
@@ -3,21 +3,22 @@ package ac.grim.grimac.checks;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.events.FlagEvent;
|
||||
import ac.grim.grimac.api.event.events.FlagEvent;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// Class from https://github.com/Tecnio/AntiCheatBase/blob/master/src/main/java/me/tecnio/anticheat/check/Check.java
|
||||
@Getter
|
||||
public class Check extends GrimProcessor implements AbstractCheck {
|
||||
protected final GrimPlayer player;
|
||||
protected @NonNull final GrimPlayer player;
|
||||
|
||||
public double violations;
|
||||
private double decay;
|
||||
@@ -30,14 +31,15 @@ public class Check extends GrimProcessor implements AbstractCheck {
|
||||
private String description;
|
||||
|
||||
private boolean experimental;
|
||||
@Setter
|
||||
private boolean isEnabled;
|
||||
private @Setter boolean isEnabled;
|
||||
|
||||
private boolean exemptPermission;
|
||||
private boolean noSetbackPermission;
|
||||
private boolean noModifyPacketPermission;
|
||||
private long lastViolationTime;
|
||||
|
||||
public Check(final GrimPlayer player) {
|
||||
public Check(final @NotNull GrimPlayer player) {
|
||||
Preconditions.checkArgument(player != null);
|
||||
this.player = player;
|
||||
|
||||
final CheckData checkData = this.getClass().getAnnotation(CheckData.class);
|
||||
@@ -62,15 +64,15 @@ public class Check extends GrimProcessor implements AbstractCheck {
|
||||
}
|
||||
|
||||
public void updatePermissions() {
|
||||
if (player.bukkitPlayer == null || checkName == null) return;
|
||||
FoliaScheduler.getEntityScheduler().run(
|
||||
player.bukkitPlayer,
|
||||
GrimAPI.INSTANCE.getPlugin(),
|
||||
t -> {
|
||||
final String id = checkName.toLowerCase();
|
||||
exemptPermission = player.bukkitPlayer.hasPermission("grim.exempt." + id);
|
||||
noSetbackPermission = player.bukkitPlayer.hasPermission("grim.nosetback." + id);
|
||||
noModifyPacketPermission = player.bukkitPlayer.hasPermission("grim.nomodifypacket." + id);
|
||||
if (player.platformPlayer == null || configName == null) return;
|
||||
GrimAPI.INSTANCE.getScheduler().getEntityScheduler().run(
|
||||
player.platformPlayer,
|
||||
GrimAPI.INSTANCE.getGrimPlugin(),
|
||||
() -> {
|
||||
final String id = configName.toLowerCase();
|
||||
exemptPermission = player.platformPlayer.hasPermission("grim.exempt." + id);
|
||||
noSetbackPermission = player.platformPlayer.hasPermission("grim.nosetback." + id);
|
||||
noModifyPacketPermission = player.platformPlayer.hasPermission("grim.nomodifypacket." + id);
|
||||
},
|
||||
() -> {}
|
||||
);
|
||||
@@ -92,14 +94,12 @@ public class Check extends GrimProcessor implements AbstractCheck {
|
||||
return flag("");
|
||||
}
|
||||
|
||||
private long lastViolationTime;
|
||||
|
||||
public final boolean flag(String verbose) {
|
||||
if (player.disableGrim || (experimental && !player.isExperimentalChecks()) || exemptPermission)
|
||||
return false; // Avoid calling event if disabled
|
||||
|
||||
FlagEvent event = new FlagEvent(player, this, verbose);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
GrimAPI.INSTANCE.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) return false;
|
||||
|
||||
player.punishmentManager.handleViolation(this);
|
||||
@@ -116,6 +116,18 @@ public class Check extends GrimProcessor implements AbstractCheck {
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean flagAndAlertWithSetback() {
|
||||
return flagAndAlertWithSetback("");
|
||||
}
|
||||
|
||||
public final boolean flagAndAlertWithSetback(String verbose) {
|
||||
if (flagAndAlert(verbose)) {
|
||||
setbackIfAboveSetbackVL();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final void reward() {
|
||||
violations = Math.max(0, violations - decay);
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
+3
-3
@@ -8,15 +8,15 @@ import ac.grim.grimac.utils.anticheat.update.RotationUpdate;
|
||||
|
||||
@CheckData(name = "AimDuplicateLook")
|
||||
public class AimDuplicateLook extends Check implements RotationCheck {
|
||||
boolean exempt = false;
|
||||
|
||||
public AimDuplicateLook(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
boolean exempt = false;
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate || player.compensatedEntities.getSelf().getRiding() != null) {
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate || player.compensatedEntities.self.getRiding() != null) {
|
||||
exempt = true;
|
||||
return;
|
||||
}
|
||||
+4
-2
@@ -20,8 +20,10 @@ public class AimModulo360 extends Check implements RotationCheck {
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
// Exempt for teleport or entering a vehicle due to rotation reset
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.vehicleData.wasVehicleSwitch) {
|
||||
// Exempt for teleport, entering a vehicle due to rotation reset or
|
||||
// after forced, client-sided rotation change after interacting with a horse (not necessarily mounting it)
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.vehicleData.wasVehicleSwitch
|
||||
|| player.packetStateData.horseInteractCausedForcedRotation) {
|
||||
lastDeltaYaw = rotationUpdate.getDeltaXRot();
|
||||
return;
|
||||
}
|
||||
+15
-21
@@ -13,26 +13,26 @@ public class AimProcessor extends Check implements RotationCheck {
|
||||
|
||||
private static final int SIGNIFICANT_SAMPLES_THRESHOLD = 15;
|
||||
private static final int TOTAL_SAMPLES_THRESHOLD = 80;
|
||||
public double sensitivityX;
|
||||
public double sensitivityY;
|
||||
public double divisorX;
|
||||
public double divisorY;
|
||||
public double modeX, modeY;
|
||||
public double deltaDotsX, deltaDotsY;
|
||||
RunningMode xRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
|
||||
RunningMode yRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
|
||||
float lastXRot;
|
||||
float lastYRot;
|
||||
|
||||
public AimProcessor(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
RunningMode xRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
|
||||
RunningMode yRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
|
||||
|
||||
float lastXRot;
|
||||
float lastYRot;
|
||||
|
||||
public double sensitivityX;
|
||||
public double sensitivityY;
|
||||
|
||||
public double divisorX;
|
||||
public double divisorY;
|
||||
|
||||
public double modeX, modeY;
|
||||
|
||||
public double deltaDotsX, deltaDotsY;
|
||||
public static double convertToSensitivity(double var13) {
|
||||
double var11 = var13 / 0.15F / 8.0D;
|
||||
double var9 = Math.cbrt(var11);
|
||||
return (var9 - 0.2f) / 0.6f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
@@ -75,10 +75,4 @@ public class AimProcessor extends Check implements RotationCheck {
|
||||
this.deltaDotsX = deltaXRot / modeX;
|
||||
this.deltaDotsY = deltaYRot / modeY;
|
||||
}
|
||||
|
||||
public static double convertToSensitivity(double var13) {
|
||||
double var11 = var13 / 0.15F / 8.0D;
|
||||
double var9 = Math.cbrt(var11);
|
||||
return (var9 - 0.2f) / 0.6f;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+1
-1
@@ -5,8 +5,8 @@ import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
|
||||
@CheckData(name = "BadPacketsC", description = "Interacted with self")
|
||||
File renamed without changes.
+1
-1
@@ -28,7 +28,7 @@ public class BadPacketsE extends Check implements PacketCheck {
|
||||
} else if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
|
||||
noReminderTicks++;
|
||||
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE
|
||||
|| (isViaPleaseStopUsingProtocolHacksOnYourServer && player.compensatedEntities.getSelf().inVehicle())) {
|
||||
|| (isViaPleaseStopUsingProtocolHacksOnYourServer && player.inVehicle())) {
|
||||
noReminderTicks = 0; // Exempt vehicles
|
||||
}
|
||||
|
||||
File renamed without changes.
File renamed without changes.
+2
-1
@@ -41,7 +41,8 @@ public class BadPacketsH extends Check implements PacketCheck {
|
||||
// I will simply disable this check for 1.8- clients on 1.9+ servers as I can't be bothered to find a way around this.
|
||||
// Stop supporting such old clients on modern servers!
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
|
||||
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) return;
|
||||
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9))
|
||||
return;
|
||||
|
||||
if (!sentAnimation && flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
File renamed without changes.
File renamed without changes.
+2
-1
@@ -24,7 +24,8 @@ public class BadPacketsL extends Check implements PacketCheck {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
|
||||
|
||||
if (packet.getAction() == DiggingAction.START_DIGGING || packet.getAction() == DiggingAction.FINISHED_DIGGING || packet.getAction() == DiggingAction.CANCELLED_DIGGING) return;
|
||||
if (packet.getAction() == DiggingAction.START_DIGGING || packet.getAction() == DiggingAction.FINISHED_DIGGING || packet.getAction() == DiggingAction.CANCELLED_DIGGING)
|
||||
return;
|
||||
|
||||
// 1.8 and above clients always send digging packets that aren't used for digging at 0, 0, 0, facing DOWN
|
||||
// 1.7 and below clients do the same, except use SOUTH for RELEASE_USE_ITEM
|
||||
+4
-4
@@ -13,14 +13,14 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientIn
|
||||
|
||||
@CheckData(name = "BadPacketsM")
|
||||
public class BadPacketsM extends Check implements PacketCheck {
|
||||
public BadPacketsM(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
// 1.7 players do not send INTERACT_AT, so we cannot check them
|
||||
private final boolean exempt = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10);
|
||||
private boolean sentInteractAt = false;
|
||||
|
||||
public BadPacketsM(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY && !exempt) {
|
||||
File renamed without changes.
File renamed without changes.
+3
-3
@@ -14,13 +14,13 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOp
|
||||
@CheckData(name = "BadPacketsP", experimental = true)
|
||||
public class BadPacketsP extends Check implements PacketCheck {
|
||||
|
||||
private int containerType = -1;
|
||||
private int containerId = -1;
|
||||
|
||||
public BadPacketsP(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
private int containerType = -1;
|
||||
private int containerId = -1;
|
||||
|
||||
@Override
|
||||
public void onPacketSend(final PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
|
||||
File renamed without changes.
+6
-6
@@ -10,22 +10,22 @@ import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
|
||||
@CheckData(name = "BadPacketsR", decay = 0.25, experimental = true)
|
||||
public class BadPacketsR extends Check implements PacketCheck {
|
||||
public BadPacketsR(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int positions = 0;
|
||||
private long clock = 0;
|
||||
private long lastTransTime;
|
||||
private int oldTransId = 0;
|
||||
|
||||
public BadPacketsR(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(final PacketReceiveEvent event) {
|
||||
if (isTransaction(event.getPacketType()) && player.packetStateData.lastTransactionPacketWasValid) {
|
||||
long ms = (player.getPlayerClockAtLeast() - clock) / 1000000L;
|
||||
long diff = (System.currentTimeMillis() - lastTransTime);
|
||||
if (diff > 2000 && ms > 2000) {
|
||||
if (positions == 0 && clock != 0 && player.gamemode != GameMode.SPECTATOR && !player.compensatedEntities.getSelf().isDead) {
|
||||
if (positions == 0 && clock != 0 && player.gamemode != GameMode.SPECTATOR && !player.compensatedEntities.self.isDead) {
|
||||
flag("time=" + ms + "ms, " + "lst=" + diff + "ms, positions=" + positions);
|
||||
} else {
|
||||
reward();
|
||||
@@ -39,7 +39,7 @@ public class BadPacketsR extends Check implements PacketCheck {
|
||||
}
|
||||
//
|
||||
if ((event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION ||
|
||||
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) && !player.compensatedEntities.getSelf().inVehicle()) {
|
||||
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) && !player.inVehicle()) {
|
||||
positions++;
|
||||
} else if ((event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE || event.getPacketType() == PacketType.Play.Client.VEHICLE_MOVE)
|
||||
&& player.inVehicle()) {
|
||||
File renamed without changes.
+4
-4
@@ -14,10 +14,6 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientIn
|
||||
|
||||
@CheckData(name = "BadPacketsT")
|
||||
public class BadPacketsT extends Check implements PacketCheck {
|
||||
public BadPacketsT(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
// 1.7 and 1.8 seem to have different hitbox "expansion" values than 1.9+
|
||||
// https://github.com/GrimAnticheat/Grim/pull/1274#issuecomment-1872458702
|
||||
// https://github.com/GrimAnticheat/Grim/pull/1274#issuecomment-1872533497
|
||||
@@ -26,6 +22,10 @@ public class BadPacketsT extends Check implements PacketCheck {
|
||||
private final double minVerticalDisplacement = -0.0001 - (hasLegacyExpansion ? 0.1 : 0);
|
||||
private final double maxVerticalDisplacement = 1.8001 + (hasLegacyExpansion ? 0.1 : 0);
|
||||
|
||||
public BadPacketsT(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(final PacketReceiveEvent event) {
|
||||
if (event.getPacketType().equals(PacketType.Play.Client.INTERACT_ENTITY)) {
|
||||
File renamed without changes.
+2
-2
@@ -12,12 +12,12 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPl
|
||||
|
||||
@CheckData(name = "BadPacketsV", description = "Did not move far enough", experimental = true)
|
||||
public class BadPacketsV extends Check implements PacketCheck {
|
||||
private int noReminderTicks;
|
||||
|
||||
public BadPacketsV(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int noReminderTicks;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (!player.canSkipTicks() && isTickPacket(event.getPacketType())) {
|
||||
File renamed without changes.
+5
-7
@@ -12,14 +12,14 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEn
|
||||
|
||||
@CheckData(name = "BadPacketsX", experimental = true)
|
||||
public class BadPacketsX extends Check implements PostPredictionCheck {
|
||||
public BadPacketsX(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean sprint;
|
||||
private boolean sneak;
|
||||
private int flags;
|
||||
|
||||
public BadPacketsX(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(final PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) {
|
||||
@@ -33,9 +33,7 @@ public class BadPacketsX extends Check implements PostPredictionCheck {
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; flags > 0; flags--) {
|
||||
if (flagAndAlert()) {
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
flagAndAlertWithSetback();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ public class BadPacketsY extends Check implements PacketCheck {
|
||||
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
|
||||
final int slot = new WrapperPlayClientHeldItemChange(event).getSlot();
|
||||
if (slot > 8 || slot < 0) { // ban
|
||||
if (flagAndAlert("slot="+slot) && shouldModifyPackets()) {
|
||||
if (flagAndAlert("slot=" + slot) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
+2
-2
@@ -12,12 +12,12 @@ import ac.grim.grimac.utils.math.GrimMath;
|
||||
// This check has been patched by Baritone for a long time and it also seems to false with cinematic camera now, so it is disabled.
|
||||
@CheckData(name = "Baritone")
|
||||
public class Baritone extends Check implements RotationCheck {
|
||||
private int verbose;
|
||||
|
||||
public Baritone(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
private int verbose;
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
final HeadRotation from = rotationUpdate.getFrom();
|
||||
+8
-7
@@ -12,20 +12,21 @@ import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@CheckData(name = "AirLiquidBreak", description = "Breaking a block that cannot be broken")
|
||||
public class AirLiquidBreak extends Check implements BlockBreakCheck {
|
||||
public final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_15_2);
|
||||
private int lastTick;
|
||||
private boolean didLastFlag;
|
||||
// Initialize to non-null values to prevent NPE when checking for blockType properties and if position equals old position
|
||||
private @NonNull Vector3i lastBreakLoc = new Vector3i();
|
||||
private @NonNull StateType lastBlockType = StateTypes.AIR;
|
||||
|
||||
public AirLiquidBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int lastTick;
|
||||
private boolean didLastFlag;
|
||||
private Vector3i lastBreakLoc;
|
||||
private StateType lastBlockType;
|
||||
|
||||
public final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_15_2);
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action != DiggingAction.START_DIGGING && blockBreak.action != DiggingAction.FINISHED_DIGGING)
|
||||
+6
-5
@@ -6,11 +6,11 @@ import ac.grim.grimac.checks.type.BlockBreakCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.math.Vector3dm;
|
||||
import ac.grim.grimac.utils.math.VectorUtils;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
@CheckData(name = "FarBreak", description = "Breaking blocks too far away", experimental = true)
|
||||
public class FarBreak extends Check implements BlockBreakCheck {
|
||||
@@ -20,19 +20,20 @@ public class FarBreak extends Check implements BlockBreakCheck {
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || player.compensatedEntities.getSelf().inVehicle() || blockBreak.action == DiggingAction.CANCELLED_DIGGING) return; // falses
|
||||
if (player.gamemode == GameMode.SPECTATOR || player.inVehicle() || blockBreak.action == DiggingAction.CANCELLED_DIGGING)
|
||||
return; // falses
|
||||
|
||||
double min = Double.MAX_VALUE;
|
||||
for (double d : player.getPossibleEyeHeights()) {
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
|
||||
Vector eyes = new Vector(player.x, player.y + d, player.z);
|
||||
Vector best = VectorUtils.cutBoxToVector(eyes, box);
|
||||
Vector3dm eyes = new Vector3dm(player.x, player.y + d, player.z);
|
||||
Vector3dm best = VectorUtils.cutBoxToVector(eyes, box);
|
||||
min = Math.min(min, eyes.distanceSquared(best));
|
||||
}
|
||||
|
||||
// getPickRange() determines this?
|
||||
// With 1.20.5+ the new attribute determines creative mode reach using a modifier
|
||||
double maxReach = player.compensatedEntities.getSelf().getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
|
||||
double maxReach = player.compensatedEntities.self.getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
|
||||
if (player.packetStateData.didLastMovementIncludePosition || player.canSkipTicks()) {
|
||||
double threshold = player.getMovementThreshold();
|
||||
maxReach += Math.hypot(threshold, threshold);
|
||||
+14
-4
@@ -12,15 +12,23 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
// Based loosely off of Hawk BlockBreakSpeedSurvival
|
||||
// Also based loosely off of NoCheatPlus FastBreak
|
||||
// Also based off minecraft wiki: https://minecraft.wiki/w/Breaking#Instant_breaking
|
||||
@CheckData(name = "FastBreak", description = "Breaking blocks too quickly")
|
||||
public class FastBreak extends Check implements BlockBreakCheck {
|
||||
|
||||
// For some reason these states flag and I don't know why.
|
||||
// Better to just exempt to not annoy legit players.
|
||||
private static final Set<StateType> EXEMPT_STATES = Set.of();
|
||||
|
||||
public FastBreak(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
@@ -45,7 +53,8 @@ public class FastBreak extends Check implements BlockBreakCheck {
|
||||
WrappedBlockState block = blockBreak.block;
|
||||
|
||||
// Exempt all blocks that do not exist in the player version
|
||||
if (WrappedBlockState.getDefaultState(player.getClientVersion(), block.getType()).getType() == StateTypes.AIR) {
|
||||
final WrappedBlockState defaultState = WrappedBlockState.getDefaultState(player.getClientVersion(), block.getType());
|
||||
if (defaultState.getType() == StateTypes.AIR || EXEMPT_STATES.contains(defaultState.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,7 +72,7 @@ public class FastBreak extends Check implements BlockBreakCheck {
|
||||
}
|
||||
|
||||
if (blockDelayBalance > 1000) { // If more than a second of advantage
|
||||
if (flagAndAlert("Delay=" + breakDelay) && shouldModifyPackets()) {
|
||||
if (flagAndAlert("delay=" + breakDelay + "ms, type=" + blockBreak.block.getType()) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
@@ -85,12 +94,13 @@ public class FastBreak extends Check implements BlockBreakCheck {
|
||||
}
|
||||
|
||||
if (blockBreakBalance > 1000) { // If more than a second of advantage
|
||||
if (flagAndAlert("Diff=" + diff + ",Balance=" + blockBreakBalance) && shouldModifyPackets()) {
|
||||
if (flagAndAlert("diff=" + diff + "ms, balance=" + blockBreakBalance + "ms, type=" + blockBreak.block.getType()) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
lastFinishBreak = System.currentTimeMillis();
|
||||
// also set start time because the breaking netcode is fucked on 1.14.4+
|
||||
lastFinishBreak = startBreak = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
File renamed without changes.
+4
-5
@@ -18,16 +18,15 @@ import java.util.List;
|
||||
|
||||
@CheckData(name = "MultiBreak", experimental = true)
|
||||
public class MultiBreak extends Check implements BlockBreakCheck {
|
||||
public MultiBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final List<String> flags = new ArrayList<>();
|
||||
|
||||
private boolean hasBroken;
|
||||
private BlockFace lastFace;
|
||||
private Vector3i lastPos;
|
||||
|
||||
public MultiBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
|
||||
+3
-3
@@ -11,13 +11,13 @@ import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
|
||||
@CheckData(name = "NoSwingBreak", description = "Did not swing while breaking block", experimental = true)
|
||||
public class NoSwingBreak extends Check implements BlockBreakCheck {
|
||||
private boolean sentAnimation;
|
||||
private boolean sentBreak;
|
||||
|
||||
public NoSwingBreak(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
private boolean sentAnimation;
|
||||
private boolean sentBreak;
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action != DiggingAction.CANCELLED_DIGGING) {
|
||||
+1
-1
@@ -17,7 +17,7 @@ public class PositionBreakA extends Check implements BlockBreakCheck {
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.compensatedEntities.getSelf().inVehicle()
|
||||
if (player.inVehicle()
|
||||
|| blockBreak.action == DiggingAction.CANCELLED_DIGGING
|
||||
|| blockBreak.block.getType() == StateTypes.REDSTONE_WIRE
|
||||
) return;
|
||||
+3
-3
@@ -11,13 +11,13 @@ import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
|
||||
@CheckData(name = "PositionBreakB", experimental = true)
|
||||
public class PositionBreakB extends Check implements BlockBreakCheck {
|
||||
private final int releaseFace = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? 0 : 255;
|
||||
private BlockFace lastFace;
|
||||
|
||||
public PositionBreakB(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private BlockFace lastFace;
|
||||
private final int releaseFace = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? 0 : 255;
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action == DiggingAction.START_DIGGING) {
|
||||
@@ -0,0 +1,122 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.BlockBreakCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import ac.grim.grimac.utils.math.Vector3dm;
|
||||
import ac.grim.grimac.utils.nmsutil.Ray;
|
||||
import ac.grim.grimac.utils.nmsutil.ReachUtils;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@CheckData(name = "RotationBreak", experimental = true)
|
||||
public class RotationBreak extends Check implements BlockBreakCheck {
|
||||
private double flagBuffer = 0; // If the player flags once, force them to play legit, or we will cancel the tick before.
|
||||
private boolean ignorePost = false;
|
||||
|
||||
public RotationBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR)
|
||||
return; // you don't send flying packets when spectating entities
|
||||
if (player.inVehicle()) return; // falses
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) return; // falses
|
||||
|
||||
if (flagBuffer > 0 && !didRayTraceHit(blockBreak)) {
|
||||
ignorePost = true;
|
||||
// If the player hit and has flagged this check recently
|
||||
if (flagAndAlert("pre-flying, action=" + blockBreak.action) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostFlyingBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR)
|
||||
return; // you don't send flying packets when spectating entities
|
||||
if (player.inVehicle()) return; // falses
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) return; // falses
|
||||
|
||||
// Don't flag twice
|
||||
if (ignorePost) {
|
||||
ignorePost = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (didRayTraceHit(blockBreak)) {
|
||||
flagBuffer = Math.max(0, flagBuffer - 0.1);
|
||||
} else {
|
||||
flagBuffer = 1;
|
||||
flagAndAlert("post-flying, action=" + blockBreak.action);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean didRayTraceHit(BlockBreak blockBreak) {
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
|
||||
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
|
||||
// Start checking if player is in the block
|
||||
double minEyeHeight = Double.MAX_VALUE;
|
||||
double maxEyeHeight = Double.MIN_VALUE;
|
||||
for (double height : possibleEyeHeights) {
|
||||
minEyeHeight = Math.min(minEyeHeight, height);
|
||||
maxEyeHeight = Math.max(maxEyeHeight, height);
|
||||
}
|
||||
|
||||
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
|
||||
eyePositions.expand(player.getMovementThreshold());
|
||||
|
||||
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
|
||||
if (eyePositions.isIntersected(box)) {
|
||||
return true;
|
||||
}
|
||||
// End checking if the player is in the block
|
||||
|
||||
List<Vector3f> possibleLookDirs = new ArrayList<>(Arrays.asList(
|
||||
new Vector3f(player.lastXRot, player.yRot, 0),
|
||||
new Vector3f(player.xRot, player.yRot, 0)
|
||||
));
|
||||
|
||||
// 1.9+ players could be a tick behind because we don't get skipped ticks
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
possibleLookDirs.add(new Vector3f(player.lastXRot, player.lastYRot, 0));
|
||||
}
|
||||
|
||||
// 1.7 players do not have any of these issues! They are always on the latest look vector
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
|
||||
possibleLookDirs = Collections.singletonList(new Vector3f(player.xRot, player.yRot, 0));
|
||||
}
|
||||
|
||||
final double distance = player.compensatedEntities.self.getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
|
||||
for (double d : possibleEyeHeights) {
|
||||
for (Vector3f lookDir : possibleLookDirs) {
|
||||
Vector3d starting = new Vector3d(player.x, player.y + d, player.z);
|
||||
Ray trace = new Ray(player, starting.getX(), starting.getY(), starting.getZ(), lookDir.getX(), lookDir.getY());
|
||||
Pair<Vector3dm, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
|
||||
|
||||
if (intercept.first() != null) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -16,14 +16,14 @@ import static ac.grim.grimac.utils.nmsutil.BlockBreakSpeed.getBlockDamage;
|
||||
|
||||
@CheckData(name = "WrongBreak")
|
||||
public class WrongBreak extends Check implements BlockBreakCheck {
|
||||
private final int exemptedY = player.getClientVersion().isOlderThan(ClientVersion.V_1_8) ? 255 : (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_14) ? -1 : 4095);
|
||||
private boolean lastBlockWasInstantBreak = false;
|
||||
private Vector3i lastBlock, lastCancelledBlock, lastLastBlock = null;
|
||||
|
||||
public WrongBreak(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean lastBlockWasInstantBreak = false;
|
||||
private Vector3i lastBlock, lastCancelledBlock, lastLastBlock = null;
|
||||
private final int exemptedY = player.getClientVersion().isOlderThan(ClientVersion.V_1_8) ? 255 : (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_14) ? -1 : 4095);
|
||||
|
||||
// The client sometimes sends a wierd cancel packet
|
||||
private boolean shouldExempt(final Vector3i pos) {
|
||||
// lastLastBlock is always null when this happens, and lastBlock isn't
|
||||
File renamed without changes.
+4
-4
@@ -14,15 +14,15 @@ import java.util.ArrayList;
|
||||
|
||||
@CheckData(name = "MultiInteractA", description = "Interacted with multiple entities in the same tick", experimental = true)
|
||||
public class MultiInteractA extends Check implements PostPredictionCheck {
|
||||
public MultiInteractA(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final ArrayList<String> flags = new ArrayList<>();
|
||||
private int lastEntity;
|
||||
private boolean lastSneaking;
|
||||
private boolean hasInteracted = false;
|
||||
|
||||
public MultiInteractA(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
+4
-4
@@ -16,14 +16,14 @@ import java.util.ArrayList;
|
||||
|
||||
@CheckData(name = "MultiInteractB", experimental = true)
|
||||
public class MultiInteractB extends Check implements PostPredictionCheck {
|
||||
public MultiInteractB(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final ArrayList<String> flags = new ArrayList<>();
|
||||
private Vector3f lastPos;
|
||||
private boolean hasInteracted = false;
|
||||
|
||||
public MultiInteractB(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
+32
-28
@@ -23,6 +23,7 @@ import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
|
||||
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
|
||||
import ac.grim.grimac.utils.math.Vector3dm;
|
||||
import ac.grim.grimac.utils.nmsutil.ReachUtils;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
@@ -35,23 +36,25 @@ import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
// You may not copy the check unless you are licensed under GPL
|
||||
@CheckData(name = "Reach", setback = 10)
|
||||
public class Reach extends Check implements PacketCheck {
|
||||
|
||||
// Only one flag per reach attack, per entity, per tick.
|
||||
// We store position because lastX isn't reliable on teleports.
|
||||
private final Int2ObjectMap<Vector3d> playerAttackQueue = new Int2ObjectOpenHashMap<>();
|
||||
private static final List<EntityType> blacklisted = Arrays.asList(
|
||||
EntityTypes.BOAT,
|
||||
EntityTypes.CHEST_BOAT,
|
||||
EntityTypes.SHULKER);
|
||||
|
||||
private static final CheckResult NONE = new CheckResult(ResultType.NONE, "");
|
||||
// Only one flag per reach attack, per entity, per tick.
|
||||
// We store position because lastX isn't reliable on teleports.
|
||||
private final Int2ObjectMap<Vector3d> playerAttackQueue = new Int2ObjectOpenHashMap<>();
|
||||
private boolean cancelImpossibleHits;
|
||||
private double threshold;
|
||||
private double cancelBuffer; // For the next 4 hits after using reach, we aggressively cancel reach
|
||||
@@ -89,10 +92,12 @@ public class Reach extends Check implements PacketCheck {
|
||||
if (entity.isDead) return;
|
||||
|
||||
// TODO: Remove when in front of via
|
||||
if (entity.getType() == EntityTypes.ARMOR_STAND && player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) return;
|
||||
if (entity.getType() == EntityTypes.ARMOR_STAND && player.getClientVersion().isOlderThan(ClientVersion.V_1_8))
|
||||
return;
|
||||
|
||||
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR) return;
|
||||
if (player.compensatedEntities.getSelf().inVehicle()) return;
|
||||
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR)
|
||||
return;
|
||||
if (player.inVehicle()) return;
|
||||
if (entity.riding != null) return;
|
||||
|
||||
boolean tooManyAttacks = playerAttackQueue.size() > 10;
|
||||
@@ -127,8 +132,9 @@ public class Reach extends Check implements PacketCheck {
|
||||
if ((blacklisted.contains(reachEntity.getType()) || !reachEntity.isLivingEntity()) && reachEntity.getType() != EntityTypes.END_CRYSTAL)
|
||||
return false; // exempt
|
||||
|
||||
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR) return false;
|
||||
if (player.compensatedEntities.getSelf().inVehicle()) return false;
|
||||
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR)
|
||||
return false;
|
||||
if (player.inVehicle()) return false;
|
||||
|
||||
// Filter out what we assume to be cheats
|
||||
if (cancelBuffer != 0) {
|
||||
@@ -139,7 +145,7 @@ public class Reach extends Check implements PacketCheck {
|
||||
if (reachEntity.getType() == EntityTypes.END_CRYSTAL) {
|
||||
targetBox = new SimpleCollisionBox(reachEntity.trackedServerPosition.getPos().subtract(1, 0, 1), reachEntity.trackedServerPosition.getPos().add(1, 2, 1));
|
||||
}
|
||||
return ReachUtils.getMinReachToBox(player, targetBox) > player.compensatedEntities.getSelf().getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
|
||||
return ReachUtils.getMinReachToBox(player, targetBox) > player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +197,7 @@ public class Reach extends Check implements PacketCheck {
|
||||
double minDistance = Double.MAX_VALUE;
|
||||
|
||||
// https://bugs.mojang.com/browse/MC-67665
|
||||
List<Vector> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
|
||||
List<Vector3dm> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
|
||||
|
||||
// If we are a tick behind, we don't know their next look so don't bother doing this
|
||||
if (!isPrediction) {
|
||||
@@ -208,17 +214,17 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
final double maxReach = player.compensatedEntities.getSelf().getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
|
||||
final double maxReach = player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
|
||||
// +3 would be 3 + 3 = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
|
||||
final double distance = maxReach + 3;
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
final Vector eyePos = new Vector(from.getX(), 0, from.getZ());
|
||||
for (Vector lookVec : possibleLookDirs) {
|
||||
final Vector3dm eyePos = new Vector3dm(from.getX(), 0, from.getZ());
|
||||
for (Vector3dm lookVec : possibleLookDirs) {
|
||||
for (double eye : possibleEyeHeights) {
|
||||
eyePos.setY(from.getY() + eye);
|
||||
Vector endReachPos = eyePos.clone().add(new Vector(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
|
||||
Vector3dm endReachPos = eyePos.clone().add(new Vector3dm(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
|
||||
|
||||
Vector intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
|
||||
Vector3dm intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
|
||||
|
||||
if (ReachUtils.isVecInside(targetBox, eyePos)) {
|
||||
minDistance = 0;
|
||||
@@ -247,21 +253,19 @@ public class Reach extends Check implements PacketCheck {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private static final CheckResult NONE = new CheckResult(ResultType.NONE, "");
|
||||
|
||||
private record CheckResult(ResultType type, String verbose) {
|
||||
public boolean isFlag() {
|
||||
return type != ResultType.NONE;
|
||||
}
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
this.cancelImpossibleHits = config.getBooleanElse("Reach.block-impossible-hits", true);
|
||||
this.threshold = config.getDoubleElse("Reach.threshold", 0.0005);
|
||||
}
|
||||
|
||||
private enum ResultType {
|
||||
REACH, HITBOX, NONE
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
this.cancelImpossibleHits = config.getBooleanElse("Reach.block-impossible-hits", true);
|
||||
this.threshold = config.getDoubleElse("Reach.threshold", 0.0005);
|
||||
private record CheckResult(ResultType type, String verbose) {
|
||||
public boolean isFlag() {
|
||||
return type != ResultType.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 625 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user