/** * Copyright (C) 2012 t7seven7t */ package net.t7seven7t.swornguard.detectors; import net.dmulloy2.util.FormatUtil; import net.dmulloy2.util.Util; import net.t7seven7t.swornguard.SwornGuard; import net.t7seven7t.swornguard.events.CheatEvent; import net.t7seven7t.swornguard.types.CheatType; import net.t7seven7t.swornguard.types.Permission; import net.t7seven7t.swornguard.types.PlayerData; import net.t7seven7t.swornguard.types.Preconditions; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; /** * @author t7seven7t */ public class FlyDetector { private static final BlockFace[] directions = new BlockFace[] { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST }; private final SwornGuard plugin; private final Preconditions preconditions; private final double suspiciousVelocity; private final int suspiciousDistFromGround; private final int suspiciousMoveDist; public FlyDetector(final SwornGuard plugin) { this.plugin = plugin; this.preconditions = plugin.getPreconditions(); this.suspiciousVelocity = plugin.getConfig().getDouble("flyDetectorSuspiciousVelocity"); this.suspiciousDistFromGround = plugin.getConfig().getInt("flyDetectorSuspiciousDistFromGround"); this.suspiciousMoveDist = plugin.getConfig().getInt("flyDetectorSuspiciousMoveDist"); new BukkitRunnable() { @Override public void run() { step(); } }.runTaskTimer(plugin, 20L, 5L); } private void step() { for (final Player player : Util.getOnlinePlayers()) { if (! plugin.getPermissionHandler().hasPermission(player, Permission.ALLOW_FLY)) { if (! player.getAllowFlight() && (player.getVelocity().getY() < suspiciousVelocity || (! isInWater(player) && getDistanceToGround(player) >= suspiciousDistFromGround))) { if (! preconditions.isPlayerFallingIntoVoid(player) && ! preconditions.isPlayerInsideCar(player) && ! player.isInsideVehicle() && ! preconditions.isNewPlayerJoin(player) && ! preconditions.hasRecentlyTeleported(player)) { final PlayerData data = plugin.getPlayerDataCache().getData(player); final Vector previousLocation = player.getLocation().toVector(); if (! data.isJailed() && System.currentTimeMillis() - data.getLastFlyWarn() > 45000L) { data.setLastFlyWarn(System.currentTimeMillis()); new BukkitRunnable() { @Override public void run() { checkPlayer(player, previousLocation); } }.runTaskLater(plugin, 5L); } } } } } } private void checkPlayer(Player player, Vector previousLocation) { PlayerData data = plugin.getPlayerDataCache().getData(player); if (player.getLocation().getY() - previousLocation.getY() > 3 || (player.getLocation().getY() >= previousLocation.getY() && (Math.abs(player.getLocation().getX() - previousLocation.getX()) > suspiciousMoveDist || Math.abs(player.getLocation().getZ() - previousLocation.getZ()) > suspiciousMoveDist))) { data.setConsecutivePings(data.getConsecutivePings() + 1); if (data.getConsecutivePings() >= 2) { CheatEvent event = new CheatEvent(player, CheatType.FLYING, FormatUtil.format(plugin.getMessage("cheat_message"), player.getName(), "flying!")); plugin.getCheatHandler().announceCheat(event); data.setConsecutivePings(0); } data.setLastFlyWarn(System.currentTimeMillis()); } else { data.setLastFlyWarn(0); } } private boolean isInWater(Player player) { Block block = player.getWorld().getBlockAt(player.getLocation()); if (isBlockWaterOrClimbable(block)) return true; for (BlockFace face : directions) { if (isBlockWaterOrClimbable(block.getRelative(face))) return true; } return false; } public boolean isBlockWaterOrClimbable(Block block) { return block != null && (block.isLiquid() || block.getType().equals(Material.LADDER) || block.getType().equals(Material.VINE)); } private int getDistanceToGround(Player player) { Location loc = player.getLocation(); int count = 1; while (loc.subtract(0, 1, 0).getY() > 1 && count < suspiciousDistFromGround && player.getWorld().getBlockAt(loc).getType().equals(Material.AIR) || player.getWorld().getBlockAt(loc).getType().equals(Material.WATER) || player.getWorld().getBlockAt(loc).getType().equals(Material.LAVA)) { count++; } return count; } }