Compare commits

..
Author SHA1 Message Date
Axionize 646c32112e Fix 1.20.2 < || > 1.21.4 Reach False with Rot only packets 2025-07-24 08:43:44 -04:00
377 changed files with 3669 additions and 7652 deletions

No files matched your search

-2
View File
@@ -7,8 +7,6 @@ indent_style = space
insert_final_newline = true
max_line_length = 100
tab_width = 4
end_of_line = crlf
trim_trailing_whitespace = true
# intellij specific configuration
ij_continuation_indent_size = 8
-8
View File
@@ -30,14 +30,6 @@ body:
validations:
required: true
- type: input
attributes:
label: Client version
description: |
Provide the version of your Minecraft client.
validations:
required: true
- type: textarea
attributes:
label: Plugins
-229
View File
@@ -1,229 +0,0 @@
name: Reusable Build and Publish
on:
workflow_call:
inputs:
is-release-build:
description: 'True if this is a release build, which affects versioning and publishing.'
required: true
type: boolean
release-version-type:
description: 'The version type for Modrinth (e.g., release, beta, alpha).'
required: true
type: string
release-changelog:
description: 'The changelog content for the release.'
required: false
type: string
default: ''
run-build-scan:
description: 'Whether to enable Develocity build scan'
required: true
type: boolean
publish-artifacts:
description: 'If true, uploads artifacts to Modrinth and other distribution sites.'
required: true
type: boolean
secrets:
MODRINTH_ID:
required: false
MODRINTH_TOKEN:
required: false
BUILD_UPDATE_TOKEN:
required: true
BUILD_UPDATE_URL:
required: true
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
env:
MODRINTH_ID: ${{ secrets.MODRINTH_ID }}
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
GRIM_MAIN_BRANCH: ${{ github.event.repository.default_branch }}
BUILD_UPDATE_TOKEN: ${{ secrets.BUILD_UPDATE_TOKEN }}
steps:
- name: Checkout repository with full history
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 200
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
server-id: github
settings-path: ${{ github.workspace }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref_name != github.event.repository.default_branch && github.ref_name != 'dev' }}
- name: Cache Gradle Loom Cache
uses: actions/cache@v4
with:
path: .gradle/loom-cache
key: loom-cache-${{ runner.os }}-${{ hashFiles('**/libs.versions.toml', 'fabric/**/build.gradle.kts') }}
restore-keys: |
loom-cache-${{ runner.os }}
- name: Set Git Environment Variables
run: |
echo "GRIM_GIT_REPO=${{ github.event.repository.name }}" >> $GITHUB_ENV
echo "GRIM_GIT_ORG=${{ github.repository_owner }}" >> $GITHUB_ENV
- name: Compute version and Build with Gradle
id: build_with_version
run: |
# If any command in a pipeline fails, treat the pipeline as failed.
set -o pipefail
BUILD_ARGS="build"
if [[ "${{ inputs.is-release-build }}" == "true" ]]; then
BUILD_ARGS="$BUILD_ARGS -Prelease=true"
fi
# Conditionally add the --scan flag
if [[ "${{ inputs.run-build-scan }}" == "true" ]]; then
BUILD_ARGS="$BUILD_ARGS --scan"
fi
echo "Running: ./gradlew printVersion $BUILD_ARGS"
# Use 'tee' to both display the output live and save it to a file for parsing
VERSION=$(./gradlew printVersion $BUILD_ARGS | tee build-output.log | grep '^VERSION=' | tail -n1 | cut -d'=' -f2)
echo "build_version=$VERSION" >> $GITHUB_OUTPUT
echo "BUILD_VERSION=$VERSION" >> $GITHUB_ENV
echo "Build version: $VERSION"
- name: Publish Build Scan URL
# Only run this step if a scan was requested
if: ${{ inputs.run-build-scan == true }}
run: |
# Search the log file for the build scan URL and extract it
SCAN_URL=$(grep -o 'https://gradle.com/s/[^ ]*' build-output.log | head -n 1 || true)
if [[ -n "$SCAN_URL" ]]; then
echo "Found build scan URL: $SCAN_URL"
# Post a highly visible link to the Job Summary page
echo "### Gradle Build Scan" >> $GITHUB_STEP_SUMMARY
echo "A public build scan has been published and is available for inspection." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "[**View Build Scan →**]($SCAN_URL)" >> $GITHUB_STEP_SUMMARY
else
echo "Could not find build scan URL in build-output.log" >> $GITHUB_STEP_SUMMARY
fi
- name: Upload Bukkit Artifact
uses: actions/upload-artifact@v4
with:
name: grimac-bukkit
path: ${{ github.workspace }}/bukkit/build/libs/grimac-bukkit-${{ env.BUILD_VERSION }}.jar
if-no-files-found: error
- name: Upload Fabric Artifact
uses: actions/upload-artifact@v4
with:
name: grimac-fabric
path: ${{ github.workspace }}/fabric/build/libs/grimac-fabric-${{ env.BUILD_VERSION }}.jar
if-no-files-found: error
#------------------------------------------------------------------
# Generate/Prepare Changelog
#------------------------------------------------------------------
- name: Generate Changelog with git-cliff (for Dev Builds)
if: ${{ !inputs.is-release-build }}
id: git-cliff
uses: orhun/git-cliff-action@v4
with:
config: cliff.toml
args: --verbose ${{ github.event.before }}..${{ github.event.after }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # git-cliff needs a token
- name: Prepare Final Changelog
id: changelog
# Add this 'env' block to safely load the changelogs as environment variables
env:
RELEASE_NOTES: ${{ inputs.release-changelog }}
DEV_NOTES: ${{ steps.git-cliff.outputs.content }}
run: |
NOTES=""
if [[ "${{ inputs.is-release-build }}" == "true" ]]; then
# Use the environment variable for the release changelog.
# The double quotes are critical to preserve newlines!
NOTES="$RELEASE_NOTES"
else
# Use the environment variable for the dev changelog.
NOTES="$DEV_NOTES"
fi
if [ -z "$NOTES" ]; then
NOTES="* No new code changes in this build."
fi
# This is the correct way to set a multi-line output variable in Actions
{
echo "notes<<EOF"
echo "$NOTES"
echo "EOF"
} >> "$GITHUB_OUTPUT"
#------------------------------------------------------------------
# Publish to Modrinth & API
#------------------------------------------------------------------
- name: Publish Bukkit to Modrinth
if: ${{ inputs.publish-artifacts == true && env.MODRINTH_ID != '' && env.MODRINTH_TOKEN != '' }}
uses: Kir-Antipov/mc-publish@v3.3
with:
modrinth-id: ${{ secrets.MODRINTH_ID }}
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
modrinth-featured: ${{ inputs.is-release-build }} # Only feature release builds
files: bukkit/build/libs/grimac-bukkit-${{ env.BUILD_VERSION }}.jar
name: Grim Anticheat (Bukkit) ${{ env.BUILD_VERSION }}
version: ${{ env.BUILD_VERSION }}
version-type: ${{ inputs.release-version-type }}
changelog: ${{ steps.changelog.outputs.notes }}
loaders: |
bukkit
spigot
paper
folia
purpur
game-versions: '>=1.7 <=1.21.8'
- name: Publish Fabric to Modrinth
if: ${{ inputs.publish-artifacts == true && env.MODRINTH_ID != '' && env.MODRINTH_TOKEN != '' }}
uses: Kir-Antipov/mc-publish@v3.3
with:
modrinth-id: ${{ secrets.MODRINTH_ID }}
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
modrinth-featured: ${{ inputs.is-release-build }} # Only feature release builds
files: fabric/build/libs/grimac-fabric-${{ env.BUILD_VERSION }}.jar
name: Grim Anticheat (Fabric) ${{ env.BUILD_VERSION }}
version: ${{ env.BUILD_VERSION }}
version-type: ${{ inputs.release-version-type }}
changelog: ${{ steps.changelog.outputs.notes }}
loaders: |
fabric
game-versions: '>=1.16.1 <=1.21.8'
dependencies: 'fabric-api'
- name: Publish to API
if: ${{ inputs.publish-artifacts == true && env.BUILD_UPDATE_TOKEN != '' }}
run: |
curl -X POST \
-H "Content-Type: application/json" \
-H "User-Agent: GrimACBuilder/v1" \
-H "Authorization: Bearer ${{ secrets.BUILD_UPDATE_TOKEN }}" \
-d '{"org": "${{ github.repository_owner }}", "repository": "${{ github.event.repository.name }}", "branch": "${{ github.ref_name }}", "version": "${{ env.BUILD_VERSION }}"}' \
"${{ secrets.BUILD_UPDATE_URL }}"
+8 -12
View File
@@ -12,9 +12,13 @@
name: "CodeQL"
on:
workflow_dispatch:
push:
branches: [ dev ]
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '30 15 * * 2'
jobs:
analyze:
@@ -28,14 +32,14 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'java-kotlin' ]
language: [ 'java' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
@@ -47,14 +51,6 @@ jobs:
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
+57 -42
View File
@@ -1,44 +1,59 @@
name: Gradle Package (Development)
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
name: Gradle Package
on: [push, workflow_dispatch]
on:
workflow_dispatch:
inputs:
run-build-scan:
description: 'Run with public build scan (adds --scan)'
required: true
type: boolean
default: false
publish-artifacts:
description: 'Upload to Modrinth & API? (Uncheck for a dry run)'
type: boolean
default: true
push:
branches:
- 'main'
- '2.0'
- 'dev'
- 'release'
- 'release/**'
paths:
- '.github/workflows/**'
- 'buildSrc/**'
- 'bukkit/**'
- 'common/**'
- 'fabric/**'
- '**.java'
- '**.kt'
- '**.kts'
- '**.toml'
jobs:
call-build-workflow:
uses: ./.github/workflows/build-and-publish.yml
with:
is-release-build: false
release-version-type: alpha # Dev builds are always 'alpha'
run-build-scan: ${{ github.event.inputs.run-build-scan == 'true' }}
publish-artifacts: ${{ github.event.inputs.publish-artifacts != 'false' }}
secrets:
MODRINTH_ID: ${{ secrets.MODRINTH_ID }}
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
BUILD_UPDATE_TOKEN: ${{ secrets.BUILD_UPDATE_TOKEN }}
BUILD_UPDATE_URL: ${{ secrets.BUILD_UPDATE_URL }}
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4 # Handles Gradle wrapper validation and basic caching
- name: Cache Gradle Loom Cache
uses: actions/cache@v4
with:
path: .gradle/loom-cache # Path to Loom cache relative to workspace root
key: loom-cache-${{ runner.os }}-${{ hashFiles('**/libs.versions.toml', 'fabric/**/build.gradle.kts') }}
restore-keys: |
loom-cache-${{ runner.os }}
- name: Build with Gradle (Actual Build for Artifacts)
run: ./gradlew build
- name: Upload Bukkit Artifact
uses: actions/upload-artifact@v4
with:
name: grimac-bukkit
# Adding if-no-files-found for robustness
path: ${{ github.workspace }}/bukkit/build/libs/grimac-bukkit-*.jar
if-no-files-found: error
- name: Upload Fabric Artifact
uses: actions/upload-artifact@v4
with:
name: grimac-fabric
# Adding if-no-files-found for robustness
path: ${{ github.workspace }}/fabric/build/libs/grimac-fabric-*.jar
if-no-files-found: error
-21
View File
@@ -1,21 +0,0 @@
name: Publish Release
on:
release:
types: [published]
jobs:
call-release-workflow:
uses: ./.github/workflows/build-and-publish.yml
with:
is-release-build: true
release-version-type: release # Official releases are 'release'
# Use the body of the GitHub Release as the changelog
release-changelog: ${{ github.event.release.body }}
run-build-scan: false
publish-artifacts: true
secrets:
MODRINTH_ID: ${{ secrets.MODRINTH_ID }}
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
BUILD_UPDATE_TOKEN: ${{ secrets.BUILD_UPDATE_TOKEN }}
BUILD_UPDATE_URL: ${{ secrets.BUILD_UPDATE_URL }}
+15 -23
View File
@@ -5,34 +5,26 @@ making pull
requests to the project. *We're usually pretty lenient with pull requests, but this guide will help
make the process go more smoothly.*
### Acceptable Pull Requests
**Bug fixes** and **new features** are welcome. However, some things like heuristic-based checks
will **not** be accepted.
### Pull Request Guidelines
- **Compatibility**
- Any changes must be compatible with
the [supported environments](https://github.com/GrimAnticheat/Grim/wiki/Supported-environments) (Spigot, Paper, Folia, Fabric, etc.)
- The plugin must be compatible with minecraft versions 1.8 and higher. Exempting checks from specific versions is acceptable.
- The plugin must be able to run on Java 17 or higher. Changes that don't support Java 17 at runtime will not be accepted.
- **Non-acceptable pull requests**
- Heuristic-based checks will not be accepted; however, basic rate limiting such as blocking attacks based on CPS is acceptable.
- Checks that can be easily circumvented that don't block packets or fix anything are likely to not be accepted.
- Checks or features that are too specific to a single environment or minecraft version are likely to not be accepted.
- Changes that require large or unnecessary dependencies will likely not be accepted.
- **Pull request formatting**
- Create a new branch for your feature or fix when forking the repository.
- Reference related issues in your pull request description if applicable.
- Write clear and descriptive commit messages.
- **Code styling**
- Add code comments for complex logic or significant changes.
- Try to keep your code clean and avoid duplication.
- Thoroughly test your changes before submitting your pull request.
- Ensure any changes are compatible with
the [supported environments](https://github.com/GrimAnticheat/Grim/wiki/Supported-environments).
- Create a new branch for your feature or fix when forking the repository.
- Write clear and descriptive commit messages.
- Reference related issues in your pull request description if applicable.
- Add code comments for complex logic or significant changes.
- Try to keep your code clean and avoid duplication.
- Thoroughly test your changes before submitting your pull request.
### Development Notes
- GrimAC is built using [Gradle](https://gradle.org/) kotlin scripts.
- Java 21 is currently required to build the project. A minimum of Java 17 is required to run it.
- GrimAC is built using [Gradle](https://gradle.org/).
- Java 21 is currently required to build the project, but it is not required to run it.
### Questions & Support
+18 -27
View File
@@ -3,35 +3,28 @@
<div>
<a href="https://github.com/GrimAnticheat/Grim/actions/workflows/gradle-publish.yml">
<img alt="Workflow" src="https://img.shields.io/github/actions/workflow/status/GrimAnticheat/Grim/gradle-publish.yml?style=flat&logo=github"/>
</a>&nbsp;&nbsp;
<a href="https://modrinth.com/plugin/grimac">
<img alt="Modrinth" src="https://img.shields.io/modrinth/v/LJNGWSvH?style=flat&label=version&logo=modrinth">
</a>&nbsp;&nbsp;
<a href="https://modrinth.com/plugin/grimac#download">
<img alt="Downloads" src="https://img.shields.io/modrinth/dt/LJNGWSvH?style=flat&logo=modrinth&label=downloads&link=https%3A%2F%2Fmodrinth.com%2Fplugin%2Fgrimac%23download">
</a>&nbsp;&nbsp;
<img alt="Workflow" src="https://github.com/GrimAnticheat/Grim/actions/workflows/gradle-publish.yml/badge.svg" />
</a>
<a href="https://discord.grim.ac">
<img alt="Discord" src="https://img.shields.io/discord/811396969670901800?style=flat&label=discord&logo=discord">
<img alt="Discord" src="https://img.shields.io/discord/811396969670901800?style=flat&label=Discord&logo=discord">
</a>
</div>
<br>
</div>
GrimAC is an open source Minecraft anticheat designed to support the latest versions of Minecraft.
It currently supports minecraft versions 1.8–1.21. Geyser players are fully exempt from the anticheat to prevent false positives.
This project is considered feature-complete for the 2.0 (open-source) branch. If you would like a bug fix or enhancement and cannot sponsor the work, pull requests are welcome.
A premium version is planned, which will offer additional subscription-based paid checks, such as heuristics.
GrimAC is an open source minecraft anticheat designed for the latest versions of minecraft with
support for versions 1.8 and higher. Geyser players are fully exempt from the anticheat to prevent
false positives. This project is currently free and open source, but future versions will eventually
become paid and/or will include additional subscription based paid checks. If you would like a
bugfix or enhancement and cannot sponsor the work, pull requests are welcome.
## Downloads
- Latest updates:
- **[Modrinth](https://modrinth.com/plugin/grimac)** *(recommended)*
- GitHub
artifacts: [Bukkit](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/grimac-bukkit.zip), [Fabric](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/grimac-fabric.zip) *(bleeding edge)*
- Major releases only:
- ~~[Hangar](https://hangar.papermc.io/GrimAnticheat/GrimAnticheat)~~
- ~~[SpigotMC](https://www.spigotmc.org/resources/grim-anticheat.99923/)~~
- [Modrinth](https://modrinth.com/plugin/grimac)
- [Hangar](https://hangar.papermc.io/GrimAnticheat/GrimAnticheat)
- [SpigotMC](https://www.spigotmc.org/resources/grim-anticheat.99923/)
- *For bleeding edge builds use GitHub
artifacts*: [Bukkit](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/grimac-bukkit.zip), [Fabric](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/grimac-fabric.zip)
## Resources
@@ -39,13 +32,6 @@ A premium version is planned, which will offer additional subscription-based pai
- For answers to commonly asked questions visit the [FAQ](https://github.com/GrimAnticheat/Grim/wiki/FAQ).
- For community support and project discussion join our [Discord](https://discord.grim.ac).
## Pull Requests
See [Contributing](CONTRIBUTING.md) for more information about contributing and what our guidelines
are.
## Requirements & Installation
- Java 17 or higher. *For more details
@@ -70,6 +56,11 @@ information.
3. `./gradlew build`
4. The final jars will compile into the `<platform>/build/libs` folders
## Pull Requests
See [Contributing](CONTRIBUTING.md) for more information about contributing and what our guidelines
are.
## Grim Supremacy
What makes Grim stand out against other anticheats?
+15 -19
View File
@@ -1,10 +1,12 @@
/**
* GrimAC Build Configuration
* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
* ┃ GrimAC Build Configuration ┃
* ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
*
* Build Flags:
* -PshadePE=true - Enables 'lite' mode
* -Prelocate=false - Adds 'no_relocate' modifier
* -Prelease=true - Removes commit/modifiers for release build
* 🔧 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
*/
@@ -14,23 +16,17 @@ import versioning.VersionUtil
BuildConfig.init(project)
val baseVersion = "2.3.73"
val baseVersion = "2.3.72"
group = "ac.grim.grimac"
version = VersionUtil.computeVersion(baseVersion)
description = "Libre simulation anticheat designed for 1.21 with 1.8–1.21 support, powered by PacketEvents 2.0."
ext["timestamp"] = System.currentTimeMillis().toString()
ext["git_branch"] = VersionUtil.getGitBranch(true)
ext["git_commit"] = VersionUtil.getGitCommitHash(true)
ext["git_org"] = System.getenv("GRIM_GIT_ORG") ?: VersionUtil.getGitUser()
ext["git_repo"] = System.getenv("GRIM_GIT_REPO") ?: "Grim"
println("Build configuration:")
println(" shadePE = ${BuildConfig.shadePE}")
println(" relocate = ${BuildConfig.relocate}")
println(" mavenLocalOverride = ${BuildConfig.mavenLocalOverride}")
println(" release = ${BuildConfig.release}")
println(" version = $version")
println("⚙️ Build configuration:")
println(" shadePE = ${BuildConfig.shadePE}")
println(" relocate = ${BuildConfig.relocate}")
println(" mavenLocalOverride = ${BuildConfig.mavenLocalOverride}")
println(" release = ${BuildConfig.release}")
println(" version = $version")
tasks.register("printVersion") {
group = "versioning"
@@ -46,4 +42,4 @@ subprojects {
options.isFork = true
options.isIncremental = true
}
}
}
+1
View File
@@ -5,6 +5,7 @@ plugins {
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
@@ -1,5 +1,3 @@
import versioning.BuildConfig
plugins {
`java-library`
id("io.freefair.lombok")
@@ -18,6 +16,11 @@ java {
withJavadocJar()
}
// Lombok configuration
//lombok {
// version.set("1.18.30") // Use the version from your version catalog if available
//}
// Spotless configuration
spotless {
java {
@@ -35,6 +38,7 @@ spotless {
}
}
tasks {
withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
@@ -48,29 +52,11 @@ tasks {
// Process resources (e.g., for plugin metadata files)
processResources {
val properties = mapOf(
"timestamp" to rootProject.ext["timestamp"],
"version" to project.version.toString(),
"git_commit" to rootProject.ext["git_commit"],
"git_branch" to rootProject.ext["git_branch"],
"git_repo" to rootProject.ext["git_repo"],
"git_org" to rootProject.ext["git_org"],
"build_shade_pe" to BuildConfig.shadePE,
"build_relocate" to BuildConfig.relocate,
"build_release" to BuildConfig.release,
)
properties.forEach { (key, value) -> inputs.property(key, value) }
filesMatching(
listOf(
"bungee.yml",
"velocity-plugin.json",
"fabric.mod.json",
"grimac.properties"
)
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(properties)
expand("version" to project.version)
}
}
@@ -95,7 +95,7 @@ fun extractEmbeddedJars(jarFile: File, project: Project): Set<DependencyIdentifi
?: 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.take(lastDotIndex) else ""
val group = if (lastDotIndex != -1) idWithDots.substring(0, lastDotIndex) else ""
// Extract name and version from the JAR filename
val jarName = entryName.substringAfterLast("/").removeSuffix(".jar")
@@ -127,7 +127,7 @@ fun parseNameAndVersionFromJarName(jarName: String): Pair<String, String>? {
val versionStartIndex = versionStartMatch.range.first
// Split the JAR name into name and version at the version start index
val name = jarName.take(versionStartIndex)
val name = jarName.substring(0, versionStartIndex)
val version = jarName.substring(versionStartIndex + 1) // Skip the hyphen
return if (name.isNotEmpty() && version.isNotEmpty()) {
@@ -300,7 +300,7 @@ project.afterEvaluate {
val allEmbeddedDependencies = mutableMapOf<DependencyIdentifier, File>()
val actuallyIncludedDependencies = mutableSetOf<DependencyIdentifier>()
fun collectAllEmbeddedDependenciesForAfterEvaluate(dependencies: Set<ResolvedDependency>) {
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 ""}"
@@ -318,13 +318,13 @@ project.afterEvaluate {
)
}
}
collectAllEmbeddedDependenciesForAfterEvaluate(dep.children)
collectAllEmbeddedDependencies(dep.children)
}
}
}
processed.clear()
collectAllEmbeddedDependenciesForAfterEvaluate(resolvedDependencies)
collectAllEmbeddedDependencies(resolvedDependencies)
processed.clear()
processDependencies(
@@ -345,7 +345,7 @@ tasks.withType<Jar>().configureEach {
val allEmbeddedDependencies = mutableMapOf<DependencyIdentifier, File>()
val actuallyIncludedDependencies = mutableSetOf<DependencyIdentifier>()
fun collectAllEmbeddedDependenciesForJar(dependencies: Set<ResolvedDependency>) {
fun collectAllEmbeddedDependencies(dependencies: Set<ResolvedDependency>) {
dependencies.forEach { dep ->
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}"
if (!processed.contains(depKey)) {
@@ -362,13 +362,13 @@ tasks.withType<Jar>().configureEach {
)
}
}
collectAllEmbeddedDependenciesForJar(dep.children)
collectAllEmbeddedDependencies(dep.children)
}
}
}
processed.clear()
collectAllEmbeddedDependenciesForJar(resolvedDependencies)
collectAllEmbeddedDependencies(resolvedDependencies)
processed.clear()
@@ -5,10 +5,17 @@ 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 = "${rootProject.name}-${project.name}-${rootProject.version}.jar"
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveFileName.set("${rootProject.name}-${project.name}-${rootProject.version}.jar")
from(shadowCommon) // Use from() instead of direct assignment
if (BuildConfig.relocate) {
if (BuildConfig.shadePE) {
@@ -2,11 +2,6 @@ package versioning
import org.gradle.api.Project
import org.gradle.internal.extensions.stdlib.toDefaultLowerCase
import versioning.BuildConfig.init
import versioning.BuildConfig.mavenLocalOverride
import versioning.BuildConfig.release
import versioning.BuildConfig.relocate
import versioning.BuildConfig.shadePE
/**
* BuildConfig provides access to user-defined build flags that control how a Grim
@@ -15,9 +10,9 @@ import versioning.BuildConfig.shadePE
*
* Flags can be defined in three ways:
*
* 1. JVM system properties (-Dflag=value)
* 2. Gradle project properties (-Pflag=value or in gradle.properties)
* 3. Environment variables (FLAG=value)
* ① JVM system properties (-Dflag=value)
* ② Gradle project properties (-Pflag=value or in gradle.properties)
* ③ Environment variables (FLAG=value)
*
* You can use these to enable/disable features like shading, relocation, or release mode.
*
@@ -61,15 +56,24 @@ object BuildConfig {
// Unified resolution logic (System > Gradle > Env)
private fun resolveRaw(project: Project, key: String): String? =
System.getProperty(key) // 1. JVM (-Dkey=value)
?: project.findProperty(key)?.toString() // 2. Gradle (-Pkey=value or gradle.properties)
?: System.getenv(key.uppercase()) // 3. ENV (KEY=value)
System.getProperty(key) // ① JVM (-Dkey=value)
?: project.findProperty(key)?.toString() // ② Gradle (-Pkey=value or gradle.properties)
?: System.getenv(key.uppercase()) // ③ ENV (KEY=value)
private fun resolveBool(project: Project, key: String, altKey: String? = null, default: Boolean): Boolean {
return resolveRaw(project, key)?.toDefaultLowerCase()?.toBooleanStrictOrNull()
?: altKey?.let {
resolveRaw(project, it)?.toDefaultLowerCase()?.toBooleanStrictOrNull()
} ?: default
val primaryValue = resolveRaw(project, key)?.toDefaultLowerCase()?.toBooleanStrictOrNull()
if (primaryValue != null) {
return primaryValue
}
if (altKey != null) {
val altValue = resolveRaw(project, altKey)?.toDefaultLowerCase()?.toBooleanStrictOrNull()
if (altValue != null) {
return altValue
}
}
return default
}
// Private backing vars (nullable because we can't use lateinit with primitives)
@@ -92,5 +96,4 @@ object BuildConfig {
val mavenLocalOverride: Boolean get() = _mavenLocalOverride
?: error("BuildConfig.release accessed before init() was called")
}
}
@@ -37,31 +37,29 @@ object VersionUtil {
val modifiers = buildList {
if (!BuildConfig.shadePE) add("lite")
if (!BuildConfig.relocate) add("no_relocate")
}.joinToString("-").takeIf { it.isNotEmpty() }
}.takeIf { it.isNotEmpty() }?.joinToString("-")
return buildString {
append(baseVersion)
append("-")
branch?.let { append("$it-") }
append(commitHash)
modifiers?.let { append("+$it") }
modifiers?.let { append("+$modifiers") }
}
}
/**
* Retrieves the current Git commit
* Retrieves the current Git commit as a short hash.
*/
fun getGitCommitHash(full: Boolean = false): String {
private fun getGitCommitHash(): String {
val stdout = ByteArrayOutputStream()
val command = listOfNotNull("git", "rev-parse", if (full) null else "--short", "HEAD")
ProcessBuilder(command)
ProcessBuilder("git", "rev-parse", "--short", "HEAD")
.redirectErrorStream(true)
.start()
.apply { waitFor() }
.inputStream
.use { stdout.writeBytes(it.readAllBytes()) }
val fullCommit = stdout.toString().trim()
return fullCommit.take(minOf(fullCommit.length, 7))
return stdout.toString().trim()
}
/**
@@ -71,7 +69,7 @@ object VersionUtil {
* Any slash (/) in the branch name is replaced with an underscore (_)
* to avoid filesystem issues.
*/
fun getGitBranch(raw: Boolean = false): String? {
private fun getGitBranch(): String? {
val stdout = ByteArrayOutputStream()
ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
@@ -80,34 +78,11 @@ object VersionUtil {
.apply { waitFor() }
.inputStream.use { stdout.writeBytes(it.readAllBytes()) }
if (raw) return stdout.toString().trim()
val branch = stdout.toString().trim()
.replace(Regex("[^a-zA-Z0-9_.-]+"), "_")
.replace(Regex("_{2,}"), "_")
.trim(' ', '.', '_', '-')
.removePrefix("heads_")
val mainBranch = System.getenv("GRIM_MAIN_BRANCH") ?: "2.0"
return when (branch) {
"main", mainBranch -> null // ← ignore these branches
else -> branch
"main", "2.0" -> null // ← ignore these branches
else -> branch.replace("/", "_")
}
}
fun getGitUser(): String {
try {
val stdout = ByteArrayOutputStream()
ProcessBuilder("git", "config", "user.name")
.redirectErrorStream(true)
.start()
.apply { waitFor() }
.inputStream.use { stdout.writeBytes(it.readAllBytes()) }
return stdout.toString().trim()
} catch (_: Exception) {
return "unknown"
}
}
}
}
+17 -68
View File
@@ -5,78 +5,34 @@ plugins {
`maven-publish`
grim.`base-conventions`
grim.`shadow-conventions`
id("de.eldoria.plugin-yml.bukkit") version "0.8.0"
id("xyz.jpenilla.run-paper") version "3.0.0-beta.1"
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
id("xyz.jpenilla.run-paper") version "2.3.1"
}
repositories {
if (BuildConfig.mavenLocalOverride) {
mavenLocal()
}
// For paper-api
exclusiveContent {
forRepository {
maven {
name = "papermc"
url = uri("https://repo.papermc.io/repository/maven-public/")
}
}
filter {
includeGroup("io.papermc.paper")
includeGroup("net.md-5")
}
maven {
name = "papermc"
url = uri("https://repo.papermc.io/repository/maven-public/")
}
exclusiveContent {
forRepository {
maven("https://libraries.minecraft.net") { // Brigadier
mavenContent { releasesOnly() }
}
}
filter {
includeModule("com.mojang", "brigadier")
}
}
// For placeholderapi
exclusiveContent {
forRepository {
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
}
filter {
includeGroup("me.clip")
}
}
// For GrimAPI and PacketEvents (transitive from :common, direct in :bukkit)
exclusiveContent {
forRepository {
maven("https://repo.grim.ac/snapshots")
}
filter {
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
maven("https://repo.grim.ac/snapshots") { // Grim API
content {
includeGroup("ac.grim.grimac")
includeGroup("com.github.retrooper")
}
}
// For Configuralize (transitive from :common)
exclusiveContent {
forRepository {
maven("https://nexus.scarsz.me/content/repositories/releases") {
mavenContent { releasesOnly() }
}
}
filter {
includeGroup("github.scarsz")
}
}
// Maven Central Fallback
mavenCentral()
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://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)
@@ -170,22 +126,15 @@ bukkit {
}
register("grim.verbose") {
description = "Receive verbose alerts for violations"
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"
"Enable verbose alerts on join. Requires grim.alerts and grim.alerts.enable-on-join"
default = Permission.Default.FALSE
}
register("grim.list") {
description =
"Shows lists of specific data"
default = Permission.Default.FALSE
}
}
}
@@ -20,7 +20,6 @@ public class BukkitPlatformPlugin implements PlatformPlugin {
return plugin.getName();
}
@SuppressWarnings("deprecation")
@Override
public String getVersion() {
return plugin.getDescription().getVersion();
@@ -1,10 +1,10 @@
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.events.GrimExtensionManager;
import ac.grim.grimac.manager.init.Initable;
import ac.grim.grimac.manager.init.start.ExemptOnlinePlayersOnReload;
import ac.grim.grimac.manager.init.start.StartableInitable;
@@ -14,6 +14,7 @@ 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.CommandAdapter;
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;
@@ -28,7 +29,6 @@ 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.resolver.BukkitResolverRegistrar;
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;
@@ -36,7 +36,6 @@ import ac.grim.grimac.platform.bukkit.utils.placeholder.PlaceholderAPIExpansion;
import ac.grim.grimac.utils.lazy.LazyHolder;
import com.github.retrooper.packetevents.PacketEventsAPI;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.ServicePriority;
@@ -48,7 +47,7 @@ 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 {
@@ -60,19 +59,22 @@ public final class GrimACBukkitLoaderPlugin extends JavaPlugin implements Platfo
private final LazyHolder<CommandManager<Sender>> commandManager = LazyHolder.simple(this::createCommandManager);
private final LazyHolder<ItemResetHandler> itemResetHandler = LazyHolder.simple(BukkitItemResetHandler::new);
@Getter private final PlatformPlayerFactory platformPlayerFactory = new BukkitPlatformPlayerFactory();
@Getter private final CommandAdapter commandAdapter = new BukkitParserDescriptorFactory();
@Getter private final PlatformPluginManager pluginManager = new BukkitPlatformPluginManager();
@Getter private final GrimPlugin plugin;
@Getter private final PlatformServer platformServer = new BukkitPlatformServer();
@Getter private final MessagePlaceHolderManager messagePlaceHolderManager = new BukkitMessagePlaceHolderManager();
@Getter private final BukkitPermissionRegistrationManager permissionManager = new BukkitPermissionRegistrationManager();
private final PlatformPlayerFactory playerFactory = new BukkitPlatformPlayerFactory();
private final CommandAdapter 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() {
GrimExtensionManager extensionManager = GrimAPI.INSTANCE.getExtensionManager();
BukkitResolverRegistrar registrar = new BukkitResolverRegistrar(extensionManager);
registrar.registerAll();
this.plugin = registrar.resolvePlugin(this);
this.plugin = new BasicGrimPlugin(
this.getLogger(),
this.getDataFolder(),
this.getDescription().getVersion(),
this.getDescription().getDescription(),
this.getDescription().getAuthors()
);
}
@Override
@@ -110,6 +112,16 @@ public final class GrimACBukkitLoaderPlugin extends JavaPlugin implements Platfo
return scheduler.get();
}
@Override
public PlatformPlayerFactory getPlatformPlayerFactory() {
return playerFactory;
}
@Override
public CommandAdapter getCommandAdapter() {
return parserFactory;
}
@Override
public PacketEventsAPI<?> getPacketEvents() {
return packetEvents.get();
@@ -130,12 +142,37 @@ public final class GrimACBukkitLoaderPlugin extends JavaPlugin implements Platfo
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();
}
@@ -4,15 +4,16 @@ 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 lombok.RequiredArgsConstructor;
import org.incendo.cloud.bukkit.data.SinglePlayerSelector;
import java.util.Collection;
import java.util.Collections;
@RequiredArgsConstructor
public class BukkitPlayerSelectorAdapter implements PlayerSelector {
private final SinglePlayerSelector bukkitSelector;
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() {
@@ -6,10 +6,8 @@ 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.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.UUID;
@@ -17,13 +15,12 @@ import java.util.concurrent.CompletableFuture;
public class BukkitGrimEntity implements GrimEntity {
protected static final boolean CAN_USE_DIRECT_GETTERS = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_1) && PaperUtils.PAPER;
private final Entity entity;
private BukkitPlatformWorld bukkitPlatformWorld;
public BukkitGrimEntity(Entity entity) {
this.entity = Objects.requireNonNull(entity);
Objects.requireNonNull(entity);
this.entity = entity;
}
public Entity getBukkitEntity() {
@@ -47,7 +44,7 @@ public class BukkitGrimEntity implements GrimEntity {
}
@Override
@NotNull
@NonNull
public Entity getNative() {
return entity;
}
@@ -79,26 +76,4 @@ public class BukkitGrimEntity implements GrimEntity {
location.getPitch()
);
}
@Override
public double distanceSquared(double oX, double oY, double oZ) {
if (CAN_USE_DIRECT_GETTERS) {
double x = this.entity.getX();
double y = this.entity.getY();
double z = this.entity.getZ();
double distX = (x - oX) * (x - oX);
double distY = (y - oY) * (y - oY);
double distZ = (z - oZ) * (z - oZ);
return distX + distY + distZ;
} else {
org.bukkit.Location location = this.entity.getLocation();
double x = location.getX();
double y = location.getY();
double z = location.getZ();
double distX = (x - oX) * (x - oX);
double distY = (y - oY) * (y - oY);
double distZ = (z - oZ) * (z - oZ);
return distX + distY + distZ;
}
}
}
@@ -5,8 +5,9 @@ import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.PistonData;
import ac.grim.grimac.utils.data.TrackedPosition;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
@@ -27,11 +28,10 @@ public class PistonEvent implements Listener {
private static final double MAX_VERTICAL_DISTANCE = 64.0;
// accuracy isn't that important, it's close enough and performant
private static boolean isCloseEnough(final int aX, final int aY, final int aZ,
final double bX, final double bY, final double bZ) {
return Math.abs(aX - bX) <= MAX_HORIZONTAL_DISTANCE
&& Math.abs(aY - bY) <= MAX_VERTICAL_DISTANCE
&& Math.abs(aZ - bZ) <= MAX_HORIZONTAL_DISTANCE;
private static boolean isCloseEnough(Vector3i vectorA, Vector3d vectorB) {
return Math.abs(vectorA.getX() - vectorB.getX()) <= MAX_HORIZONTAL_DISTANCE
&& Math.abs(vectorA.getY() - vectorB.getY()) <= MAX_VERTICAL_DISTANCE
&& Math.abs(vectorA.getZ() - vectorB.getZ()) <= MAX_HORIZONTAL_DISTANCE;
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@@ -71,13 +71,10 @@ public class PistonEvent implements Listener {
final int chunkX = event.getBlock().getX() >> 4;
final int chunkZ = event.getBlock().getZ() >> 4;
final BlockFace blockFace = BukkitConversionUtils.fromBukkitFace(event.getDirection());
final int sourceX = piston.getX();
final int sourceY = piston.getY();
final int sourceZ = piston.getZ();
final Vector3i sourcePos = new Vector3i(piston.getX(), piston.getY(), piston.getZ());
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
TrackedPosition position = player.compensatedEntities.self.trackedServerPosition;
if (player.compensatedWorld.isChunkLoaded(chunkX, chunkZ) && isCloseEnough(sourceX, sourceY, sourceZ, position.getX(), position.getY(), position.getZ())) {
if (player.compensatedWorld.isChunkLoaded(chunkX, chunkZ) && isCloseEnough(sourcePos, player.compensatedEntities.self.trackedServerPosition.getPos())) {
final int lastTrans = player.lastTransactionSent.get();
PistonData data = new PistonData(blockFace, boxes, lastTrans, true, hasSlimeBlock, hasHoneyBlock);
player.latencyUtils.addRealTimeTaskAsync(lastTrans, () -> player.compensatedWorld.activePistons.add(data));
@@ -130,16 +127,12 @@ public class PistonEvent implements Listener {
}
}
final Block block = event.getBlock();
final int chunkX = block.getX() >> 4;
final int chunkZ = block.getZ() >> 4;
final int sourceX = block.getX();
final int sourceY = block.getY();
final int sourceZ = block.getZ();
final int chunkX = event.getBlock().getX() >> 4;
final int chunkZ = event.getBlock().getZ() >> 4;
Vector3i sourcePos = new Vector3i(event.getBlock().getX(), event.getBlock().getY(), event.getBlock().getZ());
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
TrackedPosition position = player.compensatedEntities.self.trackedServerPosition;
if (player.compensatedWorld.isChunkLoaded(chunkX, chunkZ) && isCloseEnough(sourceX, sourceY, sourceZ, position.getX(), position.getY(), position.getZ())) {
if (player.compensatedWorld.isChunkLoaded(chunkX, chunkZ) && isCloseEnough(sourcePos, player.compensatedEntities.self.trackedServerPosition.getPos())) {
int lastTrans = player.lastTransactionSent.get();
PistonData data = new PistonData(face, boxes, lastTrans, false, hasSlimeBlock, hasHoneyBlock);
player.latencyUtils.addRealTimeTaskAsync(lastTrans, () -> player.compensatedWorld.activePistons.add(data));
@@ -2,14 +2,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.utils.anticheat.Constants;
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, Constants.BSTATS_PLUGIN_ID);
} catch (Exception ignored) {}
new Metrics(GrimACBukkitLoaderPlugin.LOADER, pluginId);
} catch (Exception ignored) {
}
}
}
@@ -2,212 +2,204 @@ 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 ac.grim.grimac.utils.reflection.ReflectionUtils;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import lombok.SneakyThrows;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class BukkitItemResetHandler implements ItemResetHandler {
private static final Consumer<Player> resetItemUsage;
private static final Predicate<Player> isUsingItem;
private static final Function<Player, InteractionHand> getItemUsageHand;
private final @NotNull ItemUsageReset resetItemUsage = createItemUsageResetFunction();
private final @NotNull ItemUsageHandGetter itemUsageHandGetter = createItemUsageHandGetterFunction();
@Override
@SneakyThrows
public void resetItemUsage(@Nullable PlatformPlayer player) {
if (player != null) resetItemUsage.accept((Player) player.getNative());
}
@Override
public @Nullable InteractionHand getItemUsageHand(@Nullable PlatformPlayer player) {
return player == null ? null : getItemUsageHand.apply((Player) player.getNative());
}
@Override
public boolean isUsingItem(@Nullable PlatformPlayer player) {
return player != null && isUsingItem.test((Player) player.getNative());
}
static {
final ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
boolean legacy = version.isOlderThanOrEquals(ServerVersion.V_1_8_8);
try {
Method getHandle_ = null;
if (PaperUtils.PAPER && version.isNewerThanOrEquals(ServerVersion.V_1_20_5)) {
Class<?> cls = ReflectionUtils.getClass("org.bukkit.craftbukkit.entity.CraftLivingEntity");
if (cls != null) getHandle_ = cls.getMethod("getHandle");
}
boolean obfuscated = getHandle_ == null;
String nmsPackage = obfuscated ? Bukkit.getServer().getClass().getPackageName().split("\\.")[3] : null;
if (obfuscated) {
String clazzName = legacy ? "CraftHumanEntity" : "CraftLivingEntity";
getHandle_ = Class.forName("org.bukkit.craftbukkit." + nmsPackage + ".entity." + clazzName).getMethod("getHandle");
}
final Method getHandle = getHandle_;
Class<?> clazz = getHandle_.getReturnType();
if (version.isNewerThanOrEquals(ServerVersion.V_1_10)) {
isUsingItem = Player::isHandRaised;
} else {
Method method = clazz.getMethod(switch (Objects.requireNonNull(nmsPackage)) {
case "v1_8_R3" -> "bS";
case "v1_9_R1" -> "cs";
case "v1_9_R2" -> "ct";
default -> throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
});
isUsingItem = player -> {
try {
return (boolean) method.invoke(getHandle.invoke(player));
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
}
if (legacy) {
getItemUsageHand = player -> isUsingItem.test(player) ? InteractionHand.MAIN_HAND : null;
} else if (PaperUtils.PAPER && version.isNewerThanOrEquals(ServerVersion.V_1_16_5)) {
getItemUsageHand = player -> player.isHandRaised()
? player.getHandRaised() == EquipmentSlot.OFF_HAND
? InteractionHand.OFF_HAND
: InteractionHand.MAIN_HAND
: null;
} else {
Method method = clazz.getMethod(switch (Objects.requireNonNull(nmsPackage)) {
case "v1_9_R1" -> "ct";
case "v1_9_R2" -> "cu";
case "v1_10_R1" -> "cy";
case "v1_11_R1" -> "cz";
case "v1_12_R1" -> "cH";
case "v1_13_R1", "v1_13_R2", "v1_14_R1" -> "cU";
case "v1_15_R1", "v1_16_R1", "v1_16_R2", "v1_16_R3", "v1_17_R1" -> "getRaisedHand";
case "v1_18_R1" -> "eM";
case "v1_18_R2" -> "eN";
case "v1_19_R1" -> "eU";
case "v1_19_R2" -> "fa";
case "v1_19_R3" -> "ff";
case "v1_20_R1" -> "fj";
case "v1_20_R2" -> "fn";
case "v1_20_R3" -> "fo";
case "v1_20_R4" -> "fw";
case "v1_21_R1" -> "fs";
case "v1_21_R2", "v1_21_R3", "v1_21_R4" -> "fA";
case "v1_21_R5" -> "fH";
case "v1_21_R6" -> "fP";
default -> throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
});
getItemUsageHand = player -> {
try {
return isUsingItem.test(player)
? ((Enum<?>) method.invoke(getHandle.invoke(player))).ordinal() == 0
? InteractionHand.MAIN_HAND
: InteractionHand.OFF_HAND
: null;
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
}
Method setLivingEntityFlag;
if (version.isNewerThanOrEquals(ServerVersion.V_1_19)) {
String name = obfuscated ? "c" : "setLivingEntityFlag";
setLivingEntityFlag = clazz.getDeclaredMethod(name, int.class, boolean.class);
setLivingEntityFlag.setAccessible(true);
} else {
setLivingEntityFlag = null;
}
if (PaperUtils.PAPER && version.isNewerThan(ServerVersion.V_1_17)) {
resetItemUsage = setLivingEntityFlag == null ? LivingEntity::clearActiveItem : player -> {
try {
setLivingEntityFlag.invoke(getHandle.invoke(player), 1, false);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
player.clearActiveItem();
};
} else {
Method method = clazz.getMethod(switch (Objects.requireNonNull(nmsPackage)) {
case "v1_8_R3" -> "bV";
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";
case "v1_19_R1" -> "eZ";
case "v1_19_R2" -> "ff";
case "v1_19_R3" -> "fk";
case "v1_20_R1" -> "fo";
case "v1_20_R2" -> "fs";
case "v1_20_R3" -> "ft";
case "v1_20_R4" -> "fB";
case "v1_21_R1" -> "fx";
case "v1_21_R2", "v1_21_R3", "v1_21_R4" -> "fF";
case "v1_21_R5" -> "fM";
case "v1_21_R6" -> "fU";
default -> throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
});
if (legacy) { // 1.8.8
resetItemUsage = player -> {
try {
method.invoke(getHandle.invoke(player));
// in 1.8 we need to resync item usage manually,
// only do so if the player is using an item
if (isUsingItem.test(player)) player.updateInventory();
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
} else if (setLivingEntityFlag == null) { // 1.9-1.18.2
resetItemUsage = player -> {
try {
method.invoke(getHandle.invoke(player));
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
} else { // 1.19+
resetItemUsage = player -> {
try {
Object handle = getHandle.invoke(player);
setLivingEntityFlag.invoke(handle, 1, false);
method.invoke(handle);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
}
}
} catch (Throwable t) {
throw t instanceof RuntimeException e ? e : new RuntimeException(t);
if (player != null) {
resetItemUsage.accept(((BukkitPlatformPlayer) player).getNative());
}
}
@Override
@SneakyThrows
public @Nullable InteractionHand getItemUsageHand(@Nullable PlatformPlayer platformPlayer) {
return platformPlayer == null ? null
: itemUsageHandGetter.apply(((BukkitPlatformPlayer) platformPlayer).getNative());
}
@SneakyThrows
private @NotNull ItemUsageReset createItemUsageResetFunction() {
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
if (version.isNewerThan(ServerVersion.V_1_17) && PaperUtils.PAPER) {
if (version.isOlderThan(ServerVersion.V_1_19)) {
return LivingEntity::clearActiveItem;
}
Class<?> CraftLivingEntity;
boolean obfuscated = false;
try {
CraftLivingEntity = Class.forName("org.bukkit.craftbukkit.entity.CraftLivingEntity");
} catch (ClassNotFoundException ignored) {
String nmsPackage = Bukkit.getServer().getClass().getPackageName().split("\\.")[3];
CraftLivingEntity = Class.forName("org.bukkit.craftbukkit." + nmsPackage + ".entity.CraftLivingEntity");
obfuscated = true;
}
Method getHandle = CraftLivingEntity.getMethod("getHandle");
Method setLivingEntityFlag = getHandle.getReturnType().getDeclaredMethod(
obfuscated ? "c" : "setLivingEntityFlag", int.class, boolean.class
);
setLivingEntityFlag.setAccessible(true);
return player -> {
// no gameevent, no exception
setLivingEntityFlag.invoke(getHandle.invoke(player), 1, false);
player.clearActiveItem();
};
}
if (version == ServerVersion.V_1_8_8) {
Method getHandle = Class.forName("org.bukkit.craftbukkit.v1_8_R3.entity.CraftHumanEntity").getMethod("getHandle");
Method clearActiveItem = getHandle.getReturnType().getMethod("bV");
Method isUsingItem = getHandle.getReturnType().getMethod("bS");
return player -> {
Object handle = getHandle.invoke(player);
clearActiveItem.invoke(handle);
// in 1.8 we need to resync item usage manually,
// only do so if the player was using an item
if ((boolean) isUsingItem.invoke(handle)) {
player.updateInventory();
}
};
}
String nmsPackage = Bukkit.getServer().getClass().getPackageName().split("\\.")[3];
Method getHandle = Class.forName("org.bukkit.craftbukkit." + nmsPackage + ".entity.CraftLivingEntity").getMethod("getHandle");
Method clearActiveItem = getHandle.getReturnType().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";
case "v1_19_R1" -> "eZ";
case "v1_19_R2" -> "ff";
case "v1_19_R3" -> "fk";
case "v1_20_R1" -> "fo";
case "v1_20_R2" -> "fs";
case "v1_20_R3" -> "ft";
case "v1_20_R4" -> "fB";
case "v1_21_R1" -> "fx";
case "v1_21_R2", "v1_21_R3", "v1_21_R4" -> "fF";
default -> throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
});
if (version.isOlderThan(ServerVersion.V_1_19)) {
return player -> clearActiveItem.invoke(getHandle.invoke(player));
} else {
Method setLivingEntityFlag = getHandle.getReturnType().getDeclaredMethod("c", int.class, boolean.class);
setLivingEntityFlag.setAccessible(true);
return player -> {
final Object handle = getHandle.invoke(player);
// no gameevent, no exception
setLivingEntityFlag.invoke(handle, 1, false);
clearActiveItem.invoke(handle);
};
}
}
@SneakyThrows
private @NotNull ItemUsageHandGetter createItemUsageHandGetterFunction() {
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
if (version.isNewerThanOrEquals(ServerVersion.V_1_16_5) && PaperUtils.PAPER) {
return player -> player.isHandRaised()
? player.getHandRaised() == EquipmentSlot.OFF_HAND
? InteractionHand.OFF_HAND
: InteractionHand.MAIN_HAND
: null;
}
if (version == ServerVersion.V_1_8_8) {
Method getHandle = Class.forName("org.bukkit.craftbukkit.v1_8_R3.entity.CraftHumanEntity").getMethod("getHandle");
Method isUsingItem = getHandle.getReturnType().getMethod("bS");
return player -> (boolean) isUsingItem.invoke(getHandle.invoke(player)) ? InteractionHand.MAIN_HAND : null;
}
String nmsPackage = Bukkit.getServer().getClass().getPackageName().split("\\.")[3];
Method getHandle = Class.forName("org.bukkit.craftbukkit." + nmsPackage + ".entity.CraftLivingEntity").getMethod("getHandle");
Method isUsingItem = getHandle.getReturnType().getMethod(switch (nmsPackage) {
case "v1_9_R1" -> "cs";
case "v1_9_R2" -> "ct";
case "v1_10_R1" -> "cx";
case "v1_11_R1", "v1_12_R1", "v1_13_R1", "v1_13_R2", "v1_14_R1",
"v1_15_R1", "v1_16_R1", "v1_16_R2", "v1_16_R3", "v1_17_R1" -> "isHandRaised";
case "v1_18_R1" -> "eL";
case "v1_18_R2" -> "eM";
case "v1_19_R1" -> "eT";
case "v1_19_R2" -> "eZ";
case "v1_19_R3" -> "fe";
case "v1_20_R1" -> "fi";
case "v1_20_R2" -> "fm";
case "v1_20_R3" -> "fn";
case "v1_20_R4" -> "fv";
case "v1_21_R1" -> "fr";
case "v1_21_R2", "v1_21_R3", "v1_21_R4" -> "fz";
default -> throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
});
Method getUsingItemHand = getHandle.getReturnType().getMethod(switch (nmsPackage) {
case "v1_9_R1" -> "ct";
case "v1_9_R2" -> "cu";
case "v1_10_R1" -> "cy";
case "v1_11_R1" -> "cz";
case "v1_12_R1" -> "cH";
case "v1_13_R1", "v1_13_R2", "v1_14_R1" -> "cU";
case "v1_15_R1", "v1_16_R1", "v1_16_R2", "v1_16_R3", "v1_17_R1" -> "getRaisedHand";
case "v1_18_R1" -> "eM";
case "v1_18_R2" -> "eN";
case "v1_19_R1" -> "eU";
case "v1_19_R2" -> "fa";
case "v1_19_R3" -> "ff";
case "v1_20_R1" -> "fj";
case "v1_20_R2" -> "fn";
case "v1_20_R3" -> "fo";
case "v1_20_R4" -> "fw";
case "v1_21_R1" -> "fs";
case "v1_21_R2", "v1_21_R3", "v1_21_R4" -> "fA";
default -> throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
});
return player -> {
final Object handle = getHandle.invoke(player);
return (boolean) isUsingItem.invoke(handle)
? ((Enum<?>) getUsingItemHand.invoke(handle)).ordinal() == 0
? InteractionHand.MAIN_HAND
: InteractionHand.OFF_HAND
: null;
};
}
private interface ItemUsageReset {
void accept(@NotNull Player player) throws Throwable;
}
private interface ItemUsageHandGetter {
InteractionHand apply(@NotNull Player player) throws Throwable;
}
}
@@ -5,14 +5,14 @@ import ac.grim.grimac.platform.api.player.PlatformPlayer;
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
import com.github.retrooper.packetevents.util.reflection.Reflection;
import me.clip.placeholderapi.PlaceholderAPI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BukkitMessagePlaceHolderManager implements MessagePlaceHolderManager {
public static final boolean hasPlaceholderAPI = Reflection.getClassByNameWithoutException("me.clip.placeholderapi.PlaceholderAPI") != null;
@Override
public @NotNull String replacePlaceholders(@Nullable PlatformPlayer player, @NotNull String string) {
public @NonNull String replacePlaceholders(@Nullable PlatformPlayer player, @NonNull String string) {
if (!hasPlaceholderAPI) return string;
return PlaceholderAPI.setPlaceholders(player instanceof BukkitPlatformPlayer bukkitPlatformPlayer ? bukkitPlatformPlayer.getBukkitPlayer() : null, string);
}
@@ -5,7 +5,7 @@ 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.jetbrains.annotations.Nullable;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BukkitPlatformPluginManager implements PlatformPluginManager {
@@ -1,14 +1,13 @@
package ac.grim.grimac.platform.bukkit.player;
import ac.grim.grimac.platform.api.player.OfflinePlatformPlayer;
import lombok.RequiredArgsConstructor;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.UUID;
@RequiredArgsConstructor
@lombok.RequiredArgsConstructor
public class BukkitOfflinePlatformPlayer implements OfflinePlatformPlayer {
private final OfflinePlayer offlinePlayer;
@@ -3,14 +3,16 @@ 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 lombok.RequiredArgsConstructor;
import org.bukkit.entity.Player;
@RequiredArgsConstructor
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());
@@ -9,11 +9,8 @@ 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.common.arguments.CommonGrimArguments;
import ac.grim.grimac.utils.math.Location;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.Vector3d;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import lombok.Getter;
@@ -23,33 +20,23 @@ import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
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;
@Getter
private final PlatformInventory inventory;
private final @Nullable User user;
public BukkitPlatformPlayer(Player bukkitPlayer) {
super(bukkitPlayer);
this.bukkitPlayer = bukkitPlayer;
this.inventory = new BukkitPlatformInventory(bukkitPlayer);
if (CommonGrimArguments.USE_CHAT_FAST_BYPASS.value()) {
Object channel = PacketEvents.getAPI().getProtocolManager().getChannel(bukkitPlayer.getUniqueId());
this.user = PacketEvents.getAPI().getProtocolManager().getUser(channel);
} else {
this.user = null;
}
}
@Override
@@ -79,20 +66,12 @@ public class BukkitPlatformPlayer extends BukkitGrimEntity implements PlatformPl
@Override
public void sendMessage(String message) {
if (CommonGrimArguments.USE_CHAT_FAST_BYPASS.value() && user != null) {
user.sendMessage(message);
} else {
bukkitPlayer.sendMessage(message);
}
bukkitPlayer.sendMessage(message);
}
@Override
public void sendMessage(Component message) {
if (CommonGrimArguments.USE_CHAT_FAST_BYPASS.value() && user != null) {
user.sendMessage(message);
} else {
audiences.player(bukkitPlayer).sendMessage(message);
}
audiences.player(bukkitPlayer).sendMessage(message);
}
@Override
@@ -112,12 +91,13 @@ public class BukkitPlatformPlayer extends BukkitGrimEntity implements PlatformPl
@Override
public Vector3d getPosition() {
if (CAN_USE_DIRECT_GETTERS) {
return new Vector3d(this.bukkitPlayer.getX(), this.bukkitPlayer.getY(), this.bukkitPlayer.getZ());
} else {
org.bukkit.Location location = this.bukkitPlayer.getLocation();
return new Vector3d(location.getX(), location.getY(), location.getZ());
}
org.bukkit.Location location = this.bukkitPlayer.getLocation();
return new Vector3d(location.getX(), location.getY(), location.getZ());
}
@Override
public PlatformInventory getInventory() {
return inventory;
}
@Override
@@ -171,7 +151,7 @@ public class BukkitPlatformPlayer extends BukkitGrimEntity implements PlatformPl
}
@Override
@NotNull
@NonNull
public Player getNative() {
return this.bukkitPlayer;
}
@@ -6,6 +6,7 @@ import ac.grim.grimac.platform.api.player.PlatformPlayer;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -20,7 +21,7 @@ public class BukkitPlatformPlayerFactory extends AbstractPlatformPlayerFactory<P
}
@Override
protected Player getNativePlayer(@NotNull String name) {
protected Player getNativePlayer(@NonNull String name) {
return Bukkit.getPlayer(name);
}
@@ -1,111 +0,0 @@
package ac.grim.grimac.platform.bukkit.resolver;
import ac.grim.grimac.api.plugin.BasicGrimPlugin;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.events.GrimExtensionManager;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Manages the registration of Bukkit-specific resolvers with the GrimExtensionManager.
* This class is designed to be instantiated once during plugin startup.
*/
public final class BukkitResolverRegistrar {
private final GrimExtensionManager extensionManager;
// Cache to ensure we only create one GrimPlugin wrapper per Bukkit Plugin instance.
private final Map<Plugin, GrimPlugin> pluginCache = new ConcurrentHashMap<>();
public BukkitResolverRegistrar(GrimExtensionManager extensionManager) {
this.extensionManager = extensionManager;
}
/**
* Registers all the Bukkit-specific resolvers in order of performance (fastest to slowest).
*/
public void registerAll() {
extensionManager.setFailureHandler(this::createFailureException);
extensionManager.registerResolver(this::resolvePluginInstance);
extensionManager.registerResolver(this::resolveStringName);
extensionManager.registerResolver(this::resolveClass);
}
/**
* The core logic for converting a Bukkit Plugin into a GrimPlugin, with caching.
*/
public GrimPlugin resolvePlugin(Plugin bukkitPlugin) {
return pluginCache.computeIfAbsent(bukkitPlugin, plugin -> {
PluginDescriptionFile desc = plugin.getDescription();
return new BasicGrimPlugin(
plugin.getLogger(),
plugin.getDataFolder(),
desc.getVersion(),
desc.getDescription(),
desc.getAuthors()
);
});
}
/**
* 1. Resolver for raw Plugin instances (the most common case).
*/
private GrimPlugin resolvePluginInstance(Object context) {
if (context instanceof Plugin bukkitPlugin) {
return resolvePlugin(bukkitPlugin);
}
return null;
}
/**
* 2. Resolver for String plugin names.
*/
private GrimPlugin resolveStringName(Object context) {
if (context instanceof String pluginName) {
// Use the Bukkit API to look up the plugin by name. This returns null if not found.
Plugin bukkitPlugin = Bukkit.getPluginManager().getPlugin(pluginName);
// We must check for null before applying the logic to avoid a NullPointerException.
return (bukkitPlugin != null) ? resolvePlugin(bukkitPlugin) : null;
}
return null;
}
/**
* 3. Resolver for Class objects.
*/
private GrimPlugin resolveClass(Object context) {
if (context instanceof Class) {
try {
// First, resolve the Class to a Plugin instance.
JavaPlugin providingPlugin = JavaPlugin.getProvidingPlugin((Class<?>) context);
// Then, use our shared logic directly to get the GrimPlugin wrapper.
return resolvePlugin(providingPlugin);
} catch (IllegalArgumentException | IllegalStateException e) {
// This is an expected failure if the class is not from a plugin
// or is called from a static initializer. We simply indicate that
// this resolver cannot handle this context.
return null;
}
}
// This resolver only handles Classes.
return null;
}
private RuntimeException createFailureException(Object failedContext) {
String message = """
Failed to resolve GrimPlugin context from the provided object of type '%s'.
Please ensure you are passing one of the following:
- The main instance of your plugin (e.g., 'this' from your class extending JavaPlugin).
- The plugin name as a String (e.g., "MyPluginName").
- Any Class from your plugin's JAR file (e.g., MyListener.class).
- A pre-existing GrimPlugin instance.
""".formatted(failedContext.getClass().getName());
return new IllegalArgumentException(message);
}
}
@@ -2,12 +2,12 @@ package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.checkerframework.checker.nullness.qual.NonNull;
@Getter
public class BukkitPlatformScheduler implements PlatformScheduler {
private final @NotNull BukkitAsyncScheduler asyncScheduler = new BukkitAsyncScheduler();
private final @NotNull BukkitGlobalRegionScheduler globalRegionScheduler = new BukkitGlobalRegionScheduler();
private final @NotNull BukkitEntityScheduler entityScheduler = new BukkitEntityScheduler();
private final @NotNull BukkitRegionScheduler regionScheduler = new BukkitRegionScheduler();
private final @NonNull BukkitAsyncScheduler asyncScheduler = new BukkitAsyncScheduler();
private final @NonNull BukkitGlobalRegionScheduler globalRegionScheduler = new BukkitGlobalRegionScheduler();
private final @NonNull BukkitEntityScheduler entityScheduler = new BukkitEntityScheduler();
private final @NonNull BukkitRegionScheduler regionScheduler = new BukkitRegionScheduler();
}
@@ -15,14 +15,14 @@ public class FoliaAsyncScheduler implements AsyncScheduler {
@Override
public TaskHandle runNow(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
return new FoliaTaskHandle(scheduler.runNow(GrimACBukkitLoaderPlugin.LOADER, ignored -> task.run()));
return new FoliaTaskHandle(scheduler.runNow(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run()));
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, @NotNull TimeUnit timeUnit) {
return new FoliaTaskHandle(scheduler.runDelayed(
GrimACBukkitLoaderPlugin.LOADER,
ignored -> task.run(),
(ignored) -> task.run(),
delay,
timeUnit
));
@@ -31,8 +31,7 @@ public class FoliaAsyncScheduler implements AsyncScheduler {
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, long period, @NotNull TimeUnit timeUnit) {
return new FoliaTaskHandle(scheduler.runAtFixedRate(
GrimACBukkitLoaderPlugin.LOADER,
ignored -> task.run(),
GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(),
delay,
period,
timeUnit
@@ -43,7 +42,7 @@ public class FoliaAsyncScheduler implements AsyncScheduler {
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return new FoliaTaskHandle(scheduler.runAtFixedRate(
GrimACBukkitLoaderPlugin.LOADER,
ignored -> task.run(),
(ignored) -> task.run(),
initialDelayTicks * 50,
periodTicks * 50,
TimeUnit.MILLISECONDS
@@ -6,7 +6,6 @@ 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 io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -19,37 +18,18 @@ public class FoliaEntityScheduler implements EntityScheduler {
@Override
public TaskHandle run(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired) {
ScheduledTask scheduled = ((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().run(
GrimACBukkitLoaderPlugin.LOADER,
ignored -> task.run(),
retired
);
return scheduled == null ? null : new FoliaTaskHandle(scheduled);
return new FoliaTaskHandle(((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().run(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), retired));
}
@Override
public TaskHandle runDelayed(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long delayTicks) {
ScheduledTask scheduled = ((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runDelayed(
GrimACBukkitLoaderPlugin.LOADER,
ignored -> task.run(),
retired,
delayTicks
return new FoliaTaskHandle(
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runDelayed(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), retired, delayTicks)
);
return scheduled == null ? null : new FoliaTaskHandle(scheduled);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long initialDelayTicks, long periodTicks) {
ScheduledTask scheduled = ((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runAtFixedRate(
GrimACBukkitLoaderPlugin.LOADER,
ignored -> task.run(),
retired,
initialDelayTicks,
periodTicks
);
return scheduled == null ? null : new FoliaTaskHandle(scheduled);
return new FoliaTaskHandle(((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), retired, initialDelayTicks, periodTicks));
}
}
@@ -18,17 +18,17 @@ public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
return new FoliaTaskHandle(globalRegionScheduler.run(GrimACBukkitLoaderPlugin.LOADER, ignored -> task.run()));
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));
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));
return new FoliaTaskHandle(globalRegionScheduler.runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), initialDelayTicks, periodTicks));
}
@Override
@@ -2,12 +2,12 @@ package ac.grim.grimac.platform.bukkit.scheduler.folia;
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.checkerframework.checker.nullness.qual.NonNull;
@Getter
public class FoliaPlatformScheduler implements PlatformScheduler {
private final @NotNull FoliaAsyncScheduler asyncScheduler = new FoliaAsyncScheduler();
private final @NotNull FoliaGlobalRegionScheduler globalRegionScheduler = new FoliaGlobalRegionScheduler();
private final @NotNull FoliaEntityScheduler entityScheduler = new FoliaEntityScheduler();
private final @NotNull FoliaRegionScheduler regionScheduler = new FoliaRegionScheduler();
private final @NonNull FoliaAsyncScheduler asyncScheduler = new FoliaAsyncScheduler();
private final @NonNull FoliaGlobalRegionScheduler globalRegionScheduler = new FoliaGlobalRegionScheduler();
private final @NonNull FoliaEntityScheduler entityScheduler = new FoliaEntityScheduler();
private final @NonNull FoliaRegionScheduler regionScheduler = new FoliaRegionScheduler();
}
@@ -31,7 +31,7 @@ public class FoliaRegionScheduler implements RegionScheduler {
((BukkitPlatformWorld) world).getBukkitWorld(),
chunkX,
chunkZ,
ignored -> task.run()
(ignored) -> task.run()
));
}
@@ -47,7 +47,7 @@ public class FoliaRegionScheduler implements RegionScheduler {
((BukkitPlatformWorld) world).getBukkitWorld(),
chunkX,
chunkZ,
ignored -> task.run(),
(ignored) -> task.run(),
delayTicks
));
}
@@ -64,7 +64,7 @@ public class FoliaRegionScheduler implements RegionScheduler {
((BukkitPlatformWorld) world).getBukkitWorld(),
chunkX,
chunkZ,
ignored -> task.run(),
(ignored) -> task.run(),
initialDelayTicks,
periodTicks
));
@@ -12,8 +12,8 @@ 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 org.jetbrains.annotations.NotNull;
import java.util.UUID;
@@ -78,12 +78,12 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> implements
}
@Override
public @NotNull Sender map(@NotNull CommandSender base) {
public @NonNull Sender map(@NonNull CommandSender base) {
return this.wrap(base);
}
@Override
public @NotNull CommandSender reverse(@NotNull Sender mapped) {
public @NonNull CommandSender reverse(@NonNull Sender mapped) {
return this.unwrap(mapped);
}
}
@@ -31,6 +31,11 @@ public class BukkitConversionUtils {
};
}
/**
* 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;
@@ -6,7 +6,6 @@ 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 lombok.RequiredArgsConstructor;
import org.bukkit.Chunk;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@@ -16,11 +15,14 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@RequiredArgsConstructor
public class BukkitPlatformChunk implements PlatformChunk {
private static final Map<BlockData, Integer> blockDataToId = GrimAPI.INSTANCE.getPlatform() == Platform.FOLIA ? new ConcurrentHashMap<>() : new HashMap<>();
private static final boolean isFlat = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13);
private final @NotNull Chunk chunk;
private final Chunk chunk;
public BukkitPlatformChunk(@NotNull Chunk chunk) {
this.chunk = chunk;
}
@Override
public int getBlockID(int x, int y, int z) {
@@ -28,11 +30,6 @@ public class BukkitPlatformChunk implements PlatformChunk {
return isFlat // Cache blockDataToID because Strings are expensive
? blockDataToId.computeIfAbsent(block.getBlockData(), data -> WrappedBlockState.getByString(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), data.getAsString(false)).getGlobalId())
: getLegacyBlockID(block);
}
@SuppressWarnings({ "deprecation", "UnstableApiUsage" })
private static int getLegacyBlockID(@NotNull Block block) {
return (block.getType().getId() << 4) | block.getData();
: (block.getType().getId() << 4) | block.getData();
}
}
@@ -7,7 +7,6 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
@@ -17,11 +16,14 @@ import org.jetbrains.annotations.Nullable;
import java.util.UUID;
@Getter
@RequiredArgsConstructor
public class BukkitPlatformWorld implements PlatformWorld {
private static final boolean LEGACY_SERVER_VERSION = PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_12_2);
private final @NotNull World bukkitWorld;
private final World bukkitWorld;
public BukkitPlatformWorld(@NotNull World world) {
this.bukkitWorld = world;
}
@Override
public boolean isChunkLoaded(int chunkX, int chunkZ) {
@@ -32,7 +34,6 @@ public class BukkitPlatformWorld implements PlatformWorld {
public WrappedBlockState getBlockAt(int x, int y, int z) {
if (LEGACY_SERVER_VERSION) {
Block block = bukkitWorld.getBlockAt(x, y, z);
@SuppressWarnings({"deprecation", "UnstableApiUsage"})
int blockId = (block.getType().getId() << 4) | block.getData();
return WrappedBlockState.getByGlobalId(blockId);
} else {
-47
View File
@@ -1,47 +0,0 @@
# cliff.toml - DEV BUILDS - Now with Author Info
[changelog]
body = """
## Changes in this Build (since previous push)
{%- for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | upper_first }}
{%- for commit in commits %}
- {{ commit.message | upper_first }} - *by {{ commit.author.name }}* {% if commit.breaking %}**[BREAKING]**{% endif %} \
{%- if commit.remote and commit.remote.url -%}
([`{{ commit.id | truncate(length=7, end="") }}`]({{ commit.remote.url }}/commit/{{- commit.id -}}))
{%- else -%}
(`{{ commit.id | truncate(length=7, end="") }}`)
{%- endif -%}
{% endfor %}
{% endfor %}
"""
trim = true
[git]
# Your previous settings here are perfect, no changes needed
filter_unconventional = false
skip_unconventional = false
remote = "https://github.com/GrimAnticheat/Grim"
commit_parsers = [
{ message = "^feat", group = "🚀 Features" },
{ message = "^fix", group = "🐛 Fixes" },
{ message = "^perf", group = "⚡️ Performance" },
{ message = "^refactor", group = "♻️ Refactoring" },
{ message = "^docs", group = "📖 Documentation" },
{ message = "^test", group = "✅ Tests" },
{ message = "^chore", group = "🤖 Maintenance & CI" },
{ body = ".*BREAKING CHANGE.*", group = "🚨 Breaking Changes" },
{ message = ".*", group = "Miscellaneous" } # CHANGED THIS LINE
]
commit_preprocessors = [
{ pattern = 'src/main/java/ac/grim/grimac/checks/.*', group = "✔️ Checks" },
{ pattern = 'src/main/java/ac/grim/grimac/api/.*', group = "🔌 API" },
{ pattern = 'src/main/java/ac/grim/grimac/platform/.*', group = "🏗️ Platform" },
{ pattern = 'src/main/java/ac/grim/grimac/engine/.*', group = "⚙️ Core Engine" },
{ pattern = 'src/main/java/ac/grim/grimac/config/.*', group = "⚙️ Configuration" },
{ pattern = 'pom.xml', group = "🤖 Maintenance & CI" },
{ pattern = '.github/.*', group = "🤖 Maintenance & CI" },
{ pattern = 'build.gradle.kts', group = "🤖 Maintenance & CI" },
{ pattern = 'src/.*', group = "⚙️ Core Engine" },
]
sort_commits = "oldest"
+20 -69
View File
@@ -9,65 +9,23 @@ repositories {
if (BuildConfig.mavenLocalOverride) {
mavenLocal()
}
exclusiveContent {
forRepository {
maven("https://repo.grim.ac/snapshots") // Grim API
}
filter {
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")
includeGroup("com.github.retrooper")
}
}
exclusiveContent {
forRepository {
maven("https://repo.viaversion.com") { // ViaVersion
mavenContent { releasesOnly() }
}
}
filter {
includeGroup("com.viaversion")
}
}
exclusiveContent {
forRepository {
maven("https://nexus.scarsz.me/content/repositories/releases") { // Configuralize
mavenContent { releasesOnly() }
}
}
filter {
includeGroup("github.scarsz")
}
}
exclusiveContent {
forRepository {
maven("https://repo.opencollab.dev/maven-releases/") { // Cumulus (for Floodgate)
mavenContent { releasesOnly() }
}
}
filter {
includeGroup("org.geysermc.api")
}
}
exclusiveContent {
forRepository {
maven("https://repo.opencollab.dev/maven-snapshots/") { // Floodgate
mavenContent { snapshotsOnly() }
}
}
filter {
includeGroup("org.geysermc.floodgate")
includeGroup("org.geysermc.cumulus")
includeModule("org.geysermc", "common")
includeModule("org.geysermc", "geyser-parent")
}
}
mavenCentral()
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://s01.oss.sonatype.org/content/repositories/snapshots/")
mavenCentral() // FastUtil
}
dependencies {
@@ -77,28 +35,21 @@ dependencies {
compileOnly(libs.packetevents.api)
}
api(libs.cloud.core)
api(libs.cloud.processors.requirements)
api(libs.configuralize) {
artifact {
classifier = "slim"
}
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(libs.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)
api(libs.hikaricp)
api("com.zaxxer:HikariCP:4.0.3")
api(libs.grim.api)
compileOnly(libs.geyser.base.api) {
isTransitive = false // messes with guava otherwise
}
api("ac.grim.grimac:GrimAPI:1.1.0.0")
compileOnly(libs.floodgate.api)
compileOnly(libs.viaversion)
compileOnly(libs.via.version.api)
compileOnly(libs.netty)
}
@@ -1,9 +1,8 @@
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.events.GrimExtensionManager;
import ac.grim.grimac.events.OptimizedEventBus;
import ac.grim.grimac.manager.AlertManagerImpl;
import ac.grim.grimac.manager.DiscordManager;
import ac.grim.grimac.manager.InitManager;
@@ -25,7 +24,6 @@ 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.common.arguments.CommonGrimArguments;
import ac.grim.grimac.utils.reflection.ReflectionUtils;
import lombok.Getter;
import org.incendo.cloud.CommandManager;
@@ -44,7 +42,6 @@ public final class GrimAPI {
private final DiscordManager discordManager;
private final PlayerDataManager playerDataManager;
private final TickManager tickManager;
private final GrimExtensionManager extensionManager;
private final EventBus eventBus;
private final GrimExternalAPI externalAPI;
private ViolationDatabaseManager violationDatabaseManager;
@@ -60,15 +57,12 @@ public final class GrimAPI {
this.discordManager = new DiscordManager();
this.playerDataManager = new PlayerDataManager();
this.tickManager = new TickManager();
this.extensionManager = new GrimExtensionManager();
this.eventBus = new OptimizedEventBus(extensionManager);
this.eventBus = new OptimizedEventBus();
this.externalAPI = new GrimExternalAPI(this);
}
// the order matters
private static Platform detectPlatform() {
Platform override = CommonGrimArguments.PLATFORM_OVERRIDE.value();
if (override != null) return override;
if (ReflectionUtils.hasClass("io.papermc.paper.threadedregions.RegionizedServer")) return Platform.FOLIA;
if (ReflectionUtils.hasClass("org.bukkit.Bukkit")) return Platform.BUKKIT;
if (ReflectionUtils.hasClass("net.fabricmc.loader.api.FabricLoader")) return Platform.FABRIC;
@@ -142,8 +136,4 @@ public final class GrimAPI {
public PermissionRegistrationManager getPermissionManager() {
return loader.getPermissionManager();
}
public GrimExtensionManager getExtensionManager() {
return extensionManager;
}
}
@@ -12,8 +12,9 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.common.ConfigReloadObserver;
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
@@ -41,7 +42,7 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, S
}
@Override
public @NotNull EventBus getEventBus() {
public @NonNull EventBus getEventBus() {
return api.getEventBus();
}
@@ -182,8 +183,11 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, S
// Don't reload players if the plugin hasn't started yet
if (!started) return;
// Reload checks for all players
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
player.runSafely(() -> player.reload(configManager));
for (GrimPlayer grimPlayer : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
ChannelHelper.runInEventLoop(grimPlayer.user.getChannel(), () -> {
grimPlayer.updatePermissions();
grimPlayer.reload(configManager);
});
}
}
@@ -8,14 +8,13 @@ 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 lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import static com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying.isFlying;
// 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 {
@@ -63,12 +62,19 @@ public class Check extends GrimProcessor implements AbstractCheck {
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission && !exemptPermission;
}
public final void updatePermissions() {
if (configName == null || player.platformPlayer == null) return;
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);
public void updatePermissions() {
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);
},
() -> {}
);
}
public final boolean flagAndAlert(String verbose) {
@@ -130,13 +136,14 @@ public class Check extends GrimProcessor implements AbstractCheck {
}
@Override
public final void reload(ConfigManager configuration) {
public void reload(ConfigManager configuration) {
decay = configuration.getDoubleElse(configName + ".decay", decay);
setbackVL = configuration.getDoubleElse(configName + ".setbackvl", setbackVL);
displayName = configuration.getStringElse(configName + ".displayname", checkName);
description = configuration.getStringElse(configName + ".description", description);
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
updatePermissions();
onReload(configuration);
}
@@ -164,13 +171,13 @@ public class Check extends GrimProcessor implements AbstractCheck {
return offset > 0.001 ? String.format("%.5f", offset) : String.format("%.2E", offset);
}
public static boolean isTransaction(PacketTypeCommon packetType) {
public boolean isTransaction(PacketTypeCommon packetType) {
return packetType == PacketType.Play.Client.PONG ||
packetType == PacketType.Play.Client.WINDOW_CONFIRMATION;
}
public static boolean isAsync(PacketTypeCommon packetType) {
return packetType == PacketType.Play.Client.KEEP_ALIVE;
public boolean isFlying(PacketTypeCommon packetType) {
return WrapperPlayClientPlayerFlying.isFlying(packetType);
}
public boolean isUpdate(PacketTypeCommon packetType) {
@@ -28,7 +28,7 @@ public class AimModulo360 extends Check implements RotationCheck {
return;
}
if (player.yaw < 360 && player.yaw > -360 && Math.abs(rotationUpdate.getDeltaXRot()) > 320 && Math.abs(lastDeltaYaw) < 30) {
if (player.xRot < 360 && player.xRot > -360 && Math.abs(rotationUpdate.getDeltaXRot()) > 320 && Math.abs(lastDeltaYaw) < 30) {
flagAndAlert();
} else {
reward();
@@ -10,7 +10,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientHe
@CheckData(name = "BadPacketsA", description = "Sent duplicate slot id")
public class BadPacketsA extends Check implements PacketCheck {
private int lastSlot = -1;
int lastSlot = -1;
public BadPacketsA(final GrimPlayer player) {
super(player);
@@ -22,13 +22,15 @@ public class BadPacketsD extends Check implements PacketCheck {
final float pitch = new WrapperPlayClientPlayerFlying(event).getLocation().getPitch();
if (pitch > 90 || pitch < -90) {
// Ban.
if (flagAndAlert("pitch=" + pitch) && shouldModifyPackets()) {
// prevent other checks from using an invalid pitch
if (player.pitch > 90) player.pitch = 90;
if (player.pitch < -90) player.pitch = -90;
if (flagAndAlert("pitch=" + pitch)) {
if (shouldModifyPackets()) {
// prevent other checks from using an invalid pitch
if (player.yRot > 90) player.yRot = 90;
if (player.yRot < -90) player.yRot = -90;
event.setCancelled(true);
player.onPacketCancel();
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
@@ -54,11 +54,15 @@ public class BadPacketsH extends BlockPlaceCheck {
}
public boolean shouldCancel(int sequence) {
int expected = lastSequence + 1;
if (isSupportedVersion && sequence != lastSequence + 1) {
if (flagAndAlert("expected=" + (lastSequence + 1) + ", id=" + sequence) && shouldModifyPackets()) {
lastSequence = sequence;
return true;
}
}
lastSequence = sequence;
return isSupportedVersion && sequence != expected
&& flagAndAlert("expected=" + expected + ", id=" + sequence)
&& shouldModifyPackets();
return false;
}
public void onWorldChange() {
@@ -16,11 +16,13 @@ public class BadPacketsI extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_ABILITIES
&& new WrapperPlayClientPlayerAbilities(event).isFlying() && !player.canFly
&& flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
if (event.getPacketType() == PacketType.Play.Client.PLAYER_ABILITIES) {
if (new WrapperPlayClientPlayerAbilities(event).isFlying() && !player.canFly) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
}
@@ -39,14 +39,14 @@ public class BadPacketsJ extends Check implements PacketCheck {
if (isTickPacket(event.getPacketType())) {
// due to tick skipping, the rotations sent could be last tick's
boolean allowLast = player.canSkipTicks() && (event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION || event.getPacketType() == PacketType.Play.Client.PLAYER_ROTATION);
boolean allowLast = player.canSkipTicksPreVia() && (event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION || event.getPacketType() == PacketType.Play.Client.PLAYER_ROTATION);
for (HeadRotation rotation : rotations) {
if (rotation.yaw() == player.yaw && rotation.pitch() == player.pitch) {
if (rotation.getYaw() == player.xRot && rotation.getPitch() == player.yRot) {
allowLast = false;
continue;
}
if (rotation.yaw() == player.lastYaw && rotation.pitch() == player.lastPitch && allowLast) {
if (rotation.getYaw() == player.lastXRot && rotation.getPitch() == player.lastYRot && allowLast) {
continue;
}
@@ -16,11 +16,13 @@ public class BadPacketsK extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.SPECTATE
&& player.gamemode != GameMode.SPECTATOR
&& flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
if (event.getPacketType() == PacketType.Play.Client.SPECTATE) {
if (player.gamemode != GameMode.SPECTATOR) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
}
@@ -16,11 +16,11 @@ public class BadPacketsS extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.WINDOW_CONFIRMATION
&& !new WrapperPlayClientWindowConfirmation(event).isAccepted()
&& flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
if (event.getPacketType() == PacketType.Play.Client.WINDOW_CONFIRMATION) {
if (!new WrapperPlayClientWindowConfirmation(event).isAccepted() && flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
@@ -14,20 +14,16 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientIn
@CheckData(name = "BadPacketsT")
public class BadPacketsT extends Check implements PacketCheck {
private final double maxHorizontalDisplacement;
private final double minVerticalDisplacement;
private final double maxVerticalDisplacement;
// 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
private final boolean hasLegacyExpansion = player.getClientVersion().isOlderThan(ClientVersion.V_1_9);
private final double maxHorizontalDisplacement = 0.3001 + (hasLegacyExpansion ? 0.1 : 0);
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);
// 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
double expansion = player.getClientVersion().isOlderThan(ClientVersion.V_1_9) ? 0.1 : 0;
maxHorizontalDisplacement = 0.3001 + expansion;
minVerticalDisplacement = -0.0001 - expansion;
maxVerticalDisplacement = 1.8001 + expansion;
}
@Override
@@ -31,9 +31,7 @@ public class BadPacketsU extends Check implements PacketCheck {
// except y gets wrapped?
final int expectedY = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? 4095 : 255;
final boolean failedItemCheck = packet.getItemStack().isPresent() && isEmpty(packet.getItemStack().get())
// ViaVersion can sometimes cause this part of the check to false
&& player.getClientVersion().isOlderThan(ClientVersion.V_1_9);
final boolean failedItemCheck = packet.getItemStack().isPresent() && isEmpty(packet.getItemStack().get());
final Vector3i pos = packet.getBlockPosition();
final Vector3f cursor = packet.getCursorPosition();
@@ -20,7 +20,7 @@ public class BadPacketsV extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (!player.canSkipTicks() && isTickPacket(event.getPacketType())) {
if (!player.canSkipTicksPreVia() && isTickPacket(event.getPacketType())) {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION || event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION) {
int positionAtLeastEveryNTicks = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) ? 20 : 19;
@@ -22,7 +22,7 @@ public class BadPacketsX extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flags > 0) {
setbackIfAboveSetbackVL();
}
@@ -51,7 +51,7 @@ public class BadPacketsX extends Check implements PostPredictionCheck {
switch (new WrapperPlayClientEntityAction(event).getAction()) {
case START_SNEAKING, STOP_SNEAKING -> {
if (sneak) {
if (player.canSkipTicks() || flagAndAlert()) {
if (player.canSkipTicksPreVia() || flagAndAlert()) {
flags++;
}
}
@@ -64,7 +64,7 @@ public class BadPacketsX extends Check implements PostPredictionCheck {
}
if (sprint) {
if (player.canSkipTicks() || flagAndAlert()) {
if (player.canSkipTicksPreVia() || flagAndAlert()) {
flags++;
}
}
@@ -1,32 +0,0 @@
package ac.grim.grimac.checks.impl.badpackets;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "BadPacketsZ", experimental = true)
public class BadPacketsZ extends Check implements PacketCheck {
private boolean sent;
public BadPacketsZ(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CLIENT_TICK_END) {
sent = false;
}
if (event.getPacketType() == PacketType.Play.Client.PLAYER_INPUT) {
if (sent) {
flagAndAlert();
}
sent = true;
}
}
}
@@ -23,10 +23,10 @@ public class Baritone extends Check implements RotationCheck {
final HeadRotation from = rotationUpdate.getFrom();
final HeadRotation to = rotationUpdate.getTo();
final float deltaPitch = Math.abs(to.pitch() - from.pitch());
final float deltaPitch = Math.abs(to.getPitch() - from.getPitch());
// Baritone works with small degrees, limit to 1 degree to pick up on baritone slightly moving aim to bypass anticheats
if (rotationUpdate.getDeltaXRot() == 0 && deltaPitch > 0 && deltaPitch < 1 && Math.abs(to.pitch()) != 90.0f) {
if (rotationUpdate.getDeltaXRot() == 0 && deltaPitch > 0 && deltaPitch < 1 && Math.abs(to.getPitch()) != 90.0f) {
if (rotationUpdate.getProcessor().divisorY < GrimMath.MINIMUM_DIVISOR) {
verbose++;
if (verbose > 8) {
@@ -12,7 +12,7 @@ import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import org.jetbrains.annotations.NotNull;
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 {
@@ -20,8 +20,8 @@ public class AirLiquidBreak extends Check implements BlockBreakCheck {
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 int lastX, lastY, lastZ;
private float lastHardness, lastBlastResistance;
private @NonNull Vector3i lastBreakLoc = new Vector3i();
private @NonNull StateType lastBlockType = StateTypes.AIR;
public AirLiquidBreak(GrimPlayer player) {
super(player);
@@ -40,23 +40,18 @@ public class AirLiquidBreak extends Check implements BlockBreakCheck {
// I am explicitly making this patch as narrow and specific as possible to potentially discover other blocks that exhibit similar behaviour
int newTick = GrimAPI.INSTANCE.getTickManager().currentTick;
if (lastTick == newTick
&& lastX == blockBreak.x
&& lastY == blockBreak.y
&& lastZ == blockBreak.z
&& lastBreakLoc.equals(blockBreak.position)
&& !didLastFlag
&& lastHardness == 0.0F
&& lastBlastResistance == 0.0F
&& lastBlockType.getHardness() == 0.0F
&& lastBlockType.getBlastResistance() == 0.0F
&& block == StateTypes.WATER
) return;
lastTick = newTick;
lastX = blockBreak.x;
lastY = blockBreak.y;
lastZ = blockBreak.z;
lastHardness = block.getHardness();
lastBlastResistance = block.getBlastResistance();
lastBreakLoc = blockBreak.position;
lastBlockType = block;
// the block does not have a hitbox
boolean invalid = (block == StateTypes.LIGHT && !(player.inventory.getHeldItem().is(ItemTypes.LIGHT) || player.inventory.getOffHand().is(ItemTypes.LIGHT)))
boolean invalid = (block == StateTypes.LIGHT && !(player.getInventory().getHeldItem().is(ItemTypes.LIGHT) || player.getInventory().getOffHand().is(ItemTypes.LIGHT)))
|| block.isAir()
|| block == StateTypes.WATER
|| block == StateTypes.LAVA
@@ -25,9 +25,10 @@ public class FarBreak extends Check implements BlockBreakCheck {
double min = Double.MAX_VALUE;
for (double d : player.getPossibleEyeHeights()) {
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.x, blockBreak.y, blockBreak.z);
Vector3dm best = VectorUtils.cutBoxToVector(player.x, player.y + d, player.z, box);
min = Math.min(min, best.distanceSquared(player.x, player.y + d, player.z));
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
Vector3dm eyes = new Vector3dm(player.x, player.y + d, player.z);
Vector3dm best = VectorUtils.cutBoxToVector(eyes, box);
min = Math.min(min, eyes.distanceSquared(best));
}
// getPickRange() determines this?
@@ -36,11 +36,8 @@ public class FastBreak extends Check implements BlockBreakCheck {
super(playerData);
}
// The block the player is currently breaking, represented by primitives for performance.
// `targetBlockIsSet` tracks nullness of the position, since primitives can't be null
private boolean targetBlockIsSet;
private int targetBlockX, targetBlockY, targetBlockZ;
// The block the player is currently breaking
Vector3i targetBlockPosition = null;
// The maximum amount of damage the player deals to the block
//
double maximumBlockDamage = 0;
@@ -56,7 +53,7 @@ public class FastBreak extends Check implements BlockBreakCheck {
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.action == DiggingAction.START_DIGGING) {
if (!ViaVersionUtil.isAvailable) {
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())) {
@@ -70,11 +67,8 @@ public class FastBreak extends Check implements BlockBreakCheck {
// * can we translate back "up" to server version and run check against server version to avoid loading older registries?
WrappedBlockState block = clientOlderThanServer ? WrappedBlockState.getByGlobalId(player.getClientVersion(), player.getViaTranslatedClientBlockID(blockBreak.block.getGlobalId())) : blockBreak.block;
startBreak = System.currentTimeMillis() - (!targetBlockIsSet ? 50 : 0); // ???
targetBlockIsSet = true;
targetBlockX = blockBreak.x;
targetBlockY = blockBreak.y;
targetBlockZ = blockBreak.z;
startBreak = System.currentTimeMillis() - (targetBlockPosition == null ? 50 : 0); // ???
targetBlockPosition = blockBreak.position;
maximumBlockDamage = BlockBreakSpeed.getBlockDamage(player, block);
@@ -93,7 +87,9 @@ public class FastBreak extends Check implements BlockBreakCheck {
}
clampBalance();
} else if (blockBreak.action == DiggingAction.FINISHED_DIGGING && targetBlockIsSet) {
}
if (blockBreak.action == DiggingAction.FINISHED_DIGGING && targetBlockPosition != null) {
double predictedTime = Math.ceil(1 / maximumBlockDamage) * 50;
double realTime = System.currentTimeMillis() - startBreak;
double diff = predictedTime - realTime;
@@ -121,8 +117,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())) && targetBlockIsSet) {
maximumBlockDamage = Math.max(maximumBlockDamage, BlockBreakSpeed.getBlockDamage(player, player.compensatedWorld.getBlock(targetBlockX, targetBlockY, targetBlockZ)));
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)));
}
}
@@ -21,9 +21,7 @@ public class MultiBreak extends Check implements BlockBreakCheck {
private final List<String> flags = new ArrayList<>();
private boolean hasBroken;
private BlockFace lastFace;
private int lastX;
private int lastY;
private int lastZ;
private Vector3i lastPos;
public MultiBreak(GrimPlayer player) {
super(player);
@@ -35,23 +33,11 @@ public class MultiBreak extends Check implements BlockBreakCheck {
return;
}
final int currentX = blockBreak.x;
final int currentY = blockBreak.y;
final int currentZ = blockBreak.z;
if (hasBroken && (blockBreak.face != lastFace ||
currentX != lastX ||
currentY != lastY ||
currentZ != lastZ)) {
final String currentPosString = MessageUtil.toUnlabeledString(currentX, currentY, currentZ);
final String lastPosString = MessageUtil.toUnlabeledString(lastX, lastY, lastZ);
if (hasBroken && (blockBreak.face != lastFace || !blockBreak.position.equals(lastPos))) {
final String verbose = "face=" + blockBreak.face + ", lastFace=" + lastFace
+ ", pos=" + currentPosString
+ ", lastPos=" + lastPosString;
if (!player.canSkipTicks()) {
+ ", pos=" + MessageUtil.toUnlabledString(blockBreak.position)
+ ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
blockBreak.cancel();
}
@@ -61,9 +47,7 @@ public class MultiBreak extends Check implements BlockBreakCheck {
}
lastFace = blockBreak.face;
lastX = currentX;
lastY = currentY;
lastZ = currentZ;
lastPos = blockBreak.position;
hasBroken = true;
}
@@ -76,7 +60,7 @@ public class MultiBreak extends Check implements BlockBreakCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
@@ -9,7 +9,7 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
@CheckData(name = "PositionBreakB")
@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;
@@ -7,7 +7,6 @@ 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.data.TeleportData;
import ac.grim.grimac.utils.math.Vector3dm;
import ac.grim.grimac.utils.nmsutil.Ray;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
@@ -15,7 +14,6 @@ import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.teleport.RelativeFlag;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3f;
@@ -72,7 +70,7 @@ public class RotationBreak extends Check implements BlockBreakCheck {
}
private boolean didRayTraceHit(BlockBreak blockBreak) {
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.x, blockBreak.y, blockBreak.z);
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
@@ -94,18 +92,18 @@ public class RotationBreak extends Check implements BlockBreakCheck {
// End checking if the player is in the block
List<Vector3f> possibleLookDirs = new ArrayList<>(Arrays.asList(
new Vector3f(player.lastYaw, player.pitch, 0),
new Vector3f(player.yaw, player.pitch, 0)
new Vector3f(player.lastXRot, player.yRot, 0),
new Vector3f(player.xRot, player.yRot, 0)
));
// 1.9+ players could be a tick behind because we don't get skipped ticks
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
possibleLookDirs.add(new Vector3f(player.lastYaw, player.lastPitch, 0));
possibleLookDirs.add(new Vector3f(player.lastXRot, player.lastYRot, 0));
}
// 1.7 players do not have any of these issues! They are always on the latest look vector
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
possibleLookDirs = Collections.singletonList(new Vector3f(player.yaw, player.pitch, 0));
possibleLookDirs = Collections.singletonList(new Vector3f(player.xRot, player.yRot, 0));
}
final double distance = player.compensatedEntities.self.getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
@@ -113,8 +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());
Vector3dm pointAtDistance = trace.getPointAtDistance(distance);
Pair<Vector3dm, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOriginX(), trace.getOriginY(), trace.getOriginZ(), pointAtDistance.getX(), pointAtDistance.getY(), pointAtDistance.getZ());
Pair<Vector3dm, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.first() != null) return true;
}
@@ -6,8 +6,6 @@ import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.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;
@@ -17,16 +15,9 @@ 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 final int exemptedY = player.getClientVersion().isOlderThan(ClientVersion.V_1_8) ? 255 : (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14) ? -1 : 4095);
private boolean lastBlockWasInstantBreak = false;
private boolean lastBlockIsSet;
private int lastBlockX, lastBlockY, lastBlockZ;
private boolean lastCancelledBlockIsSet;
private int lastCancelledBlockX, lastCancelledBlockY, lastCancelledBlockZ;
private boolean lastLastBlockIsSet;
private Vector3i lastBlock, lastCancelledBlock, lastLastBlock = null;
public WrongBreak(final GrimPlayer player) {
super(player);
@@ -34,7 +25,8 @@ public class WrongBreak extends Check implements BlockBreakCheck {
// The client sometimes sends a wierd cancel packet
private boolean shouldExempt(final WrappedBlockState block, int yPos) {
if (lastLastBlockIsSet || !lastBlockIsSet)
// 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
@@ -47,29 +39,22 @@ public class WrongBreak extends Check implements BlockBreakCheck {
@Override
public void onBlockBreak(BlockBreak blockBreak) {
final int x = blockBreak.x;
final int y = blockBreak.y;
final int z = blockBreak.z;
if (blockBreak.action == DiggingAction.START_DIGGING) {
final Vector3i pos = blockBreak.position;
lastBlockWasInstantBreak = getBlockDamage(player, blockBreak.block) >= 1;
lastCancelledBlockIsSet = false;
lastCancelledBlock = null;
lastLastBlock = lastBlock;
lastBlock = pos;
}
lastLastBlockIsSet = lastBlockIsSet;
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
final Vector3i pos = blockBreak.position;
lastBlockIsSet = true;
lastBlockX = x;
lastBlockY = y;
lastBlockZ = z;
} else if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
boolean notLastBlock = !lastBlockIsSet || x != lastBlockX || y != lastBlockY || z != lastBlockZ;
if (!shouldExempt(blockBreak.block, y) && notLastBlock) {
if (!shouldExempt(blockBreak.block, pos.y) && !pos.equals(lastBlock)) {
// https://github.com/GrimAnticheat/Grim/issues/1512
boolean isLastCancelled = lastCancelledBlockIsSet && x == lastCancelledBlockX && y == lastCancelledBlockY && z == lastCancelledBlockZ;
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || (!lastBlockWasInstantBreak && isLastCancelled)) {
String lastBlockStr = lastBlockIsSet ? MessageUtil.toUnlabeledString(lastBlockX, lastBlockY, lastBlockZ) : "null";
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + lastBlockStr + ", pos=" + MessageUtil.toUnlabeledString(x, y, z))) {
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || (!lastBlockWasInstantBreak && pos.equals(lastCancelledBlock))) {
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
if (shouldModifyPackets()) {
blockBreak.cancel();
}
@@ -77,20 +62,18 @@ public class WrongBreak extends Check implements BlockBreakCheck {
}
}
lastCancelledBlockIsSet = true;
lastCancelledBlockX = x;
lastCancelledBlockY = y;
lastCancelledBlockZ = z;
lastCancelledBlock = pos;
lastLastBlock = null;
lastBlock = null;
return;
}
lastLastBlockIsSet = lastBlockIsSet = false;
} else if (blockBreak.action == DiggingAction.FINISHED_DIGGING) {
boolean notLastCancelled = !lastCancelledBlockIsSet || x != lastCancelledBlockX || y != lastCancelledBlockY || z != lastCancelledBlockZ;
boolean notLastBlock = !lastBlockIsSet || x != lastBlockX || y != lastBlockY || z != lastBlockZ;
if (blockBreak.action == DiggingAction.FINISHED_DIGGING) {
final Vector3i pos = blockBreak.position;
// when a player looks away from the mined block, they send a cancel, and if they look at it again, they don't send another start. (thanks mojang!)
if (notLastCancelled && (!lastBlockWasInstantBreak || player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) && notLastBlock) {
String lastBlockStr = lastBlockIsSet ? MessageUtil.toUnlabeledString(lastBlockX, lastBlockY, lastBlockZ) : "null";
if (flagAndAlert("action=FINISHED_DIGGING" + ", last=" + lastBlockStr + ", pos=" + MessageUtil.toUnlabeledString(x, y, z))) {
if (!pos.equals(lastCancelledBlock) && (!lastBlockWasInstantBreak || player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) && !pos.equals(lastBlock)) {
if (flagAndAlert("action=FINISHED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
if (shouldModifyPackets()) {
blockBreak.cancel();
}
@@ -99,7 +82,9 @@ public class WrongBreak extends Check implements BlockBreakCheck {
// 1.14.4+ clients don't send another start break in protected regions
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) {
lastCancelledBlockIsSet = lastLastBlockIsSet = lastBlockIsSet = false;
lastCancelledBlock = null;
lastLastBlock = null;
lastBlock = null;
}
}
}
@@ -4,10 +4,9 @@ import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientTabComplete;
@CheckData(name = "ChatA", experimental = true)
@@ -19,7 +18,7 @@ public class ChatA extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13)) {
WrapperPlayClientTabComplete wrapper = new WrapperPlayClientTabComplete(event);
String text = wrapper.getText();
if (text.equals("/") || text.trim().isEmpty()) {
@@ -4,12 +4,9 @@ import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import ac.grim.grimac.utils.via.ViaHooks;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatCommand;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatCommandUnsigned;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatMessage;
@@ -26,8 +23,11 @@ public class ChatB extends Check implements PacketCheck {
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CHAT_MESSAGE) {
String message = new WrapperPlayClientChatMessage(event).getMessage();
if (checkChatMessage(message)) {
event.setCancelled(true);
if (message.isEmpty() || !message.trim().equals(message) || message.startsWith("/") && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_19)) {
if (flagAndAlert("message=" + message)) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
@@ -42,7 +42,6 @@ public class ChatB extends Check implements PacketCheck {
}
if (event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND) {
// TODO make previa after making wrapper parse by client version instead of server version
String command = "/" + new WrapperPlayClientChatCommand(event).getCommand();
if (!command.trim().equals(command)) {
if (flagAndAlert("command=" + command)) {
@@ -52,21 +51,4 @@ public class ChatB extends Check implements PacketCheck {
}
}
}
// returns whether the packet should be cancelled
public boolean checkChatMessage(String message) {
if (message.isEmpty() || !message.trim().equals(message) || message.startsWith("/") && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_19)) {
if (flagAndAlert("message=" + message) && shouldModifyPackets()) {
player.onPacketCancel();
return true;
}
}
return false;
}
static {
if (ViaVersionUtil.isAvailable && PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_11)) {
ViaHooks.injectVia();
}
}
}
@@ -28,7 +28,6 @@ public class ChatC extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CHAT_MESSAGE) {
// TODO make previa after making wrapper parse by client version instead of server version
check(new WrapperPlayClientChatMessage(event).getMessage(), event);
}
@@ -37,7 +36,6 @@ public class ChatC extends Check implements PacketCheck {
}
if (event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND) {
// TODO make previa after making wrapper parse by client version instead of server version
check("/" + new WrapperPlayClientChatCommand(event).getCommand(), event);
}
}
@@ -33,7 +33,7 @@ public class MultiInteractA extends Check implements PostPredictionCheck {
if (hasInteracted && entity != lastEntity) {
String verbose = "lastEntity=" + lastEntity + ", entity=" + entity
+ ", lastSneaking=" + lastSneaking + ", sneaking=" + sneaking;
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -55,7 +55,7 @@ public class MultiInteractA extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
@@ -35,7 +35,7 @@ public class MultiInteractB extends Check implements PostPredictionCheck {
if (hasInteracted && !pos.equals(lastPos)) {
String verbose = "pos=" + MessageUtil.toUnlabledString(pos) + ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -56,7 +56,7 @@ public class MultiInteractB extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
@@ -143,10 +143,7 @@ public class Reach extends Check implements PacketCheck {
} else {
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
if (reachEntity.type == EntityTypes.END_CRYSTAL) {
final double x = reachEntity.trackedServerPosition.getX();
final double y = reachEntity.trackedServerPosition.getX();
final double z = reachEntity.trackedServerPosition.getX();
targetBox = new SimpleCollisionBox(x - 1, y, z - 1, x + 1, y + 2, z + 1);
targetBox = new SimpleCollisionBox(reachEntity.trackedServerPosition.getPos().subtract(1, 0, 1), reachEntity.trackedServerPosition.getPos().add(1, 2, 1));
}
return ReachUtils.getMinReachToBox(player, targetBox) > player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
}
@@ -178,10 +175,7 @@ public class Reach extends Check implements PacketCheck {
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
if (reachEntity.type == EntityTypes.END_CRYSTAL) { // Hardcode end crystal box
final double x = reachEntity.trackedServerPosition.getX();
final double y = reachEntity.trackedServerPosition.getX();
final double z = reachEntity.trackedServerPosition.getX();
targetBox = new SimpleCollisionBox(x - 1, y, z - 1, x + 1, y + 2, z + 1);
targetBox = new SimpleCollisionBox(reachEntity.trackedServerPosition.getPos().subtract(1, 0, 1), reachEntity.trackedServerPosition.getPos().add(1, 2, 1));
}
// 1.7 and 1.8 players get a bit of extra hitbox (this is why you should use 1.8 on cross version servers)
@@ -203,20 +197,20 @@ public class Reach extends Check implements PacketCheck {
double minDistance = Double.MAX_VALUE;
// https://bugs.mojang.com/browse/MC-67665
List<Vector3dm> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.yaw, player.pitch)));
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) {
possibleLookDirs.add(ReachUtils.getLook(player, player.lastYaw, player.pitch));
possibleLookDirs.add(ReachUtils.getLook(player, player.lastXRot, player.yRot));
// 1.9+ players could be a tick behind because we don't get skipped ticks
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
possibleLookDirs.add(ReachUtils.getLook(player, player.lastYaw, player.lastPitch));
possibleLookDirs.add(ReachUtils.getLook(player, player.lastXRot, player.lastYRot));
}
// 1.7 players do not have any of these issues! They are always on the latest look vector
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
possibleLookDirs = Collections.singletonList(ReachUtils.getLook(player, player.yaw, player.pitch));
possibleLookDirs = Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot));
}
}
@@ -224,27 +218,21 @@ 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 double eyePosX = from.getX();
final double eyePosZ = from.getZ();
final Vector3dm eyePos = new Vector3dm(from.getX(), 0, from.getZ());
for (Vector3dm lookVec : possibleLookDirs) {
for (double eye : possibleEyeHeights) {
final double eyePosY = from.getY() + eye;
eyePos.setY(from.getY() + eye);
Vector3dm endReachPos = eyePos.clone().add(new Vector3dm(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
final double endX = eyePosX + lookVec.getX() * distance;
final double endY = eyePosY + lookVec.getY() * distance;
final double endZ = eyePosZ + lookVec.getZ() * distance;
Vector3dm intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
Vector3dm intercept = ReachUtils.calculateIntercept(targetBox, eyePosX, eyePosY, eyePosZ, endX, endY, endZ).first();
if (ReachUtils.isVecInside(targetBox, eyePosX, eyePosY, eyePosZ)) {
if (ReachUtils.isVecInside(targetBox, eyePos)) {
minDistance = 0;
break;
}
if (intercept != null) {
minDistance = Math.min(intercept.distance(eyePosX, eyePosY, eyePosZ), minDistance);
minDistance = Math.min(eyePos.distance(intercept), minDistance);
}
}
}
@@ -22,7 +22,7 @@ public class CrashH extends Check implements PacketCheck {
String text = wrapper.getText();
final int length = text.length();
// general length limit
if (length > (!player.canUseGameMasterBlocks() ? 256 : 32500)) {
if (length > 256) {
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -10,7 +10,7 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "ElytraA", description = "Started gliding while already gliding")
@CheckData(name = "ElytraA", description = "Started gliding while already gliding", experimental = true)
public class ElytraA extends Check implements PostPredictionCheck {
private boolean setback;
@@ -9,7 +9,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "ElytraB", description = "Started gliding without jumping")
@CheckData(name = "ElytraB", description = "Started gliding without jumping", experimental = true)
public class ElytraB extends Check implements PostPredictionCheck {
private boolean glide;
private boolean setback;
@@ -22,7 +22,7 @@ public class ElytraB extends Check implements PostPredictionCheck {
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
&& player.supportsEndTick()
&& player.supportsEndTickPreVia()
) {
if (player.packetStateData.knownInput.jump()) {
if (flagAndAlert("no release")) {
@@ -11,7 +11,7 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "ElytraC", description = "Started gliding too frequently")
@CheckData(name = "ElytraC", description = "Started gliding too frequently", experimental = true)
public class ElytraC extends Check implements PostPredictionCheck {
private boolean glideThisTick, glideLastTick, setback;
private int flags;
@@ -33,7 +33,7 @@ public class ElytraC extends Check implements PostPredictionCheck {
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION && new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA && !exempt) {
if (glideThisTick || glideLastTick) {
if (player.canSkipTicks()) {
if (player.canSkipTicksPreVia()) {
flags++;
} else {
if (flagAndAlert()) {
@@ -58,7 +58,7 @@ public class ElytraC extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (player.canSkipTicks()) {
if (player.canSkipTicksPreVia()) {
if (player.isTickingReliablyFor(3)) {
for (; flags > 0; flags--) {
flagAndAlert();
@@ -10,7 +10,7 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "ElytraF", description = "Started gliding while on ground")
@CheckData(name = "ElytraF", description = "Started gliding while on ground", experimental = true)
public class ElytraF extends Check implements PostPredictionCheck {
private boolean setback;
@@ -5,9 +5,7 @@ import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.payload.PayloadItemName;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientNameItem;
@@ -26,7 +24,7 @@ public class ExploitA extends Check implements PacketCheck {
check(new WrapperPlayClientNameItem(event).getItemName(), event);
}
if (event.getPacketType() == PacketType.Play.Client.PLUGIN_MESSAGE && PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_13)) {
if (event.getPacketType() == PacketType.Play.Client.PLUGIN_MESSAGE && player.getClientVersion().isOlderThan(ClientVersion.V_1_13)) {
WrapperPlayClientPluginMessage wrapper = new WrapperPlayClientPluginMessage(event);
if (wrapper.getChannelName().equals("MC|ItemName")) {
check(PayloadItemName.CODEC.read(wrapper.getData()).itemName(), event);
@@ -5,9 +5,7 @@ import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.payload.PayloadBookEdit;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.component.ComponentTypes;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
@@ -37,7 +35,6 @@ import java.util.Set;
@CheckData(name = "ExploitB", description = "Invalid book edit")
public class ExploitB extends Check implements PacketCheck {
private static final boolean IS_1_8 = PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_8_8);
private ItemStack oldBook;
private InteractionHand hand;
@@ -47,11 +44,13 @@ public class ExploitB extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (IS_1_8 ? event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)
? event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
&& new WrapperPlayClientPlayerBlockPlacement(event).getFaceId() == 255
: event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
hand = IS_1_8 ? InteractionHand.MAIN_HAND : new WrapperPlayClientUseItem(event).getHand();
oldBook = player.inventory.getItemInHand(hand).copy();
hand = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)
? InteractionHand.MAIN_HAND : new WrapperPlayClientUseItem(event).getHand();
oldBook = player.getInventory().getItemInHand(hand).copy();
}
if (event.getPacketType() == PacketType.Play.Client.EDIT_BOOK) {
@@ -60,7 +59,7 @@ public class ExploitB extends Check implements PacketCheck {
}
// 1.13-
if (event.getPacketType() == PacketType.Play.Client.PLUGIN_MESSAGE && PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_13)) {
if (event.getPacketType() == PacketType.Play.Client.PLUGIN_MESSAGE && player.getClientVersion().isOlderThan(ClientVersion.V_1_13)) {
WrapperPlayClientPluginMessage wrapper = new WrapperPlayClientPluginMessage(event);
boolean signing;
@@ -107,7 +106,8 @@ public class ExploitB extends Check implements PacketCheck {
private void checkItemStack(ItemStack newBook, boolean signing, PacketReceiveEvent event) {
if (checkEditingBook(event)) return;
ItemType expectedType = signing && IS_1_8 ? ItemTypes.WRITTEN_BOOK : ItemTypes.WRITABLE_BOOK;
ItemType expectedType = signing && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)
? ItemTypes.WRITTEN_BOOK : ItemTypes.WRITABLE_BOOK;
if (!newBook.is(expectedType)) {
if (flagAndAlert("expectedType=" + expectedType.getName().getKey() + ", type=" + newBook.getType().getName().getKey()) && shouldModifyPackets()) {
event.setCancelled(true);
@@ -176,7 +176,7 @@ public class ExploitB extends Check implements PacketCheck {
String last = null;
for (NBTString string : newPagesNBT.getTags()) {
if (IS_1_8 && signing) {
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && signing) {
try {
JsonReader reader = new JsonReader(new StringReader(string.getValue()));
if (reader.peek() != JsonToken.BEGIN_OBJECT) throw new JsonSyntaxException("");
@@ -238,7 +238,7 @@ public class ExploitB extends Check implements PacketCheck {
player.onPacketCancel();
}
return true;
} else if (title.isEmpty() || !title.trim().equals(title) || containsInvalidCharacters(title, false)) {
} else if (title.isEmpty() || !title.trim().equals(title) || containsInvalidCharacters(title)) {
if (flagAndAlert("invalid title '" + title + "'") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -287,7 +287,7 @@ public class ExploitB extends Check implements PacketCheck {
return true;
}
if (containsInvalidCharacters(page, true)) {
if (containsInvalidCharacters(page)) {
if (flagAndAlert("invalid page characters") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -310,10 +310,10 @@ public class ExploitB extends Check implements PacketCheck {
return false;
}
private static boolean containsInvalidCharacters(@NotNull String string, boolean allowLineBreak) {
private static boolean containsInvalidCharacters(@NotNull String string) {
for (int i = 0; i < string.length(); ++i) {
char character = string.charAt(i);
if (character == 167 || character < 32 && (!allowLineBreak || character != 10) || character == 127) {
if (character == 167 || character < 32 || character == 127) {
return true;
}
}
@@ -35,10 +35,11 @@ public class NoFall extends Check implements PacketCheck {
if (player.getSetbackTeleportUtil().blockOffsets) return;
WrapperPlayClientPlayerFlying wrapper = new WrapperPlayClientPlayerFlying(event);
boolean hasPosition = false;
// If the player claims to be on the ground
// Run this code IFF the player doesn't send the position, as that won't get processed by predictions
if (wrapper.isOnGround() && !wrapper.hasPositionChanged()) {
if (wrapper.isOnGround() && !hasPosition) {
if (!isNearGround(wrapper.isOnGround())) { // If player isn't near ground
// 1.8 boats have a mind on their own... only flag if they're not near a boat or are on 1.9+
if (!GhostBlockDetector.isGhostBlock(player)) flagAndAlertWithSetback();
@@ -75,7 +76,7 @@ public class NoFall extends Check implements PacketCheck {
}
}
private boolean isNearGround(boolean onGround) {
public boolean isNearGround(boolean onGround) {
if (onGround) {
SimpleCollisionBox feetBB = GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.x, player.y, player.z, 0.6f, 0.001f);
feetBB.expand(player.getMovementThreshold()); // Movement threshold can be in any direction
@@ -14,8 +14,8 @@ public class NoSlow extends Check implements PostPredictionCheck {
// to another item that can be used. What the fuck mojang. Affects 1.8 (and most likely 1.7) clients.
public boolean didSlotChangeLastTick = false;
public boolean flaggedLastTick = false;
private double offsetToFlag;
private double bestOffset = 1;
double offsetToFlag;
double bestOffset = 1;
public NoSlow(GrimPlayer player) {
super(player);
@@ -15,8 +15,6 @@ public class VehiclePredictionRunner extends Check implements VehicleCheck {
public void process(final VehiclePositionUpdate vehicleUpdate) {
// Vehicle onGround = false always
// We don't do vehicle setbacks because vehicle netcode sucks.
player.movementCheckRunner.processAndCheckMovementPacket(new PositionUpdate(
vehicleUpdate.fromX(), vehicleUpdate.fromY(), vehicleUpdate.fromZ(), vehicleUpdate.toX(), vehicleUpdate.toY(), vehicleUpdate.toZ(),
false, null, null, vehicleUpdate.isTeleport()));
player.movementCheckRunner.processAndCheckMovementPacket(new PositionUpdate(vehicleUpdate.getFrom(), vehicleUpdate.getTo(), false, null, null, vehicleUpdate.isTeleport()));
}
}
@@ -17,7 +17,7 @@ public class MultiActionsA extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.itemInUseHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
if (new WrapperPlayClientInteractEntity(event).getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
@@ -16,7 +16,7 @@ public class MultiActionsB extends Check implements BlockBreakCheck {
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.itemInUseHand == InteractionHand.OFF_HAND)) {
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND)) {
// this is vanilla on 1.7
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
return;
@@ -12,13 +12,12 @@ import org.jetbrains.annotations.NotNull;
import java.util.StringJoiner;
@CheckData(name = "MultiActionsC", description = "Clicked in inventory while moving")
@CheckData(name = "MultiActionsC", description = "Clicked in inventory while moving", experimental = true)
public class MultiActionsC extends Check implements PacketCheck {
public MultiActionsC(GrimPlayer player) {
super(player);
}
// TODO: move this to a bett spot? not sure where to put this
@Contract(pure = true)
public static String getVerbose(@NotNull GrimPlayer player) {
StringJoiner verbose = new StringJoiner(", ");
@@ -30,7 +29,7 @@ public class MultiActionsC extends Check implements PacketCheck {
verbose.add("sneaking");
}
if (player.supportsEndTick() && player.packetStateData.knownInput.moving()) {
if (player.supportsEndTickPreVia() && player.packetStateData.knownInput.moving()) {
verbose.add("input");
}
@@ -7,7 +7,7 @@ import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "MultiActionsD", description = "Closed inventory while moving")
@CheckData(name = "MultiActionsD", description = "Closed inventory while moving", experimental = true)
public class MultiActionsD extends Check implements PacketCheck {
public MultiActionsD(GrimPlayer player) {
super(player);
@@ -21,7 +21,7 @@ public class MultiActionsE extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (!dropping && player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.itemInUseHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.ANIMATION) {
if (!dropping && player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.ANIMATION) {
// this is possible to false on 1.7
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
return;
@@ -33,7 +33,7 @@ public class MultiActionsE extends Check implements PacketCheck {
}
}
if (!isAsync(event.getPacketType())) {
if (event.getPacketType() != PacketType.Play.Client.KEEP_ALIVE) {
dropping = false;
}
@@ -16,7 +16,7 @@ import java.util.List;
@CheckData(name = "MultiActionsF", description = "Interacting with a block and an entity in the same tick", experimental = true)
public class MultiActionsF extends BlockPlaceCheck {
private final List<String> flags = new ArrayList<>();
private boolean entity, block;
boolean entity, block;
public MultiActionsF(GrimPlayer player) {
super(player);
@@ -25,7 +25,7 @@ public class PacketOrderA extends Check implements PostPredictionCheck {
if ((clickType == WindowClickType.PICKUP || clickType == WindowClickType.PICKUP_ALL) && player.packetOrderProcessor.isQuickMoveClicking()
|| clickType == WindowClickType.QUICK_MOVE && player.packetOrderProcessor.isPickUpClicking()) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -39,7 +39,7 @@ public class PacketOrderA extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
@@ -4,9 +4,7 @@ import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
@@ -18,18 +16,6 @@ public class PacketOrderB extends Check implements PacketCheck {
// I personally think 1.8 made much more sense. You swing and THEN you hit!
private final boolean is1_9 = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9);
// There is a "bug" in ViaRewind
// 1.8 packet order: ANIMATION -> INTERACT
// 1.9 packet order: INTERACT -> ANIMATION
// ViaRewind, on 1.9+ servers, delays a 1.8 client's ANIMATION to be after INTERACT (but before flying).
// Which means we see 1.9 packet order for 1.8 clients
// Due to ViaRewind also delaying the swings, we then see packet order above 20CPS like:
// INTERACT -> INTERACT -> ANIMATION -> ANIMATION
// 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!
private final boolean exempt = player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9);
private boolean sentAnimationSinceLastAttack = player.getClientVersion().isNewerThan(ClientVersion.V_1_8);
private boolean sentAttack, sentAnimation, sentSlotSwitch;
@@ -39,8 +25,6 @@ public class PacketOrderB extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (exempt) return;
if (event.getPacketType() == PacketType.Play.Client.ANIMATION) {
sentAnimationSinceLastAttack = sentAnimation = true;
sentAttack = sentSlotSwitch = false;
@@ -70,7 +54,7 @@ public class PacketOrderB extends Check implements PacketCheck {
return; // do not set sentAnimation to false
}
if (!isAsync(event.getPacketType())) {
if (event.getPacketType() != PacketType.Play.Client.KEEP_ALIVE) {
if (sentAttack && is1_9) {
flagAndAlert("post-attack");
}
@@ -42,7 +42,7 @@ public class PacketOrderE extends Check implements PostPredictionCheck {
+ ", sprinting=" + player.packetOrderProcessor.isSprinting()
+ ", gliding=" + player.packetOrderProcessor.isStartingToGlide()
+ ", mountJumping=" + player.packetOrderProcessor.isJumpingWithMount();
if (player.canSkipTicks() && flags.add(verbose) || flagAndAlert(verbose)) {
if (player.canSkipTicksPreVia() && flags.add(verbose) || flagAndAlert(verbose)) {
if (player.packetOrderProcessor.isUsing()) {
setback = true;
}
@@ -53,7 +53,7 @@ public class PacketOrderE extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (setback) {
setback = false;
setbackIfAboveSetbackVL();
@@ -39,7 +39,7 @@ public class PacketOrderF extends Check implements PostPredictionCheck {
: "openInventory")
+ ", sprinting=" + player.packetOrderProcessor.isSprinting()
+ ", sneaking=" + player.packetOrderProcessor.isSneaking();
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING
&& new WrapperPlayClientPlayerDigging(event).getAction() == DiggingAction.RELEASE_USE_ITEM
@@ -56,7 +56,7 @@ public class PacketOrderF extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
@@ -47,7 +47,7 @@ public class PacketOrderG extends Check implements PostPredictionCheck {
+ ", rightClicking=" + player.packetOrderProcessor.isRightClicking()
+ ", picking=" + player.packetOrderProcessor.isPicking()
+ ", digging=" + player.packetOrderProcessor.isDigging();
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -61,7 +61,7 @@ public class PacketOrderG extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
@@ -24,7 +24,7 @@ public class PacketOrderH extends Check implements PostPredictionCheck {
switch (new WrapperPlayClientEntityAction(event).getAction()) {
case START_SPRINTING, STOP_SPRINTING -> {
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_21_2) && player.packetOrderProcessor.isSneaking()) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
flagAndAlert();
} else {
invalid++;
@@ -33,7 +33,7 @@ public class PacketOrderH extends Check implements PostPredictionCheck {
}
case START_SNEAKING, STOP_SNEAKING -> {
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) && player.packetOrderProcessor.isSprinting()) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
flagAndAlert();
} else {
invalid++;
@@ -46,7 +46,7 @@ public class PacketOrderH extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
@@ -37,7 +37,7 @@ public class PacketOrderI extends Check implements PostPredictionCheck {
+ ", picking=" + player.packetOrderProcessor.isPicking()
+ ", releasing=" + player.packetOrderProcessor.isReleasing()
+ ", digging=" + player.packetOrderProcessor.isDigging();
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -48,7 +48,7 @@ public class PacketOrderI extends Check implements PostPredictionCheck {
}
} else if (player.packetOrderProcessor.isReleasing() || player.packetOrderProcessor.isDigging()) {
String verbose = "type=interact, releasing=" + player.packetOrderProcessor.isReleasing() + ", digging=" + player.packetOrderProcessor.isDigging();
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -62,7 +62,7 @@ public class PacketOrderI extends Check implements PostPredictionCheck {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT || event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
if (player.packetOrderProcessor.isReleasing() || digging) {
String verbose = "type=place/use, releasing=" + player.packetOrderProcessor.isReleasing() + ", digging=" + digging;
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -83,7 +83,7 @@ public class PacketOrderI extends Check implements PostPredictionCheck {
+ ", rightClicking=" + player.packetOrderProcessor.isRightClicking()
+ ", picking=" + player.packetOrderProcessor.isPicking()
+ ", digging=" + player.packetOrderProcessor.isDigging();
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose)) {
setback = true;
}
@@ -113,7 +113,7 @@ public class PacketOrderI extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (setback) {
setbackIfAboveSetbackVL();
setback = false;
@@ -20,7 +20,7 @@ public class PacketOrderJ extends Check implements PostPredictionCheck {
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT || event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
if (player.packetOrderProcessor.isAttacking() && !player.packetOrderProcessor.isInteracting()) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -34,7 +34,7 @@ public class PacketOrderJ extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
@@ -25,7 +25,7 @@ public class PacketOrderK extends Check implements PostPredictionCheck {
if (new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT) {
if (player.packetOrderProcessor.isClickingInInventory() || player.packetOrderProcessor.isClosingInventory()) {
String verbose = "open, clicking=" + player.packetOrderProcessor.isClickingInInventory() + ", closing=" + player.packetOrderProcessor.isClosingInventory();
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
flagAndAlert(verbose);
} else {
flags.add(verbose);
@@ -37,7 +37,7 @@ public class PacketOrderK extends Check implements PostPredictionCheck {
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW || event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
if (player.packetOrderProcessor.isOpeningInventory()) {
String verbose = event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW ? "click" : "close";
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -51,7 +51,7 @@ public class PacketOrderK extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
@@ -26,7 +26,7 @@ public class PacketOrderL extends Check implements PostPredictionCheck {
if (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS) {
if (new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT) {
if (player.packetOrderProcessor.isDropping()) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert("inventory") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -41,7 +41,7 @@ public class PacketOrderL extends Check implements PostPredictionCheck {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
if (new WrapperPlayClientPlayerDigging(event).getAction() == DiggingAction.SWAP_ITEM_WITH_OFFHAND) {
if (player.packetOrderProcessor.isDropping()) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert("swap") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -56,7 +56,7 @@ public class PacketOrderL extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
@@ -27,7 +27,7 @@ public class PacketOrderM extends Check implements PostPredictionCheck {
if (new WrapperPlayClientInteractEntity(event).getAction() != WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
interacting = true;
if (usingWithoutInteract) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -56,7 +56,7 @@ public class PacketOrderM extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
@@ -24,7 +24,7 @@ public class PacketOrderN extends BlockPlaceCheck {
public void onBlockPlace(BlockPlace place) {
placing = true;
if (usingWithoutPlacing) {
if (!player.canSkipTicks()) {
if (!player.canSkipTicksPreVia()) {
if (flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
place.resync();
}
@@ -53,7 +53,7 @@ public class PacketOrderN extends BlockPlaceCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (!player.canSkipTicksPreVia()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
Loaded 100 of 377 files, more files were not shown because too many files have changed in this diff. Show more