Compare commits

..
166 changed files with 841 additions and 1749 deletions

No files matched your search

-3
View File
@@ -17,6 +17,3 @@ ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_wrap_on_typing = false
[.github/ISSUE_TEMPLATE/*.yml]
indent_size = 2
+10 -10
View File
@@ -5,7 +5,7 @@ body:
- type: textarea
attributes:
label: Describe the bypass and how to replicate it
description: Provide a video or detailed instructions to help replicate it.
description: Provide a video, or detailed instructions to help replicate it.
placeholder: |
Step 1. Do this
Step 2. Then do this
@@ -17,8 +17,8 @@ body:
attributes:
label: Grim version
description: |
Provide the version of Grim running on the server. You can run `/grim version` to check.
placeholder: Examples include 2.3.73-8ddd7f1, 2.3.72, etc.
Provide the git commit or the version in the jar's name.
placeholder: A example would be b85c2d0 or grim version 2.3.5, etc
validations:
required: true
@@ -26,23 +26,23 @@ body:
attributes:
label: Server version
description: |
Run `/version` on your server to check. Provide both the server type (ie Paper, Airplane, etc) & the Minecraft version.
Run `/version` on your server to check. Provide both the server type (paper, airplane, etc) & the minecraft version.
validations:
required: true
- type: input
attributes:
label: Client version
description: |
Provide the version of your Minecraft client. Also provide the protocol version if changed.
label: Client version
description: |
Provide the version of your Minecraft client.
validations:
required: true
required: true
- type: textarea
attributes:
label: Plugins/Mods
label: Plugins
description: |
List all plugins or mods installed on your server. To list plugins on Bukkit-based servers, run `/plugins`.
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
validations:
required: true
+14 -14
View File
@@ -6,7 +6,7 @@ body:
attributes:
label: Stack trace
description: |
Provide the entire stack trace with no attachments. If you would like, you can use a text pasting site such as https://mclo.gs.
Please include the entire stack trace with no attachments. If you would like, you can use a text pasting site such as https://paste.gg.
placeholder: Paste the stack trace or link to the stack trace here
validations:
required: true
@@ -14,7 +14,7 @@ body:
- type: textarea
attributes:
label: How to replicate it if known
description: A video or detailed instructions to help replicate the issue would help.
description: A video, or detailed instructions to help replicate the issue would help.
placeholder: |
Step 1. Do this
Step 2. Then do this
@@ -26,8 +26,8 @@ body:
attributes:
label: Grim version
description: |
Provide the version of Grim running on the server. You can run `/grim version` to check.
placeholder: Examples include 2.3.73-8ddd7f1, 2.3.72, etc.
Provide the git commit or the version in the jar's name.
placeholder: A example would be b85c2d0 or grim version 2.3.5, etc
validations:
required: true
@@ -35,27 +35,27 @@ body:
attributes:
label: Server version
description: |
Run `/version` on your server to check. Provide both the server type (ie Paper, Airplane, etc) & the Minecraft version.
Run `/version` on your server to check. Provide both the server type (paper, airplane, etc) & the minecraft version.
validations:
required: true
- type: dropdown
id: type
attributes:
label: Affected Platform(s)
description: Which platforms does this issue affect? If you aren't sure, select both.
options:
- "Bukkit"
- "Fabric"
multiple: true
label: Affected Platform(s)
description: Which platforms does this issue affect? If you aren't sure, select both.
options:
- "Bukkit"
- "Fabric"
multiple: true
validations:
required: true
required: true
- type: textarea
attributes:
label: Plugins/Mods
label: Plugins/mods
description: |
List all plugins or mods installed on your server. To list plugins on Bukkit-based servers, run `/plugins`.
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
validations:
required: true
+7 -7
View File
@@ -20,8 +20,8 @@ body:
attributes:
label: Grim version
description: |
Provide the version of Grim running on the server. You can run `/grim version` to check.
placeholder: Examples include 2.3.73-8ddd7f1, 2.3.72, etc.
Provide the git commit or the version in the jar's name.
placeholder: A example would be b85c2d0 or grim version 2.3.5, etc
validations:
required: true
@@ -29,7 +29,7 @@ body:
attributes:
label: Server version
description: |
Run `/version` on your server to check. Provide both the server type (ie Paper, Airplane, etc) & the Minecraft version.
Run `/version` on your server to check. Provide both the server type (paper, airplane, etc) & the minecraft version.
validations:
required: true
@@ -37,16 +37,16 @@ body:
attributes:
label: Client version
description: |
Provide the version of your Minecraft client. You must be able to reproduce the false positive using a vanilla client.
Using Lunar Client, TLauncher, Fabric, etc, will result in your issue being closed.
Provide the version of your Minecraft client. You must be able to reproduce the false positive using the vanilla client.
Lunar Client, TLauncher etc. will result in your issue being closed.
validations:
required: true
- type: textarea
attributes:
label: Plugins/Mods
label: Plugins
description: |
List all plugins or mods installed on your server. To list plugins on Bukkit-based servers, run `/plugins`.
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
validations:
required: true
+2 -2
View File
@@ -5,6 +5,6 @@ body:
- type: textarea
attributes:
label: Feature description
description: Describe the feature and why it should be added.
description: Describe the feature and why it should be added
validations:
required: true
required: true
+14 -13
View File
@@ -5,7 +5,7 @@ body:
- type: textarea
attributes:
label: Describe the bug and how to replicate it
description: A video or detailed instructions to help replicate the issue would help.
description: A video, or detailed instructions to help replicate the issue would help.
placeholder: |
Step 1. Do this
Step 2. Then do this
@@ -16,8 +16,9 @@ body:
- type: textarea
attributes:
label: Grim version
description: Provide the version of Grim running on the server. You can run `/grim version` to check.
placeholder: Examples include 2.3.73-8ddd7f1, 2.3.72, etc.
description: |
Provide the git commit or the version in the jar's name.
placeholder: A example would be b85c2d0 or grim version 2.3.5, etc
validations:
required: true
@@ -25,27 +26,27 @@ body:
attributes:
label: Server version
description: |
Run `/version` on your server to check. Provide both the server type (ie Paper, Airplane, etc) & the Minecraft version.
Run `/version` on your server to check. Provide both the server type (paper, airplane, etc) & the minecraft version.
validations:
required: true
- type: dropdown
id: type
attributes:
label: Affected Platform(s)
description: Which platforms does this issue affect? If you aren't sure, select both.
options:
- "Bukkit"
- "Fabric"
multiple: true
label: Affected Platform(s)
description: Which platforms does this issue affect? If you aren't sure, select both.
options:
- "Bukkit"
- "Fabric"
multiple: true
validations:
required: true
required: true
- type: textarea
attributes:
label: Plugins/Mods
label: Plugins
description: |
List all plugins or mods installed on your server. To list plugins on Bukkit-based servers, run `/plugins`.
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
validations:
required: true
@@ -19,15 +19,8 @@ body:
- type: input
attributes:
label: Grim Log
description: Provide the generated /grim log link.
validations:
required: true
- type: textarea
attributes:
label: Grim version
description: Provide the version of Grim running on the server. You can run `/grim version` to check.
placeholder: Examples include 2.3.73-8ddd7f1, 2.3.72, etc.
description: |
Provide the generated /grim log link.
validations:
required: true
@@ -35,7 +28,7 @@ body:
attributes:
label: Server version
description: |
Run `/version` on your server to check. Provide both the server type (ie Paper, Airplane, etc) & the Minecraft version.
Run `/version` on your server to check. Provide both the server type (paper, airplane, etc) & the minecraft version.
validations:
required: true
@@ -43,16 +36,16 @@ body:
attributes:
label: Client version
description: |
Provide the version of your Minecraft client. You must be able to reproduce the false positive using a vanilla client.
Using Lunar Client, TLauncher, Fabric, etc, will result in your issue being closed.
Provide the version of your Minecraft client. You must be able to reproduce the false positive using the vanilla client.
Lunar Client, TLauncher etc. will result in your issue being closed.
validations:
required: true
- type: textarea
attributes:
label: Plugins/Mods
label: Plugins
description: |
List all plugins or mods installed on your server. To list plugins on Bukkit-based servers, run `/plugins`.
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
validations:
required: true
required: true
+31 -32
View File
@@ -36,7 +36,7 @@ on:
jobs:
build:
runs-on: tenki-standard-autoscale
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
@@ -85,7 +85,7 @@ jobs:
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"
@@ -94,23 +94,23 @@ jobs:
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
# 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
@@ -151,7 +151,7 @@ jobs:
- name: Prepare Final Changelog
id: changelog
# Add this 'env' block to safely load the changelogs as environment variables
# 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 }}
@@ -165,36 +165,17 @@ jobs:
# 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"
- 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.21.5 <=1.21.10'
dependencies: 'fabric-api'
#------------------------------------------------------------------
# Publish to Modrinth & API
#------------------------------------------------------------------
@@ -202,7 +183,7 @@ jobs:
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-id: ${{ secrets.MODRINTH_ID }}
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
modrinth-featured: ${{ inputs.is-release-build }} # Only feature release builds
@@ -217,7 +198,25 @@ jobs:
paper
folia
purpur
game-versions: '>=1.7 <=1.21.10'
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 != '' }}
@@ -227,4 +226,4 @@ jobs:
-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 }}"
"${{ secrets.BUILD_UPDATE_URL }}"
+5 -5
View File
@@ -14,12 +14,12 @@ name: "CodeQL"
on:
workflow_dispatch:
push:
branches: [dev]
branches: [ dev ]
jobs:
analyze:
name: Analyze
runs-on: tenki-standard-autoscale
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
@@ -28,7 +28,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: ['java-kotlin']
language: [ 'java-kotlin' ]
# 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
@@ -60,7 +60,6 @@ jobs:
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -71,5 +70,6 @@ jobs:
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v3
+2
View File
@@ -20,6 +20,8 @@ on:
- 'release'
- 'release/**'
paths:
- '.github/workflows/**'
- 'buildSrc/**'
- 'bukkit/**'
- 'common/**'
- 'fabric/**'
+13 -10
View File
@@ -33,27 +33,30 @@ A premium version is planned, which will offer additional subscription-based pai
- ~~[Hangar](https://hangar.papermc.io/GrimAnticheat/GrimAnticheat)~~
- ~~[SpigotMC](https://www.spigotmc.org/resources/grim-anticheat.99923/)~~
## Requirements & Installation
- Java 17 or higher. *For more details, see [Updating-to-Java-17](https://github.com/GrimAnticheat/Grim/wiki/Updating-to-Java-17).*
- A Spigot, Paper, Folia, or Fabric server environment. *For more details, see [Supported-environments](https://github.com/GrimAnticheat/Grim/wiki/Supported-environments).*
If you use a proxy such as Velocity or Bungeecord:
- If you use Geyser, Floodgate must be installed on the backend server (where Grim is) so Grim can access the Floodgate API.
- If you use ViaVersion, it must be installed on the backend server (where Grim is) ONLY.
Grim does not support having ViaVersion installed on the proxy, even if it is also installed on the backend.
## Resources
- For documentation and examples visit the [Wiki](https://github.com/GrimAnticheat/Grim/wiki).
- 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
see [Updating-to-Java-17](https://github.com/GrimAnticheat/Grim/wiki/Updating-to-Java-17).*
- A Spigot, Paper, Folia, or Fabric server environment. *For more details
see [Supported-environments](https://github.com/GrimAnticheat/Grim/wiki/Supported-environments).*
- If you use Geyser, place Floodgate on the backend server so grim can exempt bedrock players. Grim
cannot access the Floodgate API if it is on the proxy.
- If you use ViaVersion, it should be on the backend server as movement is highly dependent on
client version.
## Developer Plugin API
Grim's plugin API allows you to integrate Grim into your own plugins. Visit
+1 -1
View File
@@ -195,7 +195,7 @@ publishing.publications.create<MavenPublication>("maven") {
tasks {
runServer {
minecraftVersion("1.21.10")
minecraftVersion("1.21.4")
}
shadowJar {
@@ -6,8 +6,6 @@ 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;
@@ -17,8 +15,6 @@ import java.util.concurrent.CompletableFuture;
public class BukkitGrimEntity implements GrimEntity {
protected static final boolean CAN_USE_DIRECT_GETTERS = PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_20_1) && PaperUtils.PAPER;
private final Entity entity;
private BukkitPlatformWorld bukkitPlatformWorld;
@@ -79,26 +75,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;
}
}
}
@@ -74,7 +74,7 @@ public class PistonEvent implements Listener {
final Vector3i sourcePos = new Vector3i(piston.getX(), piston.getY(), piston.getZ());
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
if (isCloseEnough(sourcePos, player.compensatedEntities.self.trackedServerPosition.getPos()) && player.compensatedWorld.isChunkLoaded(chunkX, chunkZ)) {
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));
@@ -132,7 +132,7 @@ public class PistonEvent implements Listener {
Vector3i sourcePos = new Vector3i(event.getBlock().getX(), event.getBlock().getY(), event.getBlock().getZ());
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
if (isCloseEnough(sourcePos, player.compensatedEntities.self.trackedServerPosition.getPos()) && player.compensatedWorld.isChunkLoaded(chunkX, chunkZ)) {
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));
@@ -177,11 +177,10 @@ public class BukkitItemResetHandler implements ItemResetHandler {
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();
method.invoke(getHandle.invoke(player));
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
@@ -112,12 +112,8 @@ 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
@@ -96,7 +96,7 @@ public class Check extends GrimProcessor implements AbstractCheck {
if (event.isCancelled()) return false;
player.punishmentManager.handleViolation(this);
lastViolationTime = player.now();
lastViolationTime = System.currentTimeMillis();
violations++;
return true;
}
@@ -170,8 +170,7 @@ public class Check extends GrimProcessor implements AbstractCheck {
}
public static boolean isAsync(PacketTypeCommon packetType) {
return packetType == PacketType.Play.Client.KEEP_ALIVE
|| packetType == PacketType.Play.Client.CHUNK_BATCH_ACK;
return packetType == PacketType.Play.Client.KEEP_ALIVE;
}
public boolean isUpdate(PacketTypeCommon packetType) {
@@ -1,82 +0,0 @@
package ac.grim.grimac.checks.debug;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.NotNull;
public class DebugGrimPlayer extends GrimPlayer {
private static final long THRESHOLD_NANO = 200_000_000L; // 200ms
private static final long THRESHOLD_MILLIS = 200;
// Global Offsets: Volatile so all threads see the pause adjustment immediately.
// When the Netty thread pauses for 60s, it updates this.
// The Scheduler thread sees the update and "stops" the timeout check.
private volatile long offsetNano = 0;
private volatile long offsetMillis = 0;
// ThreadLocal: Each thread tracks its OWN execution time.
// This prevents the Scheduler Thread (pollData) from resetting the timer
// while the Netty Thread is sitting at a breakpoint.
private final ThreadLocal<Long> packetStartNano = ThreadLocal.withInitial(System::nanoTime);
private final ThreadLocal<Long> packetStartMillis = ThreadLocal.withInitial(System::currentTimeMillis);
public DebugGrimPlayer(@NotNull User user) {
super(user, System.currentTimeMillis(), System.nanoTime());
}
@Override
public void processingPacket() {
// Reset the timer ONLY for the current thread (Netty or Scheduler)
this.packetStartNano.set(System.nanoTime());
this.packetStartMillis.set(System.currentTimeMillis());
}
@Override
public long nano() {
// SAFETY CHECK:
// If something in the parent constructor calls nano() BEFORE we are fully initialized,
// packetStartNano will be null. We must fallback to System time to prevent NPE.
if (packetStartNano == null) return System.nanoTime();
long sysTime = System.nanoTime();
// 1. Get start time for THIS thread
long start = packetStartNano.get();
long executionTime = sysTime - start;
// 2. Check if THIS thread was paused/stuck
if (executionTime > THRESHOLD_NANO) {
// Update the global offset so ALL threads know to skip this time
synchronized (this) {
offsetNano += executionTime;
}
// Reset this thread's timer so we don't loop
packetStartNano.set(sysTime);
} else if (executionTime < 0) {
// Self-healing for rare thread-local init edge cases or system clock jumps
packetStartNano.set(sysTime);
}
// 3. Return System Time minus the Global Pause Offset
return sysTime - offsetNano;
}
@Override
public long now() {
if (packetStartMillis == null) return System.currentTimeMillis();
long sysTime = System.currentTimeMillis();
long start = packetStartMillis.get();
long executionTime = sysTime - start;
if (executionTime > THRESHOLD_MILLIS) {
synchronized (this) {
offsetMillis += executionTime;
}
packetStartMillis.set(sysTime);
}
return sysTime - offsetMillis;
}
}
@@ -1,35 +0,0 @@
package ac.grim.grimac.checks.debug;
import ac.grim.grimac.utils.common.arguments.CommonGrimArguments;
import java.lang.management.ManagementFactory;
public class GrimDebugSettings {
public static boolean shouldEnable() {
// 1. If the argument is disabled, never enable debug mode.
if (!CommonGrimArguments.DEBUG_BREAKPOINT_MODE.value()) {
return false;
}
// 2. Check for Debugger (Startup Agent OR Dynamic Attach)
return isDebuggerAttached();
}
private static boolean isDebuggerAttached() {
// Fast Path: Check startup arguments for -agentlib:jdwp
if (ManagementFactory.getRuntimeMXBean().getInputArguments().toString().contains("jdwp")) {
return true;
}
// Slow Path (Dynamic Attach): Scan threads for JDWP/Signal Dispatcher
try {
for (Thread t : Thread.getAllStackTraces().keySet()) {
String name = t.getName();
if (name.contains("JDWP")) return true;
}
} catch (Throwable ignored) {}
return false;
}
}
@@ -23,7 +23,7 @@ public class BadPacketsR extends Check implements PacketCheck {
public void onPacketReceive(final PacketReceiveEvent event) {
if (isTransaction(event.getPacketType()) && player.packetStateData.lastTransactionPacketWasValid) {
long ms = (player.getPlayerClockAtLeast() - clock) / 1000000L;
long diff = (player.now() - lastTransTime);
long diff = (System.currentTimeMillis() - lastTransTime);
if (diff > 2000 && ms > 2000) {
if (positions == 0 && clock != 0 && player.gamemode != GameMode.SPECTATOR && !player.compensatedEntities.self.isDead) {
flag("time=" + ms + "ms, " + "lst=" + diff + "ms, positions=" + positions);
@@ -34,7 +34,7 @@ public class BadPacketsR extends Check implements PacketCheck {
player.compensatedWorld.removeInvalidPistonLikeStuff(oldTransId);
positions = 0;
clock = player.getPlayerClockAtLeast();
lastTransTime = player.now();
lastTransTime = System.currentTimeMillis();
oldTransId = player.lastTransactionSent.get();
}
}
@@ -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;
}
}
}
@@ -26,8 +26,9 @@ public class FarBreak extends Check implements BlockBreakCheck {
double min = Double.MAX_VALUE;
for (double d : player.getPossibleEyeHeights()) {
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
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));
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?
@@ -7,7 +7,7 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.nmsutil.BlockBreakSpeed;
import ac.grim.grimac.utils.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@@ -67,12 +67,12 @@ 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 = player.now() - (targetBlockPosition == null ? 50 : 0); // ???
startBreak = System.currentTimeMillis() - (targetBlockPosition == null ? 50 : 0); // ???
targetBlockPosition = blockBreak.position;
maximumBlockDamage = BlockBreakSpeed.getBlockDamage(player, block);
double breakDelay = player.now() - lastFinishBreak;
double breakDelay = System.currentTimeMillis() - lastFinishBreak;
if (breakDelay >= 275) { // Reduce buffer if "close enough"
blockDelayBalance *= 0.9;
@@ -91,7 +91,7 @@ public class FastBreak extends Check implements BlockBreakCheck {
if (blockBreak.action == DiggingAction.FINISHED_DIGGING && targetBlockPosition != null) {
double predictedTime = Math.ceil(1 / maximumBlockDamage) * 50;
double realTime = player.now() - startBreak;
double realTime = System.currentTimeMillis() - startBreak;
double diff = predictedTime - realTime;
clampBalance();
@@ -109,7 +109,7 @@ public class FastBreak extends Check implements BlockBreakCheck {
}
// also set start time because the breaking netcode is fucked on 1.14.4+
lastFinishBreak = startBreak = player.now();
lastFinishBreak = startBreak = System.currentTimeMillis();
}
}
@@ -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;
@@ -4,6 +4,8 @@ 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;
@@ -12,6 +14,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientCh
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatCommandUnsigned;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatMessage;
// this can false from click events, but I doubt this would actually
// happen unless they're trying to flag, or if the server is set up badly
@CheckData(name = "ChatB", description = "Invalid chat message")
@@ -61,4 +64,10 @@ public class ChatB extends Check implements PacketCheck {
}
return false;
}
static {
if (ViaVersionUtil.isAvailable && PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_11)) {
ViaHooks.injectVia();
}
}
}
@@ -22,7 +22,6 @@ import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.data.packetentity.PacketEntitySizeable;
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
import ac.grim.grimac.utils.math.Vector3dm;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
@@ -95,10 +94,7 @@ public class Reach extends Check implements PacketCheck {
// TODO: Remove when in front of via
if (entity.type == EntityTypes.ARMOR_STAND && player.getClientVersion().isOlderThan(ClientVersion.V_1_8))
return;
//Prevents Happy Ghast Reach false on 1.21.6+ servers with ViaBackwards set up
if (entity.type == EntityTypes.HAPPY_GHAST && player.getClientVersion().isOlderThan(ClientVersion.V_1_21_6)) {
return;
}
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR)
return;
if (player.inVehicle()) return;
@@ -162,16 +158,10 @@ public class Reach extends Check implements PacketCheck {
switch (result.type()) {
case REACH -> {
String added = ", type=" + reachEntity.type.getName().getKey();
if (reachEntity instanceof PacketEntitySizeable sizeable) {
added += ", size=" + sizeable.size;
}
flagAndAlert(result.verbose() + added);
}
case HITBOX -> {
String added = "type=" + reachEntity.type.getName().getKey();
if (reachEntity instanceof PacketEntitySizeable sizeable) {
added += ", size=" + sizeable.size;
}
player.checkManager.getCheck(Hitboxes.class).flagAndAlert(result.verbose() + added);
}
}
@@ -232,7 +222,7 @@ public class Reach extends Check implements PacketCheck {
for (Vector3dm lookVec : possibleLookDirs) {
for (double eye : possibleEyeHeights) {
eyePos.setY(from.getY() + eye);
Vector3dm endReachPos = eyePos.clone().add(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance);
Vector3dm endReachPos = eyePos.clone().add(new Vector3dm(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
Vector3dm intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
@@ -20,9 +20,10 @@ public class CrashC extends Check implements PacketCheck {
WrapperPlayClientPlayerFlying flying = new WrapperPlayClientPlayerFlying(event);
if (flying.hasPositionChanged()) {
Location pos = flying.getLocation();
if (!Double.isFinite(pos.getX()) || !Double.isFinite(pos.getY()) || !Double.isFinite(pos.getZ())
|| !Float.isFinite(pos.getYaw()) || !Float.isFinite(pos.getPitch())
) {
if (Double.isNaN(pos.getX()) || Double.isNaN(pos.getY()) || Double.isNaN(pos.getZ())
|| Double.isInfinite(pos.getX()) || Double.isInfinite(pos.getY()) || Double.isInfinite(pos.getZ()) ||
Float.isNaN(pos.getYaw()) || Float.isNaN(pos.getPitch()) ||
Float.isInfinite(pos.getYaw()) || Float.isInfinite(pos.getPitch())) {
flagAndAlert("xyzYP: " + pos.getX() + ", " + pos.getY() + ", " + pos.getZ() + ", " + pos.getYaw() + ", " + pos.getPitch());
player.getSetbackTeleportUtil().executeViolationSetback();
event.setCancelled(true);
@@ -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;
@@ -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;
@@ -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;
@@ -29,7 +29,7 @@ public class ExploitA extends Check implements PacketCheck {
if (event.getPacketType() == PacketType.Play.Client.PLUGIN_MESSAGE && PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_13)) {
WrapperPlayClientPluginMessage wrapper = new WrapperPlayClientPluginMessage(event);
if (wrapper.getChannelName().equals("MC|ItemName")) {
check(new PayloadItemName(wrapper.getData()).itemName(), event);
check(PayloadItemName.CODEC.read(wrapper.getData()).itemName(), event);
}
}
}
@@ -72,7 +72,7 @@ public class ExploitB extends Check implements PacketCheck {
}
}
ItemStack newBook = new PayloadBookEdit(wrapper.getData()).itemStack();
ItemStack newBook = PayloadBookEdit.CODEC.read(wrapper.getData()).itemStack();
checkItemStack(newBook, signing, event);
oldBook = null;
}
@@ -287,14 +287,13 @@ public class ExploitB extends Check implements PacketCheck {
return true;
}
// commented out because existing characters are not considered
// if (containsInvalidCharacters(page, true)) {
// if (flagAndAlert("invalid page characters") && shouldModifyPackets()) {
// event.setCancelled(true);
// player.onPacketCancel();
// }
// return true;
// }
if (containsInvalidCharacters(page, true)) {
if (flagAndAlert("invalid page characters") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
return true;
}
return false;
}
@@ -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(", ");
@@ -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);
@@ -30,8 +30,9 @@ public class FarPlace extends BlockPlaceCheck {
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (double d : possibleEyeHeights) {
SimpleCollisionBox box = new SimpleCollisionBox(blockPos);
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));
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?
@@ -12,18 +12,18 @@ public class NegativeTimer extends Timer implements PostPredictionCheck {
public NegativeTimer(GrimPlayer player) {
super(player);
timerBalanceRealTime = player.nano() + clockDrift;
timerBalanceRealTime = System.nanoTime() + clockDrift;
}
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
// We can't negative timer check a 1.9+ player who is standing still.
if (player.uncertaintyHandler.lastPointThree.hasOccurredSince(2) || !predictionComplete.isChecked()) {
timerBalanceRealTime = player.nano() + clockDrift;
timerBalanceRealTime = System.nanoTime() + clockDrift;
}
if (timerBalanceRealTime < lastMovementPlayerClock - clockDrift) {
int lostMS = (int) ((player.nano() - timerBalanceRealTime) / 1e6);
int lostMS = (int) ((System.nanoTime() - timerBalanceRealTime) / 1e6);
flagAndAlertWithSetback("-" + lostMS);
timerBalanceRealTime += 50e6;
}
@@ -14,8 +14,8 @@ public class Timer extends Check implements PacketCheck {
protected long timerBalanceRealTime = 0;
// Default value is real time minus max keep-alive time
protected long knownPlayerClockTime = (long) (player.nano() - 6e10);
protected long lastMovementPlayerClock = (long) (player.nano() - 6e10);
protected long knownPlayerClockTime = (long) (System.nanoTime() - 6e10);
protected long lastMovementPlayerClock = (long) (System.nanoTime() - 6e10);
// How long should the player be able to fall back behind their ping? (nanos)
// Default: 120 milliseconds
@@ -71,7 +71,7 @@ public class Timer extends Check implements PacketCheck {
}
public void doCheck(final PacketReceiveEvent event) {
if (timerBalanceRealTime > player.nano()) {
if (timerBalanceRealTime > System.nanoTime()) {
if (flagAndAlert()) {
// Cancel the packet
if (shouldModifyPackets()) {
@@ -19,7 +19,7 @@ public class TimerLimit extends Timer {
@Override
public void doCheck(final PacketReceiveEvent event) {
// 1:1 with Timer minus cancelling the packet
if (timerBalanceRealTime > player.nano()) {
if (timerBalanceRealTime > System.nanoTime()) {
// If timer check already flagged, don't flag.
if (!event.isCancelled()) {
if (flagAndAlert() && shouldSetback()) {
@@ -38,8 +38,8 @@ public class TimerLimit extends Timer {
protected void limitFallBehind() {
// Limit using transaction ping if over 1000ms (default)
long playerClock = lastMovementPlayerClock;
if (limitAbuseOverPing != -1 && player.nano() - playerClock > limitAbuseOverPing) {
playerClock = player.nano() - limitAbuseOverPing;
if (limitAbuseOverPing != -1 && System.nanoTime() - playerClock > limitAbuseOverPing) {
playerClock = System.nanoTime() - limitAbuseOverPing;
}
timerBalanceRealTime = Math.max(timerBalanceRealTime, playerClock - clockDrift);
}
@@ -1,5 +1,6 @@
package ac.grim.grimac.checks.impl.velocity;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
@@ -45,6 +46,9 @@ public class KnockbackHandler extends Check implements PostPredictionCheck {
WrapperPlayServerEntityVelocity velocity = new WrapperPlayServerEntityVelocity(event);
int entityId = velocity.getEntityId();
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
// Detect whether this knockback packet affects the player or if it is useless
// Mojang sends extra useless knockback packets for no apparent reason
if (player.compensatedEntities.serverPlayerVehicle != null && entityId != player.compensatedEntities.serverPlayerVehicle) {
@@ -7,7 +7,7 @@ import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.common.PropertiesUtil;
import ac.grim.grimac.utils.reflection.ReflectionUtils;
import ac.grim.grimac.utils.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -51,9 +51,9 @@ public class GrimDump implements BuildableCommand {
GrimLog.sendLogAsync(sender, generateDump(), string -> link = string, "text/yaml");
}
public static JsonObject getDumpInfo() {
public static JsonObject getBasicInfo(String type) {
JsonObject base = new JsonObject();
base.addProperty("type", "dump");
base.addProperty("type", type);
base.addProperty("timestamp", System.currentTimeMillis());
// versions
JsonObject versions = new JsonObject();
@@ -68,11 +68,6 @@ public class GrimDump implements BuildableCommand {
if (GrimAPI.INSTANCE.isInitialized()) states.addProperty("platform", GrimAPI.INSTANCE.getPlatform().toString());
if (ViaVersionUtil.isAvailable) states.addProperty("has_viaversion", true);
if (PAPER) states.addProperty("has_paper", true);
// include some relevant settings if not default
JsonObject settings = new JsonObject();
if (GrimAPI.INSTANCE.getAlertManager().hasConsoleVerboseEnabled()) settings.addProperty("console_verbose", true);
if (!GrimAPI.INSTANCE.getAlertManager().hasConsoleAlertsEnabled()) settings.addProperty("console_alerts", false);
if (settings.size() > 0) states.add("settings", settings);
// system
JsonObject system = new JsonObject();
base.add("system", system);
@@ -80,17 +75,8 @@ public class GrimDump implements BuildableCommand {
system.addProperty("java_version", System.getProperty("java.version"));
system.addProperty("user_language", System.getProperty("user.language"));
// build
JsonObject build = new JsonObject();
base.add("build", getBuildInfo());
// plugins
JsonArray plugins = new JsonArray();
base.add("plugins", plugins);
for (PlatformPlugin plugin : GrimAPI.INSTANCE.getPluginManager().getPlugins()) {
JsonObject pluginJson = new JsonObject();
pluginJson.addProperty("enabled", plugin.isEnabled());
pluginJson.addProperty("name", plugin.getName());
pluginJson.addProperty("version", plugin.getVersion());
plugins.add(pluginJson);
}
return base;
}
@@ -112,7 +98,17 @@ public class GrimDump implements BuildableCommand {
* @return A JSON-formatted string containing the diagnostic dump.
*/
private String generateDump() {
JsonObject base = getDumpInfo();
JsonObject base = getBasicInfo("dump");
// plugins
JsonArray plugins = new JsonArray();
base.add("plugins", plugins);
for (PlatformPlugin plugin : GrimAPI.INSTANCE.getPluginManager().getPlugins()) {
JsonObject pluginJson = new JsonObject();
pluginJson.addProperty("enabled", plugin.isEnabled());
pluginJson.addProperty("name", plugin.getName());
pluginJson.addProperty("version", plugin.getVersion());
plugins.add(pluginJson);
}
return gson.toJson(base);
}
}
@@ -495,7 +495,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT) {
WrapperPlayClientPlayerBlockPlacement packet = new WrapperPlayClientPlayerBlockPlacement(event);
player.lastBlockPlaceUseItem = player.now();
player.lastBlockPlaceUseItem = System.currentTimeMillis();
ItemStack placedWith = player.inventory.getHeldItem();
if (packet.getHand() == InteractionHand.OFF_HAND) {
@@ -562,7 +562,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
if (event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
WrapperPlayClientUseItem packet = new WrapperPlayClientUseItem(event);
player.placeUseItemPackets.add(new BlockPlaceSnapshot(packet, player.isSneaking));
player.lastBlockPlaceUseItem = player.now();
player.lastBlockPlaceUseItem = System.currentTimeMillis();
}
// Call the packet checks last as they can modify the contents of the packet
@@ -663,7 +663,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
private static void handleFlying(GrimPlayer player, double x, double y, double z, float yaw, float pitch, boolean hasPosition, boolean hasLook, boolean onGround, TeleportAcceptData teleportData, PacketReceiveEvent event) {
long now = player.now();
long now = System.currentTimeMillis();
if (!hasPosition) {
// This may need to be secured later, although nothing that is very important relies on this
@@ -759,7 +759,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
private static void handleDigging(GrimPlayer player, PacketReceiveEvent event) {
player.lastBlockBreak = player.now();
player.lastBlockBreak = System.currentTimeMillis();
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
final DiggingAction action = packet.getAction();
@@ -44,7 +44,7 @@ public class PacketEntityAction extends PacketListenerAbstract {
break;
case START_FLYING_WITH_ELYTRA:
if (player.onGround || player.lastOnGround) {
player.getSetbackTeleportUtil().executeNonSimulatingForceResync();
player.getSetbackTeleportUtil().executeForceResync();
if (player.platformPlayer != null) {
// Client ignores sneaking, use it to resync
@@ -66,7 +66,7 @@ public class PacketEntityAction extends PacketListenerAbstract {
player.pointThreeEstimator.updatePlayerGliding();
} else {
// A client is flying with a ghost elytra, resync
player.getSetbackTeleportUtil().executeNonSimulatingForceResync();
player.getSetbackTeleportUtil().executeForceResync();
if (player.platformPlayer != null) {
// Client ignores sneaking, use it to resync
player.platformPlayer.setSneaking(!player.platformPlayer.isSneaking());
@@ -10,7 +10,7 @@ import ac.grim.grimac.utils.data.TrackerData;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.data.packetentity.PacketEntityHook;
import ac.grim.grimac.utils.data.packetentity.PacketEntityTrackXRot;
import ac.grim.grimac.utils.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
@@ -72,7 +72,7 @@ public class PacketPingListener extends PacketListenerAbstract {
if (id <= 0) {
if (player.didWeSendThatTrans.remove(id)) {
player.packetStateData.lastServerTransWasValid = true;
player.transactionsSent.add(new Pair<>(id, player.nano()));
player.transactionsSent.add(new Pair<>(id, System.nanoTime()));
player.lastTransactionSent.getAndIncrement();
}
}
@@ -91,7 +91,7 @@ public class PacketPingListener extends PacketListenerAbstract {
Short shortID = ((short) id);
if (player.didWeSendThatTrans.remove(shortID)) {
player.packetStateData.lastServerTransWasValid = true;
player.transactionsSent.add(new Pair<>(shortID, player.nano()));
player.transactionsSent.add(new Pair<>(shortID, System.nanoTime()));
player.lastTransactionSent.getAndIncrement();
}
}
@@ -228,7 +228,7 @@ public class PacketPlayerDigging extends PacketListenerAbstract {
// do we need to do this with block breaks too?
// Prevent issues if the player switches slots, while lagging, standing still, and is placing blocks
CheckManagerListener.handleQueuedPlaces(player, false, 0, 0, player.now());
CheckManagerListener.handleQueuedPlaces(player, false, 0, 0, System.currentTimeMillis());
if (player.packetStateData.lastSlotSelected != slot) {
if (player.isResetItemUsageOnSlotChange() && GrimAPI.INSTANCE.getItemResetHandler().getItemUsageHand(player.platformPlayer) == InteractionHand.MAIN_HAND) {
@@ -210,9 +210,7 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
}
player.pose = Pose.STANDING;
player.clientVelocity = new Vector3dm();
if (!GrimAPI.INSTANCE.getSpectateManager().isSpectating(player.uuid)) {
player.gamemode = respawn.getGameMode();
}
player.gamemode = respawn.getGameMode();
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_17)) {
player.compensatedWorld.setDimension(respawn.getDimensionType(), event.getUser());
}
@@ -31,7 +31,7 @@ public class PacketWorldBorder extends Check implements PacketCheck {
}
public double getCurrentDiameter() {
double d0 = (double) (player.now() - startTime) / ((double) endTime - startTime);
double d0 = (double) (System.currentTimeMillis() - startTime) / ((double) endTime - startTime);
return d0 < 1.0D ? GrimMath.lerp(d0, oldDiameter, newDiameter) : newDiameter;
}
@@ -125,7 +125,7 @@ public class PacketWorldBorder extends Check implements PacketCheck {
private void setLerp(double oldDiameter, double newDiameter, long length) {
this.oldDiameter = oldDiameter;
this.newDiameter = newDiameter;
this.startTime = player.now();
this.startTime = System.currentTimeMillis();
this.endTime = this.startTime + length;
}
}
@@ -158,7 +158,7 @@ public class BasePacketWorldReader extends PacketListenerAbstract {
Vector3i blockPosition = blockChange.getBlockPosition();
// Don't spam transactions (block changes are sent in batches)
if (Math.abs(blockPosition.getX() - player.x) < range && Math.abs(blockPosition.getY() - player.y) < range && Math.abs(blockPosition.getZ() - player.z) < range &&
player.lastTransSent + 2 < player.now())
player.lastTransSent + 2 < System.currentTimeMillis())
player.sendTransaction();
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.compensatedWorld.updateBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), blockChange.getBlockId()));
@@ -172,7 +172,7 @@ public class BasePacketWorldReader extends PacketListenerAbstract {
final var blocks = multiBlockChange.getBlocks();
for (WrapperPlayServerMultiBlockChange.EncodedBlock blockChange : blocks) {
// Don't send a transaction unless it's within 16 blocks of the player
if (Math.abs(blockChange.getX() - player.x) < range && Math.abs(blockChange.getY() - player.y) < range && Math.abs(blockChange.getZ() - player.z) < range && player.lastTransSent + 2 < player.now()) {
if (Math.abs(blockChange.getX() - player.x) < range && Math.abs(blockChange.getY() - player.y) < range && Math.abs(blockChange.getZ() - player.z) < range && player.lastTransSent + 2 < System.currentTimeMillis()) {
player.sendTransaction();
break;
}
@@ -24,7 +24,7 @@ public class ActionManager extends Check implements PacketCheck {
if (action.getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
player.totalFlyingPacketsSent = 0;
attacking = true;
lastAttack = player.now();
lastAttack = System.currentTimeMillis();
}
} else if (isTickPacketIncludingNonMovement(event.getPacketType())) {
player.totalFlyingPacketsSent++;
@@ -33,6 +33,6 @@ public class ActionManager extends Check implements PacketCheck {
}
public boolean hasAttackedSince(long time) {
return player.now() - lastAttack < time;
return System.currentTimeMillis() - lastAttack < time;
}
}
@@ -75,10 +75,8 @@ public class CheckManager {
private final ClassToInstanceMap<BlockPlaceCheck> blockPlaceChecks;
private final ClassToInstanceMap<PostPredictionCheck> postPredictionChecks;
private PacketEntityReplication packetEntityReplication = null;
private final GrimPlayer player;
public CheckManager(GrimPlayer player) {
this.player = player;
packetChecks = new ImmutableClassToInstanceMap.Builder<PacketCheck>()
.put(PacketOrderProcessor.class, player.packetOrderProcessor)
.put(Reach.class, new Reach(player))
@@ -118,7 +116,6 @@ public class CheckManager {
.put(BadPacketsU.class, new BadPacketsU(player))
.put(BadPacketsV.class, new BadPacketsV(player))
.put(BadPacketsY.class, new BadPacketsY(player))
.put(BadPacketsZ.class, new BadPacketsZ(player))
.put(MultiActionsA.class, new MultiActionsA(player))
.put(MultiActionsC.class, new MultiActionsC(player))
.put(MultiActionsD.class, new MultiActionsD(player))
@@ -127,7 +124,7 @@ public class CheckManager {
.put(PacketOrderC.class, new PacketOrderC(player))
.put(PacketOrderD.class, new PacketOrderD(player))
.put(PacketOrderO.class, new PacketOrderO(player))
// .put(PacketOrderP.class, new PacketOrderP(player))
.put(PacketOrderP.class, new PacketOrderP(player))
.put(SprintA.class, new SprintA(player))
.put(VehicleA.class, new VehicleA(player))
.put(VehicleB.class, new VehicleB(player))
@@ -296,8 +293,6 @@ public class CheckManager {
}
public void onPacketReceive(final PacketReceiveEvent packet) {
player.processingPacket();
for (PacketCheck check : packetChecks.values()) {
check.onPacketReceive(packet);
}
@@ -313,8 +308,6 @@ public class CheckManager {
}
public void onPacketSend(final PacketSendEvent packet) {
player.processingPacket();
for (PacketCheck check : prePredictionChecks.values()) {
check.onPacketSend(packet);
}
@@ -177,7 +177,7 @@ public class PunishmentManager implements ConfigReloadable {
public void handleViolation(Check check) {
for (PunishGroup group : groups) {
if (group.checks.contains(check)) {
long currentTime = player.now();
long currentTime = System.currentTimeMillis();
group.violations.put(currentTime, check);
// Remove violations older than the defined time in the config
@@ -100,13 +100,6 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
blockMovementsUntilResync(true, true);
}
public void executeNonSimulatingForceResync() {
if (player.gamemode == GameMode.SPECTATOR || player.disableGrim)
return; // We don't care about spectators, they don't flag
if (lastKnownGoodPosition == null) return; // Player hasn't spawned yet
blockMovementsUntilResync(false, true);
}
public void executeNonSimulatingSetback() {
if (player.gamemode == GameMode.SPECTATOR || player.disableGrim)
return; // We don't care about spectators, they don't flag
@@ -138,17 +131,15 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
} else if (player.wasTouchingLava) {
vector.multiply(0.5D);
if (player.hasGravity)
vector.add(0.0D, -player.gravity / 4.0D, 0.0D);
vector.add(new Vector3dm(0.0D, -player.gravity / 4.0D, 0.0D));
} else if (player.isGliding) {
PredictionEngineElytra.getElytraMovement(player, vector, ReachUtils.getLook(player, player.yaw, player.pitch)).multiply(player.stuckSpeedMultiplier).multiply(0.99F, 0.98F, 0.99F);
PredictionEngineElytra.getElytraMovement(player, vector, ReachUtils.getLook(player, player.yaw, player.pitch)).multiply(player.stuckSpeedMultiplier).multiply(new Vector3dm(0.99F, 0.98F, 0.99F));
vector.setY(vector.getY() - 0.05); // Make the player fall a bit
} else { // Gliding doesn't have friction, we handle it differently
PredictionEngineNormal.staticVectorEndOfTick(player, vector); // Lava and normal movement
vector.multiply(player.stuckSpeedMultiplier); // Prevent abusing setbacks to move out of blocks like webs
}
// Prevent abusing setbacks to move out of blocks like webs
vector.multiply(player.stuckSpeedMultiplier);
// stop 1.8 players from stepping onto 1.25 high blocks, because why not?
new PredictionEngine().applyMovementThreshold(player, new HashSet<>(Collections.singletonList(new VectorData(vector, VectorData.VectorType.BestVelPicked))));
}
@@ -161,9 +152,9 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
if (isPendingSetback()) return; // Don't spam setbacks
// Only let us full resync once every five seconds to prevent unneeded bukkit load
if (player.now() - lastWorldResync > 5 * 1000) {
if (System.currentTimeMillis() - lastWorldResync > 5 * 1000) {
player.resyncPositions(player.boundingBox.copy().expand(1));
lastWorldResync = player.now();
lastWorldResync = System.currentTimeMillis();
}
Vector3dm clientVel = lastKnownGoodPosition.vector.clone();
@@ -217,7 +208,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
blockOffsets = true;
}
SetBackData data = new SetBackData(new TeleportData(position, new Vector3d(), RelativeFlag.YAW.or(RelativeFlag.PITCH), player.lastTransactionSent.get(), 0), player.yaw, player.pitch, clientVel, player.inVehicle(), false);
SetBackData data = new SetBackData(new TeleportData(position, new Vector3d(), new RelativeFlag(0b11000), player.lastTransactionSent.get(), 0), player.yaw, player.pitch, clientVel, player.inVehicle(), false);
sendSetback(data);
}
@@ -384,7 +375,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
private boolean isPendingSetback() {
// Relative setbacks shouldn't count
if (requiredSetBack != null && (requiredSetBack.getTeleportData().isRelativeX() || requiredSetBack.getTeleportData().isRelativeY() || requiredSetBack.getTeleportData().isRelativeZ())) {
if (requiredSetBack.getTeleportData().isRelativeX() || requiredSetBack.getTeleportData().isRelativeY() || requiredSetBack.getTeleportData().isRelativeZ()) {
return false;
}
// The setback is not complete
@@ -2,7 +2,7 @@ package ac.grim.grimac.manager.init.start;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
@@ -2,7 +2,7 @@ package ac.grim.grimac.manager.init.start;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.viaversion.viaversion.api.Via;
@@ -12,7 +12,6 @@ public class ViaVersion implements StartableInitable {
@Override
public void start() {
if (!ViaVersionUtil.isAvailable) return;
ViaVersionUtil.injectHooks();
ServerVersion serverVersion = PacketEvents.getAPI().getServerManager().getVersion();
@@ -7,6 +7,7 @@ import ac.grim.grimac.platform.api.world.PlatformWorld;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerAcknowledgeBlockChanges;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBlockChange;
@@ -115,7 +116,7 @@ public class DefaultResyncHandler implements ResyncHandler {
GrimAPI.INSTANCE.getScheduler().getRegionScheduler().execute(GrimAPI.INSTANCE.getGrimPlugin(), world, chunkX, chunkZ, () -> {
if (!player.platformPlayer.isOnline() || !player.getSetbackTeleportUtil().hasAcceptedSpawnTeleport)
return;
if (player.platformPlayer.distanceSquared(x, y, z) >= 64 * 64)
if (player.platformPlayer.getPosition().distance(new Vector3d(x, y, z)) >= 64)
return;
if (!world.isChunkLoaded(chunkX, chunkZ)) return; // Don't load chunks sync
@@ -6,7 +6,6 @@ import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.manager.init.ReloadableInitable;
import ac.grim.grimac.manager.init.start.StartableInitable;
import ac.grim.grimac.manager.violationdatabase.mysql.MySQLViolationDatabase;
import ac.grim.grimac.manager.violationdatabase.postgresql.PostgresqlViolationDatabase;
import ac.grim.grimac.manager.violationdatabase.sqlite.SQLiteViolationDatabase;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
@@ -94,28 +93,6 @@ public class ViolationDatabaseManager implements StartableInitable, ReloadableIn
}
}
case "POSTGRESQL" -> {
String host = cfg.getStringElse("history.database.host", "localhost:3306");
String db = cfg.getStringElse("history.database.database", "grimac");
String user = cfg.getStringElse("history.database.username", "root");
String pwd = cfg.getStringElse("history.database.password", "password");
if (database instanceof PostgresqlViolationDatabase postgresql
&& postgresql.sameConfig(host, db, user, pwd)) {
break; // nothing changed → keep pool
}
database.disconnect();
database = new PostgresqlViolationDatabase(host, db, user, pwd);
try {
database.connect();
loaded = true;
} catch (SQLException e) {
LogUtil.error(e);
this.database = NoOpViolationDatabase.INSTANCE;
loaded = false;
}
}
default -> { // NOOP or invalid
if (!(database instanceof NoOpViolationDatabase)) {
database.disconnect();
@@ -1,31 +0,0 @@
package ac.grim.grimac.manager.violationdatabase.postgresql;
import ac.grim.grimac.manager.violationdatabase.DatabaseDialect;
public class PostgresqlDialect implements DatabaseDialect {
@Override
public String getUuidColumnType() {
return "UUID";
}
@Override
public String getAutoIncrementPrimaryKeySyntax() {
return "BIGSERIAL PRIMARY KEY";
}
@Override
public String getInsertOrIgnoreSyntax(String tableName, String columnNames) {
return "INSERT INTO " + tableName + " (" + columnNames + ") VALUES (?) ON CONFLICT DO NOTHING";
}
@Override
public String getUniqueConstraintViolationSQLState() {
return "23505"; // Postgresql duplicate key error
}
@Override
public int getUniqueConstraintViolationErrorCode() {
return 0; // Postgresql is not using numbers
}
}
@@ -1,286 +0,0 @@
package ac.grim.grimac.manager.violationdatabase.postgresql;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.manager.violationdatabase.*;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
public class PostgresqlViolationDatabase implements ViolationDatabase {
private static String quoteVerboseColumn() {
return "\"" + DatabaseConstants.VIOLATIONS_VERBOSE_COLUMN + "\"";
}
private HikariDataSource dataSource;
private final DatabaseDialect dialect;
public PostgresqlViolationDatabase(String url, String database, String username, String password) {
this.dialect = new PostgresqlDialect();
setupDataSource(url, database, username, password);
}
private void setupDataSource(String url, String database, String username, String password) {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://" + url + "/" + database);
config.setUsername(username);
config.setPassword(password);
config.setMaximumPoolSize(10);
config.setAutoCommit(true);
dataSource = new HikariDataSource(config);
}
@Override
public void connect() throws SQLException {
try (Connection connection = dataSource.getConnection()) {
String pkSyntax = dialect.getAutoIncrementPrimaryKeySyntax();
String uuidType = dialect.getUuidColumnType();
// 1. Create Lookup Table for Server Names
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS " + DatabaseConstants.SERVERS_TABLE + "(" +
"id " + pkSyntax + ", " +
DatabaseConstants.SERVERS_STRING_COLUMN + " VARCHAR(255) NOT NULL UNIQUE" +
")"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.SERVERS_TABLE + "_name ON " + DatabaseConstants.SERVERS_TABLE + "(" + DatabaseConstants.SERVERS_STRING_COLUMN + ");"
).execute();
// 2. Create Lookup Table for Check Names
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS " + DatabaseConstants.CHECK_NAMES_TABLE + "(" +
"id " + pkSyntax + ", " +
DatabaseConstants.CHECK_NAMES_STRING_COLUMN + " VARCHAR(255) NOT NULL UNIQUE" +
")"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.CHECK_NAMES_TABLE + "_string ON " + DatabaseConstants.CHECK_NAMES_TABLE + "(" + DatabaseConstants.CHECK_NAMES_STRING_COLUMN + ");"
).execute();
// --- NEW LOOKUP TABLES ---
// 3. Create Lookup Table for Grim Versions
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS " + DatabaseConstants.GRIM_VERSIONS_TABLE + "(" +
"id " + pkSyntax + ", " +
DatabaseConstants.GRIM_VERSIONS_STRING_COLUMN + " VARCHAR(255) NOT NULL UNIQUE" +
")"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.GRIM_VERSIONS_TABLE + "_string ON " + DatabaseConstants.GRIM_VERSIONS_TABLE + "(" + DatabaseConstants.GRIM_VERSIONS_STRING_COLUMN + ");"
).execute();
// 4. Create Lookup Table for Client Brands
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS " + DatabaseConstants.CLIENT_BRANDS_TABLE + "(" +
"id " + pkSyntax + ", " +
DatabaseConstants.CLIENT_BRANDS_STRING_COLUMN + " VARCHAR(255) NOT NULL UNIQUE" +
")"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.CLIENT_BRANDS_TABLE + "_string ON " + DatabaseConstants.CLIENT_BRANDS_TABLE + "(" + DatabaseConstants.CLIENT_BRANDS_STRING_COLUMN + ");"
).execute();
// 5. Create Lookup Table for Client Versions
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS " + DatabaseConstants.CLIENT_VERSIONS_TABLE + "(" +
"id " + pkSyntax + ", " +
DatabaseConstants.CLIENT_VERSIONS_STRING_COLUMN + " VARCHAR(255) NOT NULL UNIQUE" +
")"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.CLIENT_VERSIONS_TABLE + "_string ON " + DatabaseConstants.CLIENT_VERSIONS_TABLE + "(" + DatabaseConstants.CLIENT_VERSIONS_STRING_COLUMN + ");"
).execute();
// 6. Create Lookup Table for Server Versions
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS " + DatabaseConstants.SERVER_VERSIONS_TABLE + "(" +
"id " + pkSyntax + ", " +
DatabaseConstants.SERVER_VERSIONS_STRING_COLUMN + " VARCHAR(255) NOT NULL UNIQUE" +
")"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.SERVER_VERSIONS_TABLE + "_string ON " + DatabaseConstants.SERVER_VERSIONS_TABLE + "(" + DatabaseConstants.SERVER_VERSIONS_STRING_COLUMN + ");"
).execute();
// --- END NEW LOOKUP TABLES ---
// 7. Create Main Violations Table with ALL Foreign Keys and optimized UUID
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS " + DatabaseConstants.VIOLATIONS_TABLE + "(" +
"id " + pkSyntax + ", " +
DatabaseConstants.VIOLATIONS_SERVER_ID_COLUMN + " BIGINT NOT NULL, " +
DatabaseConstants.VIOLATIONS_UUID_COLUMN + " " + uuidType + " NOT NULL, " +
DatabaseConstants.VIOLATIONS_CHECK_NAME_ID_COLUMN + " BIGINT NOT NULL, " +
quoteVerboseColumn() + " TEXT NOT NULL, " +
DatabaseConstants.VIOLATIONS_VL_COLUMN + " INT NOT NULL, " +
DatabaseConstants.VIOLATIONS_CREATED_AT_COLUMN + " BIGINT NOT NULL, " +
DatabaseConstants.VIOLATIONS_GRIM_VERSION_ID_COLUMN + " BIGINT NOT NULL, " + // NEW
DatabaseConstants.VIOLATIONS_CLIENT_BRAND_ID_COLUMN + " BIGINT NOT NULL, " + // NEW
DatabaseConstants.VIOLATIONS_CLIENT_VERSION_ID_COLUMN + " BIGINT NOT NULL, " + // NEW
DatabaseConstants.VIOLATIONS_SERVER_VERSION_ID_COLUMN + " BIGINT NOT NULL, " + // NEW
"FOREIGN KEY (" + DatabaseConstants.VIOLATIONS_SERVER_ID_COLUMN + ") REFERENCES " + DatabaseConstants.SERVERS_TABLE + "(id), " +
"FOREIGN KEY (" + DatabaseConstants.VIOLATIONS_CHECK_NAME_ID_COLUMN + ") REFERENCES " + DatabaseConstants.CHECK_NAMES_TABLE + "(id), " +
"FOREIGN KEY (" + DatabaseConstants.VIOLATIONS_GRIM_VERSION_ID_COLUMN + ") REFERENCES " + DatabaseConstants.GRIM_VERSIONS_TABLE + "(id), " + // NEW
"FOREIGN KEY (" + DatabaseConstants.VIOLATIONS_CLIENT_BRAND_ID_COLUMN + ") REFERENCES " + DatabaseConstants.CLIENT_BRANDS_TABLE + "(id), " + // NEW
"FOREIGN KEY (" + DatabaseConstants.VIOLATIONS_CLIENT_VERSION_ID_COLUMN + ") REFERENCES " + DatabaseConstants.CLIENT_VERSIONS_TABLE + "(id), " + // NEW
"FOREIGN KEY (" + DatabaseConstants.VIOLATIONS_SERVER_VERSION_ID_COLUMN + ") REFERENCES " + DatabaseConstants.SERVER_VERSIONS_TABLE + "(id)" + // NEW
")"
).execute();
// 8. Create Indexes for efficient querying on main table (includes new FKs)
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.VIOLATIONS_TABLE + "_uuid ON " + DatabaseConstants.VIOLATIONS_TABLE + "(" + DatabaseConstants.VIOLATIONS_UUID_COLUMN + ");"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.VIOLATIONS_TABLE + "_created_at ON " + DatabaseConstants.VIOLATIONS_TABLE + "(" + DatabaseConstants.VIOLATIONS_CREATED_AT_COLUMN + ");"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.VIOLATIONS_TABLE + "_server_id ON " + DatabaseConstants.VIOLATIONS_TABLE + "(" + DatabaseConstants.VIOLATIONS_SERVER_ID_COLUMN + ");"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.VIOLATIONS_TABLE + "_check_name_id ON " + DatabaseConstants.VIOLATIONS_TABLE + "(" + DatabaseConstants.VIOLATIONS_CHECK_NAME_ID_COLUMN + ");"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.VIOLATIONS_TABLE + "_grim_version_id ON " + DatabaseConstants.VIOLATIONS_TABLE + "(" + DatabaseConstants.VIOLATIONS_GRIM_VERSION_ID_COLUMN + ");" // NEW
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.VIOLATIONS_TABLE + "_client_brand_id ON " + DatabaseConstants.VIOLATIONS_TABLE + "(" + DatabaseConstants.VIOLATIONS_CLIENT_BRAND_ID_COLUMN + ");" // NEW
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.VIOLATIONS_TABLE + "_client_version_id ON " + DatabaseConstants.VIOLATIONS_TABLE + "(" + DatabaseConstants.VIOLATIONS_CLIENT_VERSION_ID_COLUMN + ");" // NEW
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_" + DatabaseConstants.VIOLATIONS_TABLE + "_server_version_id ON " + DatabaseConstants.VIOLATIONS_TABLE + "(" + DatabaseConstants.VIOLATIONS_SERVER_VERSION_ID_COLUMN + ");" // NEW
).execute();
} catch (SQLException ex) {
LogUtil.error("Failed to generate violations database:", ex);
throw ex;
}
}
@Override
// Updated method signature to accept all new parameters
public synchronized void logAlert(GrimPlayer player, String grimVersion, String verbose, String checkName, int vls) {
try (Connection connection = dataSource.getConnection();
// Updated INSERT statement with all new columns
PreparedStatement insertAlert = connection.prepareStatement(
"INSERT INTO " + DatabaseConstants.VIOLATIONS_TABLE + " (" +
DatabaseConstants.VIOLATIONS_SERVER_ID_COLUMN + ", " +
DatabaseConstants.VIOLATIONS_UUID_COLUMN + ", " +
DatabaseConstants.VIOLATIONS_CHECK_NAME_ID_COLUMN + ", " +
quoteVerboseColumn() + ", " +
DatabaseConstants.VIOLATIONS_VL_COLUMN + ", " +
DatabaseConstants.VIOLATIONS_CREATED_AT_COLUMN + ", " +
DatabaseConstants.VIOLATIONS_GRIM_VERSION_ID_COLUMN + ", " + // NEW
DatabaseConstants.VIOLATIONS_CLIENT_BRAND_ID_COLUMN + ", " + // NEW
DatabaseConstants.VIOLATIONS_CLIENT_VERSION_ID_COLUMN + ", " + // NEW
DatabaseConstants.VIOLATIONS_SERVER_VERSION_ID_COLUMN + // NEW
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" // Total 10 parameters now
)
) {
// Get or create IDs for all deduplicated strings
String serverName = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("history.server-name", "Prison");
long serverId = DatabaseUtils.getOrCreateId(connection, dialect, DatabaseConstants.SERVERS_TABLE, DatabaseConstants.SERVERS_STRING_COLUMN, serverName);
long checkNameId = DatabaseUtils.getOrCreateId(connection, dialect, DatabaseConstants.CHECK_NAMES_TABLE, DatabaseConstants.CHECK_NAMES_STRING_COLUMN, checkName);
long grimVersionId = DatabaseUtils.getOrCreateId(connection, dialect, DatabaseConstants.GRIM_VERSIONS_TABLE, DatabaseConstants.GRIM_VERSIONS_STRING_COLUMN, grimVersion);
long clientBrandId = DatabaseUtils.getOrCreateId(connection, dialect, DatabaseConstants.CLIENT_BRANDS_TABLE, DatabaseConstants.CLIENT_BRANDS_STRING_COLUMN, player.getBrand());
long clientVersionId = DatabaseUtils.getOrCreateId(connection, dialect, DatabaseConstants.CLIENT_VERSIONS_TABLE, DatabaseConstants.CLIENT_VERSIONS_STRING_COLUMN, player.getClientVersion().getReleaseName());
long serverVersionId = DatabaseUtils.getOrCreateId(connection, dialect, DatabaseConstants.SERVER_VERSIONS_TABLE, DatabaseConstants.SERVER_VERSIONS_STRING_COLUMN, PacketEvents.getAPI().getServerManager().getVersion().toString());
// Set parameters for the PreparedStatement
insertAlert.setLong(1, serverId);
insertAlert.setObject(2, player.getUniqueId());
insertAlert.setLong(3, checkNameId);
insertAlert.setString(4, verbose);
insertAlert.setInt(5, vls);
insertAlert.setLong(6, System.currentTimeMillis());
insertAlert.setLong(7, grimVersionId); // NEW
insertAlert.setLong(8, clientBrandId); // NEW
insertAlert.setLong(9, clientVersionId); // NEW
insertAlert.setLong(10, serverVersionId); // NEW
insertAlert.execute();
} catch (SQLException ex) {
LogUtil.error("Failed to log alert", ex);
}
}
@Override
public synchronized int getLogCount(UUID uuid) {
try (Connection connection = dataSource.getConnection();
PreparedStatement countLogs = connection.prepareStatement(
"SELECT COUNT(*) FROM " + DatabaseConstants.VIOLATIONS_TABLE + " WHERE " + DatabaseConstants.VIOLATIONS_UUID_COLUMN + " = ?"
)
) {
countLogs.setObject(1, uuid);
ResultSet result = countLogs.executeQuery();
if (result.next()) {
return result.getInt(1);
}
} catch (SQLException ex) {
LogUtil.error("Failed to count logs", ex);
}
return 0;
}
@Override
public synchronized List<Violation> getViolations(UUID uuid, int page, int limit) {
try (Connection connection = dataSource.getConnection();
// Updated SELECT statement with all new joins and column selections
PreparedStatement fetchLogs = connection.prepareStatement(
"SELECT " +
"v." + DatabaseConstants.VIOLATIONS_ID_COLUMN + ", " +
"s." + DatabaseConstants.SERVERS_STRING_COLUMN + ", " +
"v." + DatabaseConstants.VIOLATIONS_UUID_COLUMN + ", " +
"cn." + DatabaseConstants.CHECK_NAMES_STRING_COLUMN + ", " +
"v." + quoteVerboseColumn() + ", " +
"v." + DatabaseConstants.VIOLATIONS_VL_COLUMN + ", " +
"v." + DatabaseConstants.VIOLATIONS_CREATED_AT_COLUMN + ", " +
"gv." + DatabaseConstants.GRIM_VERSIONS_STRING_COLUMN + ", " + // NEW
"cb." + DatabaseConstants.CLIENT_BRANDS_STRING_COLUMN + ", " + // NEW
"clv." + DatabaseConstants.CLIENT_VERSIONS_STRING_COLUMN + ", " + // NEW
"srv." + DatabaseConstants.SERVER_VERSIONS_STRING_COLUMN + " " + // NEW
"FROM " + DatabaseConstants.VIOLATIONS_TABLE + " v " +
"JOIN " + DatabaseConstants.SERVERS_TABLE + " s ON v." + DatabaseConstants.VIOLATIONS_SERVER_ID_COLUMN + " = s.id " +
"JOIN " + DatabaseConstants.CHECK_NAMES_TABLE + " cn ON v." + DatabaseConstants.VIOLATIONS_CHECK_NAME_ID_COLUMN + " = cn.id " +
"JOIN " + DatabaseConstants.GRIM_VERSIONS_TABLE + " gv ON v." + DatabaseConstants.VIOLATIONS_GRIM_VERSION_ID_COLUMN + " = gv.id " + // NEW
"JOIN " + DatabaseConstants.CLIENT_BRANDS_TABLE + " cb ON v." + DatabaseConstants.VIOLATIONS_CLIENT_BRAND_ID_COLUMN + " = cb.id " + // NEW
"JOIN " + DatabaseConstants.CLIENT_VERSIONS_TABLE + " clv ON v." + DatabaseConstants.VIOLATIONS_CLIENT_VERSION_ID_COLUMN + " = clv.id " + // NEW
"JOIN " + DatabaseConstants.SERVER_VERSIONS_TABLE + " srv ON v." + DatabaseConstants.VIOLATIONS_SERVER_VERSION_ID_COLUMN + " = srv.id " + // NEW
"WHERE v." + DatabaseConstants.VIOLATIONS_UUID_COLUMN + " = ? ORDER BY v." + DatabaseConstants.VIOLATIONS_CREATED_AT_COLUMN + " DESC LIMIT ? OFFSET ?"
)
) {
fetchLogs.setObject(1, uuid);
fetchLogs.setInt(2, limit);
fetchLogs.setInt(3, Math.max(0, (page - 1)) * limit); // postgresql is not allowing negative numbers
return Violation.fromResultSet(fetchLogs.executeQuery());
} catch (SQLException ex) {
LogUtil.error("Failed to fetch logs", ex);
return null;
}
}
@Override
public void disconnect() {
if (dataSource != null && !dataSource.isClosed()) {
dataSource.close();
}
}
public boolean sameConfig(String host, String db, String user, String pwd) {
String wantUrl = "jdbc:postgresql://" + host + "/" + db;
return wantUrl.equalsIgnoreCase(dataSource.getJdbcUrl())
&& user.equals(dataSource.getUsername())
&& pwd.equals(dataSource.getPassword());
}
}
@@ -25,6 +25,4 @@ public interface GrimEntity extends GrimIdentity {
PlatformWorld getWorld();
Location getLocation();
double distanceSquared(double x, double y, double z);
}
@@ -39,7 +39,7 @@ import ac.grim.grimac.utils.nmsutil.BlockProperties;
import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.Materials;
import ac.grim.grimac.utils.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
@@ -120,13 +120,13 @@ public class GrimPlayer implements GrimUser {
public long lastTransSent = 0;
public long lastTransReceived = 0;
@Getter
private long playerClockAtLeast;
private long playerClockAtLeast = System.nanoTime();
public double lastWasClimbing = 0;
public boolean canSwimHop = false;
public int riptideSpinAttackTicks = 0;
public int powderSnowFrozenTicks = 0;
public boolean hasGravity = true;
public final long joinTime;
public final long joinTime = System.currentTimeMillis();
public boolean playerEntityHasGravity = true;
public VectorData predictedVelocity = new VectorData(new Vector3dm(), VectorData.VectorType.Normal);
public Vector3dm actualMovement = new Vector3dm();
@@ -272,12 +272,6 @@ public class GrimPlayer implements GrimUser {
public boolean lastJumping;
public GrimPlayer(@NotNull User user) {
this(user, System.currentTimeMillis(), System.nanoTime());
}
protected GrimPlayer(@NotNull User user, long joinTime, long clockStart) {
this.joinTime = joinTime;
this.playerClockAtLeast = clockStart;
this.user = user;
this.uuid = user.getUUID();
fireworks = new CompensatedFireworks(this); // Must be before checkmanager
@@ -403,7 +397,7 @@ public class GrimPlayer implements GrimUser {
// Transactions that we send don't count towards total limit
if (viaPacketTracker != null) viaPacketTracker.setIntervalPackets(viaPacketTracker.getIntervalPackets() - 1);
if (skipped > 0 && now() - joinTime > 5000)
if (skipped > 0 && System.currentTimeMillis() - joinTime > 5000)
checkManager.getCheck(TransactionOrder.class).flagAndAlert("skipped: " + skipped);
do {
@@ -412,14 +406,14 @@ public class GrimPlayer implements GrimUser {
break;
lastTransactionReceived.incrementAndGet();
lastTransReceived = now();
transactionPing = (this.nano() - data.second());
lastTransReceived = System.currentTimeMillis();
transactionPing = (System.nanoTime() - data.second());
playerClockAtLeast = data.second();
} while (data.first() != id);
// A transaction means a new tick, so handle any block interactions
CheckManagerListener.handleQueuedPlaces(this, false, 0, 0, now());
CheckManagerListener.handleQueuedBreaks(this, false, 0, 0, now());
CheckManagerListener.handleQueuedPlaces(this, false, 0, 0, System.currentTimeMillis());
CheckManagerListener.handleQueuedBreaks(this, false, 0, 0, System.currentTimeMillis());
latencyUtils.handleNettySyncTransaction(lastTransactionReceived.get());
}
@@ -467,11 +461,11 @@ public class GrimPlayer implements GrimUser {
if (user.getEncoderState() != ConnectionState.PLAY) return;
// Send a packet once every 15 seconds to avoid any memory leaks
if (disableGrim && (this.nano() - getPlayerClockAtLeast()) > 15e9) {
if (disableGrim && (System.nanoTime() - getPlayerClockAtLeast()) > 15e9) {
return;
}
lastTransSent = now();
lastTransSent = System.currentTimeMillis();
short transactionID = (short) (-1 * (transactionIDCounter.getAndIncrement() & 0x7FFF));
try {
@@ -530,20 +524,15 @@ public class GrimPlayer implements GrimUser {
}
public void pollData() {
// Reset the debug timer for the Scheduler Thread.
// In Production: This is a no-op (0 cost).
// In Debug: This tells the clock "I am starting a new tick, don't freeze time."
this.processingPacket();
// Send a transaction at least once a tick, for timer and post check purposes
// Don't be the first to send the transaction, or we will stack overflow
//
// This will only really activate if there's no entities around the player being tracked
// 80 is a magic value that is roughly every other tick, we don't want to spam too many packets.
if (lastTransSent != 0 && lastTransSent + 80 < now()) {
if (lastTransSent != 0 && lastTransSent + 80 < System.currentTimeMillis()) {
sendTransaction(true); // send on netty thread
}
if ((this.nano() - getPlayerClockAtLeast()) > maxTransactionTime * 1e9) {
if ((System.nanoTime() - getPlayerClockAtLeast()) > maxTransactionTime * 1e9) {
timedOut();
}
@@ -999,27 +988,4 @@ public class GrimPlayer implements GrimUser {
return blockStateId;
}
/**
* Returns the current high-resolution time in nanoseconds.
* In Debug Mode, this will subtract time spent paused at breakpoints.
*/
public long nano() {
return System.nanoTime();
}
/**
* Returns the current wall-clock time in milliseconds.
* In Debug Mode, this will subtract time spent paused at breakpoints.
*/
public long now() {
return System.currentTimeMillis();
}
/**
* Called immediately when a packet starts processing.
* Used by DebugGrimPlayer to differentiate "Lag" (Pre-Packet) from "Breakpoints" (Intra-Packet).
* Optimized away (Dead Code Elimination) in production.
*/
public void processingPacket() {}
}
@@ -70,14 +70,13 @@ public class MovementCheckRunner extends Check implements PositionCheck {
if (!invalidVehicle && !data.isTeleport()) {
// Teleport the player back to avoid players being able to simply ignore transactions
// We shouldn't simulate movement in unloaded chunks
player.getSetbackTeleportUtil().executeNonSimulatingForceResync();
player.getSetbackTeleportUtil().executeForceResync();
}
}
long start = player.nano();
long start = System.nanoTime();
check(data);
long length = player.nano() - start;
long length = System.nanoTime() - start;
if (!player.disableGrim) {
predictionNanos = (predictionNanos * 499 / 500d) + (length / 500d);
@@ -197,6 +196,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
player.vehicleData.wasVehicleSwitch = false;
if (riding != null) {
Vector3dm pos = new Vector3dm(player.x, player.y, player.z);
SimpleCollisionBox interTruePositions = riding.getPossibleCollisionBoxes();
// We shrink the expanded bounding box to what the packet positions can be, for a smaller box
@@ -206,7 +206,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
interTruePositions.expand(-width, 0, -width);
interTruePositions.expandMax(0, -height, 0);
Vector3dm cutTo = VectorUtils.cutBoxToVector(player.x, player.y, player.z, interTruePositions);
Vector3dm cutTo = VectorUtils.cutBoxToVector(pos, interTruePositions);
// Now we need to simulate a tick starting at the most optimal position
// The start position is never sent, so we assume the most optimal start position
@@ -352,7 +352,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
boolean clientClaimsRiptide = player.packetStateData.tryingToRiptide;
if (player.packetStateData.tryingToRiptide) {
long currentTime = player.now();
long currentTime = System.currentTimeMillis();
boolean isInWater = player.isInWaterOrRain();
if (currentTime - player.packetStateData.lastRiptide < 450 || !isInWater) {
@@ -567,7 +567,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// Patch sprint jumping with elytra exploit
if (player.platformPlayer != null && player.isGliding && player.predictedVelocity.isJump() && player.isSprinting && !allowSprintJumpingWithElytra) {
SetbackTeleportUtil.SetbackPosWithVector lastKnownGoodPosition = player.getSetbackTeleportUtil().lastKnownGoodPosition;
lastKnownGoodPosition.setVector(lastKnownGoodPosition.getVector().multiply(0.6 * 0.91, 1, 0.6 * 0.91));
lastKnownGoodPosition.setVector(lastKnownGoodPosition.getVector().multiply(new Vector3dm(0.6 * 0.91, 1, 0.6 * 0.91)));
player.getSetbackTeleportUtil().executeNonSimulatingSetback();
}
@@ -157,12 +157,12 @@ public class UncertaintyHandler {
Vector3dm maxLocation = new Vector3dm(entityBox.maxX, entityBox.maxY, entityBox.maxZ);
Vector3dm minLocation = new Vector3dm(entityBox.minX, entityBox.minY, entityBox.minZ);
Vector3dm diff = minLocation.subtract(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ).multiply(0.1);
Vector3dm diff = minLocation.subtract(new Vector3dm(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
fishingRodPullBox.minX = Math.min(0, diff.getX());
fishingRodPullBox.minY = Math.min(0, diff.getY());
fishingRodPullBox.minZ = Math.min(0, diff.getZ());
diff = maxLocation.subtract(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ).multiply(0.1);
diff = maxLocation.subtract(new Vector3dm(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
fishingRodPullBox.maxX = Math.max(0, diff.getX());
fishingRodPullBox.maxY = Math.max(0, diff.getY());
fishingRodPullBox.maxZ = Math.max(0, diff.getZ());
@@ -15,7 +15,7 @@ import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.FluidFallingAdjustedMovement;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.MainSupportingBlockPosFinder;
import ac.grim.grimac.utils.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import ac.grim.grimac.utils.team.EntityPredicates;
import ac.grim.grimac.utils.team.EntityTeam;
import ac.grim.grimac.utils.team.TeamHandler;
@@ -233,7 +233,7 @@ public class MovementTicker {
player.predictedVelocity = new VectorData(collide.clone(), player.predictedVelocity.lastVector, player.predictedVelocity.vectorType);
float f = BlockProperties.getBlockSpeedFactor(player, player.mainSupportingBlockData, new Vector3d(player.x, player.y, player.z));
player.clientVelocity.multiply(f, 1, f);
player.clientVelocity.multiply(new Vector3dm(f, 1, f));
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2)) {
return;
@@ -446,14 +446,14 @@ public class MovementTicker {
// Lava movement changed in 1.16
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_16) && player.slightlyTouchingLava) {
player.clientVelocity = player.clientVelocity.multiply(0.5D, 0.800000011920929D, 0.5D);
player.clientVelocity = player.clientVelocity.multiply(new Vector3dm(0.5D, 0.800000011920929D, 0.5D));
player.clientVelocity = FluidFallingAdjustedMovement.getFluidFallingAdjustedMovement(player, playerGravity, isFalling, player.clientVelocity);
} else {
player.clientVelocity.multiply(0.5D);
}
if (player.hasGravity)
player.clientVelocity.add(0.0D, -playerGravity / 4.0D, 0.0D);
player.clientVelocity.add(new Vector3dm(0.0D, -playerGravity / 4.0D, 0.0D));
} else if (player.isGliding) {
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_5) && Collisions.onClimbable(player, player.lastX, player.lastY, player.lastZ)) {
@@ -30,7 +30,7 @@ public class MovementTickerStrider extends MovementTickerRideable {
if (isAbove(player) && player.compensatedWorld.getLavaFluidLevelAt((int) Math.floor(player.x), (int) Math.floor(player.y + 1), (int) Math.floor(player.z)) == 0) {
player.onGround = true;
} else {
player.clientVelocity.multiply(0.5).add(0, 0.05, 0);
player.clientVelocity.multiply(0.5).add(new Vector3dm(0, 0.05, 0));
}
}
}
@@ -417,7 +417,7 @@ public class PredictionEngine {
data.vector.setZ(data.vector.getZ() * 0.6);
data.addVectorType(VectorData.VectorType.AttackSlow);
} else {
velocities.add(data.returnNewModified(data.vector.clone().multiply(0.6, 1, 0.6), VectorData.VectorType.AttackSlow));
velocities.add(data.returnNewModified(data.vector.clone().multiply(new Vector3dm(0.6, 1, 0.6)), VectorData.VectorType.AttackSlow));
}
}
@@ -31,24 +31,24 @@ public class PredictionEngineElytra extends PredictionEngine {
recalculatedGravity = player.getClientVersion().isOlderThan(ClientVersion.V_1_20_5) ? 0.01 : Math.min(recalculatedGravity, 0.01);
}
vector.add(0.0D, recalculatedGravity * (-1.0D + vertCosRotation * 0.75D), 0.0D);
vector.add(new Vector3dm(0.0D, recalculatedGravity * (-1.0D + vertCosRotation * 0.75D), 0.0D));
double d5;
// Handle slowing the player down when falling
if (vector.getY() < 0.0D && horizontalSqrt > 0.0D) {
d5 = vector.getY() * -0.1D * vertCosRotation;
vector.add(lookVector.getX() * d5 / horizontalSqrt, d5, lookVector.getZ() * d5 / horizontalSqrt);
vector.add(new Vector3dm(lookVector.getX() * d5 / horizontalSqrt, d5, lookVector.getZ() * d5 / horizontalSqrt));
}
// Handle accelerating the player when they are looking down
if (pitchRadians < 0.0F && horizontalSqrt > 0.0D) {
d5 = horizontalLength * (double) (-player.trigHandler.sin(pitchRadians)) * 0.04D;
vector.add(-lookVector.getX() * d5 / horizontalSqrt, d5 * 3.2D, -lookVector.getZ() * d5 / horizontalSqrt);
vector.add(new Vector3dm(-lookVector.getX() * d5 / horizontalSqrt, d5 * 3.2D, -lookVector.getZ() * d5 / horizontalSqrt));
}
// Handle accelerating the player sideways
if (horizontalSqrt > 0) {
vector.add((lookVector.getX() / horizontalSqrt * horizontalLength - vector.getX()) * 0.1D, 0.0D, (lookVector.getZ() / horizontalSqrt * horizontalLength - vector.getZ()) * 0.1D);
vector.add(new Vector3dm((lookVector.getX() / horizontalSqrt * horizontalLength - vector.getX()) * 0.1D, 0.0D, (lookVector.getZ() / horizontalSqrt * horizontalLength - vector.getZ()) * 0.1D));
}
return vector;
@@ -67,7 +67,7 @@ public class PredictionEngineElytra extends PredictionEngine {
for (VectorData data : possibleVectors) {
Vector3dm elytraResult = getElytraMovement(player, data.vector.clone(), currentLook);
if (applyStuckSpeed != 0) elytraResult.multiply(player.stuckSpeedMultiplier);
elytraResult.multiply(0.99F, 0.98F, 0.99F);
elytraResult.multiply(new Vector3dm(0.99F, 0.98F, 0.99F));
VectorData modified = data.returnNewModified(elytraResult, VectorData.VectorType.InputResult);
modified.input = new Vector3dm(0, 0, 0);
results.add(modified);
@@ -16,7 +16,7 @@ public class PredictionEngineLava extends PredictionEngine {
double extraVelFromVertTickSkipUpwards = GrimMath.clamp(player.actualMovement.getY(), vector.vector.clone().getY(), vector.vector.clone().getY() + 0.05f);
existingVelocities.add(new VectorData(vector.vector.clone().setY(extraVelFromVertTickSkipUpwards), vector, VectorData.VectorType.Jump));
} else {
existingVelocities.add(new VectorData(vector.vector.clone().add(0, 0.04f, 0), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector3dm(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
}
if (player.slightlyTouchingLava && player.lastOnGround && !player.onGround) {
@@ -56,7 +56,7 @@ public class PredictionEngineNormal extends PredictionEngine {
JumpPower.jumpFromGround(player, jump);
} else {
jump.add(0, player.flySpeed * 3, 0);
jump.add(new Vector3dm(0, player.flySpeed * 3, 0));
if (!player.wasFlying) {
Vector3dm edgeCaseJump = jump.clone();
JumpPower.jumpFromGround(player, edgeCaseJump);
@@ -20,7 +20,7 @@ public class PredictionEngineWater extends PredictionEngine {
private float swimmingFriction;
public static void staticVectorEndOfTick(GrimPlayer player, Vector3dm vector, float swimmingFriction, double playerGravity, boolean isFalling) {
vector.multiply(swimmingFriction, 0.8F, swimmingFriction);
vector.multiply(new Vector3dm(swimmingFriction, 0.8F, swimmingFriction));
Vector3dm fluidVector = FluidFallingAdjustedMovement.getFluidFallingAdjustedMovement(player, playerGravity, isFalling, vector);
vector.setX(fluidVector.getX());
vector.setY(fluidVector.getY());
@@ -76,7 +76,7 @@ public class PredictionEngineWater extends PredictionEngine {
double extraVelFromVertTickSkipUpwards = GrimMath.clamp(player.actualMovement.getY(), vector.vector.clone().getY(), vector.vector.clone().getY() + 0.05f);
existingVelocities.add(new VectorData(vector.vector.clone().setY(extraVelFromVertTickSkipUpwards), vector, VectorData.VectorType.Jump));
} else {
existingVelocities.add(new VectorData(vector.vector.clone().add(0, 0.04f, 0), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector3dm(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
}
if (player.slightlyTouchingWater && player.lastOnGround && !player.onGround) {
@@ -47,10 +47,10 @@ public class PredictionEngineWaterLegacy extends PredictionEngine {
@Override
public void addJumpsToPossibilities(GrimPlayer player, Set<VectorData> existingVelocities) {
for (VectorData vector : new HashSet<>(existingVelocities)) {
existingVelocities.add(new VectorData(vector.vector.clone().add(0, 0.04f, 0), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector3dm(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
if (player.skippedTickInActualMovement) {
existingVelocities.add(new VectorData(vector.vector.clone().add(0, 0.02f, 0), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector3dm(0, 0.02f, 0)), vector, VectorData.VectorType.Jump));
}
}
}
@@ -60,7 +60,7 @@ public class PredictionEngineWaterLegacy extends PredictionEngine {
super.endOfTick(player, playerGravity);
for (VectorData vector : player.getPossibleVelocitiesMinusKnockback()) {
vector.vector.multiply(swimmingFriction, 0.8F, swimmingFriction);
vector.vector.multiply(new Vector3dm(swimmingFriction, 0.8F, swimmingFriction));
// Gravity
vector.vector.setY(vector.vector.getY() - 0.02D);
@@ -59,7 +59,7 @@ public final class PredictionEngineRideableUtils {
}
final double multiplier = (double) (22.2222F * player.vehicleData.horseJump) * camel.getAttributeValue(Attributes.MOVEMENT_SPEED) * (double) BlockProperties.getBlockSpeedFactor(player, player.mainSupportingBlockData, new Vector3d(player.lastX, player.lastY, player.lastZ));
Vector3dm jumpVelocity = ReachUtils.getLook(player, player.yaw, player.pitch).multiply(1.0, 0.0, 1.0).normalize().multiply(multiplier).add(0, (double) (1.4285F * player.vehicleData.horseJump) * jumpYVelocity, 0);
Vector3dm jumpVelocity = ReachUtils.getLook(player, player.yaw, player.pitch).multiply(new Vector3dm(1.0, 0.0, 1.0)).normalize().multiply(multiplier).add(new Vector3dm(0, (double) (1.4285F * player.vehicleData.horseJump) * jumpYVelocity, 0));
for (VectorData vectorData : possibleVectors) {
vectorData.vector.add(jumpVelocity);
@@ -3,8 +3,6 @@ package ac.grim.grimac.utils.anticheat;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.event.events.GrimJoinEvent;
import ac.grim.grimac.api.event.events.GrimQuitEvent;
import ac.grim.grimac.checks.debug.DebugGrimPlayer;
import ac.grim.grimac.checks.debug.GrimDebugSettings;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.reflection.GeyserUtil;
import com.github.retrooper.packetevents.PacketEvents;
@@ -14,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -68,21 +67,12 @@ public class PlayerDataManager {
public void addUser(final @NotNull User user) {
if (shouldCheck(user)) {
GrimPlayer player = this.createPlayer(user);
GrimPlayer player = new GrimPlayer(user);
playerDataMap.put(user, player);
GrimAPI.INSTANCE.getEventBus().post(new GrimJoinEvent(player));
}
}
public GrimPlayer createPlayer(User user) {
// Simple Global Check
if (GrimDebugSettings.shouldEnable()) {
return new DebugGrimPlayer(user);
} else {
return new GrimPlayer(user);
}
}
public GrimPlayer remove(final @NotNull User user) {
return playerDataMap.remove(user);
}
@@ -22,7 +22,7 @@ import ac.grim.grimac.utils.collisions.datatypes.NoCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.packetentity.PacketEntityStrider;
import ac.grim.grimac.utils.nmsutil.Materials;
import ac.grim.grimac.utils.viaversion.ViaVersionUtil;
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
@@ -1018,30 +1018,6 @@ public enum CollisionData implements CollisionFactory {
}
}, StateTypes.DRIED_GHAST),
SHELF((player, version, data, x, y, z) -> {
if (version.isOlderThan(ClientVersion.V_1_21_9)) {
// ViaVersion replacement block (planks)
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
}
return switch (data.getFacing()) {
case NORTH -> new ComplexCollisionBox(3, new HexCollisionBox(0, 12, 11, 16, 16, 13), new HexCollisionBox(0, 0, 13, 16, 16, 16), new HexCollisionBox(0, 0, 11, 16, 4, 13));
case SOUTH -> new ComplexCollisionBox(3, new HexCollisionBox(0, 12, 3, 16, 16, 5), new HexCollisionBox(0, 0, 0, 16, 16, 3), new HexCollisionBox(0, 0, 3, 16, 4, 5));
case WEST -> new ComplexCollisionBox(3, new HexCollisionBox(11, 12, 0, 13, 16, 16), new HexCollisionBox(13, 0, 0, 16, 16, 16), new HexCollisionBox(11, 0, 0, 13, 4, 16));
case EAST -> new ComplexCollisionBox(3, new HexCollisionBox(3, 12, 0, 5, 16, 16), new HexCollisionBox(0, 0, 0, 3, 16, 16), new HexCollisionBox(3, 0, 0, 5, 4, 16));
default -> throw new IllegalStateException("Unexpected value: " + data.getFacing());
};
}, BlockTags.WOODEN_SHELVES.getStates().toArray(new StateType[0])),
COPPER_GOLEM_STATUE((player, version, data, x, y, z) -> {
if (version.isOlderThan(ClientVersion.V_1_21_9)) {
// ViaVersion replacement block (copper block)
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
}
return new HexCollisionBox(3, 0, 3, 13, 14, 13);
}, BlockTags.COPPER_GOLEM_STATUES.getStates().toArray(new StateType[0])),
DEFAULT(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.STONE);
// This should be an array... but a hashmap will do for now...
@@ -1073,7 +1049,7 @@ public enum CollisionData implements CollisionFactory {
this.materials = mList.toArray(new StateType[0]);
}
private static CollisionBox getAmethystBox(ClientVersion version, BlockFace facing, int param_0, int param_1) {
private static CollisionBox getAmethystBox(ClientVersion version, com.github.retrooper.packetevents.protocol.world.BlockFace facing, int param_0, int param_1) {
if (version.isOlderThanOrEquals(ClientVersion.V_1_16_4))
return NoCollisionBox.INSTANCE;
@@ -1170,11 +1146,7 @@ public enum CollisionData implements CollisionFactory {
// Would pre-computing all states be worth the memory cost? I doubt it
public static CollisionData getData(StateType state) { // TODO: Find a better hack for lava and scaffolding
// What the fuck mojang, why put noCollision() and then give PITCHER_CROP collision?
return state.isSolid() || state == StateTypes.LAVA || state == StateTypes.SCAFFOLDING
|| state == StateTypes.PITCHER_CROP || state == StateTypes.HEAVY_CORE
|| state == StateTypes.PALE_MOSS_CARPET || BlockTags.WALL_HANGING_SIGNS.contains(state)
|| BlockTags.COPPER_GOLEM_STATUES.contains(state)
? rawLookupMap.getOrDefault(state, DEFAULT) : NO_COLLISION;
return state.isSolid() || state == StateTypes.LAVA || state == StateTypes.SCAFFOLDING || state == StateTypes.PITCHER_CROP || state == StateTypes.HEAVY_CORE || state == StateTypes.PALE_MOSS_CARPET || BlockTags.WALL_HANGING_SIGNS.contains(state) ? rawLookupMap.getOrDefault(state, DEFAULT) : NO_COLLISION;
}
// TODO: This is wrong if a block doesn't have any hitbox and isn't specified, light block?
@@ -29,10 +29,4 @@ public class CommonGrimArguments {
* This setting is opt-in (default: false) and requires a server restart to change.
*/
public final static SystemArgument<Boolean> USE_CHAT_FAST_BYPASS = FACTORY.create(string("ChatFastBypass", true));
/**
* If TRUE, and a Debugger is detected attached to the JVM, Grim will use the
* DebugGrimPlayer implementation which absorbs breakpoint pauses > 200ms.
* Default: false (Safety).
*/
public final static SystemArgument<Boolean> DEBUG_BREAKPOINT_MODE = FACTORY.create(string("DebugBreakpointMode", false));
}
@@ -40,7 +40,7 @@ public class ReachInterpolationData {
private int cancelledLerpInterpolationStepsLowBound = Integer.MAX_VALUE;
public ReachInterpolationData(GrimPlayer player, SimpleCollisionBox startingLocation, TrackedPosition position, PacketEntity entity) {
final boolean unreliableTicking = !player.inVehicle() && player.canSkipTicks();
final boolean isPointNine = !player.inVehicle() && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9);
this.startingLocation = startingLocation;
final Vector3d pos = position.getPos();
@@ -50,7 +50,7 @@ public class ReachInterpolationData {
// 1.9 -> 1.8 precision loss in packets
// (ViaVersion is doing some stuff that makes this code difficult)
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9) && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
if (!isPointNine && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
targetLocation.expand(0.03125);
}
@@ -66,8 +66,7 @@ public class ReachInterpolationData {
interpolationSteps = 1;
}
// If the player doesn't tick reliably, their interpolation is anywhere between min and max steps.
if (unreliableTicking) interpolationStepsHighBound = getInterpolationSteps();
if (isPointNine) interpolationStepsHighBound = getInterpolationSteps();
}
// While riding entities, there is no interpolation.
@@ -33,26 +33,23 @@ public enum EquipmentType {
}
if (item == ItemTypes.LEATHER_BOOTS || item == ItemTypes.CHAINMAIL_BOOTS
|| item == ItemTypes.IRON_BOOTS || item == ItemTypes.DIAMOND_BOOTS
|| item == ItemTypes.GOLDEN_BOOTS || item == ItemTypes.NETHERITE_BOOTS
|| item == ItemTypes.COPPER_BOOTS) {
|| item == ItemTypes.GOLDEN_BOOTS || item == ItemTypes.NETHERITE_BOOTS) {
return FEET;
}
if (item == ItemTypes.LEATHER_LEGGINGS || item == ItemTypes.CHAINMAIL_LEGGINGS
|| item == ItemTypes.IRON_LEGGINGS || item == ItemTypes.DIAMOND_LEGGINGS
|| item == ItemTypes.GOLDEN_LEGGINGS || item == ItemTypes.NETHERITE_LEGGINGS
|| item == ItemTypes.COPPER_LEGGINGS) {
|| item == ItemTypes.GOLDEN_LEGGINGS || item == ItemTypes.NETHERITE_LEGGINGS) {
return LEGS;
}
if (item == ItemTypes.LEATHER_CHESTPLATE || item == ItemTypes.CHAINMAIL_CHESTPLATE
|| item == ItemTypes.IRON_CHESTPLATE || item == ItemTypes.DIAMOND_CHESTPLATE
|| item == ItemTypes.GOLDEN_CHESTPLATE || item == ItemTypes.NETHERITE_CHESTPLATE
|| item == ItemTypes.COPPER_CHESTPLATE) {
|| item == ItemTypes.GOLDEN_CHESTPLATE || item == ItemTypes.NETHERITE_CHESTPLATE) {
return CHEST;
}
if (item == ItemTypes.LEATHER_HELMET || item == ItemTypes.CHAINMAIL_HELMET
|| item == ItemTypes.IRON_HELMET || item == ItemTypes.DIAMOND_HELMET
|| item == ItemTypes.GOLDEN_HELMET || item == ItemTypes.NETHERITE_HELMET
|| item == ItemTypes.COPPER_HELMET || item == ItemTypes.TURTLE_HELMET) {
|| item == ItemTypes.TURTLE_HELMET) {
return HEAD;
}
return ItemTypes.SHIELD == item ? OFFHAND : MAINHAND;
@@ -287,9 +287,9 @@ public class CompensatedEntities {
if (sizeObject != null) {
Object value = sizeObject.getValue();
if (value instanceof Integer) {
sizeable.size = (int) value;
sizeable.size = Math.max((int) value, 1);
} else if (value instanceof Byte) {
sizeable.size = (byte) value;
sizeable.size = Math.max((byte) value, 1);
}
}
}
@@ -501,7 +501,6 @@ public class CompensatedInventory extends Check implements PacketCheck {
* Closes the player's currently open inventory on the client by resetting to the player's inventory.
*/
private void closeActiveInventory() {
isPacketInventoryActive = true;
openWindowID = 0;
menu = inventory;
menu.setCarried(ItemStack.EMPTY); // Reset carried item
@@ -66,35 +66,23 @@ public class Vector3dm implements Cloneable, Serializable {
}
public @NotNull Vector3dm add(@NotNull Vector3dm vec) {
return add(vec.x, vec.y, vec.z);
}
public @NotNull Vector3dm add(double x, double y, double z) {
this.x += x;
this.y += y;
this.z += z;
this.x += vec.x;
this.y += vec.y;
this.z += vec.z;
return this;
}
public @NotNull Vector3dm subtract(@NotNull Vector3dm vec) {
return subtract(vec.x, vec.y, vec.z);
}
public @NotNull Vector3dm subtract(double x, double y, double z) {
this.x -= x;
this.y -= y;
this.z -= z;
this.x -= vec.x;
this.y -= vec.y;
this.z -= vec.z;
return this;
}
public @NotNull Vector3dm multiply(@NotNull Vector3dm vec) {
return multiply(vec.x, vec.y, vec.z);
}
public @NotNull Vector3dm multiply(double x, double y, double z) {
this.x *= x;
this.y *= y;
this.z *= z;
this.x *= vec.x;
this.y *= vec.y;
this.z *= vec.z;
return this;
}
@@ -121,19 +109,11 @@ public class Vector3dm implements Cloneable, Serializable {
}
public double distance(@NotNull Vector3dm o) {
return Math.sqrt(distanceSquared(o));
return Math.sqrt(GrimMath.square(this.x - o.x) + GrimMath.square(this.y - o.y) + GrimMath.square(this.z - o.z));
}
public double distanceSquared(@NotNull Vector3dm o) {
return distanceSquared(o.x, o.y, o.z);
}
public double distance(double oX, double oY, double oZ) {
return Math.sqrt(distanceSquared(oX, oY, oZ));
}
public double distanceSquared(double oX, double oY, double oZ) {
return GrimMath.square(this.x - oX) + GrimMath.square(this.y - oY) + GrimMath.square(this.z - oZ);
return GrimMath.square(this.x - o.x) + GrimMath.square(this.y - o.y) + GrimMath.square(this.z - o.z);
}
public @NotNull Vector3dm midpoint(@NotNull Vector3dm other) {
@@ -15,13 +15,9 @@ public class VectorUtils {
@Contract("_, _ -> new")
public static @NotNull Vector3dm cutBoxToVector(@NotNull Vector3dm vectorCutTo, @NotNull SimpleCollisionBox box) {
return cutBoxToVector(vectorCutTo.getX(), vectorCutTo.getY(), vectorCutTo.getZ(), box);
}
public static @NotNull Vector3dm cutBoxToVector(double x, double y, double z, @NotNull SimpleCollisionBox box) {
return new Vector3dm(GrimMath.clamp(x, box.minX, box.maxX),
GrimMath.clamp(y, box.minY, box.maxY),
GrimMath.clamp(z, box.minZ, box.maxZ));
return new Vector3dm(GrimMath.clamp(vectorCutTo.getX(), box.minX, box.maxX),
GrimMath.clamp(vectorCutTo.getY(), box.minY, box.maxY),
GrimMath.clamp(vectorCutTo.getZ(), box.minZ, box.maxZ));
}
@Contract("_ -> new")
@@ -27,33 +27,33 @@ public final class BoundingBoxSize {
private static float getWidthMinusBaby(GrimPlayer player, PacketEntity packetEntity) {
final EntityType type = packetEntity.type;
if (type == EntityTypes.AXOLOTL) {
if (EntityTypes.AXOLOTL.equals(type)) {
return 0.75f;
} else if (type == EntityTypes.PANDA) {
} else if (EntityTypes.PANDA.equals(type)) {
return 1.3f;
} else if (type == EntityTypes.BAT || type == EntityTypes.PARROT || type == EntityTypes.COD || type == EntityTypes.EVOKER_FANGS || type == EntityTypes.TROPICAL_FISH || type == EntityTypes.FROG || type == EntityTypes.COPPER_GOLEM) {
} else if (EntityTypes.BAT.equals(type) || EntityTypes.PARROT.equals(type) || EntityTypes.COD.equals(type) || EntityTypes.EVOKER_FANGS.equals(type) || EntityTypes.TROPICAL_FISH.equals(type) || EntityTypes.FROG.equals(type)) {
return 0.5f;
} else if (type == EntityTypes.ARMADILLO || type == EntityTypes.BEE || type == EntityTypes.PUFFERFISH || type == EntityTypes.SALMON || type == EntityTypes.SNOW_GOLEM || type == EntityTypes.CAVE_SPIDER) {
} else if (EntityTypes.ARMADILLO.equals(type) || EntityTypes.BEE.equals(type) || EntityTypes.PUFFERFISH.equals(type) || EntityTypes.SALMON.equals(type) || EntityTypes.SNOW_GOLEM.equals(type) || EntityTypes.CAVE_SPIDER.equals(type)) {
return 0.7f;
} else if (type == EntityTypes.WITHER_SKELETON) {
} else if (EntityTypes.WITHER_SKELETON.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 0.7f : 0.72f;
} else if (type == EntityTypes.WITHER_SKULL || type == EntityTypes.SHULKER_BULLET) {
} else if (EntityTypes.WITHER_SKULL.equals(type) || EntityTypes.SHULKER_BULLET.equals(type)) {
return 0.3125f;
} else if (type == EntityTypes.HOGLIN || type == EntityTypes.ZOGLIN) {
} else if (EntityTypes.HOGLIN.equals(type) || EntityTypes.ZOGLIN.equals(type)) {
return 1.3964844f;
} else if (type == EntityTypes.SKELETON_HORSE || type == EntityTypes.ZOMBIE_HORSE || type == EntityTypes.HORSE || type == EntityTypes.DONKEY || type == EntityTypes.MULE) {
} else if (EntityTypes.SKELETON_HORSE.equals(type) || EntityTypes.ZOMBIE_HORSE.equals(type) || EntityTypes.HORSE.equals(type) || EntityTypes.DONKEY.equals(type) || EntityTypes.MULE.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 1.3964844f : 1.4f;
} else if (EntityTypes.isTypeInstanceOf(type, EntityTypes.BOAT)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 1.375f : 1.5f;
} else if (type == EntityTypes.HAPPY_GHAST) {
} else if (EntityTypes.HAPPY_GHAST.equals(type)) {
return 4.0f;
} else if (type == EntityTypes.CHICKEN || type == EntityTypes.ENDERMITE || type == EntityTypes.SILVERFISH || type == EntityTypes.VEX || type == EntityTypes.TADPOLE) {
} else if (EntityTypes.CHICKEN.equals(type) || EntityTypes.ENDERMITE.equals(type) || EntityTypes.SILVERFISH.equals(type) || EntityTypes.VEX.equals(type) || EntityTypes.TADPOLE.equals(type)) {
return 0.4f;
} else if (type == EntityTypes.RABBIT) {
} else if (EntityTypes.RABBIT.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 0.4f : 0.6f;
} else if (type == EntityTypes.CREAKING || type == EntityTypes.STRIDER || type == EntityTypes.COW || type == EntityTypes.SHEEP || type == EntityTypes.MOOSHROOM || type == EntityTypes.PIG || type == EntityTypes.LLAMA || type == EntityTypes.DOLPHIN || type == EntityTypes.WITHER || type == EntityTypes.TRADER_LLAMA || type == EntityTypes.WARDEN || type == EntityTypes.GOAT) {
} else if (EntityTypes.CREAKING.equals(type) || EntityTypes.STRIDER.equals(type) || EntityTypes.COW.equals(type) || EntityTypes.SHEEP.equals(type) || EntityTypes.MOOSHROOM.equals(type) || EntityTypes.PIG.equals(type) || EntityTypes.LLAMA.equals(type) || EntityTypes.DOLPHIN.equals(type) || EntityTypes.WITHER.equals(type) || EntityTypes.TRADER_LLAMA.equals(type) || EntityTypes.WARDEN.equals(type) || EntityTypes.GOAT.equals(type)) {
return 0.9f;
} else if (type == EntityTypes.PHANTOM) {
} else if (EntityTypes.PHANTOM.equals(type)) {
if (packetEntity instanceof PacketEntitySizeable sizeable) {
return 0.9f + sizeable.size * 0.2f;
}
@@ -61,21 +61,21 @@ public final class BoundingBoxSize {
return 1.5f;
} else if (packetEntity instanceof PacketEntityGuardian packetEntityGuardian) { // TODO: 2.35 * guardian?
return packetEntityGuardian.isElder ? 1.9975f : 0.85f;
} else if (type == EntityTypes.END_CRYSTAL) {
} else if (EntityTypes.END_CRYSTAL.equals(type)) {
return 2f;
} else if (type == EntityTypes.ENDER_DRAGON) {
} else if (EntityTypes.ENDER_DRAGON.equals(type)) {
return 16f;
} else if (type == EntityTypes.FIREBALL) {
} else if (EntityTypes.FIREBALL.equals(type)) {
return 1f;
} else if (type == EntityTypes.GHAST) {
} else if (EntityTypes.GHAST.equals(type)) {
return 4f;
} else if (type == EntityTypes.GIANT) {
} else if (EntityTypes.GIANT.equals(type)) {
return 3.6f;
} else if (type == EntityTypes.GUARDIAN) {
} else if (EntityTypes.GUARDIAN.equals(type)) {
return 0.85f;
} else if (type == EntityTypes.IRON_GOLEM) {
} else if (EntityTypes.IRON_GOLEM.equals(type)) {
return 1.4f;
} else if (type == EntityTypes.MAGMA_CUBE) {
} else if (EntityTypes.MAGMA_CUBE.equals(type)) {
if (packetEntity instanceof PacketEntitySizeable sizeable) {
float size = sizeable.size;
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20_5)
@@ -87,15 +87,15 @@ public final class BoundingBoxSize {
return 0.98f;
} else if (EntityTypes.isTypeInstanceOf(type, EntityTypes.MINECART_ABSTRACT)) {
return 0.98f;
} else if (type == EntityTypes.PLAYER || type == EntityTypes.MANNEQUIN) {
} else if (EntityTypes.PLAYER.equals(type)) {
return 0.6f;
} else if (type == EntityTypes.POLAR_BEAR) {
} else if (EntityTypes.POLAR_BEAR.equals(type)) {
return 1.4f;
} else if (type == EntityTypes.RAVAGER) {
} else if (EntityTypes.RAVAGER.equals(type)) {
return 1.95f;
} else if (type == EntityTypes.SHULKER) {
} else if (EntityTypes.SHULKER.equals(type)) {
return 1f;
} else if (type == EntityTypes.SLIME) {
} else if (EntityTypes.SLIME.equals(type)) {
if (packetEntity instanceof PacketEntitySizeable sizeable) {
float size = sizeable.size;
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20_5)
@@ -104,27 +104,27 @@ public final class BoundingBoxSize {
}
return 0.3125f;
} else if (type == EntityTypes.SMALL_FIREBALL) {
} else if (EntityTypes.SMALL_FIREBALL.equals(type)) {
return 0.3125f;
} else if (type == EntityTypes.SPIDER) {
} else if (EntityTypes.SPIDER.equals(type)) {
return 1.4f;
} else if (type == EntityTypes.SQUID) {
} else if (EntityTypes.SQUID.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 0.8f : 0.95f;
} else if (type == EntityTypes.TURTLE) {
} else if (EntityTypes.TURTLE.equals(type)) {
return 1.2f;
} else if (type == EntityTypes.ALLAY) {
} else if (EntityTypes.ALLAY.equals(type)) {
return 0.35f;
} else if (type == EntityTypes.SNIFFER) {
} else if (EntityTypes.SNIFFER.equals(type)) {
return 1.9f;
} else if (type == EntityTypes.CAMEL) {
} else if (EntityTypes.CAMEL.equals(type)) {
return 1.7f;
} else if (type == EntityTypes.WIND_CHARGE) {
} else if (EntityTypes.WIND_CHARGE.equals(type)) {
return 0.3125f;
} else if (type == EntityTypes.ARMOR_STAND) {
} else if (EntityTypes.ARMOR_STAND.equals(type)) {
return 0.5F;
} else if (type == EntityTypes.FALLING_BLOCK) {
} else if (EntityTypes.FALLING_BLOCK.equals(type)) {
return 0.98F;
} else if (type == EntityTypes.FIREWORK_ROCKET) {
} else if (EntityTypes.FIREWORK_ROCKET.equals(type)) {
return 0.25F;
}
return 0.6f;
@@ -191,15 +191,15 @@ public final class BoundingBoxSize {
public static double getMyRidingOffset(PacketEntity packetEntity) {
final EntityType type = packetEntity.type;
if (type == EntityTypes.PIGLIN || type == EntityTypes.ZOMBIFIED_PIGLIN || type == EntityTypes.ZOMBIE) {
if (EntityTypes.PIGLIN.equals(type) || EntityTypes.ZOMBIFIED_PIGLIN.equals(type) || EntityTypes.ZOMBIE.equals(type)) {
return packetEntity.isBaby ? -0.05 : -0.45;
} else if (type == EntityTypes.SKELETON) {
} else if (EntityTypes.SKELETON.equals(type)) {
return -0.6;
} else if (type == EntityTypes.ENDERMITE || type == EntityTypes.SILVERFISH) {
} else if (EntityTypes.ENDERMITE.equals(type) || EntityTypes.SILVERFISH.equals(type)) {
return 0.1;
} else if (type == EntityTypes.EVOKER || type == EntityTypes.ILLUSIONER || type == EntityTypes.PILLAGER || type == EntityTypes.RAVAGER || type == EntityTypes.VINDICATOR || type == EntityTypes.WITCH) {
} else if (EntityTypes.EVOKER.equals(type) || EntityTypes.ILLUSIONER.equals(type) || EntityTypes.PILLAGER.equals(type) || EntityTypes.RAVAGER.equals(type) || EntityTypes.VINDICATOR.equals(type) || EntityTypes.WITCH.equals(type)) {
return -0.45;
} else if (type == EntityTypes.PLAYER || type == EntityTypes.MANNEQUIN) {
} else if (EntityTypes.PLAYER.equals(type)) {
return -0.35;
}
@@ -219,21 +219,21 @@ public final class BoundingBoxSize {
return 0;
} else if (EntityTypes.isTypeInstanceOf(type, EntityTypes.BOAT)) {
return -0.1;
} else if (type == EntityTypes.HAPPY_GHAST) {
} else if (EntityTypes.HAPPY_GHAST.equals(type)) {
return 0.5;
} else if (type == EntityTypes.HOGLIN || type == EntityTypes.ZOGLIN) {
} else if (EntityTypes.HOGLIN.equals(type) || EntityTypes.ZOGLIN.equals(type)) {
return getHeight(player, packetEntity) - (packetEntity.isBaby ? 0.2 : 0.15);
} else if (type == EntityTypes.LLAMA) {
} else if (EntityTypes.LLAMA.equals(type)) {
return getHeight(player, packetEntity) * 0.67;
} else if (type == EntityTypes.PIGLIN) {
} else if (EntityTypes.PIGLIN.equals(type)) {
return getHeight(player, packetEntity) * 0.92;
} else if (type == EntityTypes.RAVAGER) {
} else if (EntityTypes.RAVAGER.equals(type)) {
return 2.1;
} else if (type == EntityTypes.SKELETON) {
} else if (EntityTypes.SKELETON.equals(type)) {
return (getHeight(player, packetEntity) * 0.75) - 0.1875;
} else if (type == EntityTypes.SPIDER) {
} else if (EntityTypes.SPIDER.equals(type)) {
return getHeight(player, packetEntity) * 0.5;
} else if (type == EntityTypes.STRIDER) {// depends on animation position, good luck getting it exactly, this is the best you can do though
} else if (EntityTypes.STRIDER.equals(type)) {// depends on animation position, good luck getting it exactly, this is the best you can do though
return getHeight(player, packetEntity) - 0.19;
}
return getHeight(player, packetEntity) * 0.75;
@@ -241,77 +241,77 @@ public final class BoundingBoxSize {
private static float getHeightMinusBaby(GrimPlayer player, PacketEntity packetEntity) {
final EntityType type = packetEntity.type;
if (type == EntityTypes.ARMADILLO) {
if (EntityTypes.ARMADILLO.equals(type)) {
return 0.65f;
} else if (type == EntityTypes.AXOLOTL) {
} else if (EntityTypes.AXOLOTL.equals(type)) {
return 0.42f;
} else if (type == EntityTypes.BEE || type == EntityTypes.DOLPHIN || type == EntityTypes.ALLAY) {
} else if (EntityTypes.BEE.equals(type) || EntityTypes.DOLPHIN.equals(type) || EntityTypes.ALLAY.equals(type)) {
return 0.6f;
} else if (type == EntityTypes.EVOKER_FANGS || type == EntityTypes.VEX) {
} else if (EntityTypes.EVOKER_FANGS.equals(type) || EntityTypes.VEX.equals(type)) {
return 0.8f;
} else if (type == EntityTypes.SQUID) {
} else if (EntityTypes.SQUID.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 0.8f : 0.95f;
} else if (type == EntityTypes.PARROT || type == EntityTypes.BAT || type == EntityTypes.PIG || type == EntityTypes.SPIDER) {
} else if (EntityTypes.PARROT.equals(type) || EntityTypes.BAT.equals(type) || EntityTypes.PIG.equals(type) || EntityTypes.SPIDER.equals(type)) {
return 0.9f;
} else if (type == EntityTypes.WITHER_SKULL || type == EntityTypes.SHULKER_BULLET) {
} else if (EntityTypes.WITHER_SKULL.equals(type) || EntityTypes.SHULKER_BULLET.equals(type)) {
return 0.3125f;
} else if (type == EntityTypes.BLAZE) {
} else if (EntityTypes.BLAZE.equals(type)) {
return 1.8f;
} else if (EntityTypes.isTypeInstanceOf(type, EntityTypes.BOAT)) {
// WHY DOES VIAVERSION OFFSET BOATS? THIS MAKES IT HARD TO SUPPORT, EVEN IF WE INTERPOLATE RIGHT.
// I gave up and just exempted boats from the reach check and gave up with interpolation for collisions
return 0.5625f;
} else if (type == EntityTypes.HAPPY_GHAST) {
} else if (EntityTypes.HAPPY_GHAST.equals(type)) {
return 4.0f;
} else if (type == EntityTypes.CAT) {
} else if (EntityTypes.CAT.equals(type)) {
return 0.7f;
} else if (type == EntityTypes.CAVE_SPIDER) {
} else if (EntityTypes.CAVE_SPIDER.equals(type)) {
return 0.5f;
} else if (type == EntityTypes.FROG) {
} else if (EntityTypes.FROG.equals(type)) {
return 0.55f;
} else if (type == EntityTypes.CHICKEN) {
} else if (EntityTypes.CHICKEN.equals(type)) {
return 0.7f;
} else if (type == EntityTypes.HOGLIN || type == EntityTypes.ZOGLIN) {
} else if (EntityTypes.HOGLIN.equals(type) || EntityTypes.ZOGLIN.equals(type)) {
return 1.4f;
} else if (type == EntityTypes.COW) {
} else if (EntityTypes.COW.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 1.4f : 1.3f;
} else if (type == EntityTypes.STRIDER) {
} else if (EntityTypes.STRIDER.equals(type)) {
return 1.7f;
} else if (type == EntityTypes.CREEPER) {
} else if (EntityTypes.CREEPER.equals(type)) {
return 1.7f;
} else if (type == EntityTypes.DONKEY) {
} else if (EntityTypes.DONKEY.equals(type)) {
return 1.5f;
} else if (packetEntity instanceof PacketEntityGuardian packetEntityGuardian) { // TODO: 2.35 * guardian?
return packetEntityGuardian.isElder ? 1.9975f : 0.85f;
} else if (type == EntityTypes.ENDERMAN || type == EntityTypes.WARDEN) {
} else if (EntityTypes.ENDERMAN.equals(type) || EntityTypes.WARDEN.equals(type)) {
return 2.9f;
} else if (type == EntityTypes.ENDERMITE || type == EntityTypes.COD) {
} else if (EntityTypes.ENDERMITE.equals(type) || EntityTypes.COD.equals(type)) {
return 0.3f;
} else if (type == EntityTypes.END_CRYSTAL) {
} else if (EntityTypes.END_CRYSTAL.equals(type)) {
return 2f;
} else if (type == EntityTypes.ENDER_DRAGON) {
} else if (EntityTypes.ENDER_DRAGON.equals(type)) {
return 8f;
} else if (type == EntityTypes.FIREBALL) {
} else if (EntityTypes.FIREBALL.equals(type)) {
return 1f;
} else if (type == EntityTypes.FOX) {
} else if (EntityTypes.FOX.equals(type)) {
return 0.7f;
} else if (type == EntityTypes.GHAST) {
} else if (EntityTypes.GHAST.equals(type)) {
return 4f;
} else if (type == EntityTypes.GIANT) {
} else if (EntityTypes.GIANT.equals(type)) {
return 12f;
} else if (type == EntityTypes.GUARDIAN) {
} else if (EntityTypes.GUARDIAN.equals(type)) {
return 0.85f;
} else if (type == EntityTypes.HORSE) {
} else if (EntityTypes.HORSE.equals(type)) {
return 1.6f;
} else if (type == EntityTypes.IRON_GOLEM) {
} else if (EntityTypes.IRON_GOLEM.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 2.7f : 2.9f;
} else if (type == EntityTypes.CREAKING) {
} else if (EntityTypes.CREAKING.equals(type)) {
return 2.7f;
} else if (type == EntityTypes.LLAMA || type == EntityTypes.TRADER_LLAMA) {
} else if (EntityTypes.LLAMA.equals(type) || EntityTypes.TRADER_LLAMA.equals(type)) {
return 1.87f;
} else if (type == EntityTypes.TROPICAL_FISH) {
} else if (EntityTypes.TROPICAL_FISH.equals(type)) {
return 0.4f;
} else if (type == EntityTypes.MAGMA_CUBE) {
} else if (EntityTypes.MAGMA_CUBE.equals(type)) {
if (packetEntity instanceof PacketEntitySizeable sizeable) {
float size = sizeable.size;
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20_5)
@@ -323,43 +323,43 @@ public final class BoundingBoxSize {
return 0.7f;
} else if (EntityTypes.isTypeInstanceOf(type, EntityTypes.MINECART_ABSTRACT)) {
return 0.7f;
} else if (type == EntityTypes.MULE) {
} else if (EntityTypes.MULE.equals(type)) {
return 1.6f;
} else if (type == EntityTypes.MOOSHROOM) {
} else if (EntityTypes.MOOSHROOM.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 1.4f : 1.3f;
} else if (type == EntityTypes.OCELOT) {
} else if (EntityTypes.OCELOT.equals(type)) {
return 0.7f;
} else if (type == EntityTypes.PANDA) {
} else if (EntityTypes.PANDA.equals(type)) {
return 1.25f;
} else if (type == EntityTypes.PHANTOM) {
} else if (EntityTypes.PHANTOM.equals(type)) {
if (packetEntity instanceof PacketEntitySizeable sizeable) {
return 0.5f + sizeable.size * 0.1f;
}
return 1.8f;
} else if (type == EntityTypes.PLAYER || type == EntityTypes.MANNEQUIN) {
} else if (EntityTypes.PLAYER.equals(type)) {
return 1.8f;
} else if (type == EntityTypes.POLAR_BEAR) {
} else if (EntityTypes.POLAR_BEAR.equals(type)) {
return 1.4f;
} else if (type == EntityTypes.PUFFERFISH) {
} else if (EntityTypes.PUFFERFISH.equals(type)) {
return 0.7f;
} else if (type == EntityTypes.RABBIT) {
} else if (EntityTypes.RABBIT.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 0.5f : 0.7f;
} else if (type == EntityTypes.RAVAGER) {
} else if (EntityTypes.RAVAGER.equals(type)) {
return 2.2f;
} else if (type == EntityTypes.SALMON) {
} else if (EntityTypes.SALMON.equals(type)) {
return 0.4f;
} else if (type == EntityTypes.SHEEP || type == EntityTypes.GOAT) {
} else if (EntityTypes.SHEEP.equals(type) || EntityTypes.GOAT.equals(type)) {
return 1.3f;
} else if (type == EntityTypes.SHULKER) { // Could maybe guess peek size, although seems useless
} else if (EntityTypes.SHULKER.equals(type)) { // Could maybe guess peek size, although seems useless
return 2f;
} else if (type == EntityTypes.SILVERFISH) {
} else if (EntityTypes.SILVERFISH.equals(type)) {
return 0.3f;
} else if (type == EntityTypes.SKELETON) {
} else if (EntityTypes.SKELETON.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 1.99f : 1.95f;
} else if (type == EntityTypes.SKELETON_HORSE) {
} else if (EntityTypes.SKELETON_HORSE.equals(type)) {
return 1.6f;
} else if (type == EntityTypes.SLIME) {
} else if (EntityTypes.SLIME.equals(type)) {
if (packetEntity instanceof PacketEntitySizeable sizeable) {
float size = sizeable.size;
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20_5)
@@ -369,44 +369,42 @@ public final class BoundingBoxSize {
}
return 0.3125f;
} else if (type == EntityTypes.SMALL_FIREBALL) {
} else if (EntityTypes.SMALL_FIREBALL.equals(type)) {
return 0.3125f;
} else if (type == EntityTypes.SNOW_GOLEM) {
} else if (EntityTypes.SNOW_GOLEM.equals(type)) {
return 1.9f;
} else if (type == EntityTypes.STRAY) {
} else if (EntityTypes.STRAY.equals(type)) {
return 1.99f;
} else if (type == EntityTypes.TURTLE) {
} else if (EntityTypes.TURTLE.equals(type)) {
return 0.4f;
} else if (type == EntityTypes.WITHER) {
} else if (EntityTypes.WITHER.equals(type)) {
return 3.5f;
} else if (type == EntityTypes.WITHER_SKELETON) {
} else if (EntityTypes.WITHER_SKELETON.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 2.4f : 2.535f;
} else if (type == EntityTypes.WOLF) {
} else if (EntityTypes.WOLF.equals(type)) {
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? 0.85f : 0.8f;
} else if (type == EntityTypes.ZOMBIE_HORSE) {
} else if (EntityTypes.ZOMBIE_HORSE.equals(type)) {
return 1.6f;
} else if (type == EntityTypes.TADPOLE) {
} else if (EntityTypes.TADPOLE.equals(type)) {
return 0.3f;
} else if (type == EntityTypes.SNIFFER) {
} else if (EntityTypes.SNIFFER.equals(type)) {
return 1.75f;
} else if (type == EntityTypes.CAMEL) {
} else if (EntityTypes.CAMEL.equals(type)) {
return 2.375f;
} else if (type == EntityTypes.BREEZE) {
} else if (EntityTypes.BREEZE.equals(type)) {
return 1.77f;
} else if (type == EntityTypes.BOGGED) {
} else if (EntityTypes.BOGGED.equals(type)) {
return 1.99f;
} else if (type == EntityTypes.WIND_CHARGE) {
} else if (EntityTypes.WIND_CHARGE.equals(type)) {
return 0.3125f;
} else if (type == EntityTypes.ARMOR_STAND) {
} else if (EntityTypes.ARMOR_STAND.equals(type)) {
return 1.975F;
} else if (type == EntityTypes.FALLING_BLOCK) {
} else if (EntityTypes.FALLING_BLOCK.equals(type)) {
return 0.98F;
} else if (type == EntityTypes.VILLAGER && player.getClientVersion().isOlderThan(ClientVersion.V_1_9)) {
} else if (EntityTypes.VILLAGER.equals(type) && player.getClientVersion().isOlderThan(ClientVersion.V_1_9)) {
return 1.8F;
} else if (type == EntityTypes.FIREWORK_ROCKET) {
} else if (EntityTypes.FIREWORK_ROCKET.equals(type)) {
return 0.25F;
} else if (type == EntityTypes.COPPER_GOLEM) {
return 1.0F;
}
return 1.95f;
}
@@ -63,7 +63,7 @@ public class FluidTypeFlowing {
if ((state.getType() == StateTypes.WATER || state.getType() == StateTypes.LAVA) && state.getLevel() >= 8) {
for (BlockFace enumdirection : new BlockFace[]{BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST}) {
if (isSolidFace(player, originalX, originalY, originalZ, enumdirection) || isSolidFace(player, originalX, originalY + 1, originalZ, enumdirection)) {
vec3d = normalizeVectorWithoutNaN(vec3d).add(0.0D, -6.0D, 0.0D);
vec3d = normalizeVectorWithoutNaN(vec3d).add(new Vector3dm(0.0D, -6.0D, 0.0D));
break;
}
}
@@ -51,17 +51,7 @@ public class GetBoundingBox {
double minZ = centerZ - (width / 2f);
double maxZ = centerZ + (width / 2f);
// it's possible for width and/or height to be negative,
// correct the order of min and max
return new SimpleCollisionBox(
Math.min(minX, maxX),
Math.min(minY, maxY),
Math.min(minZ, maxZ),
Math.max(minX, maxX),
Math.max(minY, maxY),
Math.max(minZ, maxZ),
false
);
return new SimpleCollisionBox(minX, minY, minZ, maxX, maxY, maxZ, false);
}
public static double @NotNull [] getEntityDimensions(GrimPlayer player, @NotNull PacketEntity entity) {
@@ -77,20 +67,11 @@ public class GetBoundingBox {
double height = dimensions[1];
double halfDepth = dimensions[2] / 2.0;
double minX = box.minX - halfWidth;
double minY = box.minY; // No downward expansion
double minZ = box.minZ - halfDepth;
double maxX = box.maxX + halfWidth;
double maxY = box.maxY + height;
double maxZ = box.maxZ + halfDepth;
// it's possible for width and/or height to be negative,
// correct the order of min and max
box.minX = Math.min(minX, maxX);
box.minY = Math.min(minY, maxY);
box.minZ = Math.min(minZ, maxZ);
box.maxX = Math.max(minX, maxX);
box.maxY = Math.max(minY, maxY);
box.maxZ = Math.max(minZ, maxZ);
box.minX -= halfWidth;
box.minY -= 0; // No downward expansion
box.minZ -= halfDepth;
box.maxX += halfWidth;
box.maxY += height;
box.maxZ += halfDepth;
}
}
@@ -30,9 +30,9 @@ public class JumpPower {
if (player.isSprinting) {
float radRotation = GrimMath.radians(player.yaw);
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20_5)) {
vector.add(-player.trigHandler.sin(radRotation) * 0.2, 0.0, player.trigHandler.cos(radRotation) * 0.2);
vector.add(new Vector3dm(-player.trigHandler.sin(radRotation) * 0.2, 0.0, player.trigHandler.cos(radRotation) * 0.2));
} else {
vector.add(-player.trigHandler.sin(radRotation) * 0.2F, 0.0, player.trigHandler.cos(radRotation) * 0.2F);
vector.add(new Vector3dm(-player.trigHandler.sin(radRotation) * 0.2F, 0.0, player.trigHandler.cos(radRotation) * 0.2F));
}
}
}
@@ -179,8 +179,9 @@ public class ReachUtils {
if (giveMovementThresholdLenience) targetBox.expand(player.getMovementThreshold());
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (double eyes : possibleEyeHeights) {
Vector3dm closestPoint = VectorUtils.cutBoxToVector(player.x, player.y + eyes, player.z, targetBox);
lowest = Math.min(lowest, closestPoint.distance(player.x, player.y + eyes, player.z));
Vector3dm from = new Vector3dm(player.x, player.y + eyes, player.z);
Vector3dm closestPoint = VectorUtils.cutBoxToVector(from, targetBox);
lowest = Math.min(lowest, closestPoint.distance(from));
}
return lowest;
@@ -1,27 +0,0 @@
package ac.grim.grimac.utils.payload;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus.NonExtendable;
import org.jetbrains.annotations.ApiStatus.OverrideOnly;
import org.jetbrains.annotations.NotNull;
import static com.github.retrooper.packetevents.netty.buffer.UnpooledByteBufAllocationHelper.buffer;
import static com.github.retrooper.packetevents.netty.buffer.UnpooledByteBufAllocationHelper.wrappedBuffer;
import static com.github.retrooper.packetevents.wrapper.PacketWrapper.createUniversalPacketWrapper;
public interface Payload {
@NonExtendable
default byte[] write() {
Object buffer = buffer();
write(createUniversalPacketWrapper(buffer));
return ByteBufHelper.array(buffer);
}
@OverrideOnly
void write(PacketWrapper<?> wrapper);
static @NotNull PacketWrapper<?> wrapper(byte[] data) {
return createUniversalPacketWrapper(wrappedBuffer(data));
}
}
@@ -1,20 +1,13 @@
package ac.grim.grimac.utils.payload;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEditBook;
import org.jetbrains.annotations.NotNull;
/**
* Payload wrapper for serverbound {@code MC|BEdit} and {@code MC|BSign}, replaced by the {@link WrapperPlayClientEditBook EDIT_BOOK} packet in 1.13
* Payload wrapper for {@code MC|BEdit} and {@code MC|BSign}
*/
public record PayloadBookEdit(@NotNull ItemStack itemStack) implements Payload {
public PayloadBookEdit(byte[] data) {
this(Payload.wrapper(data).readItemStack());
}
@Override
public void write(PacketWrapper<?> wrapper) {
wrapper.writeItemStack(itemStack);
}
public record PayloadBookEdit(ItemStack itemStack) {
public static final PayloadCodec<PayloadBookEdit> CODEC = new PayloadCodec<>(
wrapper -> new PayloadBookEdit(wrapper.readItemStack()),
(wrapper, payload) -> wrapper.writeItemStack(payload.itemStack)
);
}
@@ -0,0 +1,39 @@
package ac.grim.grimac.utils.payload;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer;
import java.util.function.Function;
import static com.github.retrooper.packetevents.netty.buffer.UnpooledByteBufAllocationHelper.buffer;
import static com.github.retrooper.packetevents.netty.buffer.UnpooledByteBufAllocationHelper.copiedBuffer;
import static com.github.retrooper.packetevents.wrapper.PacketWrapper.createUniversalPacketWrapper;
public final class PayloadCodec<P> {
private final Function<PacketWrapper<?>, P> reader;
private final BiConsumer<PacketWrapper<?>, P> writer;
@Contract(pure = true)
public PayloadCodec(Function<PacketWrapper<?>, P> reader, BiConsumer<PacketWrapper<?>, P> writer) {
this.reader = reader;
this.writer = writer;
}
public P read(byte[] data) {
Object buffer = copiedBuffer(data);
P payload = reader.apply(createUniversalPacketWrapper(buffer));
ByteBufHelper.release(buffer);
return payload;
}
public byte @NotNull [] write(P payload) {
Object buffer = buffer();
writer.accept(createUniversalPacketWrapper(buffer), payload);
byte[] bytes = ByteBufHelper.array(buffer);
ByteBufHelper.release(buffer);
return bytes;
}
}
@@ -1,19 +1,10 @@
package ac.grim.grimac.utils.payload;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientNameItem;
import org.jetbrains.annotations.NotNull;
/**
* Payload wrapper for serverbound {@code MC|ItemName}, replaced by the {@link WrapperPlayClientNameItem NAME_ITEM} packet in 1.13
*/
public record PayloadItemName(@NotNull String itemName) implements Payload {
public PayloadItemName(byte[] data) {
this(Payload.wrapper(data).readString());
}
@Override
public void write(PacketWrapper<?> wrapper) {
wrapper.writeString(itemName);
}
public record PayloadItemName(@NotNull String itemName) {
public static final PayloadCodec<PayloadItemName> CODEC = new PayloadCodec<>(
wrapper -> new PayloadItemName(wrapper.readString()),
(wrapper, payload) -> wrapper.writeString(payload.itemName)
);
}
@@ -1,7 +1,6 @@
package ac.grim.grimac.utils.viaversion;
package ac.grim.grimac.utils.reflection;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.reflection.ReflectionUtils;
import lombok.experimental.UtilityClass;
@UtilityClass
@@ -13,8 +12,4 @@ public class ViaVersionUtil {
LogUtil.error("Using unsupported ViaVersion 4.0 API, update ViaVersion to 5.0");
}
}
public static void injectHooks() {
if (isAvailable) ViaVersionHooks.load();
}
}
@@ -1,34 +1,19 @@
package ac.grim.grimac.utils.viaversion;
package ac.grim.grimac.utils.via;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.chat.ChatB;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_10to1_11.Protocol1_10To1_11;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import lombok.experimental.UtilityClass;
import java.util.UUID;
@UtilityClass
class ViaVersionHooks {
// this method's only purpose is getting <clinit> called
static void load() {}
static {
inject1_11ChatHook();
}
private static void inject1_11ChatHook() {
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_11)) {
return; // not needed
}
final Protocol1_10To1_11 protocol = Via.getManager().getProtocolManager().getProtocol(Protocol1_10To1_11.class);
public class ViaHooks {
public static void injectVia() {
final var protocol = Via.getManager().getProtocolManager().getProtocol(Protocol1_10To1_11.class);
if (protocol == null) {
LogUtil.warn("Failed to inject ViaVersion message hook for 1.11+ clients: Protocol1_10To1_11 isn't registered!");
return;
+2 -2
View File
@@ -218,9 +218,9 @@ history:
# Welcher Servername soll für den History‑Befehl eingetragen werden? Nützlich, wenn dieselbe Datenbank für mehrere Server verwendet wird
server-name: Prison
database:
# SQLITE für lokale Speicherung, MYSQL oder POSTGRESQL für eine externe Datenbank. Wird nur nach Serverneustart aktualisiert
# SQLITE für lokale Speicherung, MYSQL für eine externe MySQL‑Datenbank. Wird nur nach Serverneustart aktualisiert
type: SQLITE
# Datenbank verbindungsdetails
# MySQL‑Verbindungsdetails
host: localhost
port: 3306
database: grim
+2 -2
View File
@@ -218,9 +218,9 @@ history:
# What should the inserted server name be for the history command? This is useful if you use the same database for multiple servers
server-name: Prison
database:
# Use SQLITE for local storage, use MYSQL or POSTGRESQL if you have an external database. This is only updated on server restart
# Use SQLITE for local storage, use MYSQL if you have an external MySQL database. This is only updated on server restart
type: SQLITE
# database connection details
# MySQL connection details
host: localhost
port: 3306
database: grim
+2 -2
View File
@@ -220,9 +220,9 @@ history:
# ¿Qué nombre de servidor debe insertarse para el comando history? Útil si compartes la misma base de datos entre varios servidores
server-name: Prison
database:
# Use SQLITE para almacenamiento local, use MYSQL o POSTGRESQL si tiene una base de datos externa. Esto solo se actualiza al reiniciar el servidor
# Usa SQLITE para almacenamiento local o MYSQL si tienes una base de datos MySQL externa. Solo se actualiza al reiniciar el servidor
type: SQLITE
# Detalles de conexión de la base de datos
# Detalles de conexión MySQL
host: localhost
port: 3306
database: grim
+2 -2
View File
@@ -215,9 +215,9 @@ history:
# Quel nom de serveur doit être inséré pour la commande history ? Utile si vous utilisez la même base de données pour plusieurs serveurs
server-name: Prison
database:
# Utilisez SQLITE pour le stockage local, utilisez MYSQL ou POSTGRESQL si vous avez une base de données externe. Ceci n'est mis à jour qu'au redémarrage du serveur
# Utilisez SQLITE pour un stockage local, MYSQL si vous disposez d’une base MySQL externe. Mis à jour seulement au redémarrage du serveur
type: SQLITE
# Détails de connexion à la base de données
# Détails de connexion MySQL
host: localhost
port: 3306
database: grim
+2 -2
View File
@@ -196,9 +196,9 @@ history:
# Quale nome server deve essere inserito per il comando history? Utile se usi lo stesso database per più server
server-name: Prison
database:
# Usa SQLITE per l'archiviazione locale, usa MYSQL o POSTGRESQL se hai un database esterno. Questo viene aggiornato solo al riavvio del server
# Usa SQLITE per l’archiviazione locale, MYSQL se hai un database MySQL esterno. Aggiornato solo al riavvio del server
type: SQLITE
# Dettagli di connessione al database
# Dettagli di connessione MySQL
host: localhost
port: 3306
database: grim
+2 -2
View File
@@ -227,9 +227,9 @@ history:
# history コマンドで挿入されるサーバー名は? 複数サーバーで同じデータベースを使用する場合に便利
server-name: Prison
database:
# ローカルストレージにはSQLITEを使用し、外部データベースがある場合はMYSQLまたはPOSTGRESQLを使用してください。これはサーバー再起動時にのみ更新されます
# ローカル保存には SQLITE、外部 MySQL データベースには MYSQL を使用します。サーバー再起動時にのみ反映
type: SQLITE
# データベース接続の詳細
# MySQL 接続情報
host: localhost
port: 3306
database: grim
+2 -2
View File
@@ -218,9 +218,9 @@ history:
# Welke servernaam moet voor het history‑commando worden ingevoerd? Handig als je dezelfde database voor meerdere servers gebruikt
server-name: Prison
database:
# Gebruik SQLITE voor lokale opslag, gebruik MYSQL of POSTGRESQL als u een externe database heeft. Dit wordt alleen bijgewerkt bij het herstarten van de server
# Gebruik SQLITE voor lokale opslag, MYSQL voor een externe MySQL‑database. Alleen bijgewerkt na een serverherstart
type: SQLITE
# Databaseverbindingsgegevens
# MySQL‑verbindingsgegevens
host: localhost
port: 3306
database: grim
+2 -2
View File
@@ -223,9 +223,9 @@ history:
# Qual nome de servidor deve ser inserido no comando history? Útil se você usa o mesmo banco de dados para vários servidores
server-name: Prison
database:
# Use SQLITE para armazenamento local, use MYSQL ou POSTGRESQL se você tiver um banco de dados externo. Isso só é atualizado ao reiniciar o servidor
# Use SQLITE para armazenamento local ou MYSQL para um banco MySQL externo. Atualizado somente ao reiniciar o servidor
type: SQLITE
# Detalhes de conexão do banco de dados
# Detalhes de conexão MySQL
host: localhost
port: 3306
database: grim
Loaded 100 of 166 files, more files were not shown because too many files have changed in this diff. Show more