diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/dupepreventions/EndPortalDupe.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/dupepreventions/EndPortalDupe.java index 512e5f0bc..97c553cf8 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/dupepreventions/EndPortalDupe.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/dupepreventions/EndPortalDupe.java @@ -2,7 +2,6 @@ import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import org.apache.commons.math3.util.FastMath; import org.bukkit.World; import org.bukkit.entity.ChestedHorse; import org.bukkit.entity.LivingEntity; @@ -64,8 +63,8 @@ private void onEntityDamage(EntityDamageEvent event) { ) { if ( livingEntity.getHealth() - event.getDamage() <= 0 - && FastMath.round(livingEntity.getLocation().getX()) == 100 - && FastMath.round(livingEntity.getLocation().getZ()) == 0 + && Math.round(livingEntity.getLocation().getX()) == 100 + && Math.round(livingEntity.getLocation().getZ()) == 0 ) { livingEntity.getScheduler().run(plugin, kill -> livingEntity.remove(), null); } 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 3550dcb76..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 @@ -79,12 +79,12 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); - if (!player.isGliding()) return; + if (!ElytraHelper.getInstance().isGliding(player)) return; if (!event.hasExplicitlyChangedPosition()) return; if (spawn_shouldCheckPermission && player.hasPermission("anarchyexploitfixes.bypass")) return; Location playerLoc = player.getLocation(); if (ceilingSettingsEnabled && LocationUtil.isNetherCeiling(playerLoc)) return; - if (LocationUtil.getFlatDistanceTo00(playerLoc) > spawn_Radius) return; + if (LocationUtil.getDistance2DTo00(playerLoc) > spawn_Radius) return; if (spawn_DenyElytra) { if (teleportBack) player.teleportAsync(ElytraHelper.getInstance().getFrom(event)); 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 6a222b0f5..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 @@ -89,12 +89,12 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); - if (!player.isGliding()) return; + if (!ElytraHelper.getInstance().isGliding(player)) return; if (!event.hasExplicitlyChangedPosition()) return; if (global_shouldCheckPermission && player.hasPermission("anarchyexploitfixes.bypass")) return; Location playerLoc = player.getLocation(); if (ceiling_SettingsEnabled && LocationUtil.isNetherCeiling(playerLoc)) return; - if (spawn_SettingsEnabled && LocationUtil.getFlatDistanceTo00(playerLoc) <= spawn_Radius) return; + if (spawn_SettingsEnabled && LocationUtil.getDistance2DTo00(playerLoc) <= spawn_Radius) return; if (global_DenyElytra) { if (teleportBack) player.teleportAsync(ElytraHelper.getInstance().getFrom(event)); 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 index 9fe10991e..135f7ad32 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java @@ -7,16 +7,20 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; import me.moomoo.anarchyexploitfixes.utils.LocationUtil; -import org.apache.commons.math3.util.FastMath; import org.bukkit.Chunk; import org.bukkit.Location; +import org.bukkit.entity.EntityType; 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; @@ -26,6 +30,7 @@ public class ElytraHelper implements AnarchyExploitFixesModule, Listener { private static ElytraHelper instance; private final AnarchyExploitFixes plugin; + private final Set PLAYERS_GLIDING; private final Set PLAYERS_NEAR_NEW_CHUNKS; private final Cache PLAYER_SPEEDS_INTERVAL; private final Cache LAST_GLIDE_POS; @@ -37,14 +42,15 @@ public class ElytraHelper implements AnarchyExploitFixesModule, Listener { public ElytraHelper() { instance = this; this.plugin = AnarchyExploitFixes.getInstance(); + this.PLAYERS_GLIDING = new HashSet<>(); 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 = FastMath.max(tickInterval, 1); - final Duration cacheTime = Duration.ofMillis(FastMath.max(1000, (tickInterval * 50L) + 100L)); + this.checkIntervalTicks = Math.max(tickInterval, 1); + final Duration cacheTime = Duration.ofMillis(Math.max(1000, (tickInterval * 50L) + 100L)); this.PLAYER_SPEEDS_INTERVAL = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); this.LAST_GLIDE_POS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); } @@ -70,11 +76,11 @@ public void enable() { CHECK_SCHEDULER = plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(plugin, scheduleChecks -> { for (Player player : plugin.getServer().getOnlinePlayers()) { player.getScheduler().run(plugin, checkFlight -> { - if (player.isGliding()) { + if (this.isGliding(player)) { Location currentLocation = player.getLocation().clone(); Location lastLocation = LAST_GLIDE_POS.getIfPresent(player.getUniqueId()); if (lastLocation != null) PLAYER_SPEEDS_INTERVAL.put(player.getUniqueId(), - LocationUtil.getNormalizedDistance(lastLocation, currentLocation) / checkIntervalTicks); + LocationUtil.getRelDistance3D(lastLocation, currentLocation) / checkIntervalTicks); LAST_GLIDE_POS.put(player.getUniqueId(), currentLocation); } }, null); @@ -94,14 +100,42 @@ public void disable() { if (CHECK_SCHEDULER != null) CHECK_SCHEDULER.cancel(); } - private double getFlatDistanceInChunks(Chunk chunk, Location location) { - return FastMath.hypot(chunk.getX() - location.getBlockX() >> 4, chunk.getZ() - location.getBlockZ() >> 4); + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onGlideToggle(EntityToggleGlideEvent event) { + if (event.getEntityType() != EntityType.PLAYER) return; + + if (event.isGliding()) { + PLAYERS_GLIDING.add(event.getEntity().getUniqueId()); + } else { + PLAYERS_GLIDING.remove(event.getEntity().getUniqueId()); + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onJoin(PlayerQuitEvent event) { + PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onJoin(PlayerJoinEvent event) { + if (event.getPlayer().isGliding()) { + PLAYERS_GLIDING.add(event.getPlayer().getUniqueId()); + } else { + PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); + } + } + + private double getChunkDistance(Chunk chunk, Location location) { + return Math.sqrt( + NumberConversions.square(chunk.getX() - location.getBlockX() >> 4) + + NumberConversions.square(chunk.getZ() - location.getBlockZ() >> 4) + ); } @EventHandler(priority = EventPriority.LOW) private void onChunkLoad(ChunkLoadEvent event) { for (Player player : event.getWorld().getPlayers()) { - if (this.getFlatDistanceInChunks(event.getChunk(), player.getLocation().clone()) < player.getViewDistance()) { + if (this.getChunkDistance(event.getChunk(), player.getLocation().clone()) < player.getViewDistance()) { if (event.isNewChunk()) { PLAYERS_NEAR_NEW_CHUNKS.add(player.getUniqueId()); } else { @@ -117,10 +151,10 @@ public Location getFrom(PlayerMoveEvent event) { } public double getBlocksPerTick(PlayerMoveEvent event) { - double eventSpeed = LocationUtil.getNormalizedDistance(event.getTo(), event.getFrom()); + double eventSpeed = LocationUtil.getRelDistance3D(event.getTo(), event.getFrom()); if (doIntervalCheck) { Double speedInterval = PLAYER_SPEEDS_INTERVAL.getIfPresent(event.getPlayer().getUniqueId()); - if (speedInterval != null) return FastMath.max(speedInterval, eventSpeed); + if (speedInterval != null) return Math.max(speedInterval, eventSpeed); } return eventSpeed; } @@ -128,4 +162,8 @@ public double getBlocksPerTick(PlayerMoveEvent event) { 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(); + } } 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 ddfdb07da..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 @@ -82,7 +82,7 @@ public void disable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); - if (!player.isGliding()) return; + if (!ElytraHelper.getInstance().isGliding(player)) return; if (!event.hasExplicitlyChangedPosition()) return; if (ceiling_shouldCheckPermission && player.hasPermission("anarchyexploitfixes.bypass")) return; Location playerLoc = player.getLocation(); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/lagpreventions/InventoryActionLag.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/lagpreventions/InventoryActionLag.java index 3bdf79a67..cf4fbcdbe 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/lagpreventions/InventoryActionLag.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/lagpreventions/InventoryActionLag.java @@ -7,7 +7,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; import me.moomoo.anarchyexploitfixes.utils.LogUtil; -import org.apache.commons.math3.util.FastMath; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.Entity; @@ -39,7 +38,7 @@ public InventoryActionLag() { Prevent lag generated by players quickly moving big items back and forth between inventories.\s Uses cached counters that auto-reset after the configurable time in milliseconds."""); this.logIsEnabled = config.getBoolean("lag-preventions.prevent-inventory-action-lag.log", true); - Duration cacheTime = Duration.ofMillis(FastMath.max(config.getInt("lag-preventions.prevent-inventory-action-lag.cache-time-millis", 2000, + Duration cacheTime = Duration.ofMillis(Math.max(config.getInt("lag-preventions.prevent-inventory-action-lag.cache-time-millis", 2000, "The amount of time in milliseconds an entry is kept after writing."), 1)); this.blockInventoryClicks = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); this.entityInventoryClicks = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/TeleportCoordExploit.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/TeleportCoordExploit.java index 154d393eb..d249e0cbb 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/TeleportCoordExploit.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/TeleportCoordExploit.java @@ -74,7 +74,7 @@ private void tempVanish(Player player) { private void onTeleport(PlayerTeleportEvent event) { switch (event.getCause()) { case ENDER_PEARL, COMMAND, PLUGIN -> { - if (LocationUtil.getFlatDistance(event.getFrom(), event.getTo()) >= minDistanceToVanishPlayers) { + if (LocationUtil.getRelDistance2D(event.getFrom(), event.getTo()) >= minDistanceToVanishPlayers) { this.tempVanish(event.getPlayer()); } } @@ -84,7 +84,7 @@ private void onTeleport(PlayerTeleportEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onSpawn(PlayerRespawnEvent event) { final Player player = event.getPlayer(); - if (LocationUtil.getFlatDistance(player.getLocation(), event.getRespawnLocation()) >= minDistanceToVanishPlayers) { + if (LocationUtil.getRelDistance2D(player.getLocation(), event.getRespawnLocation()) >= minDistanceToVanishPlayers) { this.tempVanish(player); } } diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/WorldChangeCrash.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/WorldChangeCrash.java index d6211f428..8295cfb4a 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/WorldChangeCrash.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/WorldChangeCrash.java @@ -5,7 +5,6 @@ import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; import me.moomoo.anarchyexploitfixes.utils.LogUtil; import me.moomoo.anarchyexploitfixes.utils.models.ExpiringSet; -import org.apache.commons.math3.util.FastMath; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; @@ -25,7 +24,7 @@ public WorldChangeCrash() { shouldEnable(); Config config = AnarchyExploitFixes.getConfiguration(); this.recentWorldChangers = new ExpiringSet<>(Duration.ofMillis( - FastMath.max(config.getInt("patches.crash-exploits.prevent-fast-world-teleport-crash.teleport-delay-millis", 1000, + Math.max(config.getInt("patches.crash-exploits.prevent-fast-world-teleport-crash.teleport-delay-millis", 1000, "Time in milliseconds until an entity can teleport to another world again."), 1))); config.addComment("patches.crash-exploits.prevent-fast-world-teleport-crash.enable", "Prevents crash methods that involve very fast teleporting between different worlds in a short time."); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/portals/EndPortalDestruction.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/portals/EndPortalDestruction.java index e3bffd410..179b17308 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/portals/EndPortalDestruction.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/portals/EndPortalDestruction.java @@ -166,7 +166,7 @@ private void onPistonExplode(EntityExplodeEvent event) { private boolean isWithinEndProtectedRadius(Location location) { if (!location.getWorld().getEnvironment().equals(World.Environment.THE_END)) return false; - return LocationUtil.getFlatDistanceTo00(location) <= endBedrockProtectRadius; + return LocationUtil.getDistance2DTo00(location) <= endBedrockProtectRadius; } private boolean isEndPortal(Material material) { diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/withers/WitherSpawningAtSpawn.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/withers/WitherSpawningAtSpawn.java index 0795670d4..66ccf7e2d 100755 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/withers/WitherSpawningAtSpawn.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/withers/WitherSpawningAtSpawn.java @@ -78,7 +78,7 @@ private void onCreatureSpawn(CreatureSpawnEvent event) { final Integer disabledRadius = worldsAndTheirRadiuses.get(world); Location witherLocation = wither.getLocation(); - if (LocationUtil.getFlatDistanceTo00(witherLocation) > disabledRadius) return; + if (LocationUtil.getDistance2DTo00(witherLocation) > disabledRadius) return; event.setCancelled(true); diff --git a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/utils/LocationUtil.java b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/utils/LocationUtil.java index 0e57c5c55..bd5a3f444 100644 --- a/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/utils/LocationUtil.java +++ b/AnarchyExploitFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/utils/LocationUtil.java @@ -4,15 +4,19 @@ import org.apache.commons.math3.util.FastMath; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.util.NumberConversions; public class LocationUtil { - public static double getFlatDistanceTo00(Location location) { - return FastMath.hypot(location.x(), location.z()); + public static boolean isNetherCeiling(Location location) { + return location.getWorld().getEnvironment() == World.Environment.NETHER + && location.y() > AnarchyExploitFixes.getConfiguration().nether_ceiling_max_y; } - public static double getFlatDistance(Location from, Location to) { + public static double getDistance2DTo00(Location location) { + return FastMath.hypot(location.getX(), location.getZ()); + } + + public static double getRelDistance2D(Location from, Location to) { double toX = to.x(); double toZ = to.z(); double fromX = from.x(); @@ -34,7 +38,7 @@ public static double getFlatDistance(Location from, Location to) { return FastMath.hypot(toX - fromX, toZ - fromZ); } - public static double getNormalizedDistance(Location from, Location to) { + public static double getRelDistance3D(Location from, Location to) { double toX = to.x(); double toZ = to.z(); double fromX = from.x(); @@ -53,13 +57,39 @@ public static double getNormalizedDistance(Location from, Location to) { } } - return Math.sqrt(NumberConversions.square(fromX - toX) - + NumberConversions.square(from.getY() - to.getY()) - + NumberConversions.square(fromZ - toZ)); + return getDistance3D(fromX - toX, from.y() - to.y(), fromZ - toZ); } - public static boolean isNetherCeiling(Location location) { - return location.getWorld().getEnvironment() == World.Environment.NETHER - && location.y() > AnarchyExploitFixes.getConfiguration().nether_ceiling_max_y; + public static double getDistance3D(final double x, final double y, final double z) { + if (Double.isInfinite(x) || Double.isInfinite(y) || Double.isInfinite(z)) { + return Double.POSITIVE_INFINITY; + } else if (Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z)) { + return Double.NaN; + } else { + final int expX = FastMath.getExponent(x); + final int expY = FastMath.getExponent(y); + final int expZ = FastMath.getExponent(z); + + if (expX > expY + 27 && expX > expZ + 27) { + // x is neglectible with respect to y and z + return FastMath.abs(y) + FastMath.abs(z); + } else if (expY > expX + 27 && expY > expZ + 27) { + // y is neglectible with respect to x and z + return FastMath.abs(x) + FastMath.abs(z); + } else if (expZ > expX + 27 && expZ > expY + 27) { + // z is neglectible with respect to x and y + return FastMath.abs(x) + FastMath.abs(y); + } else { + final int middleExp = (expX + expY + expZ) / 3; + + final double scaledX = FastMath.scalb(x, -middleExp); + final double scaledY = FastMath.scalb(y, -middleExp); + final double scaledZ = FastMath.scalb(z, -middleExp); + + final double scaledH = Math.sqrt(scaledX * scaledX + scaledY * scaledY + scaledZ * scaledZ); + + return FastMath.scalb(scaledH, middleExp); + } + } } } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/dupepreventions/EndPortalDupe.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/dupepreventions/EndPortalDupe.java index 1ceca8848..1680d9b6c 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/dupepreventions/EndPortalDupe.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/dupepreventions/EndPortalDupe.java @@ -2,7 +2,6 @@ import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; -import org.apache.commons.math3.util.FastMath; import org.bukkit.World; import org.bukkit.entity.ChestedHorse; import org.bukkit.entity.Entity; @@ -59,8 +58,8 @@ private void onEntityDamage(EntityDamageEvent event) { ) { if ( livingEntity.getHealth() - event.getDamage() <= 0 - && FastMath.round(livingEntity.getLocation().getX()) == 100 - && FastMath.round(livingEntity.getLocation().getZ()) == 0 + && Math.round(livingEntity.getLocation().getX()) == 100 + && Math.round(livingEntity.getLocation().getZ()) == 0 ) { livingEntity.remove(); } 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 eb7842555..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 @@ -70,11 +70,11 @@ public boolean shouldEnable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); - if (!player.isGliding()) return; + if (!ElytraHelper.getInstance().isGliding(player)) return; if (spawn_shouldCheckPermission && player.hasPermission("anarchyexploitfixes.bypass")) return; Location playerLoc = player.getLocation(); if (ceilingSettingsEnabled && LocationUtil.isNetherCeiling(playerLoc)) return; - if (LocationUtil.getFlatDistanceTo00(playerLoc) > spawn_Radius) return; + if (LocationUtil.getDistance2DTo00(playerLoc) > spawn_Radius) return; if (spawn_DenyElytra) { if (teleportBack) player.teleport(ElytraHelper.getInstance().getFrom(event)); 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 3871d0180..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 @@ -81,11 +81,11 @@ public boolean shouldEnable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); - if (!player.isGliding()) return; + if (!ElytraHelper.getInstance().isGliding(player)) return; if (global_shouldCheckPermission && player.hasPermission("anarchyexploitfixes.bypass")) return; Location playerLoc = player.getLocation(); if (ceiling_SettingsEnabled && LocationUtil.isNetherCeiling(playerLoc)) return; - if (spawn_SettingsEnabled && LocationUtil.getFlatDistanceTo00(playerLoc) <= spawn_Radius) return; + if (spawn_SettingsEnabled && LocationUtil.getDistance2DTo00(playerLoc) <= spawn_Radius) return; if (global_DenyElytra) { if (teleportBack) player.teleport(ElytraHelper.getInstance().getFrom(event)); 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 index a18ddb4e3..886ad834b 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java @@ -6,15 +6,19 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; import me.moomoo.anarchyexploitfixes.utils.LocationUtil; -import org.apache.commons.math3.util.FastMath; import org.bukkit.Chunk; import org.bukkit.Location; +import org.bukkit.entity.EntityType; 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; @@ -24,9 +28,10 @@ public class ElytraHelper implements AnarchyExploitFixesModule, Listener, Runnable { private static ElytraHelper instance; private final AnarchyExploitFixes plugin; + private final Set PLAYERS_GLIDING; + private final Set PLAYERS_NEAR_NEW_CHUNKS; private final Cache PLAYER_SPEEDS_INTERVAL; private final Cache LAST_GLIDE_POS; - private final Set PLAYERS_NEAR_NEW_CHUNKS; public static final double SPEED_TOLERANCE = 0.02; private final int checkIntervalTicks; private final boolean doIntervalCheck; @@ -34,14 +39,15 @@ public class ElytraHelper implements AnarchyExploitFixesModule, Listener, Runnab public ElytraHelper() { instance = this; this.plugin = AnarchyExploitFixes.getInstance(); + this.PLAYERS_GLIDING = new HashSet<>(); 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 = FastMath.max(tickInterval, 1); - final Duration cacheTime = Duration.ofMillis(FastMath.max(1000, (tickInterval * 50L) + 100L)); + this.checkIntervalTicks = Math.max(tickInterval, 1); + final Duration cacheTime = Duration.ofMillis(Math.max(1000, (tickInterval * 50L) + 100L)); this.PLAYER_SPEEDS_INTERVAL = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); this.LAST_GLIDE_POS = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); } @@ -75,24 +81,52 @@ public boolean shouldEnable() { @Override public void run() { for (Player player : plugin.getServer().getOnlinePlayers()) { - if (player.isGliding()) { + if (this.isGliding(player)) { Location currentLocation = player.getLocation().clone(); Location lastLocation = LAST_GLIDE_POS.getIfPresent(player.getUniqueId()); if (lastLocation != null) PLAYER_SPEEDS_INTERVAL.put(player.getUniqueId(), - LocationUtil.getNormalizedDistance(lastLocation, currentLocation) / checkIntervalTicks); + LocationUtil.getRelDistance3D(lastLocation, currentLocation) / checkIntervalTicks); LAST_GLIDE_POS.put(player.getUniqueId(), currentLocation); } } } - private double getFlatDistanceInChunks(Chunk chunk, Location location) { - return FastMath.hypot(chunk.getX() - location.getBlockX() >> 4, chunk.getZ() - location.getBlockZ() >> 4); + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onGlideToggle(EntityToggleGlideEvent event) { + if (event.getEntityType() != EntityType.PLAYER) return; + + if (event.isGliding()) { + PLAYERS_GLIDING.add(event.getEntity().getUniqueId()); + } else { + PLAYERS_GLIDING.remove(event.getEntity().getUniqueId()); + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onJoin(PlayerQuitEvent event) { + PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + private void onJoin(PlayerJoinEvent event) { + if (event.getPlayer().isGliding()) { + PLAYERS_GLIDING.add(event.getPlayer().getUniqueId()); + } else { + PLAYERS_GLIDING.remove(event.getPlayer().getUniqueId()); + } + } + + private double getChunkDistance(Chunk chunk, Location location) { + return Math.sqrt( + NumberConversions.square(chunk.getX() - location.getBlockX() >> 4) + + NumberConversions.square(chunk.getZ() - location.getBlockZ() >> 4) + ); } @EventHandler(priority = EventPriority.LOW) private void onChunkLoad(ChunkLoadEvent event) { for (Player player : event.getWorld().getPlayers()) { - if (this.getFlatDistanceInChunks(event.getChunk(), player.getLocation().clone()) < player.getViewDistance()) { + if (this.getChunkDistance(event.getChunk(), player.getLocation().clone()) < player.getViewDistance()) { if (event.isNewChunk()) { PLAYERS_NEAR_NEW_CHUNKS.add(player.getUniqueId()); } else { @@ -108,10 +142,10 @@ public Location getFrom(PlayerMoveEvent event) { } public double getBlocksPerTick(PlayerMoveEvent event) { - double eventSpeed = LocationUtil.getNormalizedDistance(event.getFrom(), event.getTo()); + double eventSpeed = LocationUtil.getRelDistance3D(event.getFrom(), event.getTo()); if (doIntervalCheck) { Double speedInterval = PLAYER_SPEEDS_INTERVAL.getIfPresent(event.getPlayer().getUniqueId()); - if (speedInterval != null) return FastMath.max(speedInterval, eventSpeed); + if (speedInterval != null) return Math.max(speedInterval, eventSpeed); } return eventSpeed; } @@ -119,4 +153,8 @@ public double getBlocksPerTick(PlayerMoveEvent event) { 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(); + } } 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 92d7c635c..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 @@ -75,7 +75,7 @@ public boolean shouldEnable() { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); - if (!player.isGliding()) return; + if (!ElytraHelper.getInstance().isGliding(player)) return; if (ceiling_shouldCheckPermission && player.hasPermission("anarchyexploitfixes.bypass")) return; Location playerLoc = player.getLocation(); if (!LocationUtil.isNetherCeiling(playerLoc)) return; diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraPacketFly.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraPacketFly.java index 9e95b3418..f6ca7325f 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraPacketFly.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraPacketFly.java @@ -6,7 +6,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; import me.moomoo.anarchyexploitfixes.utils.MaterialUtil; -import org.apache.commons.math3.util.FastMath; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -36,7 +35,7 @@ public ElytraPacketFly() { "If too many glide toggles occur within a timeframe, they are most likely using PacketFly\n" + "Still triggers false positives when players are jump sprinting with elytras, so play around with the values."); this.elytraOpenCounts = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds( - FastMath.max(config.getInt("elytra.packet-elytra-fly.time-in-seconds", 8, + Math.max(config.getInt("elytra.packet-elytra-fly.time-in-seconds", 8, "Will only allow players to go about 85km/h."), 1) )).build(); this.notify = config.getBoolean("elytra.packet-elytra-fly.notify-player-to-disable-packetfly", true, diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/lagpreventions/InventoryActionLag.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/lagpreventions/InventoryActionLag.java index da2e59ae2..f05ddec22 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/lagpreventions/InventoryActionLag.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/lagpreventions/InventoryActionLag.java @@ -7,7 +7,6 @@ import me.moomoo.anarchyexploitfixes.config.Config; import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; import me.moomoo.anarchyexploitfixes.utils.LogUtil; -import org.apache.commons.math3.util.FastMath; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.Entity; @@ -38,7 +37,7 @@ public InventoryActionLag() { "Prevent lag generated by players quickly moving big items back and forth between inventories.\n" + "Uses cached counters that auto-reset after the configurable time in milliseconds."); this.logIsEnabled = config.getBoolean("lag-preventions.prevent-inventory-action-lag.log", true); - Duration cacheTime = Duration.ofMillis(FastMath.max(config.getInt("lag-preventions.prevent-inventory-action-lag.cache-time-millis", 2000, + Duration cacheTime = Duration.ofMillis(Math.max(config.getInt("lag-preventions.prevent-inventory-action-lag.cache-time-millis", 2000, "The amount of time in milliseconds an entry is kept after writing."), 1)); this.blockInventoryClicks = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); this.entityInventoryClicks = Caffeine.newBuilder().expireAfterWrite(cacheTime).build(); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/TeleportCoordExploit.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/TeleportCoordExploit.java index 090cf4994..2c657a5d4 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/TeleportCoordExploit.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/TeleportCoordExploit.java @@ -76,7 +76,7 @@ private void onTeleport(PlayerTeleportEvent event) { case PLUGIN: case COMMAND: case ENDER_PEARL: - if (LocationUtil.getFlatDistance(event.getFrom(), event.getTo()) >= minDistanceToVanishPlayers) { + if (LocationUtil.getRelDistance2D(event.getFrom(), event.getTo()) >= minDistanceToVanishPlayers) { Player player = event.getPlayer(); this.vanish(player); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> this.unVanish(player), teleportVanishTime); @@ -87,7 +87,7 @@ private void onTeleport(PlayerTeleportEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onSpawn(PlayerRespawnEvent event) { Player player = event.getPlayer(); - if (LocationUtil.getFlatDistance(player.getLocation(), event.getRespawnLocation()) >= minDistanceToVanishPlayers) { + if (LocationUtil.getRelDistance2D(player.getLocation(), event.getRespawnLocation()) >= minDistanceToVanishPlayers) { this.vanish(player); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> this.unVanish(player), teleportVanishTime); } diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/crashexploits/WorldChangeCrash.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/crashexploits/WorldChangeCrash.java index b800c8555..98bb6c8ac 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/crashexploits/WorldChangeCrash.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/patches/crashexploits/WorldChangeCrash.java @@ -5,7 +5,6 @@ import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule; import me.moomoo.anarchyexploitfixes.utils.LogUtil; import me.moomoo.anarchyexploitfixes.utils.models.ExpiringSet; -import org.apache.commons.math3.util.FastMath; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -24,7 +23,7 @@ public WorldChangeCrash() { shouldEnable(); Config config = AnarchyExploitFixes.getConfiguration(); this.recentWorldChangers = new ExpiringSet<>(Duration.ofMillis( - FastMath.max(config.getInt("patches.crash-exploits.prevent-fast-world-teleport-crash.teleport-delay-millis", 1000, + Math.max(config.getInt("patches.crash-exploits.prevent-fast-world-teleport-crash.teleport-delay-millis", 1000, "Time in milliseconds until an entity can teleport to another world again."), 1))); config.addComment("patches.crash-exploits.prevent-fast-world-teleport-crash.enable", "Prevents crash methods that involve very fast teleporting between different worlds in a short time."); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/portals/EndPortalDestruction.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/portals/EndPortalDestruction.java index 3434680e2..f45f07981 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/portals/EndPortalDestruction.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/portals/EndPortalDestruction.java @@ -165,7 +165,7 @@ private void onPistonExplode(EntityExplodeEvent event) { private boolean isWithinEndProtectedRadius(Location location) { if (!location.getWorld().getEnvironment().equals(World.Environment.THE_END)) return false; - return LocationUtil.getFlatDistanceTo00(location) <= endBedrockProtectRadius; + return LocationUtil.getDistance2DTo00(location) <= endBedrockProtectRadius; } private boolean isEndPortal(Material material) { diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/withers/WitherSpawningAtSpawn.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/withers/WitherSpawningAtSpawn.java index 4e0630f65..afd8fb651 100755 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/withers/WitherSpawningAtSpawn.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/modules/preventions/withers/WitherSpawningAtSpawn.java @@ -73,7 +73,7 @@ private void onCreatureSpawn(CreatureSpawnEvent event) { final Integer disabledRadius = worldsAndTheirRadiuses.get(world); final Location witherLocation = entity.getLocation(); - if (LocationUtil.getFlatDistanceTo00(witherLocation) > disabledRadius) return; + if (LocationUtil.getDistance2DTo00(witherLocation) > disabledRadius) return; event.setCancelled(true); diff --git a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/utils/LocationUtil.java b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/utils/LocationUtil.java index cd225dfce..06d5edb22 100644 --- a/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/utils/LocationUtil.java +++ b/AnarchyExploitFixesLegacy/src/main/java/me/moomoo/anarchyexploitfixes/utils/LocationUtil.java @@ -4,15 +4,19 @@ import org.apache.commons.math3.util.FastMath; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.util.NumberConversions; public class LocationUtil { - public static double getFlatDistanceTo00(Location location) { + public static boolean isNetherCeiling(Location location) { + return location.getWorld().getEnvironment() == World.Environment.NETHER + && location.getY() > AnarchyExploitFixes.getConfiguration().nether_ceiling_max_y; + } + + public static double getDistance2DTo00(Location location) { return FastMath.hypot(location.getX(), location.getZ()); } - public static double getFlatDistance(Location from, Location to) { + public static double getRelDistance2D(Location from, Location to) { double toX = to.getX(); double toZ = to.getZ(); double fromX = from.getX(); @@ -34,7 +38,7 @@ public static double getFlatDistance(Location from, Location to) { return FastMath.hypot(toX - fromX, toZ - fromZ); } - public static double getNormalizedDistance(Location from, Location to) { + public static double getRelDistance3D(Location from, Location to) { double toX = to.getX(); double toZ = to.getZ(); double fromX = from.getX(); @@ -53,13 +57,39 @@ public static double getNormalizedDistance(Location from, Location to) { } } - return Math.sqrt(NumberConversions.square(fromX - toX) - + NumberConversions.square(from.getY() - to.getY()) - + NumberConversions.square(fromZ - toZ)); + return getDistance3D(fromX - toX, from.getY() - to.getY(), fromZ - toZ); } - public static boolean isNetherCeiling(Location location) { - return location.getWorld().getEnvironment() == World.Environment.NETHER - && location.getY() > AnarchyExploitFixes.getConfiguration().nether_ceiling_max_y; + public static double getDistance3D(final double x, final double y, final double z) { + if (Double.isInfinite(x) || Double.isInfinite(y) || Double.isInfinite(z)) { + return Double.POSITIVE_INFINITY; + } else if (Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z)) { + return Double.NaN; + } else { + final int expX = FastMath.getExponent(x); + final int expY = FastMath.getExponent(y); + final int expZ = FastMath.getExponent(z); + + if (expX > expY + 27 && expX > expZ + 27) { + // x is neglectible with respect to y and z + return FastMath.abs(y) + FastMath.abs(z); + } else if (expY > expX + 27 && expY > expZ + 27) { + // y is neglectible with respect to x and z + return FastMath.abs(x) + FastMath.abs(z); + } else if (expZ > expX + 27 && expZ > expY + 27) { + // z is neglectible with respect to x and y + return FastMath.abs(x) + FastMath.abs(y); + } else { + final int middleExp = (expX + expY + expZ) / 3; + + final double scaledX = FastMath.scalb(x, -middleExp); + final double scaledY = FastMath.scalb(y, -middleExp); + final double scaledZ = FastMath.scalb(z, -middleExp); + + final double scaledH = Math.sqrt(scaledX * scaledX + scaledY * scaledY + scaledZ * scaledZ); + + return FastMath.scalb(scaledH, middleExp); + } + } } }