From ac28cc1c6c64c6a3bcd7af4ad4f0dece2d49a1c3 Mon Sep 17 00:00:00 2001 From: 2008Choco Date: Wed, 28 Feb 2024 22:23:00 -0500 Subject: [PATCH] GrimAC made an API break :( Forced to use reflection. Support all new Grim versions --- gradle/libs.versions.toml | 4 +- veinminer-bukkit/build.gradle.kts | 2 +- .../wtf/choco/veinminer/VeinMinerPlugin.java | 2 +- .../anticheat/AntiCheatHookGrim.java | 78 +++++++++++++++++-- 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 18c12711..ba681712 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ junit = "5.10.2" # (bukkit) anticheat-aac = "5.0.0" -anticheat-grim = "add576ba8b" # https://github.com/GrimAnticheat/GrimAPI/commit/add576ba8bba1f725cbc72671b6d373c922a2345 +# anticheat-grim = "9f5aaef74b" # https://github.com/GrimAnticheat/GrimAPI/commit/9f5aaef74bf94bb3df5924a9c3f48d1ba9e2576d (REMOVED BECAUSE GRIM UPDATED IT'S API FORCING USE OF REFLECTION) anticheat-matrix = "317d4635fd" # This repository is dead now, but we're going to keep using it because it exists on JitPack :) anticheat-nocheatplus = "3.16.1-SNAPSHOT" anticheat-spartan = "1.0" @@ -38,7 +38,7 @@ junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", vers # (bukkit) anticheat-aac = { module = "de.janmm14:aac-api", version.ref = "anticheat-aac" } -anticheat-grim = { module = "com.github.GrimAnticheat:GrimAPI", version.ref = "anticheat-grim" } +# anticheat-grim = { module = "com.github.GrimAnticheat:GrimAPI", version.ref = "anticheat-grim" } (REMOVED BECAUSE GRIM UPDATED IT'S API FORCING USE OF REFLECTION) anticheat-matrix = { module = "com.github.jiangdashao:matrix-api-repo", version.ref = "anticheat-matrix" } anticheat-nocheatplus = { module = "fr.neatmonster:nocheatplus", version.ref = "anticheat-nocheatplus" } anticheat-spartan = { module = "me.vagdedes:SpartanAPI", version.ref = "anticheat-spartan" } diff --git a/veinminer-bukkit/build.gradle.kts b/veinminer-bukkit/build.gradle.kts index d5323b71..a16c4c38 100644 --- a/veinminer-bukkit/build.gradle.kts +++ b/veinminer-bukkit/build.gradle.kts @@ -32,7 +32,7 @@ dependencies { // Anti-cheats compileOnly(libs.anticheat.aac) - compileOnly(libs.anticheat.grim) + // compileOnly(libs.anticheat.grim) // (REMOVED BECAUSE GRIM UPDATED IT'S API FORCING USE OF REFLECTION) compileOnly(libs.anticheat.matrix) compileOnly(libs.anticheat.nocheatplus) compileOnly(libs.anticheat.spartan) diff --git a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/VeinMinerPlugin.java b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/VeinMinerPlugin.java index 7652e08b..860dc8cf 100644 --- a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/VeinMinerPlugin.java +++ b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/VeinMinerPlugin.java @@ -159,7 +159,7 @@ public void onEnable() { PluginManager manager = Bukkit.getPluginManager(); this.registerAntiCheatHookIfEnabled(manager, "AAC5", AntiCheatHookAAC::new); this.registerAntiCheatHookIfEnabled(manager, "AntiAura", () -> new AntiCheatHookAntiAura(this)); - this.registerAntiCheatHookIfEnabled(manager, "GrimAC", AntiCheatHookGrim::new); + this.registerAntiCheatHookIfEnabled(manager, "GrimAC", () -> new AntiCheatHookGrim(this)); this.registerAntiCheatHookIfEnabled(manager, "LightAntiCheat", () -> new AntiCheatHookLightAntiCheat(this)); this.registerAntiCheatHookIfEnabled(manager, "Matrix", AntiCheatHookMatrix::new); this.registerAntiCheatHookIfEnabled(manager, "NoCheatPlus", () -> new AntiCheatHookNCP(this)); diff --git a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/anticheat/AntiCheatHookGrim.java b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/anticheat/AntiCheatHookGrim.java index eb16c577..1e8efb4b 100644 --- a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/anticheat/AntiCheatHookGrim.java +++ b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/anticheat/AntiCheatHookGrim.java @@ -1,24 +1,76 @@ package wtf.choco.veinminer.anticheat; +import java.lang.reflect.Method; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; -import ac.grim.grimac.events.FlagEvent; +import wtf.choco.veinminer.VeinMinerPlugin; /** * The default Grim AntiCheat hook implementation. */ -public final class AntiCheatHookGrim implements AntiCheatHook, Listener { +public final class AntiCheatHookGrim implements AntiCheatHook { + + /* + * Unfortunately, in Grim 2.3.59 they decided to move the package declaration to "api". This is fine, + * it's correct. It should have been under an API package to begin with. But this now fricks up the way + * I write VeinMiner's Grim hook and forces me to use reflection unless I want to modularize VeinMiner's + * Bukkit code JUST for different Grim implementations... which I really do not want to do :( + * + * TODO: Once usage of GrimAC exceeds 75%, use of reflection should be dropped in favour of Grim's API + * again, thus dropping support for 2.3.58 and below. + */ // FlagEvent is called asynchronously, so we need a ConcurrentHashMap to be certain private final Set exempt = ConcurrentHashMap.newKeySet(); + private Method methodFlagEventGetPlayer; + private Method methodGrimUserGetUniqueId; + + private boolean supported; + + public AntiCheatHookGrim(@NotNull VeinMinerPlugin plugin) { + try { + Class eventClass = findClass(Event.class, "ac.grim.grimac.events.FlagEvent", "ac.grim.grimac.api.events.FlagEvent"); + Class grimUserClass = findClass("ac.grim.grimac.GrimUser", "ac.grim.grimac.api.GrimUser"); + + this.methodFlagEventGetPlayer = eventClass.getMethod("getPlayer"); + this.methodGrimUserGetUniqueId = grimUserClass.getMethod("getUniqueId"); + this.supported = (methodFlagEventGetPlayer != null && methodGrimUserGetUniqueId != null); + + if (supported) { + Bukkit.getPluginManager().registerEvent(eventClass, new Listener() {}, EventPriority.NORMAL, (listener, event) -> handleFlagEvent((Cancellable) event), plugin); + } + } catch (ReflectiveOperationException e) { + plugin.getLogger().severe("The version of GrimAC on this server is incompatible with Veinminer. Please post information on the spigot resource discussion page."); + this.supported = false; + } + } + + private Class findClass(Class subclass, String... classNames) throws ClassNotFoundException { + for (String string : classNames) { + try { + Class clazz = Class.forName(string).asSubclass(subclass); + return clazz; + } catch (ReflectiveOperationException ignore) { } + } + + throw new ClassNotFoundException(); + } + + private Class findClass(String... classNames) throws ClassNotFoundException { + return findClass(Object.class, classNames); + } + @Override public void exempt(@NotNull Player player) { this.exempt.add(player.getUniqueId()); @@ -34,9 +86,23 @@ public boolean shouldUnexempt(@NotNull Player player) { return exempt.contains(player.getUniqueId()); } - @EventHandler(ignoreCancelled = true) - private void onFlag(FlagEvent event) { - if (!exempt.contains(event.getPlayer().getUniqueId())) { + @Override + public boolean isSupported() { + return supported; + } + + private void handleFlagEvent(Cancellable event) { + if (event.isCancelled()) { + return; + } + + try { + Object player = methodFlagEventGetPlayer.invoke(event); + UUID playerUUID = (UUID) methodGrimUserGetUniqueId.invoke(player); + if (!exempt.contains(playerUUID)) { + return; + } + } catch (ReflectiveOperationException e) { return; }