diff --git a/pom.xml b/pom.xml index 77465f5..4790645 100644 --- a/pom.xml +++ b/pom.xml @@ -2,13 +2,17 @@ 4.0.0 tc.oc.occ Cheaty - 1.2.0-SNAPSHOT + 1.2.1-SNAPSHOT Cheaty A minecraft to discord java plugin for anti-cheat logging + + jitpack.io + https://jitpack.io + pgm-repo-snapshots https://repo.pgm.fyi/snapshots @@ -60,6 +64,18 @@ 0.2-SNAPSHOT provided + + com.github.MWHunter + GrimAPI + 9f5aaef74b + provided + + + ac.grim.grimac + grimac + 2.3.62 + provided + diff --git a/src/main/java/tc/oc/occ/cheaty/Cheaty.java b/src/main/java/tc/oc/occ/cheaty/Cheaty.java index aa1ebd8..362e561 100644 --- a/src/main/java/tc/oc/occ/cheaty/Cheaty.java +++ b/src/main/java/tc/oc/occ/cheaty/Cheaty.java @@ -2,6 +2,8 @@ import co.aikar.commands.BukkitCommandManager; import org.bukkit.plugin.java.JavaPlugin; +import tc.oc.occ.cheaty.anticheat.GrimManager; +import tc.oc.occ.cheaty.anticheat.GrimUtil; import tc.oc.occ.cheaty.commands.AdminCommands; import tc.oc.occ.cheaty.commands.BotCommands; import tc.oc.occ.cheaty.commands.CheatNotifyCommand; @@ -10,6 +12,7 @@ public class Cheaty extends JavaPlugin { private DiscordBot bot; private BotConfig config; + private GrimManager grimManager; private BukkitCommandManager commands; @Override @@ -19,6 +22,7 @@ public void onEnable() { this.config = new BotConfig(getConfig()); this.bot = new DiscordBot(config, getLogger()); + this.grimManager = GrimUtil.createManager(); this.setupCommands(); this.registerListeners(); @@ -36,10 +40,14 @@ public void setupCommands() { commands.registerCommand(new BotCommands()); commands.registerCommand(new AdminCommands()); commands.registerCommand(new CheatNotifyCommand()); + + GrimUtil.createCommands(grimManager, commands); } private void registerListeners() { this.getServer().getPluginManager().registerEvents(new BotListener(bot), this); + + GrimUtil.registerListeners(grimManager, this); } public void reloadBotConfig() { diff --git a/src/main/java/tc/oc/occ/cheaty/anticheat/GrimManager.java b/src/main/java/tc/oc/occ/cheaty/anticheat/GrimManager.java new file mode 100644 index 0000000..f9d3b2a --- /dev/null +++ b/src/main/java/tc/oc/occ/cheaty/anticheat/GrimManager.java @@ -0,0 +1,60 @@ +package tc.oc.occ.cheaty.anticheat; + +import ac.grim.grimac.api.GrimAbstractAPI; +import ac.grim.grimac.api.GrimUser; +import ac.grim.grimac.player.GrimPlayer; +import javax.annotation.Nullable; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; + +public class GrimManager { + + private GrimAbstractAPI api; + + public GrimManager() { + GrimAbstractAPI api = null; + RegisteredServiceProvider provider = + Bukkit.getServicesManager().getRegistration(GrimAbstractAPI.class); + if (provider != null) api = provider.getProvider(); + if (api == null) return; + + this.api = api; + } + + public boolean setPlayerBypass(Player player, boolean shouldBypass) { + if (player == null) return false; + + // Grim can internally throw an NPE when getting a player that is being removed + // This occurs when a player disconnects + GrimUser grimUser; + try { + grimUser = api.getGrimUser(player); + } catch (NullPointerException ignored) { + return false; + } + + if (!(grimUser instanceof GrimPlayer)) return false; + + GrimPlayer grimPlayer = (GrimPlayer) grimUser; + grimPlayer.disableGrim = shouldBypass; + + return true; + } + + public boolean togglePlayerBypass(Player player) { + GrimPlayer grimPlayer = getGrimPlayer(player); + if (grimPlayer == null) return true; + + grimPlayer.disableGrim = !grimPlayer.disableGrim; + + return grimPlayer.disableGrim; + } + + public @Nullable GrimPlayer getGrimPlayer(Player player) { + GrimUser grimUser = api.getGrimUser(player); + if (!(grimUser instanceof GrimPlayer)) return null; + + return (GrimPlayer) grimUser; + } +} diff --git a/src/main/java/tc/oc/occ/cheaty/anticheat/GrimParticipationListener.java b/src/main/java/tc/oc/occ/cheaty/anticheat/GrimParticipationListener.java new file mode 100644 index 0000000..4f54152 --- /dev/null +++ b/src/main/java/tc/oc/occ/cheaty/anticheat/GrimParticipationListener.java @@ -0,0 +1,72 @@ +package tc.oc.occ.cheaty.anticheat; + +import ac.grim.grimac.player.GrimPlayer; +import java.util.function.BooleanSupplier; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; +import tc.oc.pgm.spawns.events.ParticipantDespawnEvent; +import tc.oc.pgm.spawns.events.ParticipantSpawnEvent; + +public class GrimParticipationListener implements Listener { + + private final Plugin plugin; + private final GrimManager grimManager; + + public GrimParticipationListener(Plugin plugin, GrimManager grimManager) { + this.plugin = plugin; + this.grimManager = grimManager; + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + new ResolverTask( + () -> { + if (!player.isOnline()) return true; + if (player.spigot().getCollidesWithEntities()) return true; + + GrimPlayer grimPlayer = grimManager.getGrimPlayer(player); + if (grimPlayer == null) return false; + + grimManager.setPlayerBypass(player, true); + return true; + }) + .runTaskTimer(plugin, 1L, 5L); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onParticipantSpawn(ParticipantSpawnEvent event) { + Player bukkitPlayer = event.getPlayer().getBukkit(); + if (bukkitPlayer == null) return; + + grimManager.setPlayerBypass(bukkitPlayer, false); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onParticipantDespawn(ParticipantDespawnEvent event) { + Player bukkitPlayer = event.getPlayer().getBukkit(); + if (bukkitPlayer == null) return; + + grimManager.setPlayerBypass(bukkitPlayer, true); + } + + public static class ResolverTask extends BukkitRunnable { + + private final BooleanSupplier task; + private int attempts = 0; + + public ResolverTask(BooleanSupplier task) { + this.task = task; + } + + @Override + public void run() { + if (task.getAsBoolean() || attempts++ >= 20) this.cancel(); + } + } +} diff --git a/src/main/java/tc/oc/occ/cheaty/anticheat/GrimUtil.java b/src/main/java/tc/oc/occ/cheaty/anticheat/GrimUtil.java new file mode 100644 index 0000000..5196362 --- /dev/null +++ b/src/main/java/tc/oc/occ/cheaty/anticheat/GrimUtil.java @@ -0,0 +1,32 @@ +package tc.oc.occ.cheaty.anticheat; + +import co.aikar.commands.BukkitCommandManager; +import tc.oc.occ.cheaty.Cheaty; +import tc.oc.occ.cheaty.commands.GrimCommands; + +public class GrimUtil { + + public static GrimManager createManager() { + try { + Class.forName("ac.grim.grimac.GrimAC"); + return new GrimManager(); + } catch (ClassNotFoundException ignored) { + return null; + } + } + + public static void createCommands(GrimManager grimManager, BukkitCommandManager commands) { + if (grimManager == null) return; + + commands.registerCommand(new GrimCommands(grimManager)); + } + + public static void registerListeners(GrimManager grimManager, Cheaty plugin) { + if (grimManager == null) return; + + plugin + .getServer() + .getPluginManager() + .registerEvents(new GrimParticipationListener(plugin, grimManager), plugin); + } +} diff --git a/src/main/java/tc/oc/occ/cheaty/commands/GrimCommands.java b/src/main/java/tc/oc/occ/cheaty/commands/GrimCommands.java new file mode 100644 index 0000000..0d25eba --- /dev/null +++ b/src/main/java/tc/oc/occ/cheaty/commands/GrimCommands.java @@ -0,0 +1,65 @@ +package tc.oc.occ.cheaty.commands; + +import ac.grim.grimac.player.GrimPlayer; +import co.aikar.commands.BaseCommand; +import co.aikar.commands.InvalidCommandArgument; +import co.aikar.commands.annotation.CommandAlias; +import co.aikar.commands.annotation.CommandPermission; +import co.aikar.commands.annotation.Dependency; +import co.aikar.commands.annotation.Description; +import co.aikar.commands.annotation.Optional; +import co.aikar.commands.annotation.Subcommand; +import co.aikar.commands.annotation.Syntax; +import co.aikar.commands.bukkit.contexts.OnlinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import tc.oc.occ.cheaty.Cheaty; +import tc.oc.occ.cheaty.anticheat.GrimManager; + +@CommandAlias("cheaty") +public class GrimCommands extends BaseCommand { + + private final GrimManager grimManager; + @Dependency private Cheaty plugin; + + public GrimCommands(GrimManager grimManager) { + this.grimManager = grimManager; + } + + @Subcommand("grim status") + @Description("Check the bypass status of player") + @Syntax("[player]") + @CommandPermission("cheaty.admin") + public void status(CommandSender sender, @Optional OnlinePlayer player) { + Player target = getTargetPlayer(sender, player); + + GrimPlayer grimPlayer = grimManager.getGrimPlayer(target); + if (grimPlayer == null) + throw new InvalidCommandArgument("Unable to resolve target as grim player"); + + boolean status = grimPlayer.disableGrim; + + sender.sendMessage( + target.getDisplayName() + " Status: " + ((status) ? "Except" : "Not Exempt")); + } + + @Subcommand("grim toggle") + @Description("Toggles bypass status of player") + @Syntax("[player]") + @CommandPermission("cheaty.admin") + public void toggle(CommandSender sender, @Optional OnlinePlayer player) { + Player target = getTargetPlayer(sender, player); + boolean toggleStatus = grimManager.togglePlayerBypass(target); + + sender.sendMessage( + target.getDisplayName() + " Status: " + ((toggleStatus) ? "Except" : "Not Exempt")); + } + + private Player getTargetPlayer(CommandSender sender, OnlinePlayer onlinePlayer) { + if (onlinePlayer != null) return onlinePlayer.getPlayer(); + + if (sender instanceof Player) return ((Player) sender).getPlayer(); + + throw new InvalidCommandArgument("Unable to resolve target player"); + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f666fa4..4502d39 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -3,4 +3,4 @@ main: tc.oc.occ.cheaty.Cheaty description: A minecraft to discord bot version: ${project.version} author: applenick -softdepend: [PGM, AutoKiller, Idly] +softdepend: [PGM, AutoKiller, Idly, GrimAC]