diff --git a/src/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakListener.java b/src/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakListener.java index 9d489b47..fed40367 100644 --- a/src/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakListener.java @@ -70,20 +70,20 @@ public class BlockBreakListener implements Listener { // it may save us from doing the computationally expensive checks. // Has the player broken blocks too quickly? - if (fastBreak.isEnabled(player)) - cancelled = fastBreak.check(player, block); + if (fastBreak.isEnabled(player) && fastBreak.check(player, block)) + cancelled = true; // Did the arm of the player move before breaking this block? - if (!cancelled && noSwing.isEnabled(player)) - cancelled = noSwing.check(player); + if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player)) + cancelled = true; // Is the block really in reach distance? - if (!cancelled && reach.isEnabled(player)) - cancelled = reach.check(player, block.getLocation()); + if (!cancelled && reach.isEnabled(player) && reach.check(player, block.getLocation())) + cancelled = true; // Did the player look at the block at all? - if (!cancelled && direction.isEnabled(player)) - cancelled = direction.check(player, block.getLocation()); + if (!cancelled && direction.isEnabled(player) && direction.check(player, block.getLocation())) + cancelled = true; // At least one check failed and demanded to cancel the event. if (cancelled) diff --git a/src/fr/neatmonster/nocheatplus/checks/blockbreak/Direction.java b/src/fr/neatmonster/nocheatplus/checks/blockbreak/Direction.java index d8de7f76..0df92e2f 100644 --- a/src/fr/neatmonster/nocheatplus/checks/blockbreak/Direction.java +++ b/src/fr/neatmonster/nocheatplus/checks/blockbreak/Direction.java @@ -41,8 +41,6 @@ public class Direction extends Check { } } - private final double OFFSET = 0.5D; - /** * Checks a player. * @@ -58,7 +56,12 @@ public class Direction extends Check { boolean cancel = false; - if (!CheckUtils.intersects(player, location, location.add(1D, 1D, 1D), OFFSET)) { + // How far "off" is the player with his aim. We calculate from the players eye location and view direction to + // the center of the target block. If the line of sight is more too far off, "off" will be bigger than 0. + final double off = CheckUtils.directionCheck(player, location.getX() + 0.5D, location.getY() + 0.5D, + location.getZ() + 0.5D, 1D, 1D, 50); + + if (off > 0.1D) { // Player failed the check. Let's try to guess how far he was from looking directly to the block... final Vector direction = player.getEyeLocation().getDirection(); final Vector blockEyes = location.add(0.5D, 0.5D, 0.5D).subtract(player.getEyeLocation()).toVector(); diff --git a/src/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceListener.java b/src/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceListener.java index 8fa62b78..adeb7c35 100644 --- a/src/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceListener.java @@ -60,7 +60,7 @@ public class BlockPlaceListener implements Listener { return; final Player player = event.getPlayer(); - final Block block = event.getBlock(); + final Block block = event.getBlockPlaced(); boolean cancelled = false; @@ -74,7 +74,7 @@ public class BlockPlaceListener implements Listener { // Third, the direction check. if (!cancelled && direction.isEnabled(player)) - cancelled = direction.check(player, block.getLocation()); + cancelled = direction.check(player, block.getLocation(), event.getBlockAgainst().getLocation()); // If one of the checks requested to cancel the event, do so. if (cancelled) diff --git a/src/fr/neatmonster/nocheatplus/checks/blockplace/Direction.java b/src/fr/neatmonster/nocheatplus/checks/blockplace/Direction.java index 1cba2cb4..28fb440a 100644 --- a/src/fr/neatmonster/nocheatplus/checks/blockplace/Direction.java +++ b/src/fr/neatmonster/nocheatplus/checks/blockplace/Direction.java @@ -41,8 +41,6 @@ public class Direction extends Check { } } - private final double OFFSET = 0.5D; - /** * Checks a player. * @@ -52,16 +50,44 @@ public class Direction extends Check { * the location * @return true, if successful */ - public boolean check(final Player player, final Location location) { + public boolean check(final Player player, final Location placed, final Location against) { final BlockPlaceConfig cc = BlockPlaceConfig.getConfig(player); final BlockPlaceData data = BlockPlaceData.getData(player); boolean cancel = false; - if (!CheckUtils.intersects(player, location, location.add(1D, 1D, 1D), OFFSET)) { + // How far "off" is the player with his aim. We calculate from the players eye location and view direction to + // the center of the target block. If the line of sight is more too far off, "off" will be bigger than 0. + double off = CheckUtils.directionCheck(player, against.getX() + 0.5D, against.getY() + 0.5D, + against.getZ() + 0.5D, 1D, 1D, 75); + + // Now check if the player is looking at the block from the correct side. + double off2 = 0.0D; + + // Find out against which face the player tried to build, and if he + // stood on the correct side of it + final Location eyes = player.getEyeLocation(); + if (placed.getX() > against.getX()) + off2 = against.getX() + 0.5D - eyes.getX(); + else if (placed.getX() < against.getX()) + off2 = -(against.getX() + 0.5D - eyes.getX()); + else if (placed.getY() > against.getY()) + off2 = against.getY() + 0.5D - eyes.getY(); + else if (placed.getY() < against.getY()) + off2 = -(against.getY() + 0.5D - eyes.getY()); + else if (placed.getZ() > against.getZ()) + off2 = against.getZ() + 0.5D - eyes.getZ(); + else if (placed.getZ() < against.getZ()) + off2 = -(against.getZ() + 0.5D - eyes.getZ()); + + // If he wasn't on the correct side, add that to the "off" value + if (off2 > 0.0D) + off += off2; + + if (off > 0.1D) { // Player failed the check. Let's try to guess how far he was from looking directly to the block... final Vector direction = player.getEyeLocation().getDirection(); - final Vector blockEyes = location.add(0.5D, 0.5D, 0.5D).subtract(player.getEyeLocation()).toVector(); + final Vector blockEyes = placed.add(0.5D, 0.5D, 0.5D).subtract(player.getEyeLocation()).toVector(); final double distance = blockEyes.crossProduct(direction).length() / direction.length(); // Add the overall violation level of the check. diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java index 03544285..70c37f86 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java @@ -9,6 +9,7 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerEvent; import fr.neatmonster.nocheatplus.actions.ParameterName; +import fr.neatmonster.nocheatplus.actions.types.ActionList; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckEvent; import fr.neatmonster.nocheatplus.players.Permissions; @@ -268,6 +269,18 @@ public class NoPwnage extends Check { return cancel; } + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#executeActions(org.bukkit.entity.Player, fr.neatmonster.nocheatplus.actions.types.ActionList, double) + */ + @Override + protected boolean executeActions(final Player player, final ActionList actionList, final double violationLevel) { + if (super.executeActions(player, actionList, violationLevel)) { + ChatData.getData(player).clearNoPwnageData(); + return true; + } + return false; + } + /* (non-Javadoc) * @see fr.neatmonster.nocheatplus.checks.Check#getParameter(fr.neatmonster.nocheatplus.actions.ParameterName, org.bukkit.entity.Player) */ diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/Angle.java b/src/fr/neatmonster/nocheatplus/checks/fight/Angle.java index d27c944b..0e80b87b 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/Angle.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/Angle.java @@ -66,6 +66,10 @@ public class Angle extends Check { // Add the new location to the map. data.angleHits.put(System.currentTimeMillis(), player.getLocation()); + // Not enough data to calculate deltas. + if (data.angleHits.size() < 2) + return false; + // Declare variables. double deltaMove = 0D; long deltaTime = 0L; diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/Direction.java b/src/fr/neatmonster/nocheatplus/checks/fight/Direction.java index 91bd2043..37685d99 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/Direction.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/Direction.java @@ -1,6 +1,8 @@ package fr.neatmonster.nocheatplus.checks.fight; import net.minecraft.server.Entity; +import net.minecraft.server.EntityComplex; +import net.minecraft.server.EntityComplexPart; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -43,8 +45,6 @@ public class Direction extends Check { } } - private final double OFFSET = 0.5D; - /** * Checks a player. * @@ -60,14 +60,26 @@ public class Direction extends Check { boolean cancel = false; - final Location minimum = new Location(player.getWorld(), damaged.boundingBox.a, damaged.boundingBox.b, - damaged.boundingBox.c); - final Location maximum = new Location(player.getWorld(), damaged.boundingBox.d, damaged.boundingBox.e, - damaged.boundingBox.f); - if (!CheckUtils.intersects(player, minimum, maximum, OFFSET)) { + // Safeguard, if entity is complex, this check will fail due to giant and hard to define hitboxes. + if (damaged instanceof EntityComplex || damaged instanceof EntityComplexPart) + return false; + + // Find out how wide the entity is. + final float width = damaged.length > damaged.width ? damaged.length : damaged.width; + + // entity.height is broken and will always be 0, therefore. Calculate height instead based on boundingBox. + final double height = damaged.boundingBox.e - damaged.boundingBox.b; + + // How far "off" is the player with his aim. We calculate from the players eye location and view direction to + // the center of the target entity. If the line of sight is more too far off, "off" will be bigger than 0. + final double off = CheckUtils.directionCheck(player, damaged.locX, damaged.locY + height / 2D, damaged.locZ, + width, height, 75); + + if (off > 0.1) { // Player failed the check. Let's try to guess how far he was from looking directly to the entity... final Vector direction = player.getEyeLocation().getDirection(); - final Vector blockEyes = minimum.add(maximum).multiply(0.5D).subtract(player.getEyeLocation()).toVector(); + final Vector blockEyes = new Location(player.getWorld(), damaged.locX, damaged.locY + height / 2D, + damaged.locZ).subtract(player.getEyeLocation()).toVector(); final double distance = blockEyes.crossProduct(direction).length() / direction.length(); // Add the overall violation level of the check. diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java b/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java index 19281b18..c5a68cae 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java @@ -63,7 +63,7 @@ public class FightData { public long godModeLastTime; // Data of the instant heal check. - public int instantHealBuffer; + public long instantHealBuffer; public long instantHealLastTime; // Data of the knockback check. diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/InstantHeal.java b/src/fr/neatmonster/nocheatplus/checks/fight/InstantHeal.java index f2da0ee3..0db0538c 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/InstantHeal.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/InstantHeal.java @@ -65,7 +65,7 @@ public class InstantHeal extends Check { data.instantHealVL -= data.instantHealBuffer / 1000D; // Reset the buffer. - data.instantHealBuffer = 0; + data.instantHealBuffer = 0L; // Dispatch an instant heal event (API). final InstantHealEvent e = new InstantHealEvent(player); @@ -79,8 +79,8 @@ public class InstantHeal extends Check { data.instantHealVL *= 0.9D; // Buffer can't be bigger than 2 seconds. - if (data.instantHealBuffer > 2000) - data.instantHealBuffer = 2000; + if (data.instantHealBuffer > 2000L) + data.instantHealBuffer = 2000L; if (!cancel) // New reference time. diff --git a/src/fr/neatmonster/nocheatplus/checks/moving/NoFall.java b/src/fr/neatmonster/nocheatplus/checks/moving/NoFall.java index c5c742ed..4d496621 100644 --- a/src/fr/neatmonster/nocheatplus/checks/moving/NoFall.java +++ b/src/fr/neatmonster/nocheatplus/checks/moving/NoFall.java @@ -75,7 +75,7 @@ public class NoFall extends Check { if (cc.noFallAggressive && (from.isInLiquid() || from.isOnGround() || from.isOnLadder()) && (to.isInLiquid() || to.isOnGround() || to.isOnLadder()) && from.getY() <= to.getY() && player.getFallDistance() > 3F) { - Bukkit.broadcastMessage(ChatColor.RED + "Problem with the no fall check!"); // TODO + // Bukkit.broadcastMessage(ChatColor.RED + "Problem with the no fall check!"); // TODO data.noFallDistance = player.getFallDistance(); diff --git a/src/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java b/src/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java index d399fe0e..c49b6859 100644 --- a/src/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java +++ b/src/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java @@ -6,7 +6,6 @@ import net.minecraft.server.EntityPlayer; import net.minecraft.server.MobEffectList; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -282,7 +281,8 @@ public class SurvivalFly extends Check { // Did the player move in unexpected ways? if (result > 0D) { - Bukkit.broadcastMessage(ChatColor.RED + player.getName() + ": problem with the survival fly check!"); // TODO + // Bukkit.broadcastMessage(ChatColor.RED + player.getName() + ": problem with the survival fly check!"); // + // TODO // Increment violation counter. data.survivalFlyVL += result; diff --git a/src/fr/neatmonster/nocheatplus/utilities/CheckUtils.java b/src/fr/neatmonster/nocheatplus/utilities/CheckUtils.java index 892df9cc..0b3d0a8d 100644 --- a/src/fr/neatmonster/nocheatplus/utilities/CheckUtils.java +++ b/src/fr/neatmonster/nocheatplus/utilities/CheckUtils.java @@ -9,6 +9,57 @@ import org.bukkit.util.Vector; */ public class CheckUtils { + /** + * Check if a player looks at a target of a specific size, with a specific precision value (roughly). + * + * @param player + * the player + * @param targetX + * the target x + * @param targetY + * the target y + * @param targetZ + * the target z + * @param targetWidth + * the target width + * @param targetHeight + * the target height + * @param precision + * the precision + * @return the double + */ + public static double directionCheck(final Player player, final double targetX, final double targetY, + final double targetZ, final double targetWidth, final double targetHeight, final double precision) { + + // Get the eye location of the player. + final Location eyes = player.getEyeLocation(); + + final double factor = Math.sqrt(Math.pow(eyes.getX() - targetX, 2) + Math.pow(eyes.getY() - targetY, 2) + + Math.pow(eyes.getZ() - targetZ, 2)); + + // Get the view direction of the player. + final Vector direction = eyes.getDirection(); + + final double x = targetX - eyes.getX(); + final double y = targetY - eyes.getY(); + final double z = targetZ - eyes.getZ(); + + final double xPrediction = factor * direction.getX(); + final double yPrediction = factor * direction.getY(); + final double zPrediction = factor * direction.getZ(); + + double off = 0.0D; + + off += Math.max(Math.abs(x - xPrediction) - (targetWidth / 2 + precision), 0.0D); + off += Math.max(Math.abs(z - zPrediction) - (targetWidth / 2 + precision), 0.0D); + off += Math.max(Math.abs(y - yPrediction) - (targetHeight / 2 + precision), 0.0D); + + if (off > 1) + off = Math.sqrt(off); + + return off; + } + /** * Calculates the distance between the player and the intersection of the player's line of sight with the targeted * block. @@ -36,98 +87,6 @@ public class CheckUtils { return min; } - /** - * Check if the location is in the line of sight of the player. - * - * @param player - * the player - * @param minimum - * the minimum location - * @param maximum - * the maximum location - * @param offset - * the offset - * @return true, if successful - */ - public static boolean intersects(final Player player, final Location minimum, final Location maximum, - final double offset) { - final double x1 = minimum.getX() - offset; - final double y1 = minimum.getY() - offset; - final double z1 = minimum.getZ() - offset; - final double xH = maximum.getX() + offset; - final double yH = maximum.getY() + offset; - final double zH = maximum.getZ() + offset; - final double x0 = player.getEyeLocation().getX(); - final double y0 = player.getEyeLocation().getY(); - final double z0 = player.getEyeLocation().getZ(); - final double xD = player.getEyeLocation().getDirection().getX(); - final double yD = player.getEyeLocation().getDirection().getY(); - final double zD = player.getEyeLocation().getDirection().getZ(); - double tNear = Double.NEGATIVE_INFINITY; - double tFar = Double.POSITIVE_INFINITY; - if (xD == 0D) { - if (x0 < x1 || x0 > xH) - return false; - } else { - double t1 = (x1 - x0) / xD; - double t2 = (xH - x0) / xD; - if (t1 > t2) { - final double tTemp = t1; - t1 = t2; - t2 = tTemp; - } - if (t1 > tNear) - tNear = t1; - if (t2 < tFar) - tFar = t2; - if (tNear > tFar) - return false; - if (tFar < 0D) - return false; - } - if (yD == 0D) { - if (y0 < y1 || y0 > yH) - return false; - } else { - double t1 = (y1 - y0) / yD; - double t2 = (yH - y0) / yD; - if (t1 > t2) { - final double tTemp = t1; - t1 = t2; - t2 = tTemp; - } - if (t1 > tNear) - tNear = t1; - if (t2 < tFar) - tFar = t2; - if (tNear > tFar) - return false; - if (tFar < 0D) - return false; - } - if (zD == 0D) { - if (z0 < z1 || z0 > zH) - return false; - } else { - double t1 = (z1 - z0) / zD; - double t2 = (zH - z0) / zD; - if (t1 > t2) { - final double tTemp = t1; - t1 = t2; - t2 = tTemp; - } - if (t1 > tNear) - tNear = t1; - if (t2 < tFar) - tFar = t2; - if (tNear > tFar) - return false; - if (tFar < 0D) - return false; - } - return true; - } - /** * Return if the two Strings are similar based on the given threshold. *