From 4b707b7e273ff3ce22d8be7c3483f3e18307f077 Mon Sep 17 00:00:00 2001 From: xGinko Date: Sun, 5 Jan 2025 10:42:34 +0100 Subject: [PATCH 01/18] make ignored entities configurable --- .../agelimits/ProjectileAgeLimit.java | 60 ++++++++++++------ .../agelimits/ProjectileAgeLimit.java | 63 ++++++++++++------- .../kotlin/me.xginko.aef.wrapper.gradle.kts | 2 +- 3 files changed, 84 insertions(+), 41 deletions(-) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java index 02ce86ef..3de1142c 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java @@ -1,5 +1,6 @@ package me.xginko.aef.modules.lagpreventions.agelimits; +import com.cryptomorin.xseries.XEntityType; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.ChunkUtil; @@ -7,16 +8,24 @@ import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkLoadEvent; +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ProjectileAgeLimit extends AEFModule implements Consumer, Listener { + private final Set ignoredTypes; private final long check_period_in_ticks; private final int max_alive_time; @@ -33,6 +42,27 @@ public ProjectileAgeLimit() { "(20 ticks = 1 second) Will not touch Ender Pearls"); this.check_period_in_ticks = config.getInt(configPath + ".check-period-seconds", 20, "How frequently we should check all projectiles for their alive time") * 20L; + List defaults = Stream.of( + XEntityType.FISHING_BOBBER, + XEntityType.ENDER_PEARL, + XEntityType.WITHER_SKULL, + XEntityType.EYE_OF_ENDER) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList()); + this.ignoredTypes = config.getList(configPath + ".ignored-types", defaults) + .stream() + .map(configuredType -> { + try { + return EntityType.valueOf(configuredType); + } catch (IllegalArgumentException e) { + notRecognized(EntityType.class, configuredType); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityType.class))); } @Override @@ -60,15 +90,12 @@ public void accept(ScheduledTask task) { plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { for (Entity entity : chunk.getEntities()) { entity.getScheduler().execute(plugin, () -> { - if (EntityUtil.isProjectile(entity)) { - switch (entity.getType()) { - case ENDER_PEARL, WITHER_SKULL, FISHING_HOOK, ENDER_SIGNAL -> { - return; - } - } - if (entity.getTicksLived() > max_alive_time) { - entity.remove(); - } + if (ignoredTypes.contains(entity.getType())) { + return; + } + + if (EntityUtil.isProjectile(entity) && entity.getTicksLived() > max_alive_time) { + entity.remove(); } }, null, 1L); } @@ -84,15 +111,12 @@ private void onChunkLoad(ChunkLoadEvent event) { for (Entity entity : event.getChunk().getEntities()) { entity.getScheduler().execute(plugin, () -> { - if (EntityUtil.isProjectile(entity)) { - switch (entity.getType()) { - case ENDER_PEARL, WITHER_SKULL, FISHING_HOOK, ENDER_SIGNAL -> { - return; - } - } - if (entity.getTicksLived() > max_alive_time) { - entity.remove(); - } + if (ignoredTypes.contains(entity.getType())) { + return; + } + + if (EntityUtil.isProjectile(entity) && entity.getTicksLived() > max_alive_time) { + entity.remove(); } }, null, 1L); } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java index 065b6fad..08e39e05 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/lagpreventions/agelimits/ProjectileAgeLimit.java @@ -1,9 +1,11 @@ package me.xginko.aef.modules.lagpreventions.agelimits; +import com.cryptomorin.xseries.XEntityType; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.EntityUtil; import org.bukkit.World; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; @@ -11,8 +13,16 @@ import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.scheduler.BukkitTask; +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + public class ProjectileAgeLimit extends AEFModule implements Runnable, Listener { + private final Set ignoredTypes; private final long checkPeriod; private final int max_alive_time; @@ -29,6 +39,27 @@ public ProjectileAgeLimit() { "(20 ticks = 1 second) Will not touch Ender Pearls"); this.checkPeriod = config.getInt(configPath + ".check-period-seconds", 20, "How frequently we should check all projectiles for their alive time") * 20L; + List defaults = Stream.of( + XEntityType.FISHING_BOBBER, + XEntityType.ENDER_PEARL, + XEntityType.WITHER_SKULL, + XEntityType.EYE_OF_ENDER) + .filter(XEntityType::isSupported) + .map(XEntityType::get) + .map(Enum::name) + .collect(Collectors.toList()); + this.ignoredTypes = config.getList(configPath + ".ignored-types", defaults) + .stream() + .map(configuredType -> { + try { + return EntityType.valueOf(configuredType); + } catch (IllegalArgumentException e) { + notRecognized(EntityType.class, configuredType); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityType.class))); } @Override @@ -50,18 +81,12 @@ public void disable() { public void run() { for (World world : plugin.getServer().getWorlds()) { for (Entity entity : world.getEntities()) { - if (EntityUtil.isProjectile(entity)) { - switch (entity.getType()) { - case ENDER_PEARL: - case WITHER_SKULL: - case FISHING_HOOK: - case ENDER_SIGNAL: - continue; - } + if (ignoredTypes.contains(entity.getType())) { + continue; + } - if (entity.getTicksLived() > max_alive_time) { - entity.remove(); - } + if (EntityUtil.isProjectile(entity) && entity.getTicksLived() > max_alive_time) { + entity.remove(); } } } @@ -72,18 +97,12 @@ private void onChunkLoad(ChunkLoadEvent event) { if (event.isNewChunk()) return; for (Entity entity : event.getChunk().getEntities()) { - if (EntityUtil.isProjectile(entity)) { - switch (entity.getType()) { - case ENDER_PEARL: - case WITHER_SKULL: - case FISHING_HOOK: - case ENDER_SIGNAL: - continue; - } + if (ignoredTypes.contains(entity.getType())) { + continue; + } - if (entity.getTicksLived() > max_alive_time) { - entity.remove(); - } + if (EntityUtil.isProjectile(entity) && entity.getTicksLived() > max_alive_time) { + entity.remove(); } } } diff --git a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts index 7455a4aa..41f5266f 100755 --- a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts +++ b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.xginko" -version = "2.7.4" +version = "2.7.5-SNAPSHOT" description = "Prevent many exploits that affect anarchy servers." var url: String? = "github.com/xGinko/AnarchyExploitFixes" From 035c0a44de7be8463a92b3667007481ba3aff8e1 Mon Sep 17 00:00:00 2001 From: xGinko Date: Sun, 5 Jan 2025 19:47:36 +0100 Subject: [PATCH 02/18] make commands live reloadable --- .../me/xginko/aef/AnarchyExploitFixes.java | 5 +- .../me/xginko/aef/commands/AEFCommand.java | 100 +++++- .../java/me/xginko/aef/commands/HelpCmd.java | 10 +- .../java/me/xginko/aef/commands/SayCmd.java | 12 +- .../aef/commands/ToggleConnectionMsgsCmd.java | 10 +- .../me/xginko/aef/commands/aef/AEFCmd.java | 16 +- .../me/xginko/aef/AnarchyExploitFixes.java | 7 +- .../me/xginko/aef/commands/AEFCommand.java | 102 +++++- .../java/me/xginko/aef/commands/HelpCmd.java | 9 +- .../java/me/xginko/aef/commands/SayCmd.java | 11 +- .../aef/commands/ToggleConnectionMsgsCmd.java | 9 +- .../me/xginko/aef/commands/aef/AEFCmd.java | 15 +- .../kotlin/me.xginko.aef.wrapper.gradle.kts | 6 + .../aef/commands/BukkitCommandWrap.java | 321 ++++++++++++++++++ 14 files changed, 519 insertions(+), 114 deletions(-) create mode 100644 shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index 24668dea..3e810cf3 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -131,9 +131,6 @@ public void onEnable() { prefixedLogger.info("Loading Translations"); reloadLang(); - prefixedLogger.info("Registering Commands"); - AEFCommand.registerCommands(); - prefixedLogger.info("Loading NBT-API"); // Hide all messages with a log level lower than WARNING because of the same reason as Reflections logging. Logger.getLogger("NBTAPI").setLevel(java.util.logging.Level.WARNING); @@ -150,6 +147,7 @@ public void onDisable() { AEFPermission.unregisterAll(); if (isPacketEventsInstalled) { AEFModule.disableAll(); + AEFCommand.disableAll(); } if (languageCacheMap != null) { languageCacheMap.clear(); @@ -221,6 +219,7 @@ private void reloadConfiguration() { if (tickReporter != null) tickReporter.disable(); tickReporter = TickReporter.create(this, config.tickData_cache_duration); AEFModule.reloadModules(); + AEFCommand.reloadCommands(); config.saveConfig(); } catch (Throwable t) { prefixedLogger.error("Failed while loading config!", t); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/AEFCommand.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/AEFCommand.java index d7ca97d4..842f6076 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/AEFCommand.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/AEFCommand.java @@ -1,24 +1,100 @@ package me.xginko.aef.commands; -import me.xginko.aef.commands.aef.AEFCmd; +import com.google.common.collect.ImmutableSet; +import me.xginko.aef.AnarchyExploitFixes; +import me.xginko.aef.utils.models.ConditionalEnableable; +import me.xginko.aef.utils.models.Disableable; import me.xginko.aef.utils.models.Enableable; +import org.bukkit.command.Command; +import org.bukkit.command.PluginIdentifiableCommand; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; -public interface AEFCommand extends Enableable { +public abstract class AEFCommand extends Command implements PluginIdentifiableCommand, ConditionalEnableable, Disableable { - boolean shouldEnable(); + protected static final Set> AVAILABLE_COMMANDS; + protected static final Set ENABLED_COMMANDS; - static void registerCommands() { - for (AEFCommand command : Set.of( - new AEFCmd(), - new ToggleConnectionMsgsCmd(), - new SayCmd(), - new HelpCmd() - )) { - if (command.shouldEnable()) { - command.enable(); + static { + AVAILABLE_COMMANDS = new Reflections(AEFCommand.class.getPackage().getName()) + .get(Scanners.SubTypes.of(AEFCommand.class).asClass()) + .stream() + .filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) + .map(clazz -> (Class) clazz) + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableSet::copyOf)); + ENABLED_COMMANDS = new HashSet<>(AVAILABLE_COMMANDS.size()); + } + + private final AnarchyExploitFixes plugin; + + protected AEFCommand(@NotNull String name, @NotNull String description, @NotNull String usageMessage, @NotNull List aliases) { + super(name, description, usageMessage, aliases); + this.plugin = AnarchyExploitFixes.getInstance(); + } + + @Override + public @NotNull Plugin getPlugin() { + return plugin; + } + + @Override + public boolean shouldEnable() { + return true; + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public void enable() { + plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this); + } + + @Override + public void disable() { + Map knownCommands = new ConcurrentHashMap<>(plugin.getServer().getCommandMap().getKnownCommands()); + for (Map.Entry entry : knownCommands.entrySet()) { + if (entry.getValue() == this) { + entry.getValue().unregister(plugin.getServer().getCommandMap()); + BukkitCommandWrap.getInstance().unwrap(entry.getKey()); + knownCommands.remove(entry.getKey()); } } + BukkitCommandWrap.getInstance().setKnownCommands(knownCommands); + BukkitCommandWrap.getInstance().sync(); + } + + public static void disableAll() { + ENABLED_COMMANDS.forEach(Disableable::disable); + ENABLED_COMMANDS.clear(); + } + + public static void reloadCommands() { + disableAll(); + + for (Class cmdClass : AVAILABLE_COMMANDS) { + try { + AEFCommand aefCommand = cmdClass.getDeclaredConstructor().newInstance(); + if (aefCommand.shouldEnable()) { + ENABLED_COMMANDS.add(aefCommand); + } + } catch (Throwable t) { + if (t.getCause() instanceof NoClassDefFoundError) { + AnarchyExploitFixes.prefixedLogger().info("Dependencies for command class {} missing, not enabling.", cmdClass.getSimpleName()); + } else { + AnarchyExploitFixes.prefixedLogger().warn("Failed initialising command class '{}'.", cmdClass.getSimpleName(), t); + } + } + } + + ENABLED_COMMANDS.forEach(Enableable::enable); } } \ No newline at end of file diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java index 12920da9..80451944 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java @@ -2,7 +2,6 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.utils.permissions.AEFPermission; -import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -10,7 +9,7 @@ import java.util.Collections; import java.util.List; -public class HelpCmd extends Command implements AEFCommand { +public class HelpCmd extends AEFCommand { public HelpCmd() { super("help", "Command help overview", "/help", Collections.emptyList()); @@ -21,13 +20,6 @@ public boolean shouldEnable() { return AnarchyExploitFixes.config().cmd_help_enabled; } - @Override - @SuppressWarnings("UnstableApiUsage") - public void enable() { - AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this); - } - @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java index 41017fa0..60d0b306 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java @@ -1,11 +1,10 @@ package me.xginko.aef.commands; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.CommandUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -13,7 +12,7 @@ import java.util.Collections; import java.util.List; -public class SayCmd extends Command implements AEFCommand { +public class SayCmd extends AEFCommand { public SayCmd() { super("say", "Custom say command", "/say", Collections.emptyList()); @@ -24,13 +23,6 @@ public boolean shouldEnable() { return AnarchyExploitFixes.config().cmd_say_enabled; } - @Override - @SuppressWarnings("UnstableApiUsage") - public void enable() { - AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this); - } - @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java index dda8ef89..660ae3f5 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java @@ -5,7 +5,6 @@ import me.xginko.aef.utils.permissions.AEFPermission; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -16,7 +15,7 @@ import java.util.Collections; import java.util.List; -public class ToggleConnectionMsgsCmd extends Command implements AEFCommand { +public class ToggleConnectionMsgsCmd extends AEFCommand { public ToggleConnectionMsgsCmd() { super("toggleconnectionmsgs", "Toggle connection messages", "/toggleconnectionmsgs", Collections.singletonList("tcmsgs")); @@ -27,13 +26,6 @@ public boolean shouldEnable() { return AnarchyExploitFixes.config().cmd_toggleConMsgs_enabled; } - @Override - @SuppressWarnings("UnstableApiUsage") - public void enable() { - AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this); - } - @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java index 70325fa0..e8e79dd2 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java @@ -2,7 +2,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.AEFCommand; import me.xginko.aef.commands.SubCommand; import me.xginko.aef.commands.aef.subcommands.DisableSubCmd; @@ -13,7 +12,6 @@ import me.xginko.aef.commands.aef.subcommands.VersionSubCmd; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -25,7 +23,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class AEFCmd extends Command implements AEFCommand { +public class AEFCmd extends AEFCommand { private final @NotNull Set subCommands; private final @NotNull List tabCompletes; @@ -64,18 +62,6 @@ public AEFCmd() { .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf)); } - @Override - public boolean shouldEnable() { - return true; - } - - @Override - @SuppressWarnings("UnstableApiUsage") - public void enable() { - AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this); - } - @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index df604445..4a226c7d 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -8,9 +8,9 @@ import me.xginko.aef.config.Datastore; import me.xginko.aef.config.LanguageCache; import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.PlatformUtil; import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.permissions.PermissionHandler; -import me.xginko.aef.utils.PlatformUtil; import me.xginko.aef.utils.tickdata.TickReporter; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; @@ -141,9 +141,6 @@ public void onEnable() { prefixedLogger.info("Loading Translations"); reloadLang(); - prefixedLogger.info("Registering Commands"); - AEFCommand.registerCommands(); - prefixedLogger.info("Loading NBT-API"); // Hide all messages with a log level lower than WARNING because of the same reason as Reflections logging. java.util.logging.Logger.getLogger("NBTAPI").setLevel(java.util.logging.Level.WARNING); @@ -160,6 +157,7 @@ public void onDisable() { AEFPermission.unregisterAll(); if (isPacketEventsInstalled) { AEFModule.disableAll(); + AEFCommand.disableAll(); } if (languageCacheMap != null) { languageCacheMap.clear(); @@ -239,6 +237,7 @@ private void reloadConfiguration() { if (tickReporter != null) tickReporter.disable(); tickReporter = TickReporter.create(this, config.tps_cache_duration); AEFModule.reloadModules(); + AEFCommand.reloadCommands(); config.saveConfig(); } catch (Throwable t) { prefixedLogger.error("Failed while loading config!", t); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/AEFCommand.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/AEFCommand.java index 1a2e5c68..aed2d35d 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/AEFCommand.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/AEFCommand.java @@ -1,23 +1,99 @@ package me.xginko.aef.commands; -import com.google.common.collect.Sets; -import me.xginko.aef.commands.aef.AEFCmd; +import com.google.common.collect.ImmutableSet; +import me.xginko.aef.AnarchyExploitFixes; +import me.xginko.aef.utils.models.ConditionalEnableable; +import me.xginko.aef.utils.models.Disableable; import me.xginko.aef.utils.models.Enableable; +import org.bukkit.command.Command; +import org.bukkit.command.PluginIdentifiableCommand; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; -public interface AEFCommand extends Enableable { +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; - boolean shouldEnable(); +public abstract class AEFCommand extends Command implements PluginIdentifiableCommand, ConditionalEnableable, Disableable { - static void registerCommands() { - for (AEFCommand command : Sets.newHashSet( - new AEFCmd(), - new ToggleConnectionMsgsCmd(), - new SayCmd(), - new HelpCmd() - )) { - if (command.shouldEnable()) { - command.enable(); + protected static final Set> AVAILABLE_COMMANDS; + protected static final Set ENABLED_COMMANDS; + + static { + AVAILABLE_COMMANDS = new Reflections(AEFCommand.class.getPackage().getName()) + .get(Scanners.SubTypes.of(AEFCommand.class).asClass()) + .stream() + .filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) + .map(clazz -> (Class) clazz) + .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableSet::copyOf)); + ENABLED_COMMANDS = new HashSet<>(AVAILABLE_COMMANDS.size()); + } + + private final AnarchyExploitFixes plugin; + + protected AEFCommand(@NotNull String name, @NotNull String description, @NotNull String usageMessage, @NotNull List aliases) { + super(name, description, usageMessage, aliases); + this.plugin = AnarchyExploitFixes.getInstance(); + } + + @Override + public @NotNull Plugin getPlugin() { + return plugin; + } + + @Override + public boolean shouldEnable() { + return true; + } + + @Override + public void enable() { + plugin.getServer().getCommandMap().register(plugin.getDescription().getName().toLowerCase(), this); + } + + @Override + public void disable() { + Map knownCommands = new ConcurrentHashMap<>(plugin.getServer().getCommandMap().getKnownCommands()); + for (Map.Entry entry : knownCommands.entrySet()) { + if (entry.getValue() == this) { + entry.getValue().unregister(plugin.getServer().getCommandMap()); + BukkitCommandWrap.getInstance().unwrap(entry.getKey()); + knownCommands.remove(entry.getKey()); + } + } + BukkitCommandWrap.getInstance().setKnownCommands(knownCommands); + BukkitCommandWrap.getInstance().sync(); + } + + public static void disableAll() { + ENABLED_COMMANDS.forEach(Disableable::disable); + ENABLED_COMMANDS.clear(); + } + + public static void reloadCommands() { + disableAll(); + + for (Class cmdClass : AVAILABLE_COMMANDS) { + try { + AEFCommand aefCommand = cmdClass.getDeclaredConstructor().newInstance(); + if (aefCommand.shouldEnable()) { + ENABLED_COMMANDS.add(aefCommand); + } + } catch (Throwable t) { + if (t.getCause() instanceof NoClassDefFoundError) { + AnarchyExploitFixes.prefixedLogger().info("Dependencies for command class {} missing, not enabling.", cmdClass.getSimpleName()); + } else { + AnarchyExploitFixes.prefixedLogger().warn("Failed initialising command class '{}'.", cmdClass.getSimpleName(), t); + } } } + + ENABLED_COMMANDS.forEach(Enableable::enable); } } \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/HelpCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/HelpCmd.java index 6635414f..01267c85 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/HelpCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/HelpCmd.java @@ -2,7 +2,6 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.utils.permissions.AEFPermission; -import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -10,7 +9,7 @@ import java.util.Collections; import java.util.List; -public class HelpCmd extends Command implements AEFCommand { +public class HelpCmd extends AEFCommand { public HelpCmd() { super("help", "Command help overview", "/help", Collections.emptyList()); @@ -21,12 +20,6 @@ public boolean shouldEnable() { return AnarchyExploitFixes.config().cmd_help_enabled; } - @Override - public void enable() { - AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getCommandMap().register(plugin.getDescription().getName().toLowerCase(), this); - } - @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/SayCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/SayCmd.java index cc1493c0..e42bb9c4 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/SayCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/SayCmd.java @@ -1,10 +1,9 @@ package me.xginko.aef.commands; import me.xginko.aef.AnarchyExploitFixes; -import me.xginko.aef.utils.permissions.AEFPermission; import me.xginko.aef.utils.CommandUtil; +import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.ChatColor; -import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -12,7 +11,7 @@ import java.util.Collections; import java.util.List; -public class SayCmd extends Command implements AEFCommand { +public class SayCmd extends AEFCommand { public SayCmd() { super("say", "Custom say command", "/say", Collections.emptyList()); @@ -23,12 +22,6 @@ public boolean shouldEnable() { return AnarchyExploitFixes.config().cmd_say_enabled; } - @Override - public void enable() { - AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getCommandMap().register(plugin.getDescription().getName().toLowerCase(), this); - } - @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java index 91d399bd..90f72959 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java @@ -3,7 +3,6 @@ import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.utils.permissions.AEFPermission; import org.bukkit.ChatColor; -import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -12,7 +11,7 @@ import java.util.Collections; import java.util.List; -public class ToggleConnectionMsgsCmd extends Command implements AEFCommand { +public class ToggleConnectionMsgsCmd extends AEFCommand { public ToggleConnectionMsgsCmd() { super("toggleconnectionmsgs", "Toggle connection messages", @@ -24,12 +23,6 @@ public boolean shouldEnable() { return AnarchyExploitFixes.config().cmd_toggleConMsgs_enabled; } - @Override - public void enable() { - AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getCommandMap().register(plugin.getDescription().getName().toLowerCase(), this); - } - @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java index 05441e07..ad29f3c4 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java @@ -2,7 +2,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import me.xginko.aef.AnarchyExploitFixes; import me.xginko.aef.commands.AEFCommand; import me.xginko.aef.commands.SubCommand; import me.xginko.aef.commands.aef.subcommands.DisableSubCmd; @@ -11,7 +10,6 @@ import me.xginko.aef.commands.aef.subcommands.LagSubCmd; import me.xginko.aef.commands.aef.subcommands.ReloadSubCmd; import me.xginko.aef.commands.aef.subcommands.VersionSubCmd; -import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -23,7 +21,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class AEFCmd extends Command implements AEFCommand { +public class AEFCmd extends AEFCommand { private final Set subCommands; private final List tabCompletes, overview; @@ -61,17 +59,6 @@ public AEFCmd() { .collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf)); } - @Override - public boolean shouldEnable() { - return true; - } - - @Override - public void enable() { - AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance(); - plugin.getServer().getCommandMap().register(plugin.getDescription().getName().toLowerCase(), this); - } - @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws CommandException, IllegalArgumentException diff --git a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts index 41f5266f..60dbba5c 100755 --- a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts +++ b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts @@ -36,6 +36,11 @@ repositories { url = uri("https://repo.aikar.co/content/groups/aikar/") } + maven { + name = "mojang" + url = uri("https://libraries.minecraft.net") + } + maven { name = "jitpack.io" url = uri("https://jitpack.io") @@ -44,6 +49,7 @@ repositories { dependencies { compileOnly("com.github.retrooper:packetevents-spigot:2.7.0") // PacketEvents to patch packet based exploits + compileOnly("com.mojang:brigadier:1.0.18") api("com.github.cryptomorin:XSeries:13.0.0") // Crossversion entitytype and material support api("com.github.thatsmusic99:ConfigurationMaster-API:v2.0.0-rc.3") // ConfigurationMaster for enhanced config management api("de.tr7zw:item-nbt-api:2.14.1") // NBT API for cross version nbt tag handling diff --git a/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java b/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java new file mode 100644 index 00000000..d68a5355 --- /dev/null +++ b/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java @@ -0,0 +1,321 @@ +package me.xginko.aef.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.RootCommandNode; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; +/* +* Straight up yoinked from https://github.com/Test-Account666/PlugManX +* (Stinky reflections, but it does the job) +* */ +public final class BukkitCommandWrap { + private static BukkitCommandWrap instance; + + private final boolean nmsVersioning; + private String nmsVersion; + private Class minecraftServerClass; + private Method aMethod, getServerMethod, registerMethod, syncCommandsMethod, removeCommandMethod; + private Field bField, vanillaCommandDispatcherField, commandMapField, knownCommandsField; + private Constructor bukkitcommandWrapperConstructor; + + public BukkitCommandWrap() { + String prefix = getCraftBukkitPrefix(); + String[] packageParts = prefix.split("\\."); + String versionPart = packageParts[packageParts.length - 1]; + if (versionPart.startsWith("v1_")) { + this.nmsVersion = versionPart; + } + boolean nmsVers = true; + try { + Class.forName("net.minecraft.server.MinecraftServer"); + nmsVers = false; + } catch (ClassNotFoundException ignore) {} + this.nmsVersioning = nmsVers; + } + + public static BukkitCommandWrap getInstance() { + if (instance == null) { + instance = new BukkitCommandWrap(); + } + return instance; + } + + private static @NotNull String getCraftBukkitPrefix() { + return Bukkit.getServer().getClass().getPackage().getName(); + } + + public static @NotNull String getCraftBukkitPrefix(String cbClassName) { + return getCraftBukkitPrefix() + "." + cbClassName; + } + + private @NotNull String getNetMinecraftServerPrefix(String nmsClassName) { + if (this.nmsVersioning) return "net.minecraft.server." + this.nmsVersion + "." + nmsClassName; + return "net.minecraft.server." + nmsClassName; + } + + private boolean resolveSyncCommandsMethod() { + if (this.syncCommandsMethod != null) return true; + + try { + this.syncCommandsMethod = Class.forName(getCraftBukkitPrefix("CraftServer")).getDeclaredMethod("syncCommands"); + this.syncCommandsMethod.setAccessible(true); + return true; + } catch (NoSuchMethodException | ClassNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + private boolean fetchCommandMapField() { + if (this.commandMapField != null) return true; + try { + this.commandMapField = Class.forName(getCraftBukkitPrefix("CraftServer")).getDeclaredField("commandMap"); + this.commandMapField.setAccessible(true); + return true; + } catch (NoSuchFieldException | ClassNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + private boolean fetchKnownCommandsField() { + if (this.knownCommandsField != null) return true; + + try { + this.knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands"); + this.knownCommandsField.setAccessible(true); + return true; + } catch (NoSuchFieldException e) { + e.printStackTrace(); + return false; + } + } + + public void setKnownCommands(Map knownCommands) { + if (!this.fetchCommandMapField()) + throw new RuntimeException("Cannot find command map"); + + SimpleCommandMap commandMap; + try { + commandMap = (SimpleCommandMap) this.commandMapField.get(Bukkit.getServer()); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + if (!this.fetchKnownCommandsField()) + throw new RuntimeException("Unable to find known commands"); + + try { + this.knownCommandsField.set(commandMap, knownCommands); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + public void sync() { + if (!this.resolveSyncCommandsMethod()) return; + + try { + this.syncCommandsMethod.invoke(Bukkit.getServer()); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + + if (Bukkit.getOnlinePlayers().isEmpty()) return; + + Bukkit.getOnlinePlayers().forEach(Player::updateCommands); + } + + public void unwrap(String command) { + if (this.nmsVersion == null) return; + + if (!this.resolveMinecraftServerClass()) return; + + if (!this.resolveGetServerMethod()) return; + Object server = this.getServerInstance(); + + if (!this.resolveVanillaCommandDispatcherField()) return; + Object commandDispatcher = this.getCommandDispatcher(server); + + if (!this.resolveBField()) return; + + CommandDispatcher b = this.getDispatcher(commandDispatcher); + if (b == null) return; + + if (!this.resolveRemoveCommandMethod()) return; + + try { + this.removeCommandMethod.invoke(b.getRoot(), command); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + + private boolean resolveRemoveCommandMethod() { + if (this.removeCommandMethod == null) try { + try { + this.removeCommandMethod = RootCommandNode.class.getDeclaredMethod("removeCommand", String.class); + } catch (NoSuchMethodException | NoSuchMethodError ex) { + this.removeCommandMethod = CommandNode.class.getDeclaredMethod("removeCommand", String.class); + } + return true; + } catch (NoSuchMethodException e) { + e.printStackTrace(); + return false; + } + return true; + } + + private @Nullable CommandDispatcher getDispatcher(Object commandDispatcher) { + try { + return (CommandDispatcher) this.bField.get(commandDispatcher); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return null; + } + } + + private @Nullable Object getCommandDispatcher(Object server) { + try { + return this.vanillaCommandDispatcherField.get(server); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return null; + } + } + + private Object getServerInstance() { + try { + return this.getServerMethod.invoke(this.minecraftServerClass); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + + private boolean resolveMinecraftServerClass() { + if (this.minecraftServerClass != null) return true; + try { + this.minecraftServerClass = Class.forName(this.getNetMinecraftServerPrefix("MinecraftServer")); + return true; + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return false; + } + } + + private boolean resolveGetServerMethod() { + if (this.getServerMethod != null) return true; + try { + this.getServerMethod = this.minecraftServerClass.getMethod("getServer"); + this.getServerMethod.setAccessible(true); + return true; + } catch (NoSuchMethodException e) { + e.printStackTrace(); + return false; + } + } + + private boolean resolveVanillaCommandDispatcherField() { + if (this.vanillaCommandDispatcherField != null) return true; + try { + this.vanillaCommandDispatcherField = this.minecraftServerClass.getDeclaredField("vanillaCommandDispatcher"); + this.vanillaCommandDispatcherField.setAccessible(true); + return true; + } catch (NoSuchFieldException e) { + e.printStackTrace(); + return false; + } + } + + private boolean resolveBField() { + if (this.bField != null) return true; + try { + this.bField = Class.forName(this.getNetMinecraftServerPrefix("CommandDispatcher")).getDeclaredField("b"); + this.bField.setAccessible(true); + return true; + } catch (NoSuchFieldException | ClassNotFoundException e) { + try { + Class clazz = Class.forName("net.minecraft.commands.CommandDispatcher"); + Field gField = clazz.getDeclaredField("g"); + if (gField.getType() == CommandDispatcher.class) + this.bField = gField; + else + this.bField = clazz.getDeclaredField("h"); + this.bField.setAccessible(true); + return true; + } catch (NoSuchFieldException | ClassNotFoundException ex) { + ex.addSuppressed(e); + e.printStackTrace(); + return false; + } + } + } + + private boolean resolveRegisterCommandMethod() { + if (this.registerMethod != null) return true; + try { + this.registerMethod = Class.forName(getCraftBukkitPrefix("command.BukkitCommandWrapper")) + .getMethod("register", CommandDispatcher.class, String.class); + this.registerMethod.setAccessible(true); + return true; + } catch (NoSuchMethodException | ClassNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + private Object getAInstance(Object commandDispatcher) { + try { + return this.aMethod.invoke(commandDispatcher); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + + private @Nullable Object getCommandWrapper(Command command) { + try { + return this.bukkitcommandWrapperConstructor.newInstance(Bukkit.getServer(), command); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + + private boolean resolveBukkitCmdWrapperConstructor() { + if (this.bukkitcommandWrapperConstructor != null) return true; + try { + this.bukkitcommandWrapperConstructor = Class.forName(getCraftBukkitPrefix("command.BukkitCommandWrapper")).getDeclaredConstructor(Class.forName("org.bukkit.craftbukkit." + this.nmsVersion + ".CraftServer"), Command.class); + this.bukkitcommandWrapperConstructor.setAccessible(true); + return true; + } catch (NoSuchMethodException | ClassNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + private boolean resolveAMethod(Object commandDispatcher) { + if (this.aMethod != null) return true; + try { + this.aMethod = commandDispatcher.getClass().getDeclaredMethod("a"); + this.aMethod.setAccessible(true); + return true; + } catch (NoSuchMethodException e) { + e.printStackTrace(); + return false; + } + } +} From 2d80e99f9e4cb6f0dd31a75957fd3c89e8fdcb06 Mon Sep 17 00:00:00 2001 From: xGinko Date: Mon, 6 Jan 2025 15:16:57 +0100 Subject: [PATCH 03/18] rollback changes --- .../aef/commands/BukkitCommandWrap.java | 58 +------------------ 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java b/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java index d68a5355..b7a2e07d 100644 --- a/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java +++ b/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -25,9 +24,8 @@ public final class BukkitCommandWrap { private final boolean nmsVersioning; private String nmsVersion; private Class minecraftServerClass; - private Method aMethod, getServerMethod, registerMethod, syncCommandsMethod, removeCommandMethod; + private Method getServerMethod, syncCommandsMethod, removeCommandMethod; private Field bField, vanillaCommandDispatcherField, commandMapField, knownCommandsField; - private Constructor bukkitcommandWrapperConstructor; public BukkitCommandWrap() { String prefix = getCraftBukkitPrefix(); @@ -264,58 +262,4 @@ private boolean resolveBField() { } } - private boolean resolveRegisterCommandMethod() { - if (this.registerMethod != null) return true; - try { - this.registerMethod = Class.forName(getCraftBukkitPrefix("command.BukkitCommandWrapper")) - .getMethod("register", CommandDispatcher.class, String.class); - this.registerMethod.setAccessible(true); - return true; - } catch (NoSuchMethodException | ClassNotFoundException e) { - e.printStackTrace(); - return false; - } - } - - private Object getAInstance(Object commandDispatcher) { - try { - return this.aMethod.invoke(commandDispatcher); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - return null; - } - } - - private @Nullable Object getCommandWrapper(Command command) { - try { - return this.bukkitcommandWrapperConstructor.newInstance(Bukkit.getServer(), command); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - return null; - } - } - - private boolean resolveBukkitCmdWrapperConstructor() { - if (this.bukkitcommandWrapperConstructor != null) return true; - try { - this.bukkitcommandWrapperConstructor = Class.forName(getCraftBukkitPrefix("command.BukkitCommandWrapper")).getDeclaredConstructor(Class.forName("org.bukkit.craftbukkit." + this.nmsVersion + ".CraftServer"), Command.class); - this.bukkitcommandWrapperConstructor.setAccessible(true); - return true; - } catch (NoSuchMethodException | ClassNotFoundException e) { - e.printStackTrace(); - return false; - } - } - - private boolean resolveAMethod(Object commandDispatcher) { - if (this.aMethod != null) return true; - try { - this.aMethod = commandDispatcher.getClass().getDeclaredMethod("a"); - this.aMethod.setAccessible(true); - return true; - } catch (NoSuchMethodException e) { - e.printStackTrace(); - return false; - } - } } From aa68538c48ff746e84ff77f5d625ac679e179bac Mon Sep 17 00:00:00 2001 From: xGinko Date: Mon, 6 Jan 2025 15:29:16 +0100 Subject: [PATCH 04/18] fail silently in command reflections --- .../aef/commands/BukkitCommandWrap.java | 138 ++++++++---------- 1 file changed, 62 insertions(+), 76 deletions(-) diff --git a/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java b/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java index b7a2e07d..35af6582 100644 --- a/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java +++ b/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java @@ -23,7 +23,7 @@ public final class BukkitCommandWrap { private final boolean nmsVersioning; private String nmsVersion; - private Class minecraftServerClass; + private Class minecraftServerClass; private Method getServerMethod, syncCommandsMethod, removeCommandMethod; private Field bField, vanillaCommandDispatcherField, commandMapField, knownCommandsField; @@ -32,14 +32,14 @@ public BukkitCommandWrap() { String[] packageParts = prefix.split("\\."); String versionPart = packageParts[packageParts.length - 1]; if (versionPart.startsWith("v1_")) { - this.nmsVersion = versionPart; + nmsVersion = versionPart; } boolean nmsVers = true; try { Class.forName("net.minecraft.server.MinecraftServer"); nmsVers = false; } catch (ClassNotFoundException ignore) {} - this.nmsVersioning = nmsVers; + nmsVersioning = nmsVers; } public static BukkitCommandWrap getInstance() { @@ -58,208 +58,194 @@ public static BukkitCommandWrap getInstance() { } private @NotNull String getNetMinecraftServerPrefix(String nmsClassName) { - if (this.nmsVersioning) return "net.minecraft.server." + this.nmsVersion + "." + nmsClassName; + if (nmsVersioning) return "net.minecraft.server." + nmsVersion + "." + nmsClassName; return "net.minecraft.server." + nmsClassName; } private boolean resolveSyncCommandsMethod() { - if (this.syncCommandsMethod != null) return true; + if (syncCommandsMethod != null) return true; try { - this.syncCommandsMethod = Class.forName(getCraftBukkitPrefix("CraftServer")).getDeclaredMethod("syncCommands"); - this.syncCommandsMethod.setAccessible(true); + syncCommandsMethod = Class.forName(getCraftBukkitPrefix("CraftServer")).getDeclaredMethod("syncCommands"); + syncCommandsMethod.setAccessible(true); return true; } catch (NoSuchMethodException | ClassNotFoundException e) { - e.printStackTrace(); + return false; } } private boolean fetchCommandMapField() { - if (this.commandMapField != null) return true; + if (commandMapField != null) return true; try { - this.commandMapField = Class.forName(getCraftBukkitPrefix("CraftServer")).getDeclaredField("commandMap"); - this.commandMapField.setAccessible(true); + commandMapField = Class.forName(getCraftBukkitPrefix("CraftServer")).getDeclaredField("commandMap"); + commandMapField.setAccessible(true); return true; } catch (NoSuchFieldException | ClassNotFoundException e) { - e.printStackTrace(); + return false; } } private boolean fetchKnownCommandsField() { - if (this.knownCommandsField != null) return true; + if (knownCommandsField != null) return true; try { - this.knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands"); - this.knownCommandsField.setAccessible(true); + knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands"); + knownCommandsField.setAccessible(true); return true; } catch (NoSuchFieldException e) { - e.printStackTrace(); + return false; } } public void setKnownCommands(Map knownCommands) { - if (!this.fetchCommandMapField()) - throw new RuntimeException("Cannot find command map"); + if (!fetchCommandMapField()) return; SimpleCommandMap commandMap; try { - commandMap = (SimpleCommandMap) this.commandMapField.get(Bukkit.getServer()); + commandMap = (SimpleCommandMap) commandMapField.get(Bukkit.getServer()); } catch (Exception e) { - e.printStackTrace(); return; } - if (!this.fetchKnownCommandsField()) - throw new RuntimeException("Unable to find known commands"); + if (!fetchKnownCommandsField()) return; try { - this.knownCommandsField.set(commandMap, knownCommands); - } catch (IllegalAccessException e) { - e.printStackTrace(); + knownCommandsField.set(commandMap, knownCommands); + } catch (IllegalAccessException ignored) { } } public void sync() { - if (!this.resolveSyncCommandsMethod()) return; + if (!resolveSyncCommandsMethod()) return; try { - this.syncCommandsMethod.invoke(Bukkit.getServer()); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); + syncCommandsMethod.invoke(Bukkit.getServer()); + } catch (IllegalAccessException | InvocationTargetException ignored) { } - if (Bukkit.getOnlinePlayers().isEmpty()) return; - - Bukkit.getOnlinePlayers().forEach(Player::updateCommands); + for (Player player : Bukkit.getOnlinePlayers()) { + player.updateCommands(); + } } public void unwrap(String command) { - if (this.nmsVersion == null) return; + if (nmsVersion == null) return; - if (!this.resolveMinecraftServerClass()) return; + if (!resolveMinecraftServerClass()) return; - if (!this.resolveGetServerMethod()) return; - Object server = this.getServerInstance(); + if (!resolveGetServerMethod()) return; + Object server = getServerInstance(); - if (!this.resolveVanillaCommandDispatcherField()) return; - Object commandDispatcher = this.getCommandDispatcher(server); + if (!resolveVanillaCommandDispatcherField()) return; + Object commandDispatcher = getCommandDispatcher(server); - if (!this.resolveBField()) return; + if (!resolveBField()) return; - CommandDispatcher b = this.getDispatcher(commandDispatcher); - if (b == null) return; + CommandDispatcher dispatcher = getDispatcher(commandDispatcher); + if (dispatcher == null) return; - if (!this.resolveRemoveCommandMethod()) return; + if (!resolveRemoveCommandMethod()) return; try { - this.removeCommandMethod.invoke(b.getRoot(), command); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); + removeCommandMethod.invoke(dispatcher.getRoot(), command); + } catch (IllegalAccessException | InvocationTargetException ignored) { } } private boolean resolveRemoveCommandMethod() { - if (this.removeCommandMethod == null) try { + if (removeCommandMethod == null) try { try { - this.removeCommandMethod = RootCommandNode.class.getDeclaredMethod("removeCommand", String.class); + removeCommandMethod = RootCommandNode.class.getDeclaredMethod("removeCommand", String.class); } catch (NoSuchMethodException | NoSuchMethodError ex) { - this.removeCommandMethod = CommandNode.class.getDeclaredMethod("removeCommand", String.class); + removeCommandMethod = CommandNode.class.getDeclaredMethod("removeCommand", String.class); } return true; } catch (NoSuchMethodException e) { - e.printStackTrace(); return false; } return true; } - private @Nullable CommandDispatcher getDispatcher(Object commandDispatcher) { + private @Nullable CommandDispatcher getDispatcher(Object commandDispatcher) { try { - return (CommandDispatcher) this.bField.get(commandDispatcher); + return (CommandDispatcher) bField.get(commandDispatcher); } catch (IllegalAccessException e) { - e.printStackTrace(); return null; } } private @Nullable Object getCommandDispatcher(Object server) { try { - return this.vanillaCommandDispatcherField.get(server); + return vanillaCommandDispatcherField.get(server); } catch (IllegalAccessException e) { - e.printStackTrace(); + return null; } } private Object getServerInstance() { try { - return this.getServerMethod.invoke(this.minecraftServerClass); + return getServerMethod.invoke(minecraftServerClass); } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); + return null; } } private boolean resolveMinecraftServerClass() { - if (this.minecraftServerClass != null) return true; + if (minecraftServerClass != null) return true; try { - this.minecraftServerClass = Class.forName(this.getNetMinecraftServerPrefix("MinecraftServer")); + minecraftServerClass = Class.forName(getNetMinecraftServerPrefix("MinecraftServer")); return true; } catch (ClassNotFoundException ex) { - ex.printStackTrace(); return false; } } private boolean resolveGetServerMethod() { - if (this.getServerMethod != null) return true; + if (getServerMethod != null) return true; try { - this.getServerMethod = this.minecraftServerClass.getMethod("getServer"); - this.getServerMethod.setAccessible(true); + getServerMethod = minecraftServerClass.getMethod("getServer"); + getServerMethod.setAccessible(true); return true; } catch (NoSuchMethodException e) { - e.printStackTrace(); return false; } } private boolean resolveVanillaCommandDispatcherField() { - if (this.vanillaCommandDispatcherField != null) return true; + if (vanillaCommandDispatcherField != null) return true; try { - this.vanillaCommandDispatcherField = this.minecraftServerClass.getDeclaredField("vanillaCommandDispatcher"); - this.vanillaCommandDispatcherField.setAccessible(true); + vanillaCommandDispatcherField = minecraftServerClass.getDeclaredField("vanillaCommandDispatcher"); + vanillaCommandDispatcherField.setAccessible(true); return true; } catch (NoSuchFieldException e) { - e.printStackTrace(); return false; } } private boolean resolveBField() { - if (this.bField != null) return true; + if (bField != null) return true; try { - this.bField = Class.forName(this.getNetMinecraftServerPrefix("CommandDispatcher")).getDeclaredField("b"); - this.bField.setAccessible(true); + bField = Class.forName(getNetMinecraftServerPrefix("CommandDispatcher")).getDeclaredField("b"); + bField.setAccessible(true); return true; } catch (NoSuchFieldException | ClassNotFoundException e) { try { Class clazz = Class.forName("net.minecraft.commands.CommandDispatcher"); Field gField = clazz.getDeclaredField("g"); if (gField.getType() == CommandDispatcher.class) - this.bField = gField; + bField = gField; else - this.bField = clazz.getDeclaredField("h"); - this.bField.setAccessible(true); + bField = clazz.getDeclaredField("h"); + bField.setAccessible(true); return true; } catch (NoSuchFieldException | ClassNotFoundException ex) { - ex.addSuppressed(e); - e.printStackTrace(); return false; } } } - } From b01e8ae011e64d2259c74b98575833abe3ac4dca Mon Sep 17 00:00:00 2001 From: xGinko Date: Mon, 6 Jan 2025 15:30:55 +0100 Subject: [PATCH 05/18] remove awkward spaces --- .../me/xginko/aef/commands/BukkitCommandWrap.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java b/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java index 35af6582..810960a9 100644 --- a/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java +++ b/shared/src/main/java/me/xginko/aef/commands/BukkitCommandWrap.java @@ -70,7 +70,6 @@ private boolean resolveSyncCommandsMethod() { syncCommandsMethod.setAccessible(true); return true; } catch (NoSuchMethodException | ClassNotFoundException e) { - return false; } } @@ -82,7 +81,6 @@ private boolean fetchCommandMapField() { commandMapField.setAccessible(true); return true; } catch (NoSuchFieldException | ClassNotFoundException e) { - return false; } } @@ -95,7 +93,6 @@ private boolean fetchKnownCommandsField() { knownCommandsField.setAccessible(true); return true; } catch (NoSuchFieldException e) { - return false; } } @@ -181,7 +178,6 @@ private boolean resolveRemoveCommandMethod() { try { return vanillaCommandDispatcherField.get(server); } catch (IllegalAccessException e) { - return null; } } @@ -190,7 +186,6 @@ private Object getServerInstance() { try { return getServerMethod.invoke(minecraftServerClass); } catch (IllegalAccessException | InvocationTargetException e) { - return null; } } @@ -235,12 +230,9 @@ private boolean resolveBField() { return true; } catch (NoSuchFieldException | ClassNotFoundException e) { try { - Class clazz = Class.forName("net.minecraft.commands.CommandDispatcher"); - Field gField = clazz.getDeclaredField("g"); - if (gField.getType() == CommandDispatcher.class) - bField = gField; - else - bField = clazz.getDeclaredField("h"); + Class commandDispatcher = Class.forName("net.minecraft.commands.CommandDispatcher"); + Field gField = commandDispatcher.getDeclaredField("g"); + bField = gField.getType() == CommandDispatcher.class ? gField : commandDispatcher.getDeclaredField("h"); bField.setAccessible(true); return true; } catch (NoSuchFieldException | ClassNotFoundException ex) { From 916fff56271b78279a0592633dba64e760812a27 Mon Sep 17 00:00:00 2001 From: xGinko Date: Mon, 6 Jan 2025 16:59:27 +0100 Subject: [PATCH 06/18] improve enable versioning --- .../src/main/java/me/xginko/aef/AnarchyExploitFixes.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index 3e810cf3..21fca531 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -104,8 +104,8 @@ public void onEnable() { ServerVersion serverVersion = PacketEvents.getAPI().getServerManager().getVersion(); prefixedLogger.info("Detected {} {}", PlatformUtil.getServerType().niceName(), serverVersion.name().replace("V_", "").replace('_', '.')); - if (serverVersion.isOlderThanOrEquals(ServerVersion.V_1_19_3) || - serverVersion.equals(ServerVersion.V_1_19_4) && !PlatformUtil.isFolia()) { + if (serverVersion.isOlderThan(ServerVersion.V_1_19_4) || + (serverVersion.equals(ServerVersion.V_1_19_4) && !PlatformUtil.isFolia())) { prefixedLogger.error("This plugin jar is incompatible with your Server. Please use the Legacy jar."); getServer().getPluginManager().disablePlugin(this); return; From 658cce145d68c598c7fcb6e06803dc162ec8f12b Mon Sep 17 00:00:00 2001 From: xGinko Date: Mon, 6 Jan 2025 17:06:56 +0100 Subject: [PATCH 07/18] shutdown server if crucial checks fail --- .../src/main/java/me/xginko/aef/AnarchyExploitFixes.java | 4 ++-- .../src/main/java/me/xginko/aef/AnarchyExploitFixes.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index 21fca531..750b4d39 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -86,7 +86,7 @@ public void onEnable() { " https://ci.codemc.io/job/retrooper/job/packetevents/ ", " " ).forEach(prefixedLogger::error); - getServer().getPluginManager().disablePlugin(this); + getServer().shutdown(); return; } @@ -107,7 +107,7 @@ public void onEnable() { if (serverVersion.isOlderThan(ServerVersion.V_1_19_4) || (serverVersion.equals(ServerVersion.V_1_19_4) && !PlatformUtil.isFolia())) { prefixedLogger.error("This plugin jar is incompatible with your Server. Please use the Legacy jar."); - getServer().getPluginManager().disablePlugin(this); + getServer().shutdown(); return; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index 4a226c7d..90aaa8d6 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -69,7 +69,7 @@ public void onEnable() { if (PlatformUtil.isFolia()) { getLogger().severe("Please use the Folia jar instead of modifying the plugin.yml."); - getServer().getPluginManager().disablePlugin(this); + getServer().shutdown(); return; } @@ -92,7 +92,7 @@ public void onEnable() { " https://ci.codemc.io/job/retrooper/job/packetevents/ ", " " ).forEach(prefixedLogger::error); - getServer().getPluginManager().disablePlugin(this); + getServer().shutdown(); return; } From 0dbc95c402ddac78e1c8937c56b17244c640b4c3 Mon Sep 17 00:00:00 2001 From: xGinko Date: Mon, 6 Jan 2025 17:14:49 +0100 Subject: [PATCH 08/18] only shutdown server on missing packetevents because of plugman users --- .../src/main/java/me/xginko/aef/AnarchyExploitFixes.java | 4 ++-- .../src/main/java/me/xginko/aef/AnarchyExploitFixes.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index 750b4d39..9b795ddf 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -86,7 +86,7 @@ public void onEnable() { " https://ci.codemc.io/job/retrooper/job/packetevents/ ", " " ).forEach(prefixedLogger::error); - getServer().shutdown(); + getServer().shutdown(); // Don't allow plugman/serverutil users to hot-load this plugin if packetevents is missing. return; } @@ -107,7 +107,7 @@ public void onEnable() { if (serverVersion.isOlderThan(ServerVersion.V_1_19_4) || (serverVersion.equals(ServerVersion.V_1_19_4) && !PlatformUtil.isFolia())) { prefixedLogger.error("This plugin jar is incompatible with your Server. Please use the Legacy jar."); - getServer().shutdown(); + getServer().getPluginManager().disablePlugin(this); return; } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java index 90aaa8d6..c4a9f71a 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/AnarchyExploitFixes.java @@ -69,7 +69,7 @@ public void onEnable() { if (PlatformUtil.isFolia()) { getLogger().severe("Please use the Folia jar instead of modifying the plugin.yml."); - getServer().shutdown(); + getServer().getPluginManager().disablePlugin(this); return; } @@ -92,7 +92,7 @@ public void onEnable() { " https://ci.codemc.io/job/retrooper/job/packetevents/ ", " " ).forEach(prefixedLogger::error); - getServer().shutdown(); + getServer().shutdown(); // Don't allow plugman/serverutil users to hot-load this plugin if packetevents is missing. return; } From 22fa55aad160587c7e4206517f161613c124833d Mon Sep 17 00:00:00 2001 From: xGinko Date: Mon, 6 Jan 2025 17:38:53 +0100 Subject: [PATCH 09/18] ready minor release --- build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts index 60dbba5c..89d861ba 100755 --- a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts +++ b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.xginko" -version = "2.7.5-SNAPSHOT" +version = "2.7.5" description = "Prevent many exploits that affect anarchy servers." var url: String? = "github.com/xGinko/AnarchyExploitFixes" From 2609868788fbf7c9898fea5b64dd4f7893f588bf Mon Sep 17 00:00:00 2001 From: xGinko Date: Mon, 6 Jan 2025 17:46:20 +0100 Subject: [PATCH 10/18] go back to snapshot --- build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts index 89d861ba..a8d0ff88 100755 --- a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts +++ b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.xginko" -version = "2.7.5" +version = "2.7.6-SNAPSHOT" description = "Prevent many exploits that affect anarchy servers." var url: String? = "github.com/xGinko/AnarchyExploitFixes" From bdde47d93957932440d9c06c60f838949108f461 Mon Sep 17 00:00:00 2001 From: xGinko Date: Thu, 9 Jan 2025 15:36:55 +0100 Subject: [PATCH 11/18] fix aura modules in legacy --- .../aef/modules/combat/auras/AnchorAuraDelay.java | 14 ++------------ .../aef/modules/combat/auras/AuraDelayModule.java | 4 ++-- .../aef/modules/combat/auras/BedAuraDelay.java | 14 ++------------ .../aef/modules/combat/auras/CrystalAuraDelay.java | 14 ++------------ 4 files changed, 8 insertions(+), 38 deletions(-) diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java index a91bee7d..41f0099b 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AnchorAuraDelay.java @@ -22,14 +22,9 @@ private void onPlayerInteract(PlayerInteractEvent event) { if (event.getItem() == null || event.getItem().getType() != XMaterial.GLOWSTONE.get()) return; if (WorldUtil.isRespawnAnchorWorks(event.getPlayer().getWorld())) return; - if ( - breakCooldowns.containsKey(event.getPlayer().getUniqueId()) - && breakCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { + if (isOnCooldown(event.getPlayer().getUniqueId(), breakCooldowns, breakDelayNanos)) { event.setCancelled(true); if (updateInventory) event.getPlayer().updateInventory(); - } else { - breakCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + breakDelayNanos); } } @@ -39,14 +34,9 @@ private void onBlockPlace(BlockPlaceEvent event) { if (event.getBlock().getType() != XMaterial.RESPAWN_ANCHOR.get()) return; if (WorldUtil.isRespawnAnchorWorks(event.getPlayer().getWorld())) return; - if ( - placeCooldowns.containsKey(event.getPlayer().getUniqueId()) - && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { + if (isOnCooldown(event.getPlayer().getUniqueId(), placeCooldowns, placeDelayNanos)) { event.setCancelled(true); if (updateInventory) event.getPlayer().updateInventory(); - } else { - placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); } } } \ No newline at end of file diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java index 4e83c06c..b7c82367 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java @@ -29,9 +29,9 @@ public AuraDelayModule(String configPath, boolean defEnabled, long defPlaceDelay this.updateInventory = config.getBoolean(configPath + ".update-inventory-on-cancel", false, "Can help with desync but recommended to leave off unless you have issues."); placeDelayNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(".place-delay-millis", defPlaceDelayMillis, "1 tick = 50 ms")); + config.getLong(configPath + ".place-delay-millis", defPlaceDelayMillis, "1 tick = 50 ms")); breakDelayNanos = TimeUnit.MILLISECONDS.toNanos( - config.getLong(".break-delay-millis", defBreakDelayMillis)); + config.getLong(configPath + ".break-delay-millis", defBreakDelayMillis)); } @Override diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/BedAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/BedAuraDelay.java index db33d017..3a77f54f 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/BedAuraDelay.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/BedAuraDelay.java @@ -21,14 +21,9 @@ private void onPlayerInteract(PlayerInteractEvent event) { if (!MaterialUtil.BEDS.contains(event.getClickedBlock().getType())) return; if (WorldUtil.isBedWorks(event.getClickedBlock().getWorld())) return; - if ( - breakCooldowns.containsKey(event.getPlayer().getUniqueId()) - && breakCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { + if (isOnCooldown(event.getPlayer().getUniqueId(), breakCooldowns, breakDelayNanos)) { event.setCancelled(true); if (updateInventory) event.getPlayer().updateInventory(); - } else { - breakCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + breakDelayNanos); } } @@ -38,14 +33,9 @@ private void onBlockPlace(BlockPlaceEvent event) { if (!MaterialUtil.BEDS.contains(event.getBlockPlaced().getType())) return; if (WorldUtil.isBedWorks(event.getBlockPlaced().getWorld())) return; - if ( - placeCooldowns.containsKey(event.getPlayer().getUniqueId()) - && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { + if (isOnCooldown(event.getPlayer().getUniqueId(), placeCooldowns, placeDelayNanos)) { event.setCancelled(true); if (updateInventory) event.getPlayer().updateInventory(); - } else { - placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java index 05379e7f..9201ccd3 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/combat/auras/CrystalAuraDelay.java @@ -21,14 +21,9 @@ private void onEntityDamageByEntity(EntityDamageByEntityEvent event) { if (event.getEntityType() != XEntityType.END_CRYSTAL.get()) return; if (event.getDamager().getType() != XEntityType.PLAYER.get()) return; - if ( - breakCooldowns.containsKey(event.getDamager().getUniqueId()) - && breakCooldowns.get(event.getDamager().getUniqueId()) > System.nanoTime() - ) { + if (isOnCooldown(event.getDamager().getUniqueId(), breakCooldowns, placeDelayNanos)) { event.setCancelled(true); if (updateInventory) ((Player) event.getDamager()).updateInventory(); - } else { - breakCooldowns.put(event.getDamager().getUniqueId(), System.nanoTime() + breakDelayNanos); } } @@ -38,14 +33,9 @@ private void onPlayerInteract(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; // Need to right-click a block to place a crystal if (event.getItem() == null || event.getItem().getType() != XMaterial.END_CRYSTAL.get()) return; - if ( - placeCooldowns.containsKey(event.getPlayer().getUniqueId()) - && placeCooldowns.get(event.getPlayer().getUniqueId()) > System.nanoTime() - ) { + if (isOnCooldown(event.getPlayer().getUniqueId(), placeCooldowns, placeDelayNanos)) { event.setCancelled(true); if (updateInventory) event.getPlayer().updateInventory(); - } else { - placeCooldowns.put(event.getPlayer().getUniqueId(), System.nanoTime() + placeDelayNanos); } } } \ No newline at end of file From 9863159a63a69556a1bd342ae4d82bb15a24861a Mon Sep 17 00:00:00 2001 From: xGinko Date: Thu, 9 Jan 2025 15:38:29 +0100 Subject: [PATCH 12/18] fix aura delay in folia --- .../me/xginko/aef/modules/combat/auras/AuraDelayModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java index a35afc96..58a8af3c 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java @@ -51,8 +51,8 @@ public AuraDelayModule(String configPath, boolean defEnabled, long defPlaceDelay String typePath = configPath + "." + settingType.name().toLowerCase().replace("_", "-"); boolean enabled = config.getBoolean(typePath + ".enable", false); Cooldowns cooldowns = new Cooldowns( - config.getLong(typePath + ".place-delay-millis", defPlaceDelayMillis, "1 tick = 50 ms"), - config.getLong(typePath + ".break-delay-millis", defBreakDelayMillis)); + config.getLong(configPath + "." + typePath + ".place-delay-millis", defPlaceDelayMillis, "1 tick = 50 ms"), + config.getLong(configPath + "." + typePath + ".break-delay-millis", defBreakDelayMillis)); if (enabled) { cooldownSettings.put(settingType, cooldowns); } From 1885f4b7528245334583d0e70c56eb367de7a212 Mon Sep 17 00:00:00 2001 From: xGinko Date: Thu, 9 Jan 2025 16:05:13 +0100 Subject: [PATCH 13/18] add carpet dupe prevention --- .../modules/dupepreventions/CarpetDupe.java | 72 ++++++++++++++++++ .../modules/dupepreventions/CarpetDupe.java | 73 +++++++++++++++++++ .../me/xginko/aef/utils/MaterialUtil.java | 5 ++ 3 files changed, 150 insertions(+) create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java new file mode 100755 index 00000000..cad78cd4 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java @@ -0,0 +1,72 @@ +package me.xginko.aef.modules.dupepreventions; + +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.MaterialUtil; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPistonEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; + +import java.util.ArrayList; +import java.util.List; + +public class CarpetDupe extends AEFModule implements Listener { + + private final boolean deleteCarpet; + + public CarpetDupe() { + super("dupe-preventions.carpet-dupe", false, + "Will prevent Pistons that are pusing carpets from working."); + this.deleteCarpet = config.getBoolean(configPath + ".delete-carpet", true); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPistonExtend(BlockPistonExtendEvent event) { + onPistonEvent(event, event.getBlocks()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPistonRetract(BlockPistonRetractEvent event) { + onPistonEvent(event, event.getBlocks()); + } + + private void onPistonEvent(BlockPistonEvent event, List affectedBlocks) { + if (affectedBlocks.isEmpty()) return; + + List carpets = new ArrayList<>(8); + + for (Block block : affectedBlocks) { + if (MaterialUtil.CARPETS.contains(block.getType())) { + carpets.add(block); + } + } + + if (carpets.isEmpty()) { + return; + } + + event.setCancelled(true); + + if (deleteCarpet) { + for (Block block : carpets) { + plugin.getServer().getGlobalRegionScheduler() + .execute(plugin, () -> block.setType(XMaterial.AIR.get(), false)); + } + } + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java new file mode 100755 index 00000000..497380e3 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java @@ -0,0 +1,73 @@ +package me.xginko.aef.modules.dupepreventions; + +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.MaterialUtil; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPistonEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; + +import java.util.ArrayList; +import java.util.List; + +public class CarpetDupe extends AEFModule implements Listener { + + private final boolean deleteCarpet; + + public CarpetDupe() { + super("dupe-preventions.carpet-dupe", false, + "Will prevent Pistons that are pusing carpets from working."); + this.deleteCarpet = config.getBoolean(configPath + ".delete-carpet", true); + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPistonExtend(BlockPistonExtendEvent event) { + onPistonEvent(event, event.getBlocks()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPistonRetract(BlockPistonRetractEvent event) { + onPistonEvent(event, event.getBlocks()); + } + + private void onPistonEvent(BlockPistonEvent event, List affectedBlocks) { + if (affectedBlocks.isEmpty()) return; + + List carpets = new ArrayList<>(8); + + for (Block block : affectedBlocks) { + if (MaterialUtil.CARPETS.contains(block.getType())) { + carpets.add(block); + } + } + + if (carpets.isEmpty()) { + return; + } + + event.setCancelled(true); + + if (deleteCarpet) { + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + for (Block block : carpets) { + block.setType(XMaterial.AIR.get(), false); + } + }, 1L); + } + } +} diff --git a/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java b/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java index 3f59bea5..f3d05ca0 100755 --- a/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java @@ -35,6 +35,11 @@ public final class MaterialUtil { .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); + public static final Set CARPETS = XTag.CARPETS.getValues().stream() + .filter(XMaterial::isSupported) + .map(XMaterial::get) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); + public static final Set SIGNS = XTag.SIGNS.getValues().stream() .filter(XMaterial::isSupported) .map(XMaterial::get) From a3aaaf90e61cad91d381089838328e66f290dcad Mon Sep 17 00:00:00 2001 From: xGinko Date: Thu, 9 Jan 2025 18:05:40 +0100 Subject: [PATCH 14/18] expand carpet-dupe to blockentitydupe and make configurable --- .../dupepreventions/BlockEntityDupe.java | 104 +++++++++++++++++ .../modules/dupepreventions/CarpetDupe.java | 72 ------------ .../dupepreventions/BlockEntityDupe.java | 105 ++++++++++++++++++ .../modules/dupepreventions/CarpetDupe.java | 73 ------------ .../me/xginko/aef/utils/MaterialUtil.java | 5 + 5 files changed, 214 insertions(+), 145 deletions(-) create mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java delete mode 100755 AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java create mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java delete mode 100755 AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java new file mode 100755 index 00000000..ddf02d72 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java @@ -0,0 +1,104 @@ +package me.xginko.aef.modules.dupepreventions; + +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.MaterialUtil; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPistonEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class BlockEntityDupe extends AEFModule implements Listener { + + private final Map materials = new EnumMap<>(Material.class); + + private Set removalList; + + public BlockEntityDupe() { + super("dupe-preventions.block-entity-dupe", false, """ + Will prevent Pistons that are pusing carpets/rails/tnt from working. + This isn't recommended to be used for turning everything off. + Use papers settings for that. + This is intended for admins that want to allow specific dupes only."""); + + if (config.getBoolean(configPath + ".carpets.prevent", true)) { + boolean remove = config.getBoolean(configPath + ".carpets.delete", true); + for (Material material : MaterialUtil.CARPETS) { + materials.put(material, remove); + } + } + + if (config.getBoolean(configPath + ".rails.prevent", true)) { + boolean remove = config.getBoolean(configPath + ".rails.delete", true); + for (Material material : MaterialUtil.RAILS) { + materials.put(material, remove); + } + } + + if (config.getBoolean(configPath + ".tnt.prevent", false)) { + materials.put(XMaterial.TNT.get(), config.getBoolean(configPath + ".tnt.delete", true)); + } + } + + @Override + public void enable() { + removalList = Collections.newSetFromMap(new ConcurrentHashMap<>()); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + if (removalList != null) { + setBlocksToAir(); + removalList.clear(); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPistonExtend(BlockPistonExtendEvent event) { + onPistonEvent(event, event.getBlocks()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPistonRetract(BlockPistonRetractEvent event) { + onPistonEvent(event, event.getBlocks()); + } + + private void onPistonEvent(BlockPistonEvent event, List affectedBlocks) { + if (affectedBlocks.isEmpty()) return; + + for (Block block : affectedBlocks) { + if (materials.containsKey(block.getType())) { + event.setCancelled(true); + if (materials.get(block.getType())) { + removalList.add(block); + } + } + } + + setBlocksToAir(); + } + + private void setBlocksToAir() { + if (removalList.isEmpty()) return; + + for (Block block : removalList) { + plugin.getServer().getRegionScheduler() + .execute(plugin, block.getLocation(), () -> block.setType(XMaterial.AIR.get(), false)); + removalList.remove(block); + } + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java deleted file mode 100755 index cad78cd4..00000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java +++ /dev/null @@ -1,72 +0,0 @@ -package me.xginko.aef.modules.dupepreventions; - -import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.MaterialUtil; -import org.bukkit.block.Block; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockPistonEvent; -import org.bukkit.event.block.BlockPistonExtendEvent; -import org.bukkit.event.block.BlockPistonRetractEvent; - -import java.util.ArrayList; -import java.util.List; - -public class CarpetDupe extends AEFModule implements Listener { - - private final boolean deleteCarpet; - - public CarpetDupe() { - super("dupe-preventions.carpet-dupe", false, - "Will prevent Pistons that are pusing carpets from working."); - this.deleteCarpet = config.getBoolean(configPath + ".delete-carpet", true); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPistonExtend(BlockPistonExtendEvent event) { - onPistonEvent(event, event.getBlocks()); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPistonRetract(BlockPistonRetractEvent event) { - onPistonEvent(event, event.getBlocks()); - } - - private void onPistonEvent(BlockPistonEvent event, List affectedBlocks) { - if (affectedBlocks.isEmpty()) return; - - List carpets = new ArrayList<>(8); - - for (Block block : affectedBlocks) { - if (MaterialUtil.CARPETS.contains(block.getType())) { - carpets.add(block); - } - } - - if (carpets.isEmpty()) { - return; - } - - event.setCancelled(true); - - if (deleteCarpet) { - for (Block block : carpets) { - plugin.getServer().getGlobalRegionScheduler() - .execute(plugin, () -> block.setType(XMaterial.AIR.get(), false)); - } - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java new file mode 100755 index 00000000..a32cddc8 --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java @@ -0,0 +1,105 @@ +package me.xginko.aef.modules.dupepreventions; + +import com.cryptomorin.xseries.XMaterial; +import me.xginko.aef.modules.AEFModule; +import me.xginko.aef.utils.MaterialUtil; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPistonEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class BlockEntityDupe extends AEFModule implements Listener { + + private final Map materials = new EnumMap<>(Material.class); + + private Set removalList; + + public BlockEntityDupe() { + super("dupe-preventions.block-entity-dupe", false, + "Will prevent Pistons that are pusing carpets/rails/tnt from working.\n" + + "This isn't recommended to be used for turning everything off.\n" + + "Use papers settings for that.\n" + + "This is intended for admins that want to allow specific dupes only."); + + if (config.getBoolean(configPath + ".carpets.prevent", true)) { + boolean remove = config.getBoolean(configPath + ".carpets.delete", true); + for (Material material : MaterialUtil.CARPETS) { + materials.put(material, remove); + } + } + + if (config.getBoolean(configPath + ".rails.prevent", true)) { + boolean remove = config.getBoolean(configPath + ".rails.delete", true); + for (Material material : MaterialUtil.RAILS) { + materials.put(material, remove); + } + } + + if (config.getBoolean(configPath + ".tnt.prevent", false)) { + materials.put(XMaterial.TNT.get(), config.getBoolean(configPath + ".tnt.delete", true)); + } + } + + @Override + public void enable() { + removalList = Collections.newSetFromMap(new ConcurrentHashMap<>()); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + if (removalList != null) { + setBlocksToAir(); + removalList.clear(); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPistonExtend(BlockPistonExtendEvent event) { + onPistonEvent(event, event.getBlocks()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + private void onPistonRetract(BlockPistonRetractEvent event) { + onPistonEvent(event, event.getBlocks()); + } + + private void onPistonEvent(BlockPistonEvent event, List affectedBlocks) { + if (affectedBlocks.isEmpty()) return; + + for (Block block : affectedBlocks) { + if (materials.containsKey(block.getType())) { + event.setCancelled(true); + if (materials.get(block.getType())) { + removalList.add(block); + } + } + } + + setBlocksToAir(); + } + + private void setBlocksToAir() { + if (removalList.isEmpty()) return; + + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + for (Block block : removalList) { + block.setType(XMaterial.AIR.get(), false); + removalList.remove(block); + } + }, 1L); + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java deleted file mode 100755 index 497380e3..00000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/CarpetDupe.java +++ /dev/null @@ -1,73 +0,0 @@ -package me.xginko.aef.modules.dupepreventions; - -import com.cryptomorin.xseries.XMaterial; -import me.xginko.aef.modules.AEFModule; -import me.xginko.aef.utils.MaterialUtil; -import org.bukkit.block.Block; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockPistonEvent; -import org.bukkit.event.block.BlockPistonExtendEvent; -import org.bukkit.event.block.BlockPistonRetractEvent; - -import java.util.ArrayList; -import java.util.List; - -public class CarpetDupe extends AEFModule implements Listener { - - private final boolean deleteCarpet; - - public CarpetDupe() { - super("dupe-preventions.carpet-dupe", false, - "Will prevent Pistons that are pusing carpets from working."); - this.deleteCarpet = config.getBoolean(configPath + ".delete-carpet", true); - } - - @Override - public void enable() { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @Override - public void disable() { - HandlerList.unregisterAll(this); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPistonExtend(BlockPistonExtendEvent event) { - onPistonEvent(event, event.getBlocks()); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPistonRetract(BlockPistonRetractEvent event) { - onPistonEvent(event, event.getBlocks()); - } - - private void onPistonEvent(BlockPistonEvent event, List affectedBlocks) { - if (affectedBlocks.isEmpty()) return; - - List carpets = new ArrayList<>(8); - - for (Block block : affectedBlocks) { - if (MaterialUtil.CARPETS.contains(block.getType())) { - carpets.add(block); - } - } - - if (carpets.isEmpty()) { - return; - } - - event.setCancelled(true); - - if (deleteCarpet) { - plugin.getServer().getScheduler().runTaskLater(plugin, () -> { - for (Block block : carpets) { - block.setType(XMaterial.AIR.get(), false); - } - }, 1L); - } - } -} diff --git a/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java b/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java index f3d05ca0..7f533857 100755 --- a/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java +++ b/shared/src/main/java/me/xginko/aef/utils/MaterialUtil.java @@ -40,6 +40,11 @@ public final class MaterialUtil { .map(XMaterial::get) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); + public static final Set RAILS = XTag.RAILS.getValues().stream() + .filter(XMaterial::isSupported) + .map(XMaterial::get) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); + public static final Set SIGNS = XTag.SIGNS.getValues().stream() .filter(XMaterial::isSupported) .map(XMaterial::get) From e6bae39b0c130d53969dca09feccd68e2f6b5394 Mon Sep 17 00:00:00 2001 From: xGinko Date: Thu, 9 Jan 2025 18:12:51 +0100 Subject: [PATCH 15/18] set to null instead --- .../me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java | 2 +- .../me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java index ddf02d72..52c85f6d 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java @@ -63,7 +63,7 @@ public void disable() { HandlerList.unregisterAll(this); if (removalList != null) { setBlocksToAir(); - removalList.clear(); + removalList = null; } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java index a32cddc8..1257bd8d 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java @@ -63,7 +63,7 @@ public void disable() { HandlerList.unregisterAll(this); if (removalList != null) { setBlocksToAir(); - removalList.clear(); + removalList = null; } } From ffc60b60f1513caed5fade20c7826f53311a1ca9 Mon Sep 17 00:00:00 2001 From: xGinko Date: Thu, 9 Jan 2025 18:14:26 +0100 Subject: [PATCH 16/18] fix typo --- .../me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java | 2 +- .../me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java index 52c85f6d..d8033ff8 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java @@ -28,7 +28,7 @@ public class BlockEntityDupe extends AEFModule implements Listener { public BlockEntityDupe() { super("dupe-preventions.block-entity-dupe", false, """ - Will prevent Pistons that are pusing carpets/rails/tnt from working. + Will prevent Pistons that are pushing carpets/rails/tnt from working. This isn't recommended to be used for turning everything off. Use papers settings for that. This is intended for admins that want to allow specific dupes only."""); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java index 1257bd8d..e90f2d2c 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/xginko/aef/modules/dupepreventions/BlockEntityDupe.java @@ -28,7 +28,7 @@ public class BlockEntityDupe extends AEFModule implements Listener { public BlockEntityDupe() { super("dupe-preventions.block-entity-dupe", false, - "Will prevent Pistons that are pusing carpets/rails/tnt from working.\n" + + "Will prevent Pistons that are pushing carpets/rails/tnt from working.\n" + "This isn't recommended to be used for turning everything off.\n" + "Use papers settings for that.\n" + "This is intended for admins that want to allow specific dupes only."); From 50a8b77daa254bd4d6d052572617bf866533d7c9 Mon Sep 17 00:00:00 2001 From: xGinko Date: Thu, 9 Jan 2025 18:19:27 +0100 Subject: [PATCH 17/18] ready minor release --- build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts index a8d0ff88..c285df40 100755 --- a/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts +++ b/build-logic/src/main/kotlin/me.xginko.aef.wrapper.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "me.xginko" -version = "2.7.6-SNAPSHOT" +version = "2.7.6" description = "Prevent many exploits that affect anarchy servers." var url: String? = "github.com/xGinko/AnarchyExploitFixes" From 381da6b634f1cac25f22a06f752c422ec3bdcce7 Mon Sep 17 00:00:00 2001 From: xGinko Date: Thu, 9 Jan 2025 18:29:26 +0100 Subject: [PATCH 18/18] revert path change --- .../me/xginko/aef/modules/combat/auras/AuraDelayModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java index 58a8af3c..a35afc96 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/combat/auras/AuraDelayModule.java @@ -51,8 +51,8 @@ public AuraDelayModule(String configPath, boolean defEnabled, long defPlaceDelay String typePath = configPath + "." + settingType.name().toLowerCase().replace("_", "-"); boolean enabled = config.getBoolean(typePath + ".enable", false); Cooldowns cooldowns = new Cooldowns( - config.getLong(configPath + "." + typePath + ".place-delay-millis", defPlaceDelayMillis, "1 tick = 50 ms"), - config.getLong(configPath + "." + typePath + ".break-delay-millis", defBreakDelayMillis)); + config.getLong(typePath + ".place-delay-millis", defPlaceDelayMillis, "1 tick = 50 ms"), + config.getLong(typePath + ".break-delay-millis", defBreakDelayMillis)); if (enabled) { cooldownSettings.put(settingType, cooldowns); }