diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/ChatData.java b/src/fr/neatmonster/nocheatplus/checks/chat/ChatData.java index 84e26c49..2d933ffa 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/ChatData.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/ChatData.java @@ -73,7 +73,6 @@ public class ChatData extends AsyncCheckData { public long noPwnageJoinTime; public String noPwnageLastMessage; public long noPwnageLastMessageTime; - public long noPwnageLastMovedTime; public long noPwnageLastWarningTime; public long noPwnageLeaveTime; public int noPwnageReloginWarnings; @@ -89,7 +88,7 @@ public class ChatData extends AsyncCheckData { // colorVL <- is spared to avoid problems with spam + captcha success. noPwnageVL = 0; noPwnageSpeed.clear(System.currentTimeMillis()); - noPwnageJoinTime = noPwnageLastMessageTime = noPwnageLastMovedTime = noPwnageLastWarningTime = noPwnageLeaveTime = noPwnageReloginWarningTime = 0L; + noPwnageJoinTime = noPwnageLastMessageTime = noPwnageLastWarningTime = noPwnageLeaveTime = noPwnageReloginWarningTime = 0L; noPwnageGeneratedCaptcha = noPwnageLastMessage = ""; } diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java b/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java index ebb493f3..e36de079 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java @@ -10,7 +10,6 @@ import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; -import org.bukkit.event.player.PlayerMoveEvent; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.command.INotifyReload; @@ -204,28 +203,6 @@ public class ChatListener implements Listener, INotifyReload { event.disallow(Result.KICK_OTHER, cc.noPwnageReloginKickMessage); } - /** - * When a player moves, he will be checked for various suspicious behaviors. - * - * @param event - * the event - */ - @EventHandler( - ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerMove(final PlayerMoveEvent event) { - /* - * _____ _ __ __ - * | __ \| | | \/ | - * | |__) | | __ _ _ _ ___ _ __ | \ / | _____ _____ - * | ___/| |/ _` | | | |/ _ \ '__| | |\/| |/ _ \ \ / / _ \ - * | | | | (_| | |_| | __/ | | | | | (_) \ V / __/ - * |_| |_|\__,_|\__, |\___|_| |_| |_|\___/ \_/ \___| - * __/ | - * |___/ - */ - ChatData.getData(event.getPlayer()).noPwnageLastMovedTime = System.currentTimeMillis(); - } - @Override public void onReload() { // Read some things from the global config file. diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java index ffaae064..d572e2aa 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java @@ -10,6 +10,7 @@ import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.AsyncCheck; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; +import fr.neatmonster.nocheatplus.checks.combined.CombinedData; import fr.neatmonster.nocheatplus.players.Permissions; import fr.neatmonster.nocheatplus.utilities.CheckUtils; @@ -161,7 +162,7 @@ public class NoPwnage extends AsyncCheck implements ICaptcha{ // NoPwnage will check if a player moved within the "timeout" timeframe. If he did not move, the suspicion will // be increased by "weight" value. - if (!isCommand && cc.noPwnageMoveCheck && now - data.noPwnageLastMovedTime > cc.noPwnageMoveTimeout) + if (!isCommand && cc.noPwnageMoveCheck && now - CombinedData.getData(player).lastMoveTime > cc.noPwnageMoveTimeout) suspicion += cc.noPwnageMoveWeight; // Should a player that reaches the "warnLevel" get a text message telling him that he is under suspicion of diff --git a/src/fr/neatmonster/nocheatplus/checks/combined/Combined.java b/src/fr/neatmonster/nocheatplus/checks/combined/Combined.java index 7495ef66..5e1ab895 100644 --- a/src/fr/neatmonster/nocheatplus/checks/combined/Combined.java +++ b/src/fr/neatmonster/nocheatplus/checks/combined/Combined.java @@ -41,7 +41,7 @@ public class Combined { * @param worldName * @param data */ - private static final void feedYawRate(final Player player, final float yaw, final long now, final String worldName, final CombinedData data) { + public static final void feedYawRate(final Player player, final float yaw, final long now, final String worldName, final CombinedData data) { // Reset on world change or timeout. if (now - data.lastYawTime > 999 || !worldName.equals(data.lastWorld)){ data.lastYaw = yaw; @@ -70,7 +70,7 @@ public class Combined { * @param worldName * @return */ - private static final boolean checkYawRate(Player player, float yaw, long now, final String worldName, final CombinedData data) { + public static final boolean checkYawRate(final Player player, final float yaw, final long now, final String worldName, final CombinedData data) { feedYawRate(player, yaw, now, worldName, data); diff --git a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java index ea0e04ba..15ca597a 100644 --- a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java +++ b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java @@ -54,6 +54,8 @@ public class CombinedData extends ACheckData { public String lastWorld = ""; + public long lastMoveTime; + public CombinedData(final Player player){ // final CombinedConfig cc = CombinedConfig.getConfig(player); // TODO: Get some things from the config. diff --git a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java index 6620739a..50416ef1 100644 --- a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java @@ -36,12 +36,15 @@ public class CombinedListener implements Listener { @EventHandler(priority=EventPriority.MONITOR, ignoreCancelled = false) public final void onPlayerMove(final PlayerMoveEvent event){ - // Experimental + final long now = System.currentTimeMillis(); final Player player = event.getPlayer(); - // Just add the yaw to the list. + final Location loc = player.getLocation(); final String worldName = loc.getWorld().getName(); - Combined.feedYawRate(player, loc.getYaw(), System.currentTimeMillis(), worldName); + final CombinedData data = CombinedData.getData(player); + data.lastMoveTime = now; + // Just add the yaw to the list. + Combined.feedYawRate(player, loc.getYaw(), now, worldName, data); } // (possibly other types of events, but these combine with fighting). diff --git a/src/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java b/src/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java index ccffdead..da5b3505 100644 --- a/src/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java @@ -1,11 +1,10 @@ package fr.neatmonster.nocheatplus.checks.moving; -import net.minecraft.server.Block; - import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Vehicle; import org.bukkit.event.EventHandler; @@ -29,6 +28,7 @@ import org.bukkit.util.Vector; import fr.neatmonster.nocheatplus.NoCheatPlus; import fr.neatmonster.nocheatplus.players.Permissions; +import fr.neatmonster.nocheatplus.utilities.BlockProperties; /* * M"""""`'"""`YM oo @@ -58,18 +58,6 @@ public class MovingListener implements Listener { /** The no fall check. **/ public final static NoFall noFall = new NoFall(); - /** - * Checks if a material is liquid. - * - * @param material - * the material - * @return true, if the material is liquid - */ - public static boolean isLiquid(final Material material) { - return material == Material.LAVA || material == Material.STATIONARY_LAVA - || material == Material.STATIONARY_WATER || material == Material.WATER; - } - /** The instance of NoCheatPlus. */ private final NoCheatPlus plugin = (NoCheatPlus) Bukkit.getPluginManager().getPlugin( "NoCheatPlus"); @@ -110,27 +98,40 @@ public class MovingListener implements Listener { */ final Player player = event.getPlayer(); - // Ignore players inside a vehicle. - if (player.isInsideVehicle()) - return; + // Ignore players inside a vehicle. + if (player.isInsideVehicle()) + return; - final MovingData data = MovingData.getData(player); + final MovingData data = MovingData.getData(player); - final int blockY = event.getBlock().getY(); - if (isLiquid(event.getBlockAgainst().getType()) && event.getBlock().getType() != Material.WATER_LILY) - // The block was placed against a liquid block, cancel its placement. - event.setCancelled(true); - else if ((creativeFly.isEnabled(player) || survivalFly.isEnabled(player)) && event.getBlock() != null - && data.setBack != null && blockY + 1D >= data.setBack.getY() - && Math.abs(player.getLocation().getX() - 0.5 - event.getBlock().getX()) <= 1D - && Math.abs(player.getLocation().getZ() - 0.5 - event.getBlock().getZ()) <= 1D - && player.getLocation().getY() - blockY > 0D && player.getLocation().getY() - blockY < 2D - && (Block.i(event.getBlock().getTypeId()) || isLiquid(event.getBlock().getType()))) { - // The creative fly and/or survival fly check is enabled, the block was placed below the player and is - // solid, so do what we have to do. - data.setBack.setY(blockY + 1D); - data.survivalFlyJumpPhase = 0; - } + final org.bukkit.block.Block block = event.getBlock(); + final int blockY = block.getY(); + + final Material mat = block.getType(); + + if (BlockProperties.isLiquid(event.getBlockAgainst().getTypeId()) + && mat != Material.WATER_LILY) + // The block was placed against a liquid block, cancel its + // placement. + event.setCancelled(true); + else { + + if (!creativeFly.isEnabled(player) && !survivalFly.isEnabled(player)) return; + + if (block == null || data.setBack == null || blockY + 1D < data.setBack.getY()) return; + + final Location loc = player.getLocation(); + if (Math.abs(loc.getX() - 0.5 - block.getX()) <= 1D + && Math.abs(loc.getZ() - 0.5 - block.getZ()) <= 1D + && loc.getY() - blockY > 0D && loc.getY() - blockY < 2D + && (BlockProperties.i(mat.getId()) || BlockProperties.isLiquid(mat.getId()))) { + // The creative fly and/or survival fly check is enabled, the + // block was placed below the player and is + // solid, so do what we have to do. + data.setBack.setY(blockY + 1D); + data.survivalFlyJumpPhase = 0; + } + } } /** @@ -248,15 +249,24 @@ public class MovingListener implements Listener { * |_| |_|\__,_|\__, |\___|_| |___|_| |_|\__\___|_| \__,_|\___|\__| * |___/ */ - if (!event.getPlayer().hasPermission(Permissions.MOVING_BOATSANYWHERE) - && event.getAction() == Action.RIGHT_CLICK_BLOCK - && event.getPlayer().getItemInHand().getType() == Material.BOAT - && event.getClickedBlock().getType() != Material.WATER - && event.getClickedBlock().getType() != Material.STATIONARY_WATER - && event.getClickedBlock().getRelative(event.getBlockFace()).getType() != Material.WATER - && event.getClickedBlock().getRelative(event.getBlockFace()).getType() != Material.STATIONARY_WATER) - // If the player right clicked on a non-liquid block with a boat in his hands, cancel the event. - event.setCancelled(true); + // If the player right clicked on a non-liquid block with a boat in his hands, cancel the event. + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; + + final Player player = event.getPlayer(); + if (player.getItemInHand().getType() != Material.BOAT) return; + if (event.getPlayer().hasPermission(Permissions.MOVING_BOATSANYWHERE)) return; + + final org.bukkit.block.Block block = event.getClickedBlock(); + final Material mat = block.getType(); + + if (mat == Material.WATER || mat == Material.STATIONARY_WATER) return; + + final org.bukkit.block.Block relBlock = block.getRelative(event.getBlockFace()); + final Material relMat = relBlock.getType(); + + if (relMat == Material.WATER || relMat == Material.STATIONARY_WATER) return; + + event.setCancelled(true); } /** @@ -503,11 +513,14 @@ public class MovingListener implements Listener { * \ V / __/ | | | | (__| | __/ | | | | (_) \ V / __/ * \_/ \___|_| |_|_|\___|_|\___| |_| |_|\___/ \_/ \___| */ + final Vehicle vehicle = event.getVehicle(); + final Entity passenger = vehicle.getPassenger(); // Don't care if a player isn't inside the vehicle, for movements that are very high distance or to another // world (such that it is very likely the event data was modified by another plugin before we got it). - if (event.getVehicle().getPassenger() == null || !(event.getVehicle().getPassenger() instanceof Player) - || !event.getFrom().getWorld().equals(event.getTo().getWorld())) - return; + if (passenger == null || !(passenger instanceof Player)) return; + final Location from = event.getFrom(); + final Location to = event.getTo(); + if (!from.getWorld().equals(to.getWorld())) return; final Player player = (Player) event.getVehicle().getPassenger(); @@ -515,7 +528,7 @@ public class MovingListener implements Listener { if (morePacketsVehicle.isEnabled(player)) // If the player is handled by the more packets vehicle check, execute it. - newTo = morePacketsVehicle.check(player, event.getFrom(), event.getTo()); + newTo = morePacketsVehicle.check(player, from, to); else // Otherwise we need to clear his data. MovingData.getData(player).clearMorePacketsData(); @@ -538,6 +551,6 @@ public class MovingListener implements Listener { this.location = location; return this; } - }.set(event.getVehicle(), newTo), 1L); + }.set(vehicle, newTo), 1L); } } diff --git a/src/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java b/src/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java index d53ae038..2516d1d6 100644 --- a/src/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java +++ b/src/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java @@ -15,6 +15,7 @@ import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.players.Permissions; +import fr.neatmonster.nocheatplus.utilities.BlockProperties; import fr.neatmonster.nocheatplus.utilities.PlayerLocation; /* @@ -134,17 +135,19 @@ public class SurvivalFly extends Check { // Prevent players from walking on a liquid. // TODO: yDistance == 0D <- should there not be a tolerance +- or 0...x ? if (hDistanceAboveLimit <= 0D && hDistance > 0.1D && yDistance == 0D - && MovingListener.isLiquid(to.getLocation().getBlock().getType()) && !to.isOnGround() + && BlockProperties.isLiquid(to.getTypeId()) && !to.isOnGround() && to.getY() % 1D < 0.8D) hDistanceAboveLimit = hDistance; // Prevent players from sprinting if they're moving backwards. - if (hDistanceAboveLimit <= 0D && sprinting && !player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING)) { + if (hDistanceAboveLimit <= 0D && sprinting) { final float yaw = from.getYaw(); if (xDistance < 0D && zDistance > 0D && yaw > 180F && yaw < 270F || xDistance < 0D && zDistance < 0D && yaw > 270F && yaw < 360F || xDistance > 0D && zDistance < 0D && yaw > 0F && yaw < 90F - || xDistance > 0D && zDistance > 0D && yaw > 90F && yaw < 180F) - hDistanceAboveLimit = hDistance; + || xDistance > 0D && zDistance > 0D && yaw > 90F && yaw < 180F){ + // Assumes permission check to be the heaviest (might be mistaken). + if (!player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING)) hDistanceAboveLimit = hDistance; + } } data.bunnyhopDelay--; diff --git a/src/fr/neatmonster/nocheatplus/utilities/BlockProperties.java b/src/fr/neatmonster/nocheatplus/utilities/BlockProperties.java index 42da12b8..53c45c17 100644 --- a/src/fr/neatmonster/nocheatplus/utilities/BlockProperties.java +++ b/src/fr/neatmonster/nocheatplus/utilities/BlockProperties.java @@ -6,6 +6,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import net.minecraft.server.Block; + import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -231,6 +233,12 @@ public class BlockProperties { Material.CROPS, }; + protected static final long[] blockFlags = new long[maxBlocks]; + + /** Flag position for stairs. */ + public static final int F_STAIRS = 0x1; + public static final int F_LIQUID = 0x2; + static{ try{ initTools(); @@ -272,10 +280,24 @@ public class BlockProperties { private static void initBlocks() { - for (int i = 0; i + * TODO: Find description of this and use block properties from here, as well as a speaking method name. + * @param id + * @return + */ + public static final boolean i(final int id) { + return Block.i(id); + } + + + public static final boolean isStairs(final int id) { + return (blockFlags[id] & F_STAIRS) != 0; + } + + + public static boolean isLiquid(final int id) { + return (blockFlags[id] & F_LIQUID) != 0; + } } diff --git a/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java b/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java index f4a173b4..9111b88a 100644 --- a/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java +++ b/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java @@ -1,14 +1,11 @@ package fr.neatmonster.nocheatplus.utilities; -import java.util.Arrays; - import net.minecraft.server.AxisAlignedBB; import net.minecraft.server.Block; import net.minecraft.server.EntityPlayer; import net.minecraft.server.WorldServer; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -36,10 +33,12 @@ import org.bukkit.entity.Player; */ public class PlayerLocation { - private static final Material[] STAIRS = new Material[] {Material.WOOD_STAIRS, Material.COBBLESTONE_STAIRS, - Material.BRICK_STAIRS, Material.SMOOTH_STAIRS, Material.NETHER_BRICK_STAIRS, Material.SANDSTONE_STAIRS, - Material.SPRUCE_WOOD_STAIRS, Material.BIRCH_WOOD_STAIRS, Material.JUNGLE_WOOD_STAIRS}; - + /** Type id of the block at the position. */ + private Integer typeId; + + /** Type id of the block below. */ + private Integer typeIdBelow; + /** The original location. */ private Location location; @@ -140,7 +139,7 @@ public class PlayerLocation { */ public boolean isAboveStairs() { if (aboveStairs == null) - aboveStairs = Arrays.asList(STAIRS).contains(Material.getMaterial(world.getTypeId(x, y - 1, z))); + aboveStairs = BlockProperties.isStairs(getTypeIdBelow().intValue()); return aboveStairs; } @@ -227,7 +226,7 @@ public class PlayerLocation { if (entity.getBukkitEntity().isSneaking() || entity.getBukkitEntity().isBlocking()) onIce = world.getTypeId(x, (int) Math.floor(boundingBox.b - 0.1D), z) == Block.ICE.id; else - onIce = world.getTypeId(x, y - 1, z) == Block.ICE.id; + onIce = getTypeIdBelow() == Block.ICE.id; return onIce; } @@ -237,8 +236,10 @@ public class PlayerLocation { * @return true, if the player is on a ladder */ public boolean isOnLadder() { - if (onLadder == null) - onLadder = world.getTypeId(x, y, z) == Block.LADDER.id || world.getTypeId(x, y, z) == Block.VINE.id; + if (onLadder == null){ + final int typeId = getTypeId(); + onLadder = typeId == Block.LADDER.id || typeId == Block.VINE.id; + } return onLadder; } @@ -286,4 +287,16 @@ public class PlayerLocation { this.yOnGround = yOnGround; this.onGround = null; } + + public Integer getTypeId() { + if (typeId == null) typeId = world.getTypeId(x, y, z); + return typeId; + } + + + public Integer getTypeIdBelow() { + if (typeIdBelow == null) typeIdBelow = world.getTypeId(x, y - 1, z); + return typeIdBelow; + } + }