diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/AnarchyExploitFixesModule.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/AnarchyExploitFixesModule.java index f3c645884..3e7ef40c5 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/AnarchyExploitFixesModule.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/AnarchyExploitFixesModule.java @@ -9,7 +9,7 @@ import me.moomoo.anarchyexploitfixes.modules.combat.*; import me.moomoo.anarchyexploitfixes.modules.dupepreventions.*; import me.moomoo.anarchyexploitfixes.modules.elytra.*; -import me.moomoo.anarchyexploitfixes.modules.elytra.helper.ElytraHelper; +import me.moomoo.anarchyexploitfixes.modules.elytra.ElytraHelper; import me.moomoo.anarchyexploitfixes.modules.illegals.items.RemoveSpecificItemNames; import me.moomoo.anarchyexploitfixes.modules.illegals.items.RevertOverstacked; import me.moomoo.anarchyexploitfixes.modules.illegals.items.RevertUnbreakables; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraAtSpawn.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraAtSpawn.java index ddf93454c..1d1bba529 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraAtSpawn.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraAtSpawn.java @@ -4,7 +4,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.config.LanguageCache; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import me.moomoo.anarchyexploitfixes.modules.elytra.helper.ElytraHelper; import me.moomoo.anarchyexploitfixes.utils.LocationUtil; import me.moomoo.anarchyexploitfixes.utils.MaterialUtil; import net.kyori.adventure.text.Component; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraGlobal.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraGlobal.java index 40756d4f0..9ad5f36bf 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraGlobal.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraGlobal.java @@ -4,7 +4,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.config.LanguageCache; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import me.moomoo.anarchyexploitfixes.modules.elytra.helper.ElytraHelper; import me.moomoo.anarchyexploitfixes.utils.LocationUtil; import me.moomoo.anarchyexploitfixes.utils.MaterialUtil; import net.kyori.adventure.text.Component; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java new file mode 100755 index 000000000..ce0942d38 --- /dev/null +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java @@ -0,0 +1,184 @@ +package me.moomoo.anarchyexploitfixes.modules.elytra; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes; +import me.moomoo.anarchyexploitfixes.config.Config; +import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; +import me.moomoo.anarchyexploitfixes.utils.LocationUtil; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityToggleGlideEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.util.NumberConversions; + +import java.time.Duration; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ElytraHelper implements AnarchyExploitFixesModule, Listener { + private static ElytraHelper instance; + public static final double SPEED_TOLERANCE = 0.02; + + private final AnarchyExploitFixes plugin; + private final boolean calculate3D; + + private final Set PLAYERS_GLIDING; + private final Set PLAYERS_NEAR_NEW_CHUNKS; + private ScheduledTask scheduledSpeedCheck; + private final Cache PLAYER_SPEEDS; + private final Cache LAST_GLIDE_POS; + private final int checkIntervalTicks; + private final boolean doIntervalCheck; + + public ElytraHelper() { + instance = this; + this.plugin = AnarchyExploitFixes.getInstance(); + this.calculate3D = AnarchyExploitFixes.getConfiguration().elytra_calculate_3D; + this.PLAYERS_GLIDING = plugin.getServer().getOnlinePlayers().stream() + .filter(LivingEntity::isGliding) + .map(Player::getUniqueId) + .collect(Collectors.toCollection(HashSet::new)); + this.PLAYERS_NEAR_NEW_CHUNKS = new HashSet<>(plugin.getServer().getOnlinePlayers().size()); + Config config = AnarchyExploitFixes.getConfiguration(); + this.doIntervalCheck = config.getBoolean("elytra.patch-generic-speedhacks.enable", true, + "Patches speed-limit bypass using generic speedhacks (Timer) by additionally checking player position every x ticks"); + final int tickInterval = config.getInt("elytra.patch-generic-speedhacks.check-interval-in-ticks", 10, + "Lower value means more accuracy but also more overhead."); + this.checkIntervalTicks = Math.max(tickInterval, 1); + final Duration cacheTime = Duration.ofMillis(Math.max(1000, (tickInterval * 50L) + 100L)); + this.PLAYER_SPEEDS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); + this.LAST_GLIDE_POS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); + } + + public static ElytraHelper getInstance() { + return instance; + } + + @Override + public String name() { + return "elytra-helper"; + } + + @Override + public String category() { + return "elytra"; + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + this.scheduledSpeedCheck = plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(plugin, + scheduleChecks -> this.run(), checkIntervalTicks, checkIntervalTicks); + } + + @Override + public boolean shouldEnable() { + Config config = AnarchyExploitFixes.getConfiguration(); + return config.elytra_enable_at_spawn || config.elytra_enable_global || config.elytra_enable_netherceiling; + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + if (scheduledSpeedCheck != null) scheduledSpeedCheck.cancel(); + } + + public Location getFrom(PlayerMoveEvent event) { + final Location lastGlidePos = LAST_GLIDE_POS.getIfPresent(event.getPlayer().getUniqueId()); + return lastGlidePos != null ? lastGlidePos : event.getFrom(); + } + + public double getBlocksPerTick(PlayerMoveEvent event) { + double eventSpeed = calculate3D ? LocationUtil.getRelDistance3D(event.getTo(), event.getFrom()) : LocationUtil.getRelDistance2D(event.getTo(), event.getFrom()); + if (doIntervalCheck) { + Double speedInterval = PLAYER_SPEEDS.getIfPresent(event.getPlayer().getUniqueId()); + if (speedInterval != null) return Math.max(speedInterval, eventSpeed); + } + return eventSpeed; + } + + public boolean isInNewChunks(UUID playerUniqueId) { + return PLAYERS_NEAR_NEW_CHUNKS.contains(playerUniqueId); + } + + public boolean isGliding(Player player) { + return PLAYERS_GLIDING.contains(player.getUniqueId()) || player.isGliding(); + } + + private void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + player.getScheduler().run(plugin, checkFlight -> { + if (isGliding(player)) { + Location currentLocation = player.getLocation().clone(); + Location lastLocation = this.LAST_GLIDE_POS.getIfPresent(player.getUniqueId()); + if (lastLocation != null) this.PLAYER_SPEEDS.put( + player.getUniqueId(), + calculate3D ? LocationUtil.getRelDistance3D(lastLocation, currentLocation) : LocationUtil.getRelDistance2D(lastLocation, currentLocation) / checkIntervalTicks + ); + this.LAST_GLIDE_POS.put(player.getUniqueId(), currentLocation); + } + }, null); + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onGlideToggle(EntityToggleGlideEvent event) { + if (event.getEntityType() == EntityType.PLAYER) { + if (event.isGliding()) { + this.PLAYERS_GLIDING.add(event.getEntity().getUniqueId()); + } else { + this.PLAYERS_GLIDING.remove(event.getEntity().getUniqueId()); + } + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onQuit(PlayerQuitEvent event) { + this.PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onJoin(PlayerJoinEvent event) { + if (event.getPlayer().isGliding()) { + this.PLAYERS_GLIDING.add(event.getPlayer().getUniqueId()); + } else { + this.PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + private void onChunkLoad(ChunkLoadEvent event) { + for (Player player : event.getWorld().getPlayers()) { + if (this.getChunkDistanceSquared(event.getChunk(), player.getLocation().clone()) < NumberConversions.square(player.getViewDistance())) { + if (event.isNewChunk()) { + this.PLAYERS_NEAR_NEW_CHUNKS.add(player.getUniqueId()); + } else { + this.PLAYERS_NEAR_NEW_CHUNKS.remove(player.getUniqueId()); + } + } + } + } + + /** + * Since the distance here is only used to see whether a chunk is loaded roughly within the player's view distance, + * we can resort to comparing squared distances. + * This saves cpu usage as we don't have to use {@link Math#sqrt(double)} to get the accurate distance in chunks. + */ + private double getChunkDistanceSquared(Chunk chunk, Location location) { + return NumberConversions.square(chunk.getX() - location.getBlockX() >> 4) + NumberConversions.square(chunk.getZ() - location.getBlockZ() >> 4); + } +} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraOnCeiling.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraOnCeiling.java index ec053c457..96c6c29a5 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraOnCeiling.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraOnCeiling.java @@ -4,7 +4,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.config.LanguageCache; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import me.moomoo.anarchyexploitfixes.modules.elytra.helper.ElytraHelper; import me.moomoo.anarchyexploitfixes.utils.LocationUtil; import me.moomoo.anarchyexploitfixes.utils.MaterialUtil; import net.kyori.adventure.text.Component; diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ChunkListener.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ChunkListener.java deleted file mode 100644 index cb4232fef..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ChunkListener.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.moomoo.anarchyexploitfixes.modules.elytra.helper; - -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; -import org.bukkit.util.NumberConversions; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -public class ChunkListener extends ElytraHelper implements Listener { - - public final Set PLAYERS_NEAR_NEW_CHUNKS; - - public ChunkListener() { - this.PLAYERS_NEAR_NEW_CHUNKS = new HashSet<>(); - } - - @EventHandler(priority = EventPriority.LOWEST) - private void onChunkLoad(ChunkLoadEvent event) { - for (Player player : event.getWorld().getPlayers()) { - if (this.getChunkDistanceSquared(event.getChunk(), player.getLocation().clone()) < NumberConversions.square(player.getViewDistance())) { - if (event.isNewChunk()) { - this.PLAYERS_NEAR_NEW_CHUNKS.add(player.getUniqueId()); - } else { - this.PLAYERS_NEAR_NEW_CHUNKS.remove(player.getUniqueId()); - } - } - } - } - - /** - * Since the distance here is only used to see whether a chunk is loaded roughly within the player's view distance, - * we can resort to comparing squared distances. - * This saves cpu usage as we don't have to use {@link Math#sqrt(double)} to get the accurate distance in chunks. - */ - private double getChunkDistanceSquared(Chunk chunk, Location location) { - return NumberConversions.square(chunk.getX() - location.getBlockX() >> 4) + NumberConversions.square(chunk.getZ() - location.getBlockZ() >> 4); - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ElytraHelper.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ElytraHelper.java deleted file mode 100755 index c9dcae792..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ElytraHelper.java +++ /dev/null @@ -1,89 +0,0 @@ -package me.moomoo.anarchyexploitfixes.modules.elytra.helper; - -import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes; -import me.moomoo.anarchyexploitfixes.config.Config; -import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import me.moomoo.anarchyexploitfixes.utils.LocationUtil; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; -import org.bukkit.event.player.PlayerMoveEvent; - -import java.util.UUID; - -public class ElytraHelper implements AnarchyExploitFixesModule { - private static ElytraHelper instance; - public static final double SPEED_TOLERANCE = 0.02; - - protected final AnarchyExploitFixes plugin; - protected final boolean calculate3D; - - private GlideListener glideListener; - private ChunkListener chunkListener; - private IntervalCheck intervalCheck; - - public ElytraHelper() { - instance = this; - this.plugin = AnarchyExploitFixes.getInstance(); - this.calculate3D = AnarchyExploitFixes.getConfiguration().elytra_calculate_3D; - } - - public static ElytraHelper getInstance() { - return instance; - } - - @Override - public String name() { - return "elytra-helper"; - } - - @Override - public String category() { - return "elytra"; - } - - @Override - public void enable() { - glideListener = new GlideListener(); - plugin.getServer().getPluginManager().registerEvents(glideListener, plugin); - chunkListener = new ChunkListener(); - plugin.getServer().getPluginManager().registerEvents(chunkListener, plugin); - intervalCheck = new IntervalCheck(); - intervalCheck.startIfEnabled(); - } - - @Override - public boolean shouldEnable() { - Config config = AnarchyExploitFixes.getConfiguration(); - return config.elytra_enable_at_spawn || config.elytra_enable_global || config.elytra_enable_netherceiling; - } - - @Override - public void disable() { - HandlerList.unregisterAll(glideListener); - HandlerList.unregisterAll(chunkListener); - intervalCheck.stopIfEnabled(); - } - - public Location getFrom(PlayerMoveEvent event) { - final Location lastGlidePos = intervalCheck.LAST_GLIDE_POS.getIfPresent(event.getPlayer().getUniqueId()); - return lastGlidePos != null ? lastGlidePos : event.getFrom(); - } - - public double getBlocksPerTick(PlayerMoveEvent event) { - double eventSpeed = calculate3D ? LocationUtil.getRelDistance3D(event.getTo(), event.getFrom()) : LocationUtil.getRelDistance2D(event.getTo(), event.getFrom()); - if (intervalCheck.isEnabled) { - Double speedInterval = intervalCheck.PLAYER_SPEEDS.getIfPresent(event.getPlayer().getUniqueId()); - if (speedInterval != null) return Math.max(speedInterval, eventSpeed); - } - return eventSpeed; - } - - public boolean isInNewChunks(UUID playerUniqueId) { - return chunkListener.PLAYERS_NEAR_NEW_CHUNKS.contains(playerUniqueId); - } - - public boolean isGliding(Player player) { - return glideListener.PLAYERS_GLIDING.contains(player.getUniqueId()) || player.isGliding(); - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/GlideListener.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/GlideListener.java deleted file mode 100644 index 8ecaf5aa4..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/GlideListener.java +++ /dev/null @@ -1,54 +0,0 @@ -package me.moomoo.anarchyexploitfixes.modules.elytra.helper; - -import org.bukkit.Bukkit; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityToggleGlideEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -public class GlideListener extends ElytraHelper implements Listener { - - public final Set PLAYERS_GLIDING; - - public GlideListener() { - this.PLAYERS_GLIDING = Bukkit.getOnlinePlayers().stream() - .filter(LivingEntity::isGliding) - .map(Player::getUniqueId) - .collect(Collectors.toCollection(HashSet::new)); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onGlideToggle(EntityToggleGlideEvent event) { - if (event.getEntityType() == EntityType.PLAYER) { - if (event.isGliding()) { - this.PLAYERS_GLIDING.add(event.getEntity().getUniqueId()); - } else { - this.PLAYERS_GLIDING.remove(event.getEntity().getUniqueId()); - } - } - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onQuit(PlayerQuitEvent event) { - this.PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onJoin(PlayerJoinEvent event) { - if (event.getPlayer().isGliding()) { - this.PLAYERS_GLIDING.add(event.getPlayer().getUniqueId()); - } else { - this.PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); - } - } -} diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/IntervalCheck.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/IntervalCheck.java deleted file mode 100644 index d424af304..000000000 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/IntervalCheck.java +++ /dev/null @@ -1,59 +0,0 @@ -package me.moomoo.anarchyexploitfixes.modules.elytra.helper; - -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; -import io.papermc.paper.threadedregions.scheduler.ScheduledTask; -import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes; -import me.moomoo.anarchyexploitfixes.config.Config; -import me.moomoo.anarchyexploitfixes.utils.LocationUtil; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import java.time.Duration; -import java.util.UUID; - -public class IntervalCheck extends ElytraHelper { - - public ScheduledTask scheduledTask; - public final Cache PLAYER_SPEEDS; - public final Cache LAST_GLIDE_POS; - private final int checkIntervalTicks; - public final boolean isEnabled; - - public IntervalCheck() { - Config config = AnarchyExploitFixes.getConfiguration(); - this.isEnabled = config.getBoolean("elytra.patch-generic-speedhacks.enable", true, - "Patches speed-limit bypass using generic speedhacks (Timer) by additionally checking player position every x ticks"); - final int tickInterval = config.getInt("elytra.patch-generic-speedhacks.check-interval-in-ticks", 10, - "Lower value means more accuracy but also more overhead."); - this.checkIntervalTicks = Math.max(tickInterval, 1); - final Duration cacheTime = Duration.ofMillis(Math.max(1000, (tickInterval * 50L) + 100L)); - this.PLAYER_SPEEDS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); - this.LAST_GLIDE_POS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); - } - - public void startIfEnabled() { - if (isEnabled) this.scheduledTask = super.plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(plugin, - scheduleChecks -> this.run(), checkIntervalTicks, checkIntervalTicks); - } - - public void stopIfEnabled() { - if (scheduledTask != null) scheduledTask.cancel(); - } - - private void run() { - for (Player player : super.plugin.getServer().getOnlinePlayers()) { - player.getScheduler().run(plugin, checkFlight -> { - if (super.isGliding(player)) { - Location currentLocation = player.getLocation().clone(); - Location lastLocation = this.LAST_GLIDE_POS.getIfPresent(player.getUniqueId()); - if (lastLocation != null) this.PLAYER_SPEEDS.put( - player.getUniqueId(), - calculate3D ? LocationUtil.getRelDistance3D(lastLocation, currentLocation) : LocationUtil.getRelDistance2D(lastLocation, currentLocation) / checkIntervalTicks - ); - this.LAST_GLIDE_POS.put(player.getUniqueId(), currentLocation); - } - }, null); - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/AnarchyExploitFixesModule.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/AnarchyExploitFixesModule.java index 6afab1a05..c6bc0629e 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/AnarchyExploitFixesModule.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/AnarchyExploitFixesModule.java @@ -9,7 +9,7 @@ import me.moomoo.anarchyexploitfixes.modules.combat.*; import me.moomoo.anarchyexploitfixes.modules.dupepreventions.*; import me.moomoo.anarchyexploitfixes.modules.elytra.*; -import me.moomoo.anarchyexploitfixes.modules.elytra.helper.ElytraHelper; +import me.moomoo.anarchyexploitfixes.modules.elytra.ElytraHelper; import me.moomoo.anarchyexploitfixes.modules.illegals.items.RemoveSpecificItemNames; import me.moomoo.anarchyexploitfixes.modules.illegals.items.RevertOverstacked; import me.moomoo.anarchyexploitfixes.modules.illegals.items.RevertUnbreakables; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraAtSpawn.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraAtSpawn.java index d2bfebb6f..95b35367e 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraAtSpawn.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraAtSpawn.java @@ -4,7 +4,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.config.LanguageCache; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import me.moomoo.anarchyexploitfixes.modules.elytra.helper.ElytraHelper; import me.moomoo.anarchyexploitfixes.utils.LocationUtil; import me.moomoo.anarchyexploitfixes.utils.MaterialUtil; import org.bukkit.Location; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraGlobal.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraGlobal.java index 6d71a3fc6..e15b369bf 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraGlobal.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraGlobal.java @@ -4,7 +4,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.config.LanguageCache; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import me.moomoo.anarchyexploitfixes.modules.elytra.helper.ElytraHelper; import me.moomoo.anarchyexploitfixes.utils.LocationUtil; import me.moomoo.anarchyexploitfixes.utils.MaterialUtil; import org.bukkit.Location; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java new file mode 100755 index 000000000..9b5ee399f --- /dev/null +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java @@ -0,0 +1,173 @@ +package me.moomoo.anarchyexploitfixes.modules.elytra; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes; +import me.moomoo.anarchyexploitfixes.config.Config; +import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; +import me.moomoo.anarchyexploitfixes.utils.LocationUtil; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityToggleGlideEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.util.NumberConversions; + +import java.time.Duration; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ElytraHelper implements AnarchyExploitFixesModule, Runnable, Listener { + private static ElytraHelper instance; + public static final double SPEED_TOLERANCE = 0.02; + + private final AnarchyExploitFixes plugin; + private final boolean calculate3D; + + private final Set PLAYERS_GLIDING; + private final Set PLAYERS_NEAR_NEW_CHUNKS; + private final Cache PLAYER_SPEEDS; + private final Cache LAST_GLIDE_POS; + private final int checkIntervalTicks; + private final boolean doIntervalCheck; + + public ElytraHelper() { + instance = this; + this.plugin = AnarchyExploitFixes.getInstance(); + this.calculate3D = AnarchyExploitFixes.getConfiguration().elytra_calculate_3D; + this.PLAYERS_GLIDING = plugin.getServer().getOnlinePlayers().stream() + .filter(LivingEntity::isGliding) + .map(Player::getUniqueId) + .collect(Collectors.toCollection(HashSet::new)); + this.PLAYERS_NEAR_NEW_CHUNKS = new HashSet<>(plugin.getServer().getOnlinePlayers().size()); + Config config = AnarchyExploitFixes.getConfiguration(); + this.doIntervalCheck = config.getBoolean("elytra.patch-generic-speedhacks.enable", true, + "Patches speed-limit bypass using generic speedhacks (Timer) by additionally checking player position every x ticks"); + final int tickInterval = config.getInt("elytra.patch-generic-speedhacks.check-interval-in-ticks", 10, + "Lower value means more accuracy but also more overhead."); + this.checkIntervalTicks = Math.max(tickInterval, 1); + final Duration cacheTime = Duration.ofMillis(Math.max(1000, (tickInterval * 50L) + 100L)); + this.PLAYER_SPEEDS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); + this.LAST_GLIDE_POS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); + } + + public static ElytraHelper getInstance() { + return instance; + } + + @Override + public String name() { + return "elytra-helper"; + } + + @Override + public String category() { + return "elytra"; + } + + @Override + public void enable() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, this, checkIntervalTicks, checkIntervalTicks); + } + + @Override + public boolean shouldEnable() { + Config config = AnarchyExploitFixes.getConfiguration(); + return config.elytra_enable_at_spawn || config.elytra_enable_global || config.elytra_enable_netherceiling; + } + + public Location getFrom(PlayerMoveEvent event) { + final Location lastGlidePos = LAST_GLIDE_POS.getIfPresent(event.getPlayer().getUniqueId()); + return lastGlidePos != null ? lastGlidePos : event.getFrom(); + } + + public double getBlocksPerTick(PlayerMoveEvent event) { + double eventSpeed = calculate3D ? LocationUtil.getRelDistance3D(event.getTo(), event.getFrom()) : LocationUtil.getRelDistance2D(event.getTo(), event.getFrom()); + if (doIntervalCheck) { + Double speedInterval = PLAYER_SPEEDS.getIfPresent(event.getPlayer().getUniqueId()); + if (speedInterval != null) return Math.max(speedInterval, eventSpeed); + } + return eventSpeed; + } + + public boolean isInNewChunks(UUID playerUniqueId) { + return PLAYERS_NEAR_NEW_CHUNKS.contains(playerUniqueId); + } + + public boolean isGliding(Player player) { + return PLAYERS_GLIDING.contains(player.getUniqueId()) || player.isGliding(); + } + + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + if (this.isGliding(player)) { + Location currentLocation = player.getLocation().clone(); + Location lastLocation = LAST_GLIDE_POS.getIfPresent(player.getUniqueId()); + if (lastLocation != null) this.PLAYER_SPEEDS.put( + player.getUniqueId(), + calculate3D ? LocationUtil.getRelDistance3D(lastLocation, currentLocation) : LocationUtil.getRelDistance2D(lastLocation, currentLocation) / checkIntervalTicks + ); + LAST_GLIDE_POS.put(player.getUniqueId(), currentLocation); + } + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onGlideToggle(EntityToggleGlideEvent event) { + if (event.getEntityType() == EntityType.PLAYER) { + if (event.isGliding()) { + this.PLAYERS_GLIDING.add(event.getEntity().getUniqueId()); + } else { + this.PLAYERS_GLIDING.remove(event.getEntity().getUniqueId()); + } + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onQuit(PlayerQuitEvent event) { + this.PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onJoin(PlayerJoinEvent event) { + if (event.getPlayer().isGliding()) { + this.PLAYERS_GLIDING.add(event.getPlayer().getUniqueId()); + } else { + this.PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + private void onChunkLoad(ChunkLoadEvent event) { + for (Player player : event.getWorld().getPlayers()) { + if (this.getChunkDistanceSquared(event.getChunk(), player.getLocation().clone()) < NumberConversions.square(player.getViewDistance())) { + if (event.isNewChunk()) { + this.PLAYERS_NEAR_NEW_CHUNKS.add(player.getUniqueId()); + } else { + this.PLAYERS_NEAR_NEW_CHUNKS.remove(player.getUniqueId()); + } + } + } + } + + /** + * Since the distance here is only used to see whether a chunk is loaded roughly within the player's view distance, + * we can resort to comparing squared distances. + * This saves cpu usage as we don't have to use {@link Math#sqrt(double)} to get the accurate distance in chunks. + */ + private double getChunkDistanceSquared(Chunk chunk, Location location) { + return NumberConversions.square(chunk.getX() - location.getBlockX() >> 4) + NumberConversions.square(chunk.getZ() - location.getBlockZ() >> 4); + } +} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraOnCeiling.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraOnCeiling.java index 36092207f..ef24f54d2 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraOnCeiling.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraOnCeiling.java @@ -4,7 +4,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.config.LanguageCache; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import me.moomoo.anarchyexploitfixes.modules.elytra.helper.ElytraHelper; import me.moomoo.anarchyexploitfixes.utils.LocationUtil; import me.moomoo.anarchyexploitfixes.utils.MaterialUtil; import org.bukkit.Location; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ChunkListener.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ChunkListener.java deleted file mode 100644 index cb4232fef..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ChunkListener.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.moomoo.anarchyexploitfixes.modules.elytra.helper; - -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; -import org.bukkit.util.NumberConversions; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -public class ChunkListener extends ElytraHelper implements Listener { - - public final Set PLAYERS_NEAR_NEW_CHUNKS; - - public ChunkListener() { - this.PLAYERS_NEAR_NEW_CHUNKS = new HashSet<>(); - } - - @EventHandler(priority = EventPriority.LOWEST) - private void onChunkLoad(ChunkLoadEvent event) { - for (Player player : event.getWorld().getPlayers()) { - if (this.getChunkDistanceSquared(event.getChunk(), player.getLocation().clone()) < NumberConversions.square(player.getViewDistance())) { - if (event.isNewChunk()) { - this.PLAYERS_NEAR_NEW_CHUNKS.add(player.getUniqueId()); - } else { - this.PLAYERS_NEAR_NEW_CHUNKS.remove(player.getUniqueId()); - } - } - } - } - - /** - * Since the distance here is only used to see whether a chunk is loaded roughly within the player's view distance, - * we can resort to comparing squared distances. - * This saves cpu usage as we don't have to use {@link Math#sqrt(double)} to get the accurate distance in chunks. - */ - private double getChunkDistanceSquared(Chunk chunk, Location location) { - return NumberConversions.square(chunk.getX() - location.getBlockX() >> 4) + NumberConversions.square(chunk.getZ() - location.getBlockZ() >> 4); - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ElytraHelper.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ElytraHelper.java deleted file mode 100755 index 78d413bd1..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ElytraHelper.java +++ /dev/null @@ -1,81 +0,0 @@ -package me.moomoo.anarchyexploitfixes.modules.elytra.helper; - -import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes; -import me.moomoo.anarchyexploitfixes.config.Config; -import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import me.moomoo.anarchyexploitfixes.utils.LocationUtil; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerMoveEvent; - -import java.util.UUID; - -public class ElytraHelper implements AnarchyExploitFixesModule { - private static ElytraHelper instance; - public static final double SPEED_TOLERANCE = 0.02; - - protected final AnarchyExploitFixes plugin; - protected final boolean calculate3D; - - private GlideListener glideListener; - private ChunkListener chunkListener; - private IntervalCheck intervalCheck; - - public ElytraHelper() { - instance = this; - this.plugin = AnarchyExploitFixes.getInstance(); - this.calculate3D = AnarchyExploitFixes.getConfiguration().elytra_calculate_3D; - } - - public static ElytraHelper getInstance() { - return instance; - } - - @Override - public String name() { - return "elytra-helper"; - } - - @Override - public String category() { - return "elytra"; - } - - @Override - public void enable() { - this.glideListener = new GlideListener(); - plugin.getServer().getPluginManager().registerEvents(glideListener, plugin); - this.chunkListener = new ChunkListener(); - plugin.getServer().getPluginManager().registerEvents(chunkListener, plugin); - this.intervalCheck = new IntervalCheck(); - intervalCheck.startIfEnabled(); - } - - @Override - public boolean shouldEnable() { - Config config = AnarchyExploitFixes.getConfiguration(); - return config.elytra_enable_at_spawn || config.elytra_enable_global || config.elytra_enable_netherceiling; - } - - public Location getFrom(PlayerMoveEvent event) { - final Location lastGlidePos = intervalCheck.LAST_GLIDE_POS.getIfPresent(event.getPlayer().getUniqueId()); - return lastGlidePos != null ? lastGlidePos : event.getFrom(); - } - - public double getBlocksPerTick(PlayerMoveEvent event) { - double eventSpeed = calculate3D ? LocationUtil.getRelDistance3D(event.getTo(), event.getFrom()) : LocationUtil.getRelDistance2D(event.getTo(), event.getFrom()); - if (intervalCheck.isEnabled) { - Double speedInterval = intervalCheck.PLAYER_SPEEDS.getIfPresent(event.getPlayer().getUniqueId()); - if (speedInterval != null) return Math.max(speedInterval, eventSpeed); - } - return eventSpeed; - } - - public boolean isInNewChunks(UUID playerUniqueId) { - return chunkListener.PLAYERS_NEAR_NEW_CHUNKS.contains(playerUniqueId); - } - - public boolean isGliding(Player player) { - return glideListener.PLAYERS_GLIDING.contains(player.getUniqueId()) || player.isGliding(); - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/GlideListener.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/GlideListener.java deleted file mode 100644 index 8ecaf5aa4..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/GlideListener.java +++ /dev/null @@ -1,54 +0,0 @@ -package me.moomoo.anarchyexploitfixes.modules.elytra.helper; - -import org.bukkit.Bukkit; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityToggleGlideEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -public class GlideListener extends ElytraHelper implements Listener { - - public final Set PLAYERS_GLIDING; - - public GlideListener() { - this.PLAYERS_GLIDING = Bukkit.getOnlinePlayers().stream() - .filter(LivingEntity::isGliding) - .map(Player::getUniqueId) - .collect(Collectors.toCollection(HashSet::new)); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onGlideToggle(EntityToggleGlideEvent event) { - if (event.getEntityType() == EntityType.PLAYER) { - if (event.isGliding()) { - this.PLAYERS_GLIDING.add(event.getEntity().getUniqueId()); - } else { - this.PLAYERS_GLIDING.remove(event.getEntity().getUniqueId()); - } - } - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onQuit(PlayerQuitEvent event) { - this.PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onJoin(PlayerJoinEvent event) { - if (event.getPlayer().isGliding()) { - this.PLAYERS_GLIDING.add(event.getPlayer().getUniqueId()); - } else { - this.PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); - } - } -} diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/IntervalCheck.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/IntervalCheck.java deleted file mode 100644 index 8c91b3d12..000000000 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/IntervalCheck.java +++ /dev/null @@ -1,51 +0,0 @@ -package me.moomoo.anarchyexploitfixes.modules.elytra.helper; - -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; -import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes; -import me.moomoo.anarchyexploitfixes.config.Config; -import me.moomoo.anarchyexploitfixes.utils.LocationUtil; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import java.time.Duration; -import java.util.UUID; - -public class IntervalCheck extends ElytraHelper implements Runnable { - - public final Cache PLAYER_SPEEDS; - public final Cache LAST_GLIDE_POS; - private final int checkIntervalTicks; - public final boolean isEnabled; - - public IntervalCheck() { - Config config = AnarchyExploitFixes.getConfiguration(); - this.isEnabled = config.getBoolean("elytra.patch-generic-speedhacks.enable", true, - "Patches speed-limit bypass using generic speedhacks (Timer) by additionally checking player position every x ticks"); - final int tickInterval = config.getInt("elytra.patch-generic-speedhacks.check-interval-in-ticks", 10, - "Lower value means more accuracy but also more overhead."); - this.checkIntervalTicks = Math.max(tickInterval, 1); - final Duration cacheTime = Duration.ofMillis(Math.max(1000, (tickInterval * 50L) + 100L)); - this.PLAYER_SPEEDS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); - this.LAST_GLIDE_POS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); - } - - public void startIfEnabled() { - if (isEnabled) super.plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, this, checkIntervalTicks, checkIntervalTicks); - } - - @Override - public void run() { - for (Player player : super.plugin.getServer().getOnlinePlayers()) { - if (this.isGliding(player)) { - Location currentLocation = player.getLocation().clone(); - Location lastLocation = LAST_GLIDE_POS.getIfPresent(player.getUniqueId()); - if (lastLocation != null) this.PLAYER_SPEEDS.put( - player.getUniqueId(), - calculate3D ? LocationUtil.getRelDistance3D(lastLocation, currentLocation) : LocationUtil.getRelDistance2D(lastLocation, currentLocation) / checkIntervalTicks - ); - LAST_GLIDE_POS.put(player.getUniqueId(), currentLocation); - } - } - } -}