Platform Independence (future Sponge, Fabric, Neoforge, Velocity, etc... support) (#2024)
* 1.21.5 partial changes * leftover * cleanup * check if player is in vehicle * 1;1 input transformation * forgot to push that * notes * i hate mutability * not the case * this is the right way * note * java style * initial block collisions support * incorrect fix for powder snow issues (1.21.4) * support 1.18.2+ horizontal collision detection * Seperated/Abstracted: - Thread Management - GrimEntity/PlatformPlayer + PlatformInventory - PlatformWorld, PlatformChunk, Location - Removed many bukkit dependencies - Migrated Bukkit Events to own code section - Disabled BStats temporarily * Refactor Part 2: - Replace Vectors - Replace ChatColor.translateColorCodes() * Stash code * Almost there; just events and bukkit extensions left * Fix plugin compilation and exeution of commands * Refactor Part 3: Checkpoint Need to implement: - Fix PlaceHolderAPI and ManInMyVan's MessageUtil logic error - Add BStats back - Add platform independent Permissions - Make TickEndEvent handling platform independent Need to Test: - ProxyAlertMessenger - Commands * Platform Independence Achieved! * Multi-module project init setup * Complete multi-module project setup * Fabric Support MVP - Registering permissions likely incomplete - Building jar incomplete; only works in Debug mode - Exempting on reload not done - Plugin Channels not implemented * Platform loading fixes * Refactor resyncPosition() internally; may move to platformPlayer in future * Beta Fabric Support Complete + General Bug Fixes: - Generate autocompletions for permissions - Make OP, and enable-on-join permissions false by default even for ops - Fixed usage of isWorldLoaded() in pre-migration codebase from breaking 1.8 support - Numerous command loader bugs fixed - A lot more * Fix Fabric execution and shutdown; Initial Fabric build script * Finish Fabric buildscript; now builds runnable jar * Fix Actions workflow * Build against new Grim API instead of locally * Temporarily build against my fork to fix PacketEvent's broken Fabric support * Fix scheduler hierachy issue * Moderate refactoring and codebase cleanup Fixed GitHub actions Note that Fabric platform is missing: - Pistons - Providing an instance of GrimExternalAPI for other plugins/mods to get - and more * PE datatype refactor; Fix Folia support * Fix endTick on Folia * Refactor Fabric to support 1.21.4, 1.21.1, and (soon) 1.16.1 * Add 1.20.1 support (once PE is fixed) * Actuallly commit 1.20.4 support * Fix Legacy (< 1.16.5) Big DripLeaf CollisionBox modeling * Fix project build issues and fix 1.20.1 support * Configure builds to use shared lib versions files; push for rebuild with updated PE; (Working 1.20.1) * Code cleanup * Minor code cleanup * Bump Fabric loom version; trigger rebuild on updated PE fork with Fabric fixes * Fix 1.8 support using non-existent inventory method * Fix running fabric in IDE and dev mode Credit: @Bawnorton * Hopefully Fix inventory errors * Cleanup Fabric buildscript * Fix rare preconditions error with checking for null platformPlayer * Fix Build error from rebasing https://github.com/GrimAnticheat/Grim/commit/aab710dd8b55bc6fbe88f0f4c79aa214527a20dd * Code cleanup to address code review concerns * Fix build issues with relocation on bukkit; force rebuild for fabric registry fix with PE * Fix library relocation typo * Bump snakeyaml version for Fabric support * Build against slim configuralize for fabric support * Fix Geyser-Fabric compatability * Initable refactor; support multiple types of initables as one object; shutdown fabric bstats * Fix updating native ServerPlayerEntity reference; Refactor @NonNull annotations * Translation parity (and more/better) with pre-platform-independence port * Make Grim rely on JiJed and loaded PE API; Transition PacketPlayerDigging to be cross-platform from upstream * Add support for Spigot 1.17 - 1.18.2 itemUsageReset() - Also decrease allocated via gradle.properties - Forces rebuild with new PE which will fix Geyser detection * Only include fabricAPI modules we use, reuse dependency code for multiple projects * New API refactor with getEventBus() * Minor Build optimization * Bump RAM allocation to Gradle in root gradle.properties * Fix build issues with downloading Conditional Mixin library for PE Fabric * Partially fix lack of suggestions in cloud commands when incorrect command/typo is typed (only works when required arguments missing in a command on modern brigadier servers due to cloud bug, will fix later) - Also force rebuild with new PE * Fix build errors from rebasing * Add explicit dependency for parent mod on packetevents * Refactor to use new API with better EventBus and consolidate event-bus related code to be non-platform specific * Fix error with teleporting between dimensions * Update Loom; Buildscript consolidation and improvements * Initial 1.21.5 Support * Significantly reduce Fabric jar size * Fix 1.21.5 Support breaking with new Chunk format * Improve performance of underlying Collection used for exemptUsers * Update API; Add support for overriding player.resyncPosition(x, y, z, sequence) * Minor Annotation Style changes * Execute piston updates from Bukkit Event in player netty channel. - This fixes a rare race condition with pistons. https://github.com/GrimAnticheat/Grim/issues/2031 - Reduces load on main thread (we check for isChunkLoaded() and do processing in netty channel helper now) * Fix 1.21.5 support and entity metadata - Fixed 1.21.5 Pig Variant entity metadata handling - Read Strider isShaking value from entity metadata - (Hopefully) Fix 1.8 horse saddle modeling * Fix working with cooldown groups * Fix 1.21.5 Inventory compatability issues * Improve performance of internal sendAlert command invocations * Fix PlaceholderAPI replacements * Address code review styling concerns. Fix errors from rebasing on 2.0. * Fully replace underlying native inventory and player objects when reset on death. - Fixes fastbreak issues after dying with keepInventory off * Fix rebase on top of more 1.21.5 and other movement fixes. * Implement new versioning scheme: https://github.com/GrimAnticheat/Grim/wiki/Versions-and-Versioning * Rewrite Fabric multi-version support - handles 1.16.1 - 1.21.5 (currently only 1.19.3+ works due to Cloud command library limitations) - Java 21 -> Java 17 requirement for Fabric on older versions that didn't require Java 21 * Startup time optimization * Fix Fabric Inventory from multi-version refactor * Fix update checker by fixing version parsing for new version schema * Complete translations * Improve Reach and Hitboxes config * Fix Entity Modeling - Save data for what mobs can be hit for future hit-un-hittable-entity-check - Fix bounding boxes and modeling sizes for some entities (firework rocket, falling block, guardians, armor stands) - Fix modeling of numerous types of baby mobs * Add support for Fastbreak on blocks that don't exist in client version * Fix error when kicking player on Fabric 1.20.2+ * Fix Fabric PlatformEntity and PlatformInventory loader issue * Fix executing commands in Fabric 1.20.3+ * Build 1.17 module against 1.17.1; Fix loader naming inconsistencies * Fix logic error with FabricAsyncScheduler's runAtFixedRate() * use our own webhook system * Fix build issues with compileOnly exports and RotationData/BadPacketsB imports * Fix issue with running some commands on 1.21.2+ * update GrimAPI used in build script * Fix building with new API --------- Co-authored-by: cyramek <xcyramek@gmail.com> Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
This commit is contained in:
642 files changed
+16387
-6196
No files matched your search
@@ -27,12 +27,43 @@ jobs:
|
||||
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 Computed Version from Gradle
|
||||
id: extract-version
|
||||
run: |
|
||||
VERSION=$(./gradlew -q printVersion | grep VERSION= | cut -d '=' -f2)
|
||||
echo "VERSION: $VERSION"
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew 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/
|
||||
+32
-207
@@ -1,215 +1,40 @@
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission
|
||||
/**
|
||||
* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
* ┃ GrimAC Build Configuration ┃
|
||||
* ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
*
|
||||
* 🔧 Build Flags:
|
||||
* -PshadePE=true → Enables 'lite' mode
|
||||
* -Prelocate=false → Adds 'no_relocate' modifier
|
||||
* -Prelease=true → Removes commit/modifiers for release build
|
||||
*
|
||||
* Logic in: buildSrc/versioning/BuildConfig.kt & VersionUtil.kt
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("java")
|
||||
id("maven-publish")
|
||||
id("com.gradleup.shadow") version "9.0.0-beta6"
|
||||
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()
|
||||
}
|
||||
}
|
||||
import versioning.BuildConfig
|
||||
import versioning.VersionUtil
|
||||
|
||||
val baseVersion = "2.3.72"
|
||||
group = "ac.grim.grimac"
|
||||
version = "2.3.72"
|
||||
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
|
||||
version = VersionUtil.computeVersion(baseVersion)
|
||||
description = "Libre simulation anticheat designed for 1.21 with 1.8–1.21 support, powered by PacketEvents 2.0."
|
||||
|
||||
// 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()
|
||||
?: System.getenv("RELOCATE_JAR")?.toBoolean()
|
||||
?: true
|
||||
println("⚙️ Build configuration:")
|
||||
println(" shadePE = ${BuildConfig.shadePE}")
|
||||
println(" relocate = ${BuildConfig.relocate}")
|
||||
println(" release = ${BuildConfig.release}")
|
||||
println(" version = $version")
|
||||
|
||||
repositories {
|
||||
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://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 {
|
||||
compileOnly("io.papermc.paper:paper-api:1.20.6-R0.1-SNAPSHOT")
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.8.0-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:05e31d62f2")
|
||||
|
||||
implementation("net.kyori:adventure-text-minimessage:4.20.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("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.register("printVersion") {
|
||||
group = "versioning"
|
||||
description = "Prints the computed project version"
|
||||
doLast {
|
||||
println("VERSION=$version")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
dependsOn(tasks.spotlessApply)
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
options.release.set(17)
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
disableAutoTargetJvm()
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
artifact(tasks["shadowJar"])
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
manifest {
|
||||
attributes["paperweight-mappings-namespace"] = "mojang"
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
// ---------- Java Compile Optimization ----------
|
||||
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,76 @@
|
||||
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()
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tasks {
|
||||
withType<JavaCompile>().configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
options.release.set(17)
|
||||
}
|
||||
|
||||
build {
|
||||
// Ensure spotlessApply runs before build
|
||||
dependsOn(tasks.named("spotlessApply"))
|
||||
}
|
||||
|
||||
// Process resources (e.g., for plugin metadata files)
|
||||
processResources {
|
||||
inputs.property("version", project.version)
|
||||
filesMatching(listOf( // "plugin.yml", Bukkit variable expansion taken care of by net.minecrell.plugin-yml.bukkit
|
||||
"bungee.yml", "velocity-plugin.json", "fabric.mod.json")
|
||||
) {
|
||||
expand("version" to project.version)
|
||||
}
|
||||
}
|
||||
|
||||
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,407 @@
|
||||
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)) // Retain existing logic for top-level fabric.mod.json parsing
|
||||
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 fabricModJsonEntry: ZipEntry? = embeddedJar.getEntry("fabric.mod.json")
|
||||
if (fabricModJsonEntry != null) {
|
||||
embeddedJar.getInputStream(fabricModJsonEntry).bufferedReader().use { reader ->
|
||||
val jsonContent = reader.readText()
|
||||
val jsonElement = Json.parseToJsonElement(jsonContent)
|
||||
val jsonObject = jsonElement.jsonObject
|
||||
|
||||
// Extract id and parse into group
|
||||
val id = jsonObject["id"]?.jsonPrimitive?.content
|
||||
?: throw IllegalStateException("Missing 'id' in fabric.mod.json of embedded JAR: $entryName")
|
||||
val idWithDots = id.replace("_", ".")
|
||||
val lastDotIndex = idWithDots.lastIndexOf(".")
|
||||
val group = if (lastDotIndex != -1) idWithDots.substring(0, lastDotIndex) else ""
|
||||
|
||||
// Extract name and version from the JAR filename
|
||||
val jarName = entryName.substringAfterLast("/").removeSuffix(".jar")
|
||||
val (name, version) = parseNameAndVersionFromJarName(jarName)
|
||||
?: throw IllegalStateException("Could not parse name and version from JAR filename: $jarName")
|
||||
|
||||
// Create DependencyIdentifier (classifier is empty for now)
|
||||
val depId = DependencyIdentifier(group, name, version)
|
||||
embeddedJars.add(depId)
|
||||
project.logger.debug("Identified embedded dependency from fabric.mod.json and filename: {}", depId)
|
||||
}
|
||||
} else {
|
||||
project.logger.error("No fabric.mod.json found in embedded JAR: {}. Skipping.", entryName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
project.logger.error("Failed to analyze JAR file $jarFile for embedded JARs: ${e.message}")
|
||||
}
|
||||
return embeddedJars
|
||||
}
|
||||
|
||||
fun parseNameAndVersionFromJarName(jarName: String): Pair<String, String>? {
|
||||
val versionStartRegex = Regex("-(?=\\d)")
|
||||
// Use regex to find the position of the hyphen followed by a digit
|
||||
val versionStartMatch = versionStartRegex.find(jarName) ?: return null
|
||||
val versionStartIndex = versionStartMatch.range.first
|
||||
|
||||
// Split the JAR name into name and version at the version start index
|
||||
val name = jarName.substring(0, versionStartIndex)
|
||||
val version = jarName.substring(versionStartIndex + 1) // Skip the hyphen
|
||||
|
||||
return if (name.isNotEmpty() && version.isNotEmpty()) {
|
||||
Pair(name, version)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
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,47 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import versioning.BuildConfig
|
||||
|
||||
plugins {
|
||||
id("com.gradleup.shadow")
|
||||
}
|
||||
|
||||
// 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 (BuildConfig.relocate) {
|
||||
if (BuildConfig.shadePE) {
|
||||
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("net.kyori", "ac.grim.grimac.shaded.kyori") // use PE's built-in adventure instead when not shading PE
|
||||
}
|
||||
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("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,38 @@
|
||||
package versioning
|
||||
|
||||
/**
|
||||
* BuildConfig provides access to user-defined build flags that control how a GrimAC
|
||||
* build is assembled. These flags are set via Gradle project properties or environment variables.
|
||||
*
|
||||
* You can use these flags to enable/disable features like shading, relocation, or release mode.
|
||||
*
|
||||
* Usage (command line):
|
||||
* ```
|
||||
* ./gradlew build -PshadePE=true -Prelocate=false -Prelease=true
|
||||
* ```
|
||||
*
|
||||
* Or using environment variables:
|
||||
* ```
|
||||
* SHADE_PE=true RELOCATE_JAR=false RELEASE=true ./gradlew build
|
||||
* ```
|
||||
*
|
||||
* @property shadePE If true, shades PacketEvents into the jar. Default: true.
|
||||
* @property relocate If true, relocates shaded dependencies to avoid conflicts. Default: true.
|
||||
* @property release If true, omits commit hash and modifiers from version string. Default: false.
|
||||
*/
|
||||
object BuildConfig {
|
||||
val shadePE: Boolean
|
||||
get() = System.getProperty("shadePE")?.toBoolean()
|
||||
?: System.getenv("SHADE_PE")?.toBoolean()
|
||||
?: true
|
||||
|
||||
val relocate: Boolean
|
||||
get() = System.getProperty("relocate")?.toBoolean()
|
||||
?: System.getenv("RELOCATE_JAR")?.toBoolean()
|
||||
?: true
|
||||
|
||||
val release: Boolean
|
||||
get() = System.getProperty("release")?.toBoolean()
|
||||
?: System.getenv("RELEASE")?.toBoolean()
|
||||
?: false
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package versioning
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
/**
|
||||
* Utility for computing the version string of GrimAC artifacts.
|
||||
*
|
||||
* The version string is constructed based on:
|
||||
* - A base semantic version (e.g., "2.3.72")
|
||||
* - Git commit hash (unless in release mode)
|
||||
* - Git branch name (unless in release mode or main)
|
||||
* - Modifiers (e.g., lite, no_relocate) for non-default build configurations
|
||||
*
|
||||
* Example outputs:
|
||||
* - `2.3.72` (release build)
|
||||
* - `2.3.72-a4f8b21+lite` (preview build without PE shading)
|
||||
* - `2.3.72-feature_branch-a4f8b21+lite-no_relocate`
|
||||
*
|
||||
* @see BuildConfig for controlling the release/modifier behavior
|
||||
*/
|
||||
object VersionUtil {
|
||||
|
||||
/**
|
||||
* Computes the full version string for the build.
|
||||
*
|
||||
* @param baseVersion The base semantic version (e.g., "2.3.72")
|
||||
* @return Full version string including commit hash, branch, and modifiers if applicable
|
||||
*/
|
||||
fun computeVersion(baseVersion: String): String {
|
||||
if (BuildConfig.release) {
|
||||
return baseVersion
|
||||
}
|
||||
|
||||
val commitHash = getGitCommitHash()
|
||||
val branch = getGitBranch()
|
||||
|
||||
val modifiers = buildList {
|
||||
if (!BuildConfig.shadePE) add("lite")
|
||||
if (!BuildConfig.relocate) add("no_relocate")
|
||||
}.takeIf { it.isNotEmpty() }?.joinToString("-")
|
||||
|
||||
return buildString {
|
||||
append(baseVersion)
|
||||
append("-")
|
||||
branch?.let { append("$it-") }
|
||||
append(commitHash)
|
||||
modifiers?.let { append("+$modifiers") }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current Git commit as a short hash.
|
||||
*/
|
||||
private fun getGitCommitHash(): String {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
ProcessBuilder("git", "rev-parse", "--short", "HEAD")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.apply { waitFor() }
|
||||
.inputStream
|
||||
.use { stdout.writeBytes(it.readAllBytes()) }
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current Git branch, sanitised for use in file names.
|
||||
* If the branch is "main" or "2.0", returns null.
|
||||
*
|
||||
* Any slash (/) in the branch name is replaced with an underscore (_)
|
||||
* to avoid filesystem issues.
|
||||
*/
|
||||
private fun getGitBranch(): String? {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
|
||||
ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.apply { waitFor() }
|
||||
.inputStream.use { stdout.writeBytes(it.readAllBytes()) }
|
||||
|
||||
val branch = stdout.toString().trim()
|
||||
|
||||
return when (branch) {
|
||||
"main", "2.0" -> null // ← ignore these branches
|
||||
else -> branch.replace("/", "_")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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://repo.grim.ac/snapshots") { // Grim API
|
||||
content {
|
||||
includeGroup("ac.grim.grimac")
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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,201 @@
|
||||
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.brigadier.BrigadierSetting;
|
||||
import org.incendo.cloud.brigadier.CloudBrigadierManager;
|
||||
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.paper.LegacyPaperCommandManager;
|
||||
import org.incendo.cloud.setting.Configurable;
|
||||
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();
|
||||
CloudBrigadierManager<Sender, ?> cbm = manager.brigadierManager();
|
||||
Configurable<BrigadierSetting> settings = cbm.settings();
|
||||
settings.set(BrigadierSetting.FORCE_EXECUTABLE, true);
|
||||
} 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()
|
||||
);
|
||||
}
|
||||
}
|
||||
+21
-11
@@ -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.convert.BukkitConversionUtils;
|
||||
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;
|
||||
@@ -55,11 +55,16 @@ public class PistonEvent implements Listener {
|
||||
piston.getY() + event.getDirection().getModY(),
|
||||
piston.getZ() + event.getDirection().getModZ()));
|
||||
|
||||
boolean finalHasSlimeBlock = hasSlimeBlock;
|
||||
boolean finalHasHoneyBlock = hasHoneyBlock;
|
||||
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);
|
||||
player.latencyUtils.addRealTimeTaskAsync(player.lastTransactionSent.get(), () -> player.compensatedWorld.activePistons.add(data));
|
||||
}
|
||||
int lastTrans = player.lastTransactionSent.get();
|
||||
player.runSafely(() -> {
|
||||
if (player.compensatedWorld.isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
|
||||
PistonData data = new PistonData(BukkitConversionUtils.fromBukkitFace(event.getDirection()), boxes, lastTrans, true, finalHasSlimeBlock, finalHasHoneyBlock);
|
||||
player.latencyUtils.addRealTimeTaskAsync(lastTrans, () -> player.compensatedWorld.activePistons.add(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +84,7 @@ public class PistonEvent implements Listener {
|
||||
boolean hasHoneyBlock = false;
|
||||
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
BlockFace face = BlockFaceHelper.fromBukkitFace(event.getDirection());
|
||||
BlockFace face = BukkitConversionUtils.fromBukkitFace(event.getDirection());
|
||||
|
||||
// The event was called without blocks and is therefore in the right direction
|
||||
if (event.getBlocks().isEmpty()) {
|
||||
@@ -108,11 +113,16 @@ public class PistonEvent implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
boolean finalHasSlimeBlock = hasSlimeBlock;
|
||||
boolean finalHasHoneyBlock = hasHoneyBlock;
|
||||
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);
|
||||
player.latencyUtils.addRealTimeTaskAsync(player.lastTransactionSent.get(), () -> player.compensatedWorld.activePistons.add(data));
|
||||
}
|
||||
int lastTrans = player.lastTransactionSent.get();
|
||||
player.runSafely(() -> {
|
||||
if (player.compensatedWorld.isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
|
||||
PistonData data = new PistonData(BukkitConversionUtils.fromBukkitFace(event.getDirection()), boxes, lastTrans, false, finalHasSlimeBlock, finalHasHoneyBlock);
|
||||
player.latencyUtils.addRealTimeTaskAsync(lastTrans, () -> 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);
|
||||
}
|
||||
}
|
||||
+13
-16
@@ -1,16 +1,17 @@
|
||||
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;
|
||||
import ac.grim.grimac.utils.reflection.PaperUtils;
|
||||
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 io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
@@ -22,18 +23,18 @@ 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, Listener {
|
||||
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 (FoliaScheduler.isFolia()) {
|
||||
if (GrimAPI.INSTANCE.getPlatform() == Platform.FOLIA) {
|
||||
PaperUtils.registerTickEndEvent(this, this::tickAllFoliaPlayers);
|
||||
return;
|
||||
}
|
||||
@@ -43,23 +44,20 @@ public class TickEndEvent implements Initable, Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private void onEndOfTick(GrimPlayer player) {
|
||||
player.checkManager.getEntityReplication().onEndOfTickEvent();
|
||||
}
|
||||
|
||||
private void tickAllPlayers() {
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.disableGrim) continue;
|
||||
onEndOfTick(player);
|
||||
super.onEndOfTick(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickAllFoliaPlayers() {
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.disableGrim) continue;
|
||||
Player p = player.bukkitPlayer;
|
||||
if (p == null || !Bukkit.isOwnedByCurrentRegion(p)) continue;
|
||||
onEndOfTick(player);
|
||||
if (player.platformPlayer == null) continue;
|
||||
Player p = ((BukkitPlatformPlayer) player.platformPlayer).getNative();
|
||||
if (!Bukkit.isOwnedByCurrentRegion(p)) continue;
|
||||
super.onEndOfTick(player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,5 +91,4 @@ public class TickEndEvent implements Initable, Listener {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+26
-22
@@ -1,9 +1,12 @@
|
||||
package ac.grim.grimac.utils.nmsutil;
|
||||
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 lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -12,26 +15,24 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@UtilityClass
|
||||
public class BukkitNMS {
|
||||
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 Player player) {
|
||||
public void resetItemUsage(@Nullable PlatformPlayer player) {
|
||||
if (player != null) {
|
||||
resetItemUsage.accept(player);
|
||||
resetItemUsage.accept(((BukkitPlatformPlayer) player).getNative());
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private @NotNull ItemUsageReset createItemUsageResetFunction() {
|
||||
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
|
||||
|
||||
if (version.isNewerThanOrEquals(ServerVersion.V_1_17)) {
|
||||
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)
|
||||
@@ -67,20 +68,23 @@ public class BukkitNMS {
|
||||
}
|
||||
|
||||
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("net.minecraft.server." + nmsPackage + ".EntityLiving").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" -> "clearActiveItem";
|
||||
default -> throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
|
||||
}
|
||||
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));
|
||||
+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(commandSender instanceof OfflinePlayer offlinePlayer ? offlinePlayer : null, string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String replacePlaceholders(@Nullable PlatformPlayer object, @NonNull String string) {
|
||||
if (!MessageUtil.hasPlaceholderAPI) return string;
|
||||
return PlaceholderAPI.setPlaceholders(object instanceof BukkitPlatformPlayer bukkitPlatformPlayer ? bukkitPlatformPlayer.getBukkitPlayer() : null, 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 name The permission node to register (e.g., "grim.exempt.checkname").
|
||||
* @param defaultValue The default value for the permission.
|
||||
*/
|
||||
@Override
|
||||
public void registerPermission(String name, PermissionDefaultValue defaultValue) {
|
||||
final Permission bukkitPermission = Bukkit.getPluginManager().getPermission(name);
|
||||
if (bukkitPermission == null) {
|
||||
Bukkit.getPluginManager().addPermission(new Permission(name, BukkitConversionUtils.toBukkitPermissionDefault(defaultValue)));
|
||||
} else {
|
||||
bukkitPermission.setDefault(BukkitConversionUtils.toBukkitPermissionDefault(defaultValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
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 {
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
+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,157 @@
|
||||
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 io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
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 SpigotConversionUtil.fromBukkitGameMode(bukkitPlayer.getGameMode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameMode(GameMode gameMode) {
|
||||
bukkitPlayer.setGameMode(SpigotConversionUtil.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);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
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;
|
||||
|
||||
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 AsyncScheduler getAsyncScheduler() {
|
||||
return bukkitAsyncScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GlobalRegionScheduler getGlobalRegionScheduler() {
|
||||
return bukkitGlobalRegionScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull EntityScheduler getEntityScheduler() {
|
||||
return bukkitEntityScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull 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);
|
||||
}
|
||||
}
|
||||
+3
-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,7 @@ 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 +21,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) {
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
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.world.BlockFace;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this enum to a Bukkit PermissionDefault.
|
||||
*
|
||||
* @return The corresponding Bukkit PermissionDefault.
|
||||
*/
|
||||
public static org.bukkit.permissions.PermissionDefault toBukkitPermissionDefault(PermissionDefaultValue permissionDefaultValue) {
|
||||
return switch (permissionDefaultValue) {
|
||||
case TRUE -> org.bukkit.permissions.PermissionDefault.TRUE;
|
||||
case FALSE -> org.bukkit.permissions.PermissionDefault.FALSE;
|
||||
case OP -> org.bukkit.permissions.PermissionDefault.OP;
|
||||
case NOT_OP -> org.bukkit.permissions.PermissionDefault.NOT_OP;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
+4
-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
|
||||
@@ -52,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()) {
|
||||
+6
-5
@@ -1,7 +1,8 @@
|
||||
package ac.grim.grimac.utils.reflection;
|
||||
package ac.grim.grimac.platform.bukkit.utils.reflection;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
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;
|
||||
@@ -19,7 +20,7 @@ public class PaperUtils {
|
||||
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", Location.class);
|
||||
ASYNC_TELEPORT = ReflectionUtils.hasMethod(Entity.class, "teleportAsync", org.bukkit.Location.class);
|
||||
}
|
||||
|
||||
public static CompletableFuture<Boolean> teleportAsync(final Entity entity, final Location location) {
|
||||
@@ -36,10 +37,10 @@ public class PaperUtils {
|
||||
try {
|
||||
Class<?> clazz = ReflectionUtils.getClass("com.destroystokyo.paper.event.server.ServerTickEndEvent");
|
||||
if (clazz == null) return false;
|
||||
GrimAPI.INSTANCE.getPlugin().getServer().getPluginManager().registerEvent((Class<? extends Event>) clazz,
|
||||
GrimACBukkitLoaderPlugin.LOADER.getServer().getPluginManager().registerEvent((Class<? extends Event>) clazz,
|
||||
listener,
|
||||
EventPriority.NORMAL,
|
||||
(l, event) -> runnable.run(), GrimAPI.INSTANCE.getPlugin());
|
||||
(l, event) -> runnable.run(), GrimACBukkitLoaderPlugin.LOADER);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogUtil.exception("Failed to register tick end event", e);
|
||||
@@ -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,53 @@
|
||||
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://repo.grim.ac/snapshots") { // Grim API
|
||||
content {
|
||||
includeGroup("ac.grim.grimac")
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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.fastutil)
|
||||
api(libs.adventure.text.minimessage)
|
||||
api(libs.jetbrains.annotations)
|
||||
|
||||
// Used for local testing:
|
||||
// api("ac.grim.grimac:GrimAPI:1.0")
|
||||
api("ac.grim.grimac:GrimAPI:any-9d6a0e6b7f")
|
||||
|
||||
compileOnly(libs.floodgate.api)
|
||||
compileOnly(libs.via.version.api)
|
||||
compileOnly(libs.netty)
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
from(components["java"])
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.api.event.EventBus;
|
||||
import ac.grim.grimac.api.event.OptimizedEventBus;
|
||||
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.Sender;
|
||||
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.incendo.cloud.CommandManager;
|
||||
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 EventBus eventBus;
|
||||
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.eventBus = new OptimizedEventBus();
|
||||
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();
|
||||
}
|
||||
|
||||
public CommandManager<Sender> getCommandManager() {
|
||||
return loader.getCommandManager();
|
||||
}
|
||||
|
||||
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.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.getEventBus().post(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.getEventBus().post(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());
|
||||
}
|
||||
|
||||
}
|
||||
+19
-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.getEventBus().post(event);
|
||||
if (event.isCancelled()) return false;
|
||||
|
||||
player.punishmentManager.handleViolation(this);
|
||||
File renamed without changes.
File renamed without changes.
+2
-2
@@ -8,12 +8,12 @@ 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.self.getRiding() != null) {
|
||||
File renamed without changes.
+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.
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.
File renamed without changes.
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.
+4
-4
@@ -10,15 +10,15 @@ 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) {
|
||||
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.
+4
-4
@@ -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()) {
|
||||
+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();
|
||||
+4
-5
@@ -16,17 +16,16 @@ 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 AirLiquidBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
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 final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_15_2);
|
||||
public AirLiquidBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
+5
-4
@@ -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,13 +20,14 @@ public class FarBreak extends Check implements BlockBreakCheck {
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || player.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));
|
||||
}
|
||||
|
||||
+19
-13
@@ -7,6 +7,8 @@ import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockBreakSpeed;
|
||||
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
@@ -28,13 +30,14 @@ 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();
|
||||
private final boolean clientOlderThanServer = PacketEvents.getAPI().getServerManager().getVersion().getProtocolVersion() > player.getClientVersion().getProtocolVersion();
|
||||
|
||||
public FastBreak(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
// The block the player is currently breaking
|
||||
Vector3i targetBlock = null;
|
||||
Vector3i targetBlockPosition = null;
|
||||
// The maximum amount of damage the player deals to the block
|
||||
//
|
||||
double maximumBlockDamage = 0;
|
||||
@@ -50,18 +53,21 @@ public class FastBreak extends Check implements BlockBreakCheck {
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action == DiggingAction.START_DIGGING) {
|
||||
WrappedBlockState block = blockBreak.block;
|
||||
|
||||
// Exempt all blocks that do not exist in the player version
|
||||
final WrappedBlockState defaultState = WrappedBlockState.getDefaultState(player.getClientVersion(), block.getType());
|
||||
if (defaultState.getType() == StateTypes.AIR || EXEMPT_STATES.contains(defaultState.getType())) {
|
||||
return;
|
||||
if (!ViaVersionUtil.isAvailable()) {
|
||||
// Exempt all blocks that do not exist in the player version
|
||||
final WrappedBlockState defaultState = WrappedBlockState.getDefaultState(player.getClientVersion(), blockBreak.block.getType());
|
||||
if (defaultState.getType() == StateTypes.AIR || EXEMPT_STATES.contains(defaultState.getType())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If client is older than the server, fetch block client actually sees from via
|
||||
// otherwise just return the server-side block (since if client is >= server version the block is guaranteed to exist in client version)
|
||||
WrappedBlockState block = clientOlderThanServer ? WrappedBlockState.getByGlobalId(player.getClientVersion(), player.getViaTranslatedBlockID(blockBreak.block.getGlobalId())) : blockBreak.block;
|
||||
|
||||
startBreak = System.currentTimeMillis() - (targetBlock == null ? 50 : 0); // ???
|
||||
targetBlock = blockBreak.position;
|
||||
startBreak = System.currentTimeMillis() - (targetBlockPosition == null ? 50 : 0); // ???
|
||||
targetBlockPosition = blockBreak.position;
|
||||
|
||||
maximumBlockDamage = BlockBreakSpeed.getBlockDamage(player, targetBlock);
|
||||
maximumBlockDamage = BlockBreakSpeed.getBlockDamage(player, block);
|
||||
|
||||
double breakDelay = System.currentTimeMillis() - lastFinishBreak;
|
||||
|
||||
@@ -80,7 +86,7 @@ public class FastBreak extends Check implements BlockBreakCheck {
|
||||
clampBalance();
|
||||
}
|
||||
|
||||
if (blockBreak.action == DiggingAction.FINISHED_DIGGING && targetBlock != null) {
|
||||
if (blockBreak.action == DiggingAction.FINISHED_DIGGING && targetBlockPosition != null) {
|
||||
double predictedTime = Math.ceil(1 / maximumBlockDamage) * 50;
|
||||
double realTime = System.currentTimeMillis() - startBreak;
|
||||
double diff = predictedTime - realTime;
|
||||
@@ -108,8 +114,8 @@ public class FastBreak extends Check implements BlockBreakCheck {
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
// Find the most optimal block damage using the animation packet, which is sent at least once a tick when breaking blocks
|
||||
// On 1.8 clients, via screws with this packet meaning we must fall back to the 1.8 idle flying packet
|
||||
if ((player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? event.getPacketType() == PacketType.Play.Client.ANIMATION : WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) && targetBlock != null) {
|
||||
maximumBlockDamage = Math.max(maximumBlockDamage, BlockBreakSpeed.getBlockDamage(player, targetBlock));
|
||||
if ((player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? event.getPacketType() == PacketType.Play.Client.ANIMATION : WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) && targetBlockPosition != null) {
|
||||
maximumBlockDamage = Math.max(maximumBlockDamage, BlockBreakSpeed.getBlockDamage(player, player.compensatedWorld.getBlock(targetBlockPosition)));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
File renamed without changes.
+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) {
|
||||
+9
-7
@@ -7,6 +7,7 @@ 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;
|
||||
@@ -16,7 +17,6 @@ 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 org.bukkit.util.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -25,16 +25,17 @@ 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
|
||||
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
|
||||
|
||||
@@ -49,7 +50,8 @@ public class RotationBreak extends Check implements BlockBreakCheck {
|
||||
|
||||
@Override
|
||||
public void onPostFlyingBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
|
||||
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
|
||||
|
||||
@@ -109,7 +111,7 @@ public class RotationBreak extends Check implements BlockBreakCheck {
|
||||
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<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
|
||||
Pair<Vector3dm, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
|
||||
|
||||
if (intercept.first() != null) return true;
|
||||
}
|
||||
+10
-9
@@ -10,32 +10,33 @@ import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
|
||||
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) {
|
||||
private boolean shouldExempt(final WrappedBlockState block, int yPos) {
|
||||
// lastLastBlock is always null when this happens, and lastBlock isn't
|
||||
if (lastLastBlock != null || lastBlock == null)
|
||||
return false;
|
||||
|
||||
// on pre 1.14.4 clients, the YPos of this packet is always the same
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) && pos.y != exemptedY)
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) && yPos != exemptedY)
|
||||
return false;
|
||||
|
||||
// and if this block is not an instant break
|
||||
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
|
||||
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, block) < 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,7 +44,7 @@ public class WrongBreak extends Check implements BlockBreakCheck {
|
||||
if (blockBreak.action == DiggingAction.START_DIGGING) {
|
||||
final Vector3i pos = blockBreak.position;
|
||||
|
||||
lastBlockWasInstantBreak = getBlockDamage(player, pos) >= 1;
|
||||
lastBlockWasInstantBreak = getBlockDamage(player, blockBreak.block) >= 1;
|
||||
lastCancelledBlock = null;
|
||||
lastLastBlock = lastBlock;
|
||||
lastBlock = pos;
|
||||
@@ -52,7 +53,7 @@ public class WrongBreak extends Check implements BlockBreakCheck {
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
|
||||
final Vector3i pos = blockBreak.position;
|
||||
|
||||
if (!shouldExempt(pos) && !pos.equals(lastBlock)) {
|
||||
if (!shouldExempt(blockBreak.block, pos.y) && !pos.equals(lastBlock)) {
|
||||
// https://github.com/GrimAnticheat/Grim/issues/1512
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || (!lastBlockWasInstantBreak && pos.equals(lastCancelledBlock))) {
|
||||
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
|
||||
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) {
|
||||
+28
-24
@@ -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,9 +92,11 @@ 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.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR)
|
||||
return;
|
||||
if (player.inVehicle()) return;
|
||||
if (entity.riding != null) return;
|
||||
|
||||
@@ -127,7 +132,8 @@ 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.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR)
|
||||
return false;
|
||||
if (player.inVehicle()) return false;
|
||||
|
||||
// Filter out what we assume to be cheats
|
||||
@@ -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) {
|
||||
@@ -212,13 +218,13 @@ public class Reach extends Check implements PacketCheck {
|
||||
// +3 would be 3 + 3 = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
|
||||
final double distance = 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.
+3
-3
@@ -16,13 +16,13 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOp
|
||||
@CheckData(name = "CrashD", description = "Clicking slots in lectern window")
|
||||
public class CrashD extends Check implements PacketCheck {
|
||||
|
||||
private MenuType type = MenuType.UNKNOWN;
|
||||
private int lecternId = -1;
|
||||
|
||||
public CrashD(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
private MenuType type = MenuType.UNKNOWN;
|
||||
private int lecternId = -1;
|
||||
|
||||
@Override
|
||||
public void onPacketSend(final PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW && isSupportedVersion()) {
|
||||
Loaded 100 of 642 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user