+ 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)
This commit is contained in:
NeatMonster 2012-04-09 03:08:22 +02:00
parent dbfe983c1e
commit b08db5bd4b
18 changed files with 343 additions and 327 deletions

View File

@ -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 --------------------------------

View File

@ -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:

View File

@ -4,7 +4,7 @@
<!-- Informations -->
<name>NoCheatPlus</name>
<version>3.5.3</version>
<version>3.5.4</version>
<description>Detect and fight the exploitation of various flaws/bugs in Minecraft.</description>
<url>http://dev.bukkit.org/server-mods/nocheatplus</url>

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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.";

View File

@ -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]");

View File

@ -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";

View File

@ -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"),