-
-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
359 additions
and
486 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
...itFixesFolia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/ElytraHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<UUID> PLAYERS_GLIDING; | ||
private final Set<UUID> PLAYERS_NEAR_NEW_CHUNKS; | ||
private ScheduledTask scheduledSpeedCheck; | ||
private final Cache<UUID, Double> PLAYER_SPEEDS; | ||
private final Cache<UUID, Location> 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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 0 additions & 45 deletions
45
...olia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ChunkListener.java
This file was deleted.
Oops, something went wrong.
89 changes: 0 additions & 89 deletions
89
...Folia/src/main/java/me/moomoo/anarchyexploitfixes/modules/elytra/helper/ElytraHelper.java
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.