mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-09-04 11:11:10 +02:00
Option to "log" to moderators + more code comments + info about active
checks at startup
This commit is contained in:
parent
a0cd0995c9
commit
02628becaf
|
@ -3,5 +3,5 @@ name: NoCheatPlugin
|
|||
author: Evenprime
|
||||
|
||||
main: cc.co.evenprime.bukkit.nocheat.NoCheatPlugin
|
||||
version: 0.5.3
|
||||
version: 0.5.3a
|
||||
|
||||
|
|
|
@ -5,30 +5,39 @@ import org.bukkit.Material;
|
|||
import org.bukkit.World;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Check if the player tries to place blocks in midair (which shouldn't be possible)
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*/
|
||||
public class BlockPlacingCheck {
|
||||
|
||||
public static void check(BlockPlaceEvent event) {
|
||||
|
||||
|
||||
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.airbuild")) {
|
||||
public static void check(BlockPlaceEvent event) {
|
||||
|
||||
// Should we check at all?
|
||||
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.airbuild")) {
|
||||
return;
|
||||
}
|
||||
else if(NoCheatPlugin.Permissions == null && event.getPlayer().isOp() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location l = event.getBlockPlaced().getLocation();
|
||||
World w = event.getBlock().getWorld();
|
||||
int airId = Material.AIR.getId();
|
||||
|
||||
if(w.getBlockTypeIdAt(l.getBlockX()-1, l.getBlockY(), l.getBlockZ()) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX()+1, l.getBlockY(), l.getBlockZ()) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY()-1, l.getBlockZ()) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY()+1, l.getBlockZ()) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ()-1) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ()+1) == airId) {
|
||||
event.setCancelled(true);
|
||||
NoCheatPlugin.log.warning("NoCheatPlugin: Airbuild violation: "+event.getPlayer().getName()+" tried to place block " + event.getBlockPlaced().getType() + " in the air");
|
||||
}
|
||||
|
||||
Location l = event.getBlockPlaced().getLocation();
|
||||
World w = event.getBlock().getWorld();
|
||||
int airId = Material.AIR.getId();
|
||||
|
||||
// Are all 6 sides "air-blocks" -> cancel the event
|
||||
if(w.getBlockTypeIdAt(l.getBlockX()-1, l.getBlockY(), l.getBlockZ()) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX()+1, l.getBlockY(), l.getBlockZ()) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY()-1, l.getBlockZ()) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY()+1, l.getBlockZ()) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ()-1) == airId &&
|
||||
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ()+1) == airId) {
|
||||
event.setCancelled(true);
|
||||
NoCheatPlugin.logNormal("NoCheatPlugin: Airbuild violation: "+event.getPlayer().getName()+" tried to place block " + event.getBlockPlaced().getType() + " in the air at " + l.getBlockX() + "," + l.getBlockY() +"," + l.getBlockZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,20 +6,28 @@ import org.bukkit.Material;
|
|||
import org.bukkit.World;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Check if the player should be allowed to make that move, e.g. is he allowed to jump here or move that far in one step
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*/
|
||||
public class MovingCheck {
|
||||
|
||||
// previously-calculated upper bound values for jumps. Minecraft is very deterministic when it comes to jumps
|
||||
// Each entry represents the maximum gain in height per move event.
|
||||
private static double jumpingPhases[] = new double[]{ 0.501D, 0.34D, 0.26D, 0.17D, 0.09D, 0.02D, 0.00D, -0.07D, -0.15D, -0.22D, -0.29D, -0.36D, -0.43D, -0.50D };
|
||||
|
||||
// Violation levels
|
||||
private static final int HEAVY = 3;
|
||||
private static final int NORMAL = 2;
|
||||
private static final int MINOR = 1;
|
||||
private static final int NONE = 0;
|
||||
|
||||
// Every player gets freebee moves to prevent them from getting stuck to easy
|
||||
private static final int freeIllegalMoves = 1;
|
||||
|
||||
// Block types that may be treated specially
|
||||
private enum BlockType {
|
||||
SOLID, NONSOLID, LADDER, LIQUID, UNKNOWN;
|
||||
}
|
||||
|
@ -117,9 +125,10 @@ public class MovingCheck {
|
|||
types[Material.CAKE_BLOCK.getId()]= BlockType.UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
public static void check(NoCheatPluginData data, PlayerMoveEvent event) {
|
||||
|
||||
|
||||
// Should we check at all
|
||||
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.moving")) {
|
||||
return;
|
||||
}
|
||||
|
@ -163,16 +172,16 @@ public class MovingCheck {
|
|||
if(onGroundFrom && onGroundTo)
|
||||
{
|
||||
// reset jumping
|
||||
data.phase = 0;
|
||||
data.movingJumpPhase = 0;
|
||||
|
||||
// Check if the player isn't 'walking' up unrealistically far in one step
|
||||
// Finally found out why this can happen:
|
||||
// If a player runs into a wall at an angle from above, the game tries to
|
||||
// place him above the block he bumped into, by placing him 0.5 m above
|
||||
// the target block
|
||||
if(!(to.getY() - from.getY() < jumpingPhases[data.phase])) {
|
||||
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
|
||||
|
||||
double offset = (to.getY() - from.getY()) - jumpingPhases[data.phase];
|
||||
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
|
||||
|
||||
if(offset > 2D) vl = vl > HEAVY ? vl : HEAVY;
|
||||
else if(offset > 0.6D) vl = vl > NORMAL ? vl : NORMAL;
|
||||
|
@ -183,12 +192,12 @@ public class MovingCheck {
|
|||
else if(onGroundFrom && !onGroundTo)
|
||||
{
|
||||
// reset jumping
|
||||
data.phase = 0;
|
||||
data.movingJumpPhase = 0;
|
||||
|
||||
// Check if player isn't jumping too high
|
||||
if(!(to.getY() - from.getY() < jumpingPhases[data.phase])) {
|
||||
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
|
||||
|
||||
double offset = (to.getY() - from.getY()) - jumpingPhases[data.phase];
|
||||
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
|
||||
|
||||
if(offset > 2D) vl = vl > HEAVY ? vl : HEAVY;
|
||||
else if(offset > 0.6D) vl = vl > NORMAL ? vl : NORMAL;
|
||||
|
@ -198,46 +207,46 @@ public class MovingCheck {
|
|||
// Very special case if running over a cliff and then immediately jumping.
|
||||
// Some sort of "air jump", MC allows it, so we have to do so too.
|
||||
}
|
||||
else data.phase++; // Setup next phase of the jump
|
||||
else data.movingJumpPhase++; // Setup next phase of the jump
|
||||
}
|
||||
// player is probably landing somewhere
|
||||
else if(!onGroundFrom && onGroundTo)
|
||||
{
|
||||
// Check if player isn't landing to high (sounds weird, but has its use)
|
||||
if(!(to.getY() - from.getY() < jumpingPhases[data.phase])) {
|
||||
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
|
||||
|
||||
double offset = (to.getY() - from.getY()) - jumpingPhases[data.phase];
|
||||
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
|
||||
|
||||
if(offset > 2D) vl = vl > HEAVY ? vl : HEAVY;
|
||||
else if(offset > 0.6D) vl = vl > NORMAL ? vl : NORMAL;
|
||||
else vl = vl > MINOR ? vl : MINOR;
|
||||
}
|
||||
else {
|
||||
data.phase = 0; // He is on ground now, so reset the jump
|
||||
data.movingJumpPhase = 0; // He is on ground now, so reset the jump
|
||||
}
|
||||
}
|
||||
// Player is moving through air (during jumping, falling)
|
||||
else {
|
||||
// May also be at the very edge of a platform (I seem to not be able to reliably tell if that's the case)
|
||||
if(!(to.getY() - from.getY() < jumpingPhases[data.phase])) {
|
||||
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
|
||||
|
||||
double offset = (to.getY() - from.getY()) - jumpingPhases[data.phase];
|
||||
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
|
||||
|
||||
if(offset > 2D) vl = vl > HEAVY ? vl : HEAVY;
|
||||
else if(offset > 0.6D) vl = vl > NORMAL ? vl : NORMAL;
|
||||
else vl = vl > MINOR ? vl : MINOR;
|
||||
}
|
||||
|
||||
data.phase++; // Enter next phase of the flight
|
||||
data.movingJumpPhase++; // Enter next phase of the flight
|
||||
}
|
||||
|
||||
// do a security check on the jumping phase, such that we don't get
|
||||
// OutOfArrayBoundsExceptions at long air times (falling off high places)
|
||||
if(!(data.phase < jumpingPhases.length)) {
|
||||
data.phase = jumpingPhases.length - 1;
|
||||
if(!(data.movingJumpPhase < jumpingPhases.length)) {
|
||||
data.movingJumpPhase = jumpingPhases.length - 1;
|
||||
}
|
||||
|
||||
// Treat the violation(s)
|
||||
// Treat the violation(s) according to their level
|
||||
switch(vl) {
|
||||
case MINOR:
|
||||
minorViolation(data, event);
|
||||
|
@ -256,86 +265,91 @@ public class MovingCheck {
|
|||
|
||||
protected static void minorViolation(NoCheatPluginData data, PlayerMoveEvent event) {
|
||||
|
||||
if(data.minorViolationsInARow == 0) {
|
||||
// Store the source location for later use
|
||||
// If it is the first violation, store the "from" location for potential later use
|
||||
if(data.movingMinorViolationsInARow == 0) {
|
||||
data.movingSetBackPoint = event.getFrom().clone();
|
||||
}
|
||||
|
||||
// Start logging only after the freebee illegal moves are over
|
||||
if(data.minorViolationsInARow == freeIllegalMoves + 1) {
|
||||
NoCheatPlugin.log.info("NoCheatPlugin: Moving violation: "+event.getPlayer().getName()+" from " + String.format("(%.5f, %.5f, %.5f) to (%.5f, %.5f, %.5f)", event.getFrom().getX(), event.getFrom().getY(), event.getFrom().getZ(), event.getTo().getX(), event.getTo().getY(), event.getTo().getZ()));
|
||||
// Start logging only after the freebee illegal moves have all been used
|
||||
if(data.movingMinorViolationsInARow == freeIllegalMoves + 1) {
|
||||
NoCheatPlugin.logMinor("NoCheatPlugin: Moving violation: "+event.getPlayer().getName()+" from " + String.format("(%.5f, %.5f, %.5f) to (%.5f, %.5f, %.5f)", event.getFrom().getX(), event.getFrom().getY(), event.getFrom().getZ(), event.getTo().getX(), event.getTo().getY(), event.getTo().getZ()));
|
||||
|
||||
}
|
||||
|
||||
data.minorViolationsInARow++;
|
||||
data.movingMinorViolationsInARow++;
|
||||
|
||||
// 16 minor violations in a row count as one normal violation
|
||||
if(data.minorViolationsInARow % 16 == 0) {
|
||||
if(data.movingMinorViolationsInARow % 16 == 0) {
|
||||
normalViolation(data, event);
|
||||
}
|
||||
else if(data.minorViolationsInARow % (freeIllegalMoves+1) == 0) {
|
||||
// now we need it
|
||||
// Each time the freebee moves are all used up, we may reset the player to his old location
|
||||
else if(data.movingMinorViolationsInARow % (freeIllegalMoves + 1) == 0) {
|
||||
resetPlayer(data, event);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void normalViolation(NoCheatPluginData data, PlayerMoveEvent event) {
|
||||
// Log the first violation in a row
|
||||
if(data.normalViolationsInARow == 0)
|
||||
NoCheatPlugin.log.warning("NoCheatPlugin: Moving violation: "+event.getPlayer().getName()+" from " + String.format("(%.5f, %.5f, %.5f) to (%.5f, %.5f, %.5f)", event.getFrom().getX(), event.getFrom().getY(), event.getFrom().getZ(), event.getTo().getX(), event.getTo().getY(), event.getTo().getZ()));
|
||||
if(data.movingNormalViolationsInARow == 0)
|
||||
NoCheatPlugin.logNormal("NoCheatPlugin: Moving violation: "+event.getPlayer().getName()+" from " + String.format("(%.5f, %.5f, %.5f) to (%.5f, %.5f, %.5f)", event.getFrom().getX(), event.getFrom().getY(), event.getFrom().getZ(), event.getTo().getX(), event.getTo().getY(), event.getTo().getZ()));
|
||||
|
||||
resetPlayer(data, event);
|
||||
|
||||
data.normalViolationsInARow++;
|
||||
data.movingNormalViolationsInARow++;
|
||||
}
|
||||
|
||||
protected static void heavyViolation(NoCheatPluginData data, PlayerMoveEvent event) {
|
||||
|
||||
if(data.heavyViolationsInARow == 0)
|
||||
NoCheatPlugin.log.severe("NoCheatPlugin: Moving violation: "+event.getPlayer().getName()+" from " + String.format("(%.5f, %.5f, %.5f) to (%.5f, %.5f, %.5f)", event.getFrom().getX(), event.getFrom().getY(), event.getFrom().getZ(), event.getTo().getX(), event.getTo().getY(), event.getTo().getZ()));
|
||||
// Log the first violation in a row
|
||||
if(data.movingHeavyViolationsInARow == 0)
|
||||
NoCheatPlugin.logHeavy("NoCheatPlugin: Moving violation: "+event.getPlayer().getName()+" from " + String.format("(%.5f, %.5f, %.5f) to (%.5f, %.5f, %.5f)", event.getFrom().getX(), event.getFrom().getY(), event.getFrom().getZ(), event.getTo().getX(), event.getTo().getY(), event.getTo().getZ()));
|
||||
|
||||
resetPlayer(data, event);
|
||||
|
||||
data.heavyViolationsInARow++;
|
||||
// Log the first violation in a row
|
||||
data.movingHeavyViolationsInARow++;
|
||||
}
|
||||
|
||||
protected static void legitimateMove(NoCheatPluginData data, PlayerMoveEvent event) {
|
||||
// Give some additional logs
|
||||
if(data.heavyViolationsInARow > 0) {
|
||||
NoCheatPlugin.log.severe("NoCheatPlugin: Moving violation stopped: "+event.getPlayer().getName() + " total Events: "+ data.heavyViolationsInARow);
|
||||
data.heavyViolationsInARow = 0;
|
||||
// Give some additional logs about now ending violations
|
||||
if(data.movingHeavyViolationsInARow > 0) {
|
||||
NoCheatPlugin.logHeavy("NoCheatPlugin: Moving violation stopped: "+event.getPlayer().getName() + " total Events: "+ data.movingHeavyViolationsInARow);
|
||||
data.movingHeavyViolationsInARow = 0;
|
||||
}
|
||||
else if(data.normalViolationsInARow > 0) {
|
||||
NoCheatPlugin.log.warning("NoCheatPlugin: Moving violation stopped: "+event.getPlayer().getName()+ " total Events: "+ data.normalViolationsInARow);
|
||||
data.normalViolationsInARow = 0;
|
||||
else if(data.movingNormalViolationsInARow > 0) {
|
||||
NoCheatPlugin.logNormal("NoCheatPlugin: Moving violation stopped: "+event.getPlayer().getName()+ " total Events: "+ data.movingNormalViolationsInARow);
|
||||
data.movingNormalViolationsInARow = 0;
|
||||
}
|
||||
else if(data.minorViolationsInARow > freeIllegalMoves) {
|
||||
NoCheatPlugin.log.info("NoCheatPlugin: Moving violation stopped: "+event.getPlayer().getName()+ " total Events: "+ data.minorViolationsInARow);
|
||||
data.minorViolationsInARow = 0;
|
||||
else if(data.movingMinorViolationsInARow > freeIllegalMoves) {
|
||||
NoCheatPlugin.logMinor("NoCheatPlugin: Moving violation stopped: "+event.getPlayer().getName()+ " total Events: "+ data.movingMinorViolationsInARow);
|
||||
data.movingMinorViolationsInARow = 0;
|
||||
}
|
||||
else {
|
||||
data.minorViolationsInARow = 0;
|
||||
data.movingMinorViolationsInARow = 0;
|
||||
}
|
||||
|
||||
// Setback point isn't needed anymore
|
||||
data.movingSetBackPoint = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the event and return the player to a stored location or if that is not available,
|
||||
* the the previous location.
|
||||
* Return the player to a stored location or if that is not available,
|
||||
* the previous location.
|
||||
* @param data
|
||||
* @param event
|
||||
*/
|
||||
private static void resetPlayer(NoCheatPluginData data, PlayerMoveEvent event) {
|
||||
|
||||
// If we only log, we never reset the player to his original location
|
||||
// If we only log, we never reset the player to his original location and can end here already
|
||||
if(NoCheatConfiguration.movingLogOnly) return;
|
||||
|
||||
if(data.phase > 7) {
|
||||
data.phase = 7;
|
||||
// Still not a perfect solution. After resetting a player his vertical momentum gets lost
|
||||
// Therefore we can't expect him to fall big distances in his next move, therefore we have to
|
||||
// set his flying phase to something he can work with.
|
||||
if(data.movingJumpPhase > 7) {
|
||||
data.movingJumpPhase = 7;
|
||||
}
|
||||
|
||||
// If we have stored a location for the player, we put him back there
|
||||
if(data.movingSetBackPoint != null) {
|
||||
|
||||
// Lets try it that way. Maybe now people don't "disappear" any longer
|
||||
|
|
|
@ -11,31 +11,50 @@ import java.util.logging.Logger;
|
|||
|
||||
import org.bukkit.util.config.Configuration;
|
||||
|
||||
/**
|
||||
* Central location for everything that's described in the configuration file
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*/
|
||||
public class NoCheatConfiguration {
|
||||
|
||||
// Our personal logger
|
||||
public static final String loggerName = "cc.co.evenprime.bukkit.nocheat";
|
||||
public static final Logger logger = Logger.getLogger(loggerName);
|
||||
|
||||
// Which checks are active
|
||||
public static boolean speedhackCheckActive = true;
|
||||
public static boolean movingCheckActive = true;
|
||||
public static boolean airbuildCheckActive = false;
|
||||
|
||||
// Limits for the speedhack check
|
||||
public static int speedhackInterval = 2000;
|
||||
public static int speedhackLow = 60;
|
||||
public static int speedhackMed = 90;
|
||||
public static int speedhackHigh = 120;
|
||||
|
||||
// Limits for the moving check
|
||||
public static double movingDistanceLow = 0.5D;
|
||||
public static double movingDistanceMed = 1.0D;
|
||||
public static double movingDistanceHigh = 5.0D;
|
||||
|
||||
// Should moving violations be punished?
|
||||
public static boolean movingLogOnly = false;
|
||||
|
||||
// The log level above which players with the permission nocheat.notify will get informed about violations
|
||||
public static Level notifyLevel = Level.OFF;
|
||||
|
||||
// Our two log outputs, the console and a file
|
||||
private static ConsoleHandler ch = null;
|
||||
private static FileHandler fh = null;
|
||||
|
||||
private NoCheatConfiguration() {}
|
||||
|
||||
/**
|
||||
* Read the configuration file and assign either standard values or whatever is declared in the file
|
||||
* @param configurationFile
|
||||
*/
|
||||
public static void config(File configurationFile) {
|
||||
|
||||
if(!configurationFile.exists()) {
|
||||
|
@ -46,7 +65,8 @@ public class NoCheatConfiguration {
|
|||
|
||||
logger.setLevel(Level.INFO);
|
||||
logger.setUseParentHandlers(false);
|
||||
|
||||
|
||||
|
||||
if(ch == null) {
|
||||
ch = new ConsoleHandler();
|
||||
|
||||
|
@ -55,9 +75,10 @@ public class NoCheatConfiguration {
|
|||
logger.addHandler(ch);
|
||||
}
|
||||
|
||||
|
||||
if(fh == null) {
|
||||
try {
|
||||
fh = new FileHandler(c.getString("logging.filename"), true);
|
||||
fh = new FileHandler(c.getString("logging.filename"), 2000, 2, true);
|
||||
fh.setLevel(stringToLevel(c.getString("logging.logtofile")));
|
||||
fh.setFormatter(Logger.getLogger("Minecraft").getHandlers()[0].getFormatter());
|
||||
logger.addHandler(fh);
|
||||
|
@ -68,6 +89,8 @@ public class NoCheatConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
notifyLevel = stringToLevel(c.getString("logging.logtonotify"));
|
||||
|
||||
speedhackCheckActive = c.getBoolean("active.speedhack", true);
|
||||
movingCheckActive = c.getBoolean("active.moving", true);
|
||||
airbuildCheckActive = c.getBoolean("active.airbuild", false);
|
||||
|
@ -80,6 +103,11 @@ public class NoCheatConfiguration {
|
|||
movingLogOnly = c.getBoolean("moving.logonly", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string into a log level
|
||||
* @param string
|
||||
* @return
|
||||
*/
|
||||
private static Level stringToLevel(String string) {
|
||||
|
||||
if(string == null) {
|
||||
|
@ -92,6 +120,10 @@ public class NoCheatConfiguration {
|
|||
return Level.OFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard configuration file for people who haven't got one yet
|
||||
* @param f
|
||||
*/
|
||||
private static void createStandardConfigFile(File f) {
|
||||
try {
|
||||
f.getParentFile().mkdirs();
|
||||
|
@ -103,6 +135,7 @@ public class NoCheatConfiguration {
|
|||
w.write(" filename: plugins/NoCheat/nocheat.log"); w.newLine();
|
||||
w.write(" logtofile: info"); w.newLine();
|
||||
w.write(" logtoconsole: severe"); w.newLine();
|
||||
w.write(" logtonotify: warn"); w.newLine();
|
||||
w.write("# Checks that are activated (true or false)"); w.newLine();
|
||||
w.write("active:"); w.newLine();
|
||||
w.write(" speedhack: true"); w.newLine();
|
||||
|
|
|
@ -3,6 +3,7 @@ package cc.co.evenprime.bukkit.nocheat;
|
|||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Server;
|
||||
|
@ -22,32 +23,60 @@ import org.bukkit.plugin.Plugin;
|
|||
*
|
||||
* NoCheatPlugin
|
||||
*
|
||||
* Check PLAYER_MOVE events for their plausibility and cancel them if they are implausible
|
||||
* Check various player events for their plausibilty and log/deny them based on configuration
|
||||
*
|
||||
* @author Evenprime
|
||||
*/
|
||||
public class NoCheatPlugin extends JavaPlugin {
|
||||
|
||||
// Various listeners needed for different Checks
|
||||
private final NoCheatPluginPlayerListener playerListener;
|
||||
private final NoCheatPluginVehicleListener vehicleListener;
|
||||
private final NoCheatPluginBlockListener blockListener;
|
||||
|
||||
public static Logger log;
|
||||
// My main logger
|
||||
private static Logger log;
|
||||
|
||||
// Permissions 2.0, if available
|
||||
public static PermissionHandler Permissions = null;
|
||||
|
||||
// A reference to the instance of the plugin
|
||||
private static NoCheatPlugin p = null;
|
||||
|
||||
// Store data between Events
|
||||
public static Map<Player, NoCheatPluginData> playerData = new HashMap<Player, NoCheatPluginData>();
|
||||
|
||||
/**
|
||||
* Ridiculously long constructor to keep supporting older bukkit versions, as long as it is possible
|
||||
*
|
||||
* @param pluginLoader
|
||||
* @param instance
|
||||
* @param desc
|
||||
* @param f1
|
||||
* @param f2
|
||||
* @param cLoader
|
||||
*/
|
||||
public NoCheatPlugin(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File f1, File f2, ClassLoader cLoader) {
|
||||
super(pluginLoader, instance, desc, f1, f2, cLoader);
|
||||
|
||||
// Create our listeners and feed them with neccessary information
|
||||
playerListener = new NoCheatPluginPlayerListener();
|
||||
vehicleListener = new NoCheatPluginVehicleListener(playerListener);
|
||||
blockListener = new NoCheatPluginBlockListener();
|
||||
|
||||
log = NoCheatConfiguration.logger;
|
||||
|
||||
p = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main access to data that needs to be stored between different events.
|
||||
* Always returns a NoCheatPluginData object, because if there isn't one
|
||||
* for the specified player, one will be created.
|
||||
*
|
||||
* @param p
|
||||
* @return
|
||||
*/
|
||||
public static NoCheatPluginData getPlayerData(Player p) {
|
||||
NoCheatPluginData data = null;
|
||||
|
||||
|
@ -71,19 +100,30 @@ public class NoCheatPlugin extends JavaPlugin {
|
|||
public void onEnable() {
|
||||
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener, Priority.Lowest, this);
|
||||
pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener, Priority.Monitor, this);
|
||||
pm.registerEvent(Event.Type.VEHICLE_EXIT, vehicleListener, Priority.Monitor, this);
|
||||
pm.registerEvent(Event.Type.VEHICLE_DAMAGE, vehicleListener, Priority.Monitor, this);
|
||||
pm.registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.Low, this);
|
||||
pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener, Priority.Lowest, this); // needed for speedhack and moving checks
|
||||
pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener, Priority.Monitor, this); // used to delete old data of users
|
||||
pm.registerEvent(Event.Type.VEHICLE_EXIT, vehicleListener, Priority.Monitor, this); // used for moving check
|
||||
pm.registerEvent(Event.Type.VEHICLE_DAMAGE, vehicleListener, Priority.Monitor, this); // used for moving check
|
||||
pm.registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.Low, this); // used for airbuild check
|
||||
|
||||
PluginDescriptionFile pdfFile = this.getDescription();
|
||||
Logger.getLogger("Minecraft").info( "NoCheat version " + pdfFile.getVersion() + " is enabled!" );
|
||||
|
||||
|
||||
// Get, if available, the Permissions 2.0 plugin
|
||||
setupPermissions();
|
||||
|
||||
// parse the nocheat.yml config file
|
||||
setupConfig();
|
||||
|
||||
String checks = (NoCheatConfiguration.movingCheckActive ? "moving ": "") +
|
||||
(NoCheatConfiguration.speedhackCheckActive ? "speedhack " : "") +
|
||||
(NoCheatConfiguration.airbuildCheckActive ? "airbuild " : "");
|
||||
|
||||
Logger.getLogger("Minecraft").info( "NoCheatPlugin version " + pdfFile.getVersion() + " is enabled with the following checks: "+checks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get, if available, a reference to the Permissions-plugin
|
||||
*/
|
||||
public void setupPermissions() {
|
||||
Plugin test = this.getServer().getPluginManager().getPlugin("Permissions");
|
||||
|
||||
|
@ -94,9 +134,56 @@ public class NoCheatPlugin extends JavaPlugin {
|
|||
this.getServer().getPluginManager().disablePlugin(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a minor violation message to all locations declared in the config file
|
||||
* @param message
|
||||
*/
|
||||
public static void logMinor(String message) {
|
||||
if(NoCheatConfiguration.notifyLevel.intValue() <= Level.INFO.intValue()) {
|
||||
for(Player player : p.getServer().getOnlinePlayers()) {
|
||||
if(Permissions.has(player, "nocheat.notify")) {
|
||||
player.sendMessage("[INFO] " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a normal violation message to all locations declared in the config file
|
||||
* @param message
|
||||
*/
|
||||
public static void logNormal(String message) {
|
||||
if(NoCheatConfiguration.notifyLevel.intValue() <= Level.WARNING.intValue()) {
|
||||
for(Player player : p.getServer().getOnlinePlayers()) {
|
||||
if(Permissions.has(player, "nocheat.notify")) {
|
||||
player.sendMessage("[WARNING] " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
log.warning(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a heavy violation message to all locations declared in the config file
|
||||
* @param message
|
||||
*/
|
||||
public static void logHeavy(String message) {
|
||||
if(NoCheatConfiguration.notifyLevel.intValue() <= Level.SEVERE.intValue()) {
|
||||
for(Player player : p.getServer().getOnlinePlayers()) {
|
||||
if(Permissions.has(player, "nocheat.notify")) {
|
||||
player.sendMessage("[SEVERE] " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
log.severe(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the config file
|
||||
*/
|
||||
public void setupConfig() {
|
||||
NoCheatConfiguration.config(new File("plugins/NoCheat/nocheat.yml"));
|
||||
|
||||
}
|
||||
}
|
|
@ -3,6 +3,12 @@ package cc.co.evenprime.bukkit.nocheat;
|
|||
import org.bukkit.event.block.BlockListener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
|
||||
/**
|
||||
* Handle events for all Block related events
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*/
|
||||
public class NoCheatPluginBlockListener extends BlockListener {
|
||||
|
||||
|
||||
|
|
|
@ -4,22 +4,23 @@ import org.bukkit.Location;
|
|||
|
||||
/**
|
||||
* Storage for data persistence between events
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*/
|
||||
public class NoCheatPluginData {
|
||||
|
||||
/**
|
||||
* Don't rely on any of these yet, they are likely going to
|
||||
* change their name/functionality
|
||||
* Don't rely on any of these yet, they are likely going to change their name/functionality
|
||||
*/
|
||||
int phase = 0; // current jumpingPhase
|
||||
int movingJumpPhase = 0; // current jumpingPhase
|
||||
long lastSpeedHackCheck = System.currentTimeMillis(); // timestamp of last check for speedhacks
|
||||
int eventsSinceLastSpeedHackCheck = 0; // used to identify speedhacks
|
||||
int ignoreNextXEvents = 0;
|
||||
int movingIgnoreNextXEvents = 0;
|
||||
|
||||
int minorViolationsInARow = 0;
|
||||
int normalViolationsInARow = 0;
|
||||
int heavyViolationsInARow = 0;
|
||||
int movingMinorViolationsInARow = 0;
|
||||
int movingNormalViolationsInARow = 0;
|
||||
int movingHeavyViolationsInARow = 0;
|
||||
Location movingSetBackPoint = null;
|
||||
|
||||
NoCheatPluginData() { }
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.bukkit.event.player.PlayerMoveEvent;
|
|||
|
||||
/**
|
||||
* Handle events for all Player related events
|
||||
*
|
||||
* @author Evenprime
|
||||
*/
|
||||
|
||||
|
@ -27,7 +28,7 @@ public class NoCheatPluginPlayerListener extends PlayerListener {
|
|||
|
||||
NoCheatPluginData data = NoCheatPlugin.playerData.get(player);
|
||||
if(data != null) {
|
||||
data.ignoreNextXEvents = count;
|
||||
data.movingIgnoreNextXEvents = count;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,8 +38,8 @@ public class NoCheatPluginPlayerListener extends PlayerListener {
|
|||
// Get the player-specific data
|
||||
NoCheatPluginData data = NoCheatPlugin.getPlayerData(event.getPlayer());
|
||||
|
||||
if(data.ignoreNextXEvents > 0 ) {
|
||||
data.ignoreNextXEvents--;
|
||||
if(data.movingIgnoreNextXEvents > 0 ) {
|
||||
data.movingIgnoreNextXEvents--;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.bukkit.event.vehicle.VehicleListener;
|
|||
|
||||
/**
|
||||
* Handle events for all Player related events
|
||||
*
|
||||
* @author Evenprime
|
||||
*/
|
||||
|
||||
|
|
|
@ -2,21 +2,26 @@ package cc.co.evenprime.bukkit.nocheat;
|
|||
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Log if a player sends to many move events in a specific time frame, usually the result of tinkering with the system clock
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*/
|
||||
public class SpeedhackCheck {
|
||||
|
||||
public static void check(NoCheatPluginData data, PlayerMoveEvent event) {
|
||||
|
||||
// Get the time of the server
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
|
||||
// Should we check at all?
|
||||
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.speedhack")) {
|
||||
return;
|
||||
}
|
||||
else if(NoCheatPlugin.Permissions == null && event.getPlayer().isOp() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the time of the server
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
// Is it time for a speedhack check now?
|
||||
if(time > NoCheatConfiguration.speedhackInterval + data.lastSpeedHackCheck ) {
|
||||
|
@ -28,11 +33,11 @@ public class SpeedhackCheck {
|
|||
int limitHigh = (int)((NoCheatConfiguration.speedhackHigh * (time - data.lastSpeedHackCheck)) / NoCheatConfiguration.speedhackInterval);
|
||||
|
||||
if(data.eventsSinceLastSpeedHackCheck > limitHigh)
|
||||
NoCheatPlugin.log.severe("NoCheatPlugin: "+event.getPlayer().getName()+" sent "+ data.eventsSinceLastSpeedHackCheck + " move events, but only "+limitLow+ " were allowed. Speedhack?");
|
||||
NoCheatPlugin.logHeavy("NoCheatPlugin: "+event.getPlayer().getName()+" sent "+ data.eventsSinceLastSpeedHackCheck + " move events, but only "+limitLow+ " were allowed. Speedhack?");
|
||||
else if(data.eventsSinceLastSpeedHackCheck > limitMed)
|
||||
NoCheatPlugin.log.warning("NoCheatPlugin: "+event.getPlayer().getName()+" sent "+ data.eventsSinceLastSpeedHackCheck + " move events, but only "+limitLow+ " were allowed. Speedhack?");
|
||||
NoCheatPlugin.logNormal("NoCheatPlugin: "+event.getPlayer().getName()+" sent "+ data.eventsSinceLastSpeedHackCheck + " move events, but only "+limitLow+ " were allowed. Speedhack?");
|
||||
else if(data.eventsSinceLastSpeedHackCheck > limitLow)
|
||||
NoCheatPlugin.log.info("NoCheatPlugin: "+event.getPlayer().getName()+" sent "+ data.eventsSinceLastSpeedHackCheck + " move events, but only "+limitLow+ " were allowed. Speedhack?");
|
||||
NoCheatPlugin.logMinor("NoCheatPlugin: "+event.getPlayer().getName()+" sent "+ data.eventsSinceLastSpeedHackCheck + " move events, but only "+limitLow+ " were allowed. Speedhack?");
|
||||
// Reset values for next check
|
||||
data.eventsSinceLastSpeedHackCheck = 0;
|
||||
data.lastSpeedHackCheck = time;
|
||||
|
|
Loading…
Reference in New Issue
Block a user