Ignore vehicles and movement with positive Y-Velocity in Speedhack

check + reset speedhack event counter in case of teleports + version
bump
This commit is contained in:
Evenprime 2011-03-26 17:20:27 +01:00
parent 74e39bc99e
commit d93438db24
6 changed files with 100 additions and 102 deletions

View File

@ -3,7 +3,7 @@ name: NoCheatPlugin
author: Evenprime author: Evenprime
main: cc.co.evenprime.bukkit.nocheat.NoCheatPlugin main: cc.co.evenprime.bukkit.nocheat.NoCheatPlugin
version: 0.7.4a version: 0.7.5
commands: commands:
nocheat: nocheat:

View File

@ -76,17 +76,17 @@ public class NoCheatConfiguration {
ircLevel = stringToLevel(c.getString("logging.logtoirc")); ircLevel = stringToLevel(c.getString("logging.logtoirc"));
ircTag = c.getString("logging.logtoirctag", "nocheat"); ircTag = c.getString("logging.logtoirctag", "nocheat");
plugin.speedhackCheck.limitLow = c.getInt("speedhack.limits.low", plugin.speedhackCheck.limitLow); plugin.speedhackCheck.limits[0] = c.getInt("speedhack.limits.low", plugin.speedhackCheck.limits[0]);
plugin.speedhackCheck.limitMed = c.getInt("speedhack.limits.med", plugin.speedhackCheck.limitMed); plugin.speedhackCheck.limits[1] = c.getInt("speedhack.limits.med", plugin.speedhackCheck.limits[1]);
plugin.speedhackCheck.limitHigh = c.getInt("speedhack.limits.high", plugin.speedhackCheck.limitHigh); plugin.speedhackCheck.limits[2] = c.getInt("speedhack.limits.high", plugin.speedhackCheck.limits[2]);
plugin.movingCheck.actions[0] = c.getString("moving.action.low", plugin.movingCheck.actions[0]); plugin.movingCheck.actions[0] = c.getString("moving.action.low", plugin.movingCheck.actions[0]);
plugin.movingCheck.actions[1] = c.getString("moving.action.med", plugin.movingCheck.actions[1]); plugin.movingCheck.actions[1] = c.getString("moving.action.med", plugin.movingCheck.actions[1]);
plugin.movingCheck.actions[2] = c.getString("moving.action.high", plugin.movingCheck.actions[2]); plugin.movingCheck.actions[2] = c.getString("moving.action.high", plugin.movingCheck.actions[2]);
plugin.speedhackCheck.actionLow = c.getString("speedhack.action.low", plugin.speedhackCheck.actionLow); plugin.speedhackCheck.actions[0] = c.getString("speedhack.action.low", plugin.speedhackCheck.actions[0]);
plugin.speedhackCheck.actionMed = c.getString("speedhack.action.med", plugin.speedhackCheck.actionMed); plugin.speedhackCheck.actions[1] = c.getString("speedhack.action.med", plugin.speedhackCheck.actions[1]);
plugin.speedhackCheck.actionHigh = c.getString("speedhack.action.high", plugin.speedhackCheck.actionHigh); plugin.speedhackCheck.actions[2] = c.getString("speedhack.action.high", plugin.speedhackCheck.actions[2]);
plugin.airbuildCheck.limits[0] = c.getInt("airbuild.limits.low", plugin.airbuildCheck.limits[0]); plugin.airbuildCheck.limits[0] = c.getInt("airbuild.limits.low", plugin.airbuildCheck.limits[0]);
plugin.airbuildCheck.limits[1] = c.getInt("airbuild.limits.med", plugin.airbuildCheck.limits[1]); plugin.airbuildCheck.limits[1] = c.getInt("airbuild.limits.med", plugin.airbuildCheck.limits[1]);
@ -146,14 +146,14 @@ public class NoCheatConfiguration {
w.write("# Speedhack specific options"); w.newLine(); w.write("# Speedhack specific options"); w.newLine();
w.write("speedhack:"); w.newLine(); w.write("speedhack:"); w.newLine();
w.write(" limits:"); w.newLine(); w.write(" limits:"); w.newLine();
w.write(" low: "+plugin.speedhackCheck.limitLow); w.newLine(); w.write(" low: "+plugin.speedhackCheck.limits[0]); w.newLine();
w.write(" med: "+plugin.speedhackCheck.limitMed); w.newLine(); w.write(" med: "+plugin.speedhackCheck.limits[1]); w.newLine();
w.write(" high: "+plugin.speedhackCheck.limitHigh); w.newLine(); w.write(" high: "+plugin.speedhackCheck.limits[2]); w.newLine();
w.write("# Speedhack Action, one or more of 'loglow logmed loghigh reset'"); w.newLine(); w.write("# Speedhack Action, one or more of 'loglow logmed loghigh reset'"); w.newLine();
w.write(" action:"); w.newLine(); w.write(" action:"); w.newLine();
w.write(" low: "+plugin.speedhackCheck.actionLow); w.newLine(); w.write(" low: "+plugin.speedhackCheck.actions[0]); w.newLine();
w.write(" med: "+plugin.speedhackCheck.actionMed); w.newLine(); w.write(" med: "+plugin.speedhackCheck.actions[1]); w.newLine();
w.write(" high: "+plugin.speedhackCheck.actionHigh); w.newLine(); w.write(" high: "+plugin.speedhackCheck.actions[2]); w.newLine();
w.write("# Moving specific options") ; w.newLine(); w.write("# Moving specific options") ; w.newLine();
w.write("moving:"); w.newLine(); w.write("moving:"); w.newLine();
w.write("# Moving Action, one or more of 'loglow logmed loghigh reset'"); w.newLine(); w.write("# Moving Action, one or more of 'loglow logmed loghigh reset'"); w.newLine();

View File

@ -16,12 +16,15 @@ public class NoCheatData {
*/ */
public int movingJumpPhase = 0; // current jumpingPhase public int movingJumpPhase = 0; // current jumpingPhase
public long movingLastViolationTime = 0;
public int movingViolationsInARow[] = { 0, 0, 0 }; public int movingViolationsInARow[] = { 0, 0, 0 };
public World movingLastWorld = null; public World movingLastWorld = null;
public int movingHorizFreeMoves = 4; public int movingHorizFreeMoves = 4;
public Location movingSetBackPoint = null; public Location movingSetBackPoint = null;
public Location movingLocation = null; public Location movingLocation = null;
public Runnable movingRunnable = null;
public int legitMoves = 0;
public boolean reset = false; public boolean reset = false;
public long speedhackLastCheck = System.currentTimeMillis(); // timestamp of last check for speedhacks public long speedhackLastCheck = System.currentTimeMillis(); // timestamp of last check for speedhacks

View File

@ -49,8 +49,8 @@ public class AirbuildCheck extends Check {
} }
}; };
// Give a summary in 50 ticks ~ 1 second // Give a summary in 20 ticks ~ 1 second
plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.airbuildRunnable, 50); plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.airbuildRunnable, 20);
} }
data.airbuildPerSecond++; data.airbuildPerSecond++;

View File

@ -3,6 +3,7 @@ package cc.co.evenprime.bukkit.nocheat.checks;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import cc.co.evenprime.bukkit.nocheat.NoCheatData; import cc.co.evenprime.bukkit.nocheat.NoCheatData;
@ -189,21 +190,15 @@ public class MovingCheck extends Check {
data.speedhackSetBackPoint = null; data.speedhackSetBackPoint = null;
return; return;
} }
// The server believes the player should be moving up, so we ignore this event
if(event.getPlayer().getVelocity().getY() >= 0) {
data.movingSetBackPoint = null;
data.speedhackSetBackPoint = null;
return;
}
// The actual movingCheck starts here // The actual movingCheck starts here
// Get the two locations of the event // Get the two locations of the event
Location from = event.getFrom(); Location from = event.getFrom();
Location to = event.getTo(); Location to = event.getTo();
// First check the distance the player has moved horizontally // First check the distance the player has moved horizontally
// TODO: Make this check much more precise // TODO: Make this check much more precise
double xDistance = Math.abs(from.getX() - to.getX()); double xDistance = Math.abs(from.getX() - to.getX());
@ -215,20 +210,20 @@ public class MovingCheck extends Check {
return; // players are allowed to "teleport" into a bed over short distances return; // players are allowed to "teleport" into a bed over short distances
} }
int vlx = -1; int vl = -1;
// How far are we off? // How far are we off?
if(combined > moveLimits[2]) { if(combined > moveLimits[2]) {
vlx = max(vlx, 2); vl = max(vl, 2);
} }
else if(combined > moveLimits[1]) { else if(combined > moveLimits[1]) {
vlx = max(vlx, 1); vl = max(vl, 1);
} }
else if(combined > moveLimits[0]) { else if(combined > moveLimits[0]) {
if(data.movingHorizFreeMoves > 0) { if(data.movingHorizFreeMoves > 0) {
data.movingHorizFreeMoves--; data.movingHorizFreeMoves--;
} }
else vlx = max(vlx, 0); else vl = max(vl, 0);
} }
else{ else{
data.movingHorizFreeMoves = 4; data.movingHorizFreeMoves = 4;
@ -243,6 +238,13 @@ public class MovingCheck extends Check {
boolean onGroundFrom = playerIsOnGround(from.getWorld(), fromValues, from); boolean onGroundFrom = playerIsOnGround(from.getWorld(), fromValues, from);
boolean onGroundTo = playerIsOnGround(to.getWorld(), toValues, to); boolean onGroundTo = playerIsOnGround(to.getWorld(), toValues, to);
// Ignore events if the player has positive y-Velocity
if(event.getPlayer().getVelocity().getY() > 0.0D) {
data.movingSetBackPoint = from.clone();
data.movingJumpPhase = 0;
return;
}
// Handle 4 distinct cases: Walk, Jump, Land, Fly // Handle 4 distinct cases: Walk, Jump, Land, Fly
// Walk // Walk
@ -251,9 +253,9 @@ public class MovingCheck extends Check {
double limit = stepHeight; double limit = stepHeight;
double distance = to.getY() - from.getY(); double distance = to.getY() - from.getY();
vlx = max(vlx, heightLimitCheck(limit, distance)); vl = max(vl, heightLimitCheck(limit, distance));
if(vlx < 0) if(vl < 0)
{ {
// reset jumping // reset jumping
data.movingJumpPhase = 0; data.movingJumpPhase = 0;
@ -267,9 +269,9 @@ public class MovingCheck extends Check {
double distance = to.getY() - from.getY(); double distance = to.getY() - from.getY();
// Check if player isn't jumping too high // Check if player isn't jumping too high
vlx = max(vlx, heightLimitCheck(limit, distance)); vl = max(vl, heightLimitCheck(limit, distance));
if(vlx < 0) { if(vl < 0) {
// Setup next phase of the jump // Setup next phase of the jump
data.movingJumpPhase = 1; data.movingJumpPhase = 1;
data.movingSetBackPoint = from.clone(); data.movingSetBackPoint = from.clone();
@ -289,9 +291,9 @@ public class MovingCheck extends Check {
double distance = to.getY() - l.getY(); double distance = to.getY() - l.getY();
// Check if player isn't jumping too high // Check if player isn't jumping too high
vlx = max(vlx, heightLimitCheck(limit, distance)); vl = max(vl, heightLimitCheck(limit, distance));
if(vlx < 0) { if(vl < 0) {
data.movingJumpPhase = 0; // He is on ground now, so reset the jump data.movingJumpPhase = 0; // He is on ground now, so reset the jump
data.movingSetBackPoint = to.clone(); data.movingSetBackPoint = to.clone();
} }
@ -309,9 +311,9 @@ public class MovingCheck extends Check {
double distance = to.getY() - l.getY(); double distance = to.getY() - l.getY();
// Check if player isn't jumping too high // Check if player isn't jumping too high
vlx = max(vlx, heightLimitCheck(limit, distance)); vl = max(vl, heightLimitCheck(limit, distance));
if(vlx < 0) { if(vl < 0) {
data.movingJumpPhase++; // Enter next phase of the flight data.movingJumpPhase++; // Enter next phase of the flight
// Setback point stays the same. IF we don't have one, take the "from" location as a setback point for now // Setback point stays the same. IF we don't have one, take the "from" location as a setback point for now
if(data.movingSetBackPoint == null) { if(data.movingSetBackPoint == null) {
@ -320,12 +322,28 @@ public class MovingCheck extends Check {
} }
} }
if(vlx < 0 && (onGroundFrom || onGroundTo)) { if(vl < 0 && (onGroundFrom || onGroundTo) && data.legitMoves < 100) {
legitimateMove(data, event); data.legitMoves++;
} }
else if(vlx >= 0) { else if(vl >= 0) {
data.movingLastViolationTime = System.currentTimeMillis(); final Player p = event.getPlayer();
final NoCheatData d = data;
if(data.movingRunnable == null) {
data.movingRunnable = new Runnable() {
@Override
public void run() {
summary(p, d);
// deleting its own reference
d.movingRunnable = null;
}
};
// Give a summary in 100 ticks ~ 5 second
plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.movingRunnable, 100);
}
// If we haven't already got a setback point, make this location the new setback point // If we haven't already got a setback point, make this location the new setback point
if(data.movingSetBackPoint == null) { if(data.movingSetBackPoint == null) {
@ -336,30 +354,12 @@ public class MovingCheck extends Check {
boolean log = true; boolean log = true;
// Find out with what actions to treat the violation(s) // Find out with what actions to treat the violation(s)
if(vlx == 0) { if(vl >= 0) {
if(data.movingViolationsInARow[0] > 0) log = false; if(data.movingViolationsInARow[vl] > 0) log = false; // only log the first violation of that level
data.movingViolationsInARow[0]++; data.movingViolationsInARow[vl]++;
action = actions[0]; action = actions[vl];
// after a set number of minor violations a normal violation gets thrown
if(data.movingViolationsInARow[0] % 40 == 0) {
vlx = 1;
log = true;
}
} }
if(vlx == 1) {
if(data.movingViolationsInARow[1] > 0) log = false;
data.movingViolationsInARow[1]++;
action = actions[1];
}
if(vlx == 2) {
if(data.movingViolationsInARow[2] > 0) log = false;
data.movingViolationsInARow[2]++;
action = actions[2];
}
action(event, action, log); action(event, action, log);
} }
} }
@ -372,8 +372,9 @@ public class MovingCheck extends Check {
} }
else { else {
if(!event.isCancelled()) { if(!event.isCancelled()) {
// If it wasn't our plugin that ordered the teleport, forget all our information and start from scratch at the new location // If it wasn't our plugin that ordered the teleport, forget (almost) all our information and start from scratch at the new location
data.speedhackSetBackPoint = event.getTo().clone(); data.speedhackSetBackPoint = event.getTo().clone();
data.speedhackEventsSinceLastCheck = 0;
data.movingSetBackPoint = event.getTo().clone(); data.movingSetBackPoint = event.getTo().clone();
data.movingJumpPhase = 0; data.movingJumpPhase = 0;
} }
@ -398,32 +399,20 @@ public class MovingCheck extends Check {
resetPlayer(event); resetPlayer(event);
} }
} }
private void summary(Player p, NoCheatData data) {
String action;
// Give a summary (to the highest violation level that occured)
if(data.movingViolationsInARow[2] > 0) action = actions[2];
else if(data.movingViolationsInARow[1] > 0) action = actions[1];
else if(data.movingViolationsInARow[0] > 0) action = actions[0];
else action = "";
plugin.logAction(action, "Moving summary of last ~5 seconds: "+p.getName() + " total Violations: ("+ data.movingViolationsInARow[0] + "," + data.movingViolationsInARow[1] + "," + data.movingViolationsInARow[2] + ")");
data.movingViolationsInARow[2] = 0;
data.movingViolationsInARow[1] = 0;
protected void legitimateMove(NoCheatData data, PlayerMoveEvent event) { data.movingViolationsInARow[0] = 0;
// Give some logging about violations if the player hasn't done any for at least two seconds
if(data.movingLastViolationTime != 0 && data.movingLastViolationTime + 2000L < System.currentTimeMillis()) {
data.movingLastViolationTime = 0;
// Give some additional logs about now ending violations
if(data.movingViolationsInARow[2] > 0) {
plugin.logAction(actions[2], "Moving violation ended: "+event.getPlayer().getName() + " total Events: "+ data.movingViolationsInARow[2]);
data.movingViolationsInARow[2] = 0;
}
if(data.movingViolationsInARow[1] > 0) {
plugin.logAction(actions[1], "Moving violation ended: "+event.getPlayer().getName()+ " total Events: "+ data.movingViolationsInARow[1]);
data.movingViolationsInARow[1] = 0;
}
if(data.movingViolationsInARow[0] > 0) {
plugin.logAction(actions[0], "Moving violation ended: "+event.getPlayer().getName()+ " total Events: "+ data.movingViolationsInARow[0]);
data.movingViolationsInARow[0] = 0;
}
data.movingViolationsInARow[0] = 0;
}
} }
private int heightLimitCheck(double limit, double value) { private int heightLimitCheck(double limit, double value) {

View File

@ -23,14 +23,10 @@ public class SpeedhackCheck extends Check {
private static final int violationsLimit = 3; private static final int violationsLimit = 3;
// Limits for the speedhack check // Limits for the speedhack check
public int limitLow = 30; public int limits[] = { 30, 45, 60 };
public int limitMed = 45;
public int limitHigh = 60;
// How should speedhack violations be treated? // How should speedhack violations be treated?
public String actionLow = "loglow reset"; public String actions[] = { "loglow reset", "logmed reset", "loghigh reset" };
public String actionMed = "logmed reset";
public String actionHigh = "loghigh reset";
public void check(PlayerMoveEvent event) { public void check(PlayerMoveEvent event) {
@ -41,6 +37,16 @@ public class SpeedhackCheck extends Check {
// Get the player-specific data // Get the player-specific data
NoCheatData data = plugin.getPlayerData(event.getPlayer()); NoCheatData data = plugin.getPlayerData(event.getPlayer());
// Ignore events if the player has positive y-Velocity (these can be the cause of event spam between server and client)
if(event.getPlayer().getVelocity().getY() > 0.0D) {
return;
}
// Ignore events of players in vehicles (these can be the cause of event spam between server and client)
if(event.getPlayer().isInsideVehicle()) {
return;
}
// Get the time of the server // Get the time of the server
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
@ -50,14 +56,14 @@ public class SpeedhackCheck extends Check {
// TODO: Needs some better handling for server lag // TODO: Needs some better handling for server lag
String action = null; String action = null;
int low = (int)((limitLow * (time - data.speedhackLastCheck)) / interval); int low = (int)((limits[0] * (time - data.speedhackLastCheck)) / interval);
int med = (int)((limitMed * (time - data.speedhackLastCheck)) / interval); int med = (int)((limits[1] * (time - data.speedhackLastCheck)) / interval);
int high = (int)((limitHigh * (time - data.speedhackLastCheck)) / interval); int high = (int)((limits[2] * (time - data.speedhackLastCheck)) / interval);
if(data.speedhackEventsSinceLastCheck > high) action = actionLow; if(data.speedhackEventsSinceLastCheck > high) action = actions[2];
else if(data.speedhackEventsSinceLastCheck > med) action = actionMed; else if(data.speedhackEventsSinceLastCheck > med) action = actions[1];
else if(data.speedhackEventsSinceLastCheck > low) action = actionHigh; else if(data.speedhackEventsSinceLastCheck > low) action = actions[0];
if(action == null) { if(action == null) {
data.speedhackSetBackPoint = event.getFrom().clone(); data.speedhackSetBackPoint = event.getFrom().clone();
@ -89,7 +95,7 @@ public class SpeedhackCheck extends Check {
if(actions == null) return; if(actions == null) return;
// LOGGING IF NEEDED // LOGGING IF NEEDED
if(actions.contains("log")) { if(actions.contains("log")) {
plugin.logAction(actions, event.getPlayer().getName()+" sent "+ data.speedhackEventsSinceLastCheck + " move events, but only "+limitLow+ " were allowed. Speedhack?"); plugin.logAction(actions, event.getPlayer().getName()+" sent "+ data.speedhackEventsSinceLastCheck + " move events, but only "+limits[0]+ " were allowed. Speedhack?");
} }
// RESET IF NEEDED // RESET IF NEEDED
if(actions.contains("reset")) { if(actions.contains("reset")) {