From b08db5bd4ba9b920179713a75dc6cf64dd2e14cf Mon Sep 17 00:00:00 2001 From: NeatMonster Date: Mon, 9 Apr 2012 03:08:22 +0200 Subject: [PATCH] + Added the Projectile check to prevent various cheats + Added the AutoSign check to prevent players from spamming signs + Added the Tracker check to prevent players from staying too much time in the air = Improved the FastBreak check (should work with various plugins) = Improved the FastPlace check (shouldn't throw any false positive) --- Instructions.txt | 45 ++- plugin.yml | 4 + pom.xml | 2 +- .../checks/blockbreak/BlockBreakConfig.java | 4 + .../checks/blockbreak/BlockBreakData.java | 5 +- .../checks/blockbreak/FastBreakCheck.java | 328 +----------------- .../blockplace/BlockPlaceCheckListener.java | 93 ++++- .../checks/blockplace/BlockPlaceConfig.java | 9 + .../checks/blockplace/BlockPlaceData.java | 16 +- .../checks/blockplace/FastPlaceCheck.java | 21 +- .../checks/blockplace/ProjectileCheck.java | 54 +++ .../checks/moving/MovingCheckListener.java | 51 ++- .../checks/moving/MovingConfig.java | 7 + .../nocheatplus/checks/moving/MovingData.java | 3 + .../nocheatplus/config/ConfPaths.java | 11 + .../config/DefaultConfiguration.java | 14 +- .../nocheatplus/config/Permissions.java | 2 + .../nocheatplus/data/Statistics.java | 1 + 18 files changed, 343 insertions(+), 327 deletions(-) create mode 100644 src/me/neatmonster/nocheatplus/checks/blockplace/ProjectileCheck.java diff --git a/Instructions.txt b/Instructions.txt index b94d6154..3a55d225 100644 --- a/Instructions.txt +++ b/Instructions.txt @@ -240,6 +240,15 @@ - nocheatplus.checks.blockplace.direction Don't force players to look at the blocks that they try to place. + + - nocheatplus.checks.blockplace.projectile + Allows the player to throw projectiles very quickly, like expbottles, eggs, + monster eggs, eyes of ender, ender pearls. This is usually used by griefers + to level up very quickly or to crash the server by spawning too much mobs. + + - nocheatplus.checks.blockplace.autosign + Allows the player to place multiple signs with the same text. This is usually + used by griefers to place quickly a lot of signs with their signature. --------------------- INVENTORY Permissions for CHECKS ------------------------- @@ -597,6 +606,20 @@ fall distance in blocks that the player tried to avoid. It gets increased every time that the player fails the check, and decreased over time if the player doesn't fail the check. + + TRACKER: + This is an entire subsection dedicated to a recently introduced check + specially designed to prevent players from staying in the air longer + than a defined value. + + active: + Should players get checked for this type of movement related hacks at + all. If deactivated, player may stay in the air without being noticed + by NoCheat+. + + maxtime: + The maximum interval (in milliseconds) before kicking the player who + flies (it takes less than 6000 ms to fall from Y = 256 to Y = 0); FLYING: This is an entire subsection dedicated to the "moving.flying" check. @@ -837,7 +860,7 @@ combined with placing a lot of blocks in a certain shape. active: - Should players get checked for this type of hack + Should players get checked for this type of hack. precision: How strict should NoCheatPlus be when comparing the players line of view @@ -859,6 +882,26 @@ the distance in Blocks between the line of view of the player and the block. It increases with every failure and decreases with every successful block placement. + + 4) PROJECTILE + + Players may throw projectiles (experience bottles, eggs, monster eggs, + eyes of ender, ender pearls) really quickly in order to crash the server. + + active: + Should players get checked for this type of hack. + + interval: + The time (in milliseconds) between each thrown projectile. It takes + more than 150 ms if the player is keeping its right button pressed. + + actions: + What should happen if a player fails this check. Default is to prevent + the placing of the block ("cancel" it) and after repeated/more severe + offenses to log a message and kick the player. The Violation Level (VL) + for this check is the interval elapsed subtracted to the interval defined + in the configuration's file; It increases with every failure and decreases + with every successfully thrown projectile. ------------------------------- CHAT Subsection -------------------------------- diff --git a/plugin.yml b/plugin.yml index f3dc46bf..0dc7605e 100644 --- a/plugin.yml +++ b/plugin.yml @@ -73,6 +73,10 @@ permissions: description: Allow a player to place blocks at maximum range (about 6-7 blocks) nocheatplus.checks.blockplace.direction: description: Allow a player to place blocks outside their line of view + nocheatplus.checks.blockplace.projectile: + description: Allow a player to throw projectiles very quickly + nocheatplus.checks.blockplace.autosign: + description: Allow a player to create multiple signs with the same text nocheatplus.checks.chat: description: Allow the player to bypass all chat checks children: diff --git a/pom.xml b/pom.xml index 684db5f2..02bc7326 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ NoCheatPlus - 3.5.3 + 3.5.4 Detect and fight the exploitation of various flaws/bugs in Minecraft. http://dev.bukkit.org/server-mods/nocheatplus diff --git a/src/me/neatmonster/nocheatplus/checks/blockbreak/BlockBreakConfig.java b/src/me/neatmonster/nocheatplus/checks/blockbreak/BlockBreakConfig.java index f52a6014..a3ed65b1 100644 --- a/src/me/neatmonster/nocheatplus/checks/blockbreak/BlockBreakConfig.java +++ b/src/me/neatmonster/nocheatplus/checks/blockbreak/BlockBreakConfig.java @@ -15,6 +15,8 @@ import me.neatmonster.nocheatplus.config.Permissions; public class BlockBreakConfig implements ConfigItem { public final boolean fastBreakCheck; + public final int fastBreakIntervalSurvival; + public final int fastBreakIntervalCreative; public final ActionList fastBreakActions; public final boolean reachCheck; @@ -32,6 +34,8 @@ public class BlockBreakConfig implements ConfigItem { public BlockBreakConfig(final NoCheatPlusConfiguration data) { fastBreakCheck = data.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_CHECK); + fastBreakIntervalSurvival = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_INTERVALSURVIVAL); + fastBreakIntervalCreative = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_INTERVALCREATIVE); fastBreakActions = data.getActionList(ConfPaths.BLOCKBREAK_FASTBREAK_ACTIONS, Permissions.BLOCKBREAK_FASTBREAK); reachCheck = data.getBoolean(ConfPaths.BLOCKBREAK_REACH_CHECK); reachDistance = 535D / 100D; diff --git a/src/me/neatmonster/nocheatplus/checks/blockbreak/BlockBreakData.java b/src/me/neatmonster/nocheatplus/checks/blockbreak/BlockBreakData.java index 3349c599..7683fdc7 100644 --- a/src/me/neatmonster/nocheatplus/checks/blockbreak/BlockBreakData.java +++ b/src/me/neatmonster/nocheatplus/checks/blockbreak/BlockBreakData.java @@ -15,9 +15,12 @@ public class BlockBreakData implements DataItem { public double directionVL = 0.0D; public double noswingVL = 0.0D; - // Used the know when the player has broke his previous block + // Used to know when the player has broken his previous block public long lastBreakTime = 0; + // Used to know if the previous event was refused + public boolean previousRefused = false; + // Used for the penalty time feature of the direction check public long directionLastViolationTime = 0; diff --git a/src/me/neatmonster/nocheatplus/checks/blockbreak/FastBreakCheck.java b/src/me/neatmonster/nocheatplus/checks/blockbreak/FastBreakCheck.java index 34f7cf79..90c78c9a 100644 --- a/src/me/neatmonster/nocheatplus/checks/blockbreak/FastBreakCheck.java +++ b/src/me/neatmonster/nocheatplus/checks/blockbreak/FastBreakCheck.java @@ -8,8 +8,6 @@ import me.neatmonster.nocheatplus.actions.ParameterName; import me.neatmonster.nocheatplus.data.Statistics.Id; import org.bukkit.GameMode; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; public class FastBreakCheck extends BlockBreakCheck { @@ -19,297 +17,39 @@ public class FastBreakCheck extends BlockBreakCheck { public boolean check(final NoCheatPlusPlayer player, final BlockBreakData data, final BlockBreakConfig cc) { - int level = 0; - - // Get the player's item in hand material - Material tool = player.getPlayer().getItemInHand() == null ? null : player.getPlayer().getItemInHand() - .getType(); - if (isTool(tool)) - // It's a tool, let's check its enchantment level - level = player.getPlayer().getItemInHand().getEnchantmentLevel(Enchantment.DIG_SPEED); - else - // It's not a tool but something else - tool = null; - - // Get the block's material - final Material block = player.getPlayer().getWorld() - .getBlockAt(data.brokenBlockLocation.x, data.brokenBlockLocation.y, data.brokenBlockLocation.z) - .getType(); - - // Default break time value (creative mode minimum break time) - long breakTime = 145L; - if (player.getPlayer().getGameMode() == GameMode.SURVIVAL) - breakTime = Math.round(getBreakTime(level, tool, block)); + // Get the minimum break time for the player's game mode + int breakTime = cc.fastBreakIntervalSurvival; + if (player.getPlayer().getGameMode() == GameMode.CREATIVE) + breakTime = cc.fastBreakIntervalCreative; // Elapsed time since the previous block was broken - final long elapsedTime = Math.round((System.nanoTime() - data.lastBreakTime) / Math.pow(10, 6)); + final long elapsedTime = System.currentTimeMillis() - data.lastBreakTime; boolean cancel = false; - // Has the player broke blocks too quickly + // Has the player broken the blocks too quickly if (data.lastBreakTime != 0 && elapsedTime < breakTime) { - // He failed, increase vl and statistics - data.fastBreakVL += breakTime - elapsedTime; - incrementStatistics(player, Id.BB_FASTBREAK, breakTime - elapsedTime); - // Execute whatever actions are associated with this check and the - // violation level and find out if we should cancel the event - cancel = executeActions(player, cc.fastBreakActions, data.fastBreakVL); - } else + if (data.previousRefused) { + // He failed, increase vl and statistics + data.fastBreakVL += breakTime - elapsedTime; + incrementStatistics(player, Id.BB_FASTBREAK, breakTime - elapsedTime); + // Execute whatever actions are associated with this check and the + // violation level and find out if we should cancel the event + cancel = executeActions(player, cc.fastBreakActions, data.fastBreakVL); + } + data.previousRefused = true; + } else { // Reward with lowering of the violation level data.fastBreakVL *= 0.90D; + data.previousRefused = false; + } - data.lastBreakTime = System.nanoTime(); + data.lastBreakTime = System.currentTimeMillis(); return cancel; } - private double getBreakTime(final int level, final Material tool, final Material block) { - - double breakTime = -1D; - - /** SHOVEL **/ - if (block == Material.CLAY || block == Material.GRASS || block == Material.GRAVEL || block == Material.MYCEL) { - if (tool == null) - breakTime = 900D; - else if (isWood(tool)) - breakTime = 450D; - else if (isStone(tool)) - breakTime = 250D; - else if (isIron(tool) || isDiamond(tool)) - breakTime = 150D; - else if (isGold(tool)) - breakTime = 100D; - } else if (block == Material.DIRT || block == Material.SAND || block == Material.SOUL_SAND) { - if (tool == null) - breakTime = 750D; - else if (isWood(tool)) - breakTime = 400D; - else if (isStone(tool)) - breakTime = 200D; - else if (isIron(tool)) - breakTime = 150D; - else if (isDiamond(tool) || isGold(tool)) - breakTime = 100D; - } else if (block == Material.SNOW_BLOCK) { - if (tool == null) - breakTime = 1000D; - else if (isWood(tool)) - breakTime = 150D; - else if (isStone(tool)) - breakTime = 100D; - else if (isIron(tool) || isDiamond(tool) || isGold(tool)) - breakTime = 50D; - } else if (block == Material.SNOW) { - if (tool == null) - breakTime = 500D; - else if (isWood(tool)) - breakTime = 100D; - else if (isStone(tool) || isIron(tool) || isDiamond(tool) || isGold(tool)) - breakTime = 50D; - } - - /** AXE **/ - else if (block == Material.CHEST) { - if (tool == null) - breakTime = 3750D; - else if (isWood(tool)) - breakTime = 1900D; - else if (isStone(tool)) - breakTime = 950D; - else if (isIron(tool)) - breakTime = 650D; - else if (isDiamond(tool)) - breakTime = 500D; - else if (isGold(tool)) - breakTime = 350D; - } else if (block == Material.LOG || block == Material.WOOD) { - if (tool == null) - breakTime = 3000D; - else if (isStone(tool)) - breakTime = 1500D; - else if (isStone(tool)) - breakTime = 750D; - else if (isIron(tool)) - breakTime = 500D; - else if (isDiamond(tool)) - breakTime = 400D; - else if (isGold(tool)) - breakTime = 250D; - } else if (block == Material.BOOKSHELF) { - if (tool == null) - breakTime = 2250D; - else if (isWood(tool)) - breakTime = 1150D; - else if (isStone(tool)) - breakTime = 600D; - else if (isIron(tool)) - breakTime = 400D; - else if (isDiamond(tool)) - breakTime = 300D; - else if (isGold(tool)) - breakTime = 200D; - } - - /** PICKAXE **/ - else if (block == Material.OBSIDIAN) { - if (tool == null) - breakTime = 250000D; - else if (isWood(tool) || isStone(tool) || isIron(tool) || isGold(tool)) - breakTime = 50000D; - else if (isDiamond(tool)) - breakTime = 10000D; - } else if (block == Material.IRON_DOOR || block == Material.MOB_SPAWNER) { - if (tool == null) - breakTime = 25000D; - else if (isWood(tool) || isStone(tool) || isIron(tool) || isGold(tool) || isDiamond(tool)) - breakTime = 75000D; - } else if (block == Material.DIAMOND_BLOCK) { - if (tool == null || isWood(tool) || isStone(tool) || isGold(tool)) - breakTime = 25000D; - else if (isIron(tool)) - breakTime = 1250D; - else if (isDiamond(tool)) - breakTime = 850D; - } else if (block == Material.IRON_BLOCK) { - if (tool == null || isWood(tool) || isGold(tool)) - breakTime = 25000D; - else if (isStone(tool)) - breakTime = 2500D; - else if (isIron(tool)) - breakTime = 1250D; - else if (isDiamond(tool)) - breakTime = 950D; - } else if (block == Material.DISPENSER || block == Material.FURNACE) { - if (tool == null) - breakTime = 17500D; - else if (isStone(tool) || isWood(tool) || isGold(tool) || isIron(tool) || isDiamond(tool)) - breakTime = 5250D; - } else if (block == Material.COAL_ORE) { - if (tool == null) - breakTime = 15000D; - else if (isWood(tool)) - breakTime = 2250D; - else if (isStone(tool)) - breakTime = 1150D; - else if (isIron(tool)) - breakTime = 750D; - else if (isDiamond(tool)) - breakTime = 600D; - else if (isGold(tool)) - breakTime = 400D; - } else if (block == Material.DIAMOND_ORE || block == Material.GOLD_ORE || block == Material.REDSTONE_ORE - || block == Material.GOLD_BLOCK) { - if (tool == null || isWood(tool) || isStone(tool) || isGold(tool)) - breakTime = 15000D; - else if (isIron(tool)) - breakTime = 750D; - else if (isDiamond(tool)) - breakTime = 600D; - } else if (block == Material.IRON_ORE || block == Material.LAPIS_ORE || block == Material.LAPIS_BLOCK) { - if (tool == null || isWood(tool) || isGold(tool)) - breakTime = 15000D; - else if (isStone(tool)) - breakTime = 1150D; - else if (isIron(tool)) - breakTime = 750D; - else if (isDiamond(tool)) - breakTime = 600D; - } else if (block == Material.BRICK || block == Material.NETHER_BRICK || block == Material.WOOD_STAIRS - || block == Material.COBBLESTONE_STAIRS || block == Material.BRICK_STAIRS - || block == Material.SMOOTH_STAIRS || block == Material.NETHER_BRICK_STAIRS) { - if (tool == null) - breakTime = 10000D; - else if (isStone(tool) || isWood(tool) || isGold(tool) || isIron(tool) || isDiamond(tool)) - breakTime = 3000D; - } else if (block == Material.COBBLESTONE || block == Material.MOSSY_COBBLESTONE || block == Material.STEP) { - if (tool == null) - breakTime = 10000D; - else if (isWood(tool)) - breakTime = 1500D; - else if (isStone(tool)) - breakTime = 750D; - else if (isIron(tool)) - breakTime = 500D; - else if (isDiamond(tool)) - breakTime = 400D; - else if (isGold(tool)) - breakTime = 250D; - } else if (block == Material.STONE || block == Material.GLOWSTONE) { - if (tool == null) - breakTime = 7500D; - else if (isWood(tool)) - breakTime = 1150D; - else if (isStone(tool)) - breakTime = 600D; - else if (isIron(tool)) - breakTime = 400D; - else if (isDiamond(tool)) - breakTime = 300D; - else if (isGold(tool)) - breakTime = 200D; - } else if (block == Material.SANDSTONE) { - if (tool == null) - breakTime = 4000D; - else if (isWood(tool)) - breakTime = 600D; - else if (isStone(tool)) - breakTime = 300D; - else if (isIron(tool)) - breakTime = 200D; - else if (isDiamond(tool)) - breakTime = 150D; - else if (isGold(tool)) - breakTime = 100D; - } else if (block == Material.ICE) { - if (tool == null) - breakTime = 1000D; - else if (isWood(tool)) - breakTime = 400D; - else if (isStone(tool)) - breakTime = 200D; - else if (isIron(tool)) - breakTime = 150D; - else if (isDiamond(tool) || isGold(tool)) - breakTime = 100D; - } else if (block == Material.WOOD_PLATE || block == Material.STONE_PLATE) { - if (tool == null) - breakTime = 2500D; - else if (isWood(tool) || isStone(tool) || isIron(tool) || isDiamond(tool) || isGold(tool)) - breakTime = 750D; - } else if (block == Material.NETHERRACK) { - if (tool == null) - breakTime = 2000D; - else if (isWood(tool)) - breakTime = 300D; - else if (isStone(tool)) - breakTime = 150D; - else if (isIron(tool)) - breakTime = 100D; - else if (isDiamond(tool)) - breakTime = 100D; - else if (isGold(tool)) - breakTime = 50D; - } else if (block == Material.MONSTER_EGGS) - if (tool == null || isStone(tool) || isWood(tool) || isGold(tool) || isIron(tool) || isDiamond(tool)) - breakTime = 3000D; - - // If we haven't any data for the current block, just apply the default value - if (breakTime == -1D) - return 45D; - - // Adjust break time if the tool is enchanted - for (int i = level; i > 0; i--) - breakTime = breakTime -= 0.25D * breakTime; - - // Set a minimum value for the break time - if (breakTime < 50D) - return 45D; - - // Subtract 5 ms (margin of error) - return breakTime - 5D; - } - @Override public String getParameter(final ParameterName wildcard, final NoCheatPlusPlayer player) { @@ -318,34 +58,4 @@ public class FastBreakCheck extends BlockBreakCheck { else return super.getParameter(wildcard, player); } - - private boolean isDiamond(final Material tool) { - return tool == Material.DIAMOND_AXE || tool == Material.DIAMOND_PICKAXE || tool == Material.DIAMOND_SPADE - || tool == Material.DIAMOND_SWORD; - } - - private boolean isGold(final Material tool) { - return tool == Material.GOLD_AXE || tool == Material.GOLD_PICKAXE || tool == Material.GOLD_SPADE - || tool == Material.GOLD_SWORD; - } - - private boolean isIron(final Material tool) { - return tool == Material.IRON_AXE || tool == Material.IRON_PICKAXE || tool == Material.IRON_SPADE - || tool == Material.IRON_SWORD; - } - - private boolean isStone(final Material tool) { - return tool == Material.STONE_AXE || tool == Material.STONE_PICKAXE || tool == Material.STONE_SPADE - || tool == Material.STONE_SWORD; - } - - private boolean isTool(final Material tool) { - return isWood(tool) || isStone(tool) || isIron(tool) || isDiamond(tool) || isGold(tool); - } - - private boolean isWood(final Material tool) { - return tool == Material.WOOD_AXE || tool == Material.WOOD_PICKAXE || tool == Material.WOOD_SPADE - || tool == Material.WOOD_SWORD; - } - } diff --git a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java index d3b1b5d7..eeb77792 100644 --- a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java +++ b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java @@ -9,10 +9,17 @@ import me.neatmonster.nocheatplus.NoCheatPlusPlayer; import me.neatmonster.nocheatplus.config.ConfigurationCacheStore; import me.neatmonster.nocheatplus.config.Permissions; +import org.bukkit.Material; +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.block.Action; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.player.PlayerInteractEvent; /** * Central location to listen to Block-related events and dispatching them to @@ -21,10 +28,11 @@ import org.bukkit.event.block.BlockPlaceEvent; */ public class BlockPlaceCheckListener implements Listener, EventManager { - private final FastPlaceCheck fastPlaceCheck; - private final ReachCheck reachCheck; - private final DirectionCheck directionCheck; - private final NoCheatPlus plugin; + private final FastPlaceCheck fastPlaceCheck; + private final ReachCheck reachCheck; + private final DirectionCheck directionCheck; + private final ProjectileCheck projectileCheck; + private final NoCheatPlus plugin; public BlockPlaceCheckListener(final NoCheatPlus plugin) { @@ -33,6 +41,7 @@ public class BlockPlaceCheckListener implements Listener, EventManager { fastPlaceCheck = new FastPlaceCheck(plugin); reachCheck = new ReachCheck(plugin); directionCheck = new DirectionCheck(plugin); + projectileCheck = new ProjectileCheck(plugin); } @Override @@ -92,4 +101,80 @@ public class BlockPlaceCheckListener implements Listener, EventManager { if (cancelled) event.setCancelled(cancelled); } + + @EventHandler( + ignoreCancelled = true, priority = EventPriority.LOWEST) + public void monsterEgg(final PlayerInteractEvent event) { + + // We are only interested by monster eggs + if (event.getAction() != Action.RIGHT_CLICK_BLOCK || event.getPlayer().getItemInHand() == null + || event.getPlayer().getItemInHand().getType() != Material.MONSTER_EGG) + return; + + final NoCheatPlusPlayer player = plugin.getPlayer(event.getPlayer()); + final BlockPlaceConfig cc = BlockPlaceCheck.getConfig(player); + final BlockPlaceData data = BlockPlaceCheck.getData(player); + + // Do the actual check + if (cc.projectileCheck && !player.hasPermission(Permissions.BLOCKPLACE_PROJECTILE) + && projectileCheck.check(player, data, cc)) + // If the check is positive, cancel the event + event.setCancelled(true); + } + + @EventHandler( + ignoreCancelled = true, priority = EventPriority.LOWEST) + public void otherProjectiles(final ProjectileLaunchEvent event) { + + // We are only interested by enderpears, endersignals, eggs, snowballs and expbottles + if (event.getEntityType() != EntityType.ENDER_PEARL && event.getEntityType() != EntityType.ENDER_SIGNAL + && event.getEntityType() != EntityType.EGG && event.getEntityType() != EntityType.SNOWBALL + && event.getEntityType() != EntityType.THROWN_EXP_BOTTLE) + return; + + final NoCheatPlusPlayer player = plugin.getPlayer((Player) event.getEntity().getShooter()); + final BlockPlaceConfig cc = BlockPlaceCheck.getConfig(player); + final BlockPlaceData data = BlockPlaceCheck.getData(player); + + // Do the actual check + if (cc.projectileCheck && !player.hasPermission(Permissions.BLOCKPLACE_PROJECTILE) + && projectileCheck.check(player, data, cc)) + // If the check is positive, cancel the event + event.setCancelled(true); + } + + /** + * If the player places three times the same sign, + * the sign will be destroyed and looted + * + * @param event + * the SignChange event + */ + @EventHandler( + ignoreCancelled = true, priority = EventPriority.LOWEST) + public void sign(final SignChangeEvent event) { + + final NoCheatPlusPlayer player = plugin.getPlayer(event.getPlayer()); + final BlockPlaceData data = BlockPlaceCheck.getData(player); + + // Check if the text is the same + if (!event.getPlayer().hasPermission(Permissions.BLOCKPLACE_AUTOSIGN) + && event.getLine(0).equals(data.lastSignText[0]) && event.getLine(1).equals(data.lastSignText[1]) + && event.getLine(2).equals(data.lastSignText[2]) && event.getLine(3).equals(data.lastSignText[3]) + && data.lastSignText[0].equals(data.lastLastSignText[0]) + && data.lastSignText[1].equals(data.lastLastSignText[1]) + && data.lastSignText[2].equals(data.lastLastSignText[2]) + && data.lastSignText[3].equals(data.lastLastSignText[3])) + event.getBlock().breakNaturally(); + + // Save the text + data.lastLastSignText[3] = data.lastSignText[3]; + data.lastLastSignText[2] = data.lastSignText[2]; + data.lastLastSignText[1] = data.lastSignText[1]; + data.lastLastSignText[0] = data.lastSignText[0]; + data.lastSignText[3] = event.getLine(3); + data.lastSignText[2] = event.getLine(2); + data.lastSignText[1] = event.getLine(1); + data.lastSignText[0] = event.getLine(0); + } } diff --git a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceConfig.java b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceConfig.java index e97fe454..d8d03b9b 100644 --- a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceConfig.java +++ b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceConfig.java @@ -27,6 +27,10 @@ public class BlockPlaceConfig implements ConfigItem { public final long directionPenaltyTime; public final double directionPrecision; + public final boolean projectileCheck; + public final int projectileInterval; + public final ActionList projectileActions; + public BlockPlaceConfig(final NoCheatPlusConfiguration data) { fastPlaceCheck = data.getBoolean(ConfPaths.BLOCKPLACE_FASTPLACE_CHECK); @@ -41,5 +45,10 @@ public class BlockPlaceConfig implements ConfigItem { directionPenaltyTime = data.getInt(ConfPaths.BLOCKPLACE_DIRECTION_PENALTYTIME); directionPrecision = data.getInt(ConfPaths.BLOCKPLACE_DIRECTION_PRECISION) / 100D; directionActions = data.getActionList(ConfPaths.BLOCKPLACE_DIRECTION_ACTIONS, Permissions.BLOCKPLACE_DIRECTION); + + projectileCheck = data.getBoolean(ConfPaths.BLOCKPLACE_PROJECTILE_CHECK); + projectileInterval = data.getInt(ConfPaths.BLOCKPLACE_PROJECTILE_INTERVAL); + projectileActions = data.getActionList(ConfPaths.BLOCKPLACE_PROJECTILE_ACTIONS, + Permissions.BLOCKPLACE_PROJECTILE); } } diff --git a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceData.java b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceData.java index 93389f0e..e005771a 100644 --- a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceData.java +++ b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceData.java @@ -13,10 +13,14 @@ public class BlockPlaceData implements DataItem { public double fastPlaceVL = 0.0D; public double reachVL = 0.0D; public double directionVL = 0.0D; + public double projectileVL = 0.0D; - // Used the know when the player has placed his previous block + // Used to know when the player has placed his previous block public long lastPlaceTime = 0; + // Used to know if the previous event was refused + public boolean previousRefused = false; + // Used for the penalty time feature of the direction check public long directionLastViolationTime = 0; @@ -28,4 +32,14 @@ public class BlockPlaceData implements DataItem { // For logging, remember the reachDistance that was calculated in the // reach check public double reachdistance; + + // Store the two previous signs' text + public String[] lastSignText = new String[] {"", "", "", ""}; + public String[] lastLastSignText = new String[] {"", "", "", ""}; + + // Used to store the last time a projectile was thrown + public long lastProjectileTime = 0; + + // Used to know if the previous projectile-thrown-event was refused + public boolean previousProjectileRefused = false; } diff --git a/src/me/neatmonster/nocheatplus/checks/blockplace/FastPlaceCheck.java b/src/me/neatmonster/nocheatplus/checks/blockplace/FastPlaceCheck.java index ab97eeaa..5f85bb2e 100644 --- a/src/me/neatmonster/nocheatplus/checks/blockplace/FastPlaceCheck.java +++ b/src/me/neatmonster/nocheatplus/checks/blockplace/FastPlaceCheck.java @@ -19,17 +19,22 @@ public class FastPlaceCheck extends BlockPlaceCheck { // Has the player placed blocks too quickly if (data.lastPlaceTime != 0 && System.currentTimeMillis() - data.lastPlaceTime < cc.fastPlaceInterval) { - // He failed, increase vl and statistics - data.fastPlaceVL += cc.fastPlaceInterval - System.currentTimeMillis() + data.lastPlaceTime; - incrementStatistics(player, Id.BP_FASTPLACE, cc.fastPlaceInterval - System.currentTimeMillis() - + data.lastPlaceTime); + if (data.previousRefused) { + // He failed, increase vl and statistics + data.fastPlaceVL += cc.fastPlaceInterval - System.currentTimeMillis() + data.lastPlaceTime; + incrementStatistics(player, Id.BP_FASTPLACE, cc.fastPlaceInterval - System.currentTimeMillis() + + data.lastPlaceTime); - // Execute whatever actions are associated with this check and the - // violation level and find out if we should cancel the event - cancel = executeActions(player, cc.fastPlaceActions, data.fastPlaceVL); - } else + // Execute whatever actions are associated with this check and the + // violation level and find out if we should cancel the event + cancel = executeActions(player, cc.fastPlaceActions, data.fastPlaceVL); + } + data.previousRefused = true; + } else { // Reward with lowering of the violation level data.fastPlaceVL *= 0.90D; + data.previousRefused = false; + } data.lastPlaceTime = System.currentTimeMillis(); diff --git a/src/me/neatmonster/nocheatplus/checks/blockplace/ProjectileCheck.java b/src/me/neatmonster/nocheatplus/checks/blockplace/ProjectileCheck.java new file mode 100644 index 00000000..c2c95b72 --- /dev/null +++ b/src/me/neatmonster/nocheatplus/checks/blockplace/ProjectileCheck.java @@ -0,0 +1,54 @@ +package me.neatmonster.nocheatplus.checks.blockplace; + +import java.util.Locale; + +import me.neatmonster.nocheatplus.NoCheatPlus; +import me.neatmonster.nocheatplus.NoCheatPlusPlayer; +import me.neatmonster.nocheatplus.actions.ParameterName; +import me.neatmonster.nocheatplus.data.Statistics.Id; + +public class ProjectileCheck extends BlockPlaceCheck { + + public ProjectileCheck(final NoCheatPlus plugin) { + super(plugin, "blockplace.projectile"); + } + + public boolean check(final NoCheatPlusPlayer player, final BlockPlaceData data, final BlockPlaceConfig cc) { + + boolean cancel = false; + + // Has the player thrown the projectiles too quickly + if (data.lastProjectileTime != 0 + && System.currentTimeMillis() - data.lastProjectileTime < cc.projectileInterval) { + if (data.previousProjectileRefused) { + // He failed, increase vl and statistics + data.projectileVL += cc.projectileInterval - System.currentTimeMillis() + data.lastProjectileTime; + incrementStatistics(player, Id.BP_PROJECTILE, cc.projectileInterval - System.currentTimeMillis() + + data.lastProjectileTime); + + // Execute whatever actions are associated with this check and the + // violation level and find out if we should cancel the event + cancel = executeActions(player, cc.projectileActions, data.projectileVL); + } + data.previousProjectileRefused = true; + } else { + // Reward with lowering of the violation level + data.projectileVL *= 0.90D; + data.previousProjectileRefused = false; + } + + data.lastProjectileTime = System.currentTimeMillis(); + + return cancel; + + } + + @Override + public String getParameter(final ParameterName wildcard, final NoCheatPlusPlayer player) { + + if (wildcard == ParameterName.VIOLATIONS) + return String.format(Locale.US, "%d", (int) getData(player).projectileVL); + else + return super.getParameter(wildcard, player); + } +} diff --git a/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java b/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java index cd659709..42b10137 100644 --- a/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java +++ b/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java @@ -11,6 +11,8 @@ import me.neatmonster.nocheatplus.config.ConfigurationCacheStore; import me.neatmonster.nocheatplus.config.Permissions; import me.neatmonster.nocheatplus.data.PreciseLocation; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -55,6 +57,52 @@ public class MovingCheckListener implements Listener, EventManager { morePacketsVehicleCheck = new MorePacketsVehicleCheck(plugin); waterWalkCheck = new WaterWalkCheck(plugin); + // Schedule a new synchronized repeating task repeated 20 times/s. + Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() { + + @Override + public void run() { + + for (final Player bukkitPlayer : Bukkit.getOnlinePlayers()) { + + // Get some data about the player/config + final NoCheatPlusPlayer player = plugin.getPlayer(bukkitPlayer); + final MovingConfig cc = MovingCheck.getConfig(player); + final MovingData data = MovingCheck.getData(player); + + // Do not do the check if it's disabled, if flying is allowed, if the player is + // allowed to fly because of its game mode or if he has the required permission. + if (!cc.tracker || cc.allowFlying || bukkitPlayer.getGameMode() == GameMode.CREATIVE + || bukkitPlayer.getAllowFlight() || bukkitPlayer.hasPermission(Permissions.MOVING_RUNFLY)) + return; + + // If the player is in water or in vines, then do not run the check + if (bukkitPlayer.getLocation().getBlock().getType() == Material.WATER + || bukkitPlayer.getLocation().getBlock().getType() == Material.STATIONARY_WATER + || bukkitPlayer.getLocation().getBlock().getType() == Material.VINE) + return; + + // If the player isn't falling or jumping + if (Math.abs(bukkitPlayer.getVelocity().getY()) > 0.1D) { + + // The player is falling/jumping, check if he was previously on the ground + if (data.fallingSince == 0) + data.fallingSince = System.currentTimeMillis(); + + // Check if he has stayed too much time in the air + else if (System.currentTimeMillis() - data.fallingSince > cc.maxtime) { + // He has, so now kick it + bukkitPlayer.kickPlayer("Flying isn't enabled on this server!"); + data.fallingSince = 0; + } + } else // The player isn't falling/jumping, check if he was previous on the air + if (data.fallingSince > 0) + // Reset the timer + data.fallingSince = 0; + } + } + }, 1L, 1L); + this.plugin = plugin; } @@ -187,7 +235,8 @@ public class MovingCheckListener implements Listener, EventManager { newTo = runningCheck.check(player, data, cc); /** WATERWALK CHECK SECTION **/ - if (newTo == null && cc.waterWalkCheck && (!player.isCreative() || !cc.identifyCreativeMode) + if (newTo == null && cc.waterWalkCheck && !cc.allowFlying && (!player.isCreative() || !cc.identifyCreativeMode) + && (!cc.runflyCheck || !player.hasPermission(Permissions.MOVING_FLYING)) && !player.hasPermission(Permissions.MOVING_WATERWALK)) newTo = waterWalkCheck.check(player, data, cc); diff --git a/src/me/neatmonster/nocheatplus/checks/moving/MovingConfig.java b/src/me/neatmonster/nocheatplus/checks/moving/MovingConfig.java index 948e289e..930d1821 100644 --- a/src/me/neatmonster/nocheatplus/checks/moving/MovingConfig.java +++ b/src/me/neatmonster/nocheatplus/checks/moving/MovingConfig.java @@ -22,6 +22,10 @@ public class MovingConfig implements ConfigItem { public final boolean sneakingCheck; public final double sneakingSpeedLimit; public final ActionList actions; + + public final boolean tracker; + public final int maxtime; + public final boolean allowFlying; public final double flyingSpeedLimitVertical; public final double flyingSpeedLimitHorizontal; @@ -62,6 +66,9 @@ public class MovingConfig implements ConfigItem { sneakingCheck = !data.getBoolean(ConfPaths.MOVING_RUNFLY_ALLOWFASTSNEAKING); actions = data.getActionList(ConfPaths.MOVING_RUNFLY_ACTIONS, Permissions.MOVING_RUNFLY); + tracker = data.getBoolean(ConfPaths.MOVING_RUNFLY_TRACKER_CHECK); + maxtime = data.getInt(ConfPaths.MOVING_RUNFLY_TRACKER_MAXTIME); + allowFlying = data.getBoolean(ConfPaths.MOVING_RUNFLY_FLYING_ALLOWALWAYS); flyingSpeedLimitVertical = data.getInt(ConfPaths.MOVING_RUNFLY_FLYING_SPEEDLIMITVERTICAL) / 100D; flyingSpeedLimitHorizontal = data.getInt(ConfPaths.MOVING_RUNFLY_FLYING_SPEEDLIMITHORIZONTAL) / 100D; diff --git a/src/me/neatmonster/nocheatplus/checks/moving/MovingData.java b/src/me/neatmonster/nocheatplus/checks/moving/MovingData.java index 462fe275..e3461576 100644 --- a/src/me/neatmonster/nocheatplus/checks/moving/MovingData.java +++ b/src/me/neatmonster/nocheatplus/checks/moving/MovingData.java @@ -42,6 +42,9 @@ public class MovingData implements DataItem { public float fallDistance; public float lastAddedFallDistance; + // Keep in mind since when the player in falling/jumping + public long fallingSince = 0L; + // Keep track of when "morePackets" last time checked and how much packets // a player sent and may send before failing the check public long morePacketsLastTime; diff --git a/src/me/neatmonster/nocheatplus/config/ConfPaths.java b/src/me/neatmonster/nocheatplus/config/ConfPaths.java index 23cab1d5..17757801 100644 --- a/src/me/neatmonster/nocheatplus/config/ConfPaths.java +++ b/src/me/neatmonster/nocheatplus/config/ConfPaths.java @@ -57,6 +57,10 @@ public abstract class ConfPaths { public final static String MOVING_RUNFLY_NOFALLAGGRESSIVE = MOVING_RUNFLY + "nofallaggressivemode"; public final static String MOVING_RUNFLY_NOFALLACTIONS = MOVING_RUNFLY + "nofallactions"; + private final static String MOVING_RUNFLY_TRACKER = MOVING_RUNFLY + "tracker."; + public final static String MOVING_RUNFLY_TRACKER_CHECK = MOVING_RUNFLY_TRACKER + "active"; + public final static String MOVING_RUNFLY_TRACKER_MAXTIME = MOVING_RUNFLY_TRACKER + "maxtime"; + private final static String MOVING_RUNFLY_FLYING = MOVING_RUNFLY + "flying."; public final static String MOVING_RUNFLY_FLYING_ALLOWALWAYS = MOVING_RUNFLY_FLYING + "allowflyingalways"; public final static String MOVING_RUNFLY_FLYING_ALLOWINCREATIVE = MOVING_RUNFLY_FLYING @@ -84,6 +88,8 @@ public abstract class ConfPaths { private final static String BLOCKBREAK_FASTBREAK = BLOCKBREAK + "fastbreak."; public final static String BLOCKBREAK_FASTBREAK_CHECK = BLOCKBREAK_FASTBREAK + "active"; + public final static String BLOCKBREAK_FASTBREAK_INTERVALSURVIVAL = BLOCKBREAK_FASTBREAK + "intervalsurvival"; + public final static String BLOCKBREAK_FASTBREAK_INTERVALCREATIVE = BLOCKBREAK_FASTBREAK + "intervalcreative"; public final static String BLOCKBREAK_FASTBREAK_ACTIONS = BLOCKBREAK_FASTBREAK + "actions"; private final static String BLOCKBREAK_REACH = BLOCKBREAK + "reach."; @@ -117,6 +123,11 @@ public abstract class ConfPaths { public final static String BLOCKPLACE_DIRECTION_PENALTYTIME = BLOCKPLACE_DIRECTION + "penaltytime"; public final static String BLOCKPLACE_DIRECTION_ACTIONS = BLOCKPLACE_DIRECTION + "actions"; + private final static String BLOCKPLACE_PROJECTILE = BLOCKPLACE + "projectile."; + public final static String BLOCKPLACE_PROJECTILE_CHECK = BLOCKPLACE_PROJECTILE + "active"; + public final static String BLOCKPLACE_PROJECTILE_INTERVAL = BLOCKPLACE_PROJECTILE + "interval"; + public final static String BLOCKPLACE_PROJECTILE_ACTIONS = BLOCKPLACE_PROJECTILE + "actions"; + private final static String CHAT = CHECKS + "chat."; private final static String CHAT_COLOR = CHAT + "color."; diff --git a/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java b/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java index 068af65b..69e73a45 100644 --- a/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java +++ b/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java @@ -53,6 +53,9 @@ public class DefaultConfiguration extends NoCheatPlusConfiguration { set(ConfPaths.MOVING_RUNFLY_NOFALLAGGRESSIVE, true); set(ConfPaths.MOVING_RUNFLY_NOFALLACTIONS, "log:nofall:0:5:cif cancel"); + set(ConfPaths.MOVING_RUNFLY_TRACKER_CHECK, true); + set(ConfPaths.MOVING_RUNFLY_TRACKER_MAXTIME, 6000); + set(ConfPaths.MOVING_RUNFLY_FLYING_ALLOWALWAYS, false); set(ConfPaths.MOVING_RUNFLY_FLYING_ALLOWINCREATIVE, true); set(ConfPaths.MOVING_RUNFLY_FLYING_SPEEDLIMITHORIZONTAL, 60); @@ -74,8 +77,10 @@ public class DefaultConfiguration extends NoCheatPlusConfiguration { /*** BLOCKBREAK ***/ set(ConfPaths.BLOCKBREAK_FASTBREAK_CHECK, true); + set(ConfPaths.BLOCKBREAK_FASTBREAK_INTERVALSURVIVAL, 45); + set(ConfPaths.BLOCKBREAK_FASTBREAK_INTERVALCREATIVE, 145); set(ConfPaths.BLOCKBREAK_FASTBREAK_ACTIONS, - "vl>200 cancel vl> 1000 log:bbfastbreak:2:5:cif cancel vl>400 log:bbfastbreak:3:5:cif cmd:kick cancel"); + "cancel vl>100 log:bbfastbreak:3:5:cif cancel vl>2000 log:bbfastbreak:3:5:cif cmd:kick cancel"); set(ConfPaths.BLOCKBREAK_REACH_CHECK, true); set(ConfPaths.BLOCKBREAK_REACH_ACTIONS, "cancel vl>5 log:bbreach:0:2:if cancel"); @@ -103,6 +108,11 @@ public class DefaultConfiguration extends NoCheatPlusConfiguration { set(ConfPaths.BLOCKPLACE_DIRECTION_PENALTYTIME, 100); set(ConfPaths.BLOCKPLACE_DIRECTION_ACTIONS, "cancel vl>10 log:bpdirection:0:3:if cancel"); + set(ConfPaths.BLOCKPLACE_PROJECTILE_CHECK, true); + set(ConfPaths.BLOCKPLACE_PROJECTILE_INTERVAL, 150); + set(ConfPaths.BLOCKPLACE_PROJECTILE_ACTIONS, + "cancel vl>150 log:bpprojectile:3:5:if cancel vl>1000 log:bpprojectile:3:5:cif cancel vl>4000 log:bpprojectile:3:5:cif cancel cmd:kick"); + /*** CHAT ***/ set(ConfPaths.CHAT_COLOR_CHECK, true); @@ -165,6 +175,8 @@ public class DefaultConfiguration extends NoCheatPlusConfiguration { "[player] failed [check]: tried to interact with a block over distance [reachdistance]. VL [violations]"); set(ConfPaths.STRINGS + ".bpdirection", "[player] failed [check]: tried to interact with a block out of line of sight. VL [violations]"); + set(ConfPaths.STRINGS + ".bpprojectile", + "[player] failed [check]: tried to throw items too quicly. VL [violations]"); set(ConfPaths.STRINGS + ".color", "[player] failed [check]: Sent colored chat message '[text]'. VL [violations]"); set(ConfPaths.STRINGS + ".spam", "[player] failed [check]: Last sent message '[text]'. VL [violations]"); diff --git a/src/me/neatmonster/nocheatplus/config/Permissions.java b/src/me/neatmonster/nocheatplus/config/Permissions.java index 1cec9a5d..63c34871 100644 --- a/src/me/neatmonster/nocheatplus/config/Permissions.java +++ b/src/me/neatmonster/nocheatplus/config/Permissions.java @@ -27,6 +27,8 @@ public class Permissions { public static final String BLOCKPLACE_FASTPLACE = BLOCKPLACE + ".fastplace"; public static final String BLOCKPLACE_REACH = BLOCKPLACE + ".reach"; public static final String BLOCKPLACE_DIRECTION = BLOCKPLACE + ".direction"; + public static final String BLOCKPLACE_PROJECTILE = BLOCKPLACE + ".projectile"; + public static final String BLOCKPLACE_AUTOSIGN = BLOCKPLACE + ".autosign"; private static final String CHAT = CHECKS + ".chat"; public static final String CHAT_SPAM = CHAT + ".spam"; diff --git a/src/me/neatmonster/nocheatplus/data/Statistics.java b/src/me/neatmonster/nocheatplus/data/Statistics.java index 0fcd3331..a9c1526e 100644 --- a/src/me/neatmonster/nocheatplus/data/Statistics.java +++ b/src/me/neatmonster/nocheatplus/data/Statistics.java @@ -16,6 +16,7 @@ public class Statistics { BP_FASTPLACE("blockplace.fastplace"), BP_DIRECTION("blockplace.direction"), BP_REACH("blockplace.reach"), + BP_PROJECTILE("blockplace.projectile"), CHAT_COLOR("chat.color"), CHAT_SPAM("chat.spam"), FI_DIRECTION("fight.direction"),