diff --git a/plugin.yml b/plugin.yml index e0915af5..9be36829 100644 --- a/plugin.yml +++ b/plugin.yml @@ -3,7 +3,7 @@ name: NoCheat author: Evenprime main: cc.co.evenprime.bukkit.nocheat.NoCheat -version: 1.00a +version: 1.00b commands: nocheat: diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java index 87ab03b4..ba1009c4 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java +++ b/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java @@ -4,7 +4,6 @@ package cc.co.evenprime.bukkit.nocheat; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; -import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -31,7 +30,6 @@ import com.ensifera.animosity.craftirc.CraftIRC; import com.nijikokun.bukkit.Permissions.Permissions; import com.nijiko.permissions.PermissionHandler; import org.bukkit.plugin.Plugin; -import org.bukkit.util.config.Configuration; /** * @@ -56,8 +54,8 @@ public class NoCheat extends JavaPlugin implements CommandSender { private boolean exceptionWithPermissions = false; - private boolean cleanUpTaskSetup = false; - private boolean serverLagMeasureTaskSetup = false; + private int cleanUpTaskId = -1; + private int serverLagMeasureTaskSetup = -1; private int serverTicks = 0; private long serverLagInMilliSeconds = 0; @@ -124,6 +122,13 @@ public class NoCheat extends JavaPlugin implements CommandSender { if(config != null) config.cleanup(); + try { + teardownCleanupTask(); + teardownServerLagMeasureTask(); + + NoCheatData.cancelPlayerDataTasks(); + } + catch(Exception e) { /* Can't do much in case of error here... */ } Logger.getLogger("Minecraft").info( "[NoCheat] version [" + pdfFile.getVersion() + "] is disabled."); } @@ -142,9 +147,6 @@ public class NoCheat extends JavaPlugin implements CommandSender { // just for convenience checks = new Check[] { movingCheck, bedteleportCheck, speedhackCheck, airbuildCheck, itemdupeCheck, bogusitemsCheck }; - // parse the nocheat.yml config file - setupConfig(); - if(!allowFlightSet && movingCheck.isActive()) { Logger.getLogger("Minecraft").warning( "[NoCheat] you have set \"allow-flight=false\" in your server.properties file. That builtin anti-flying-mechanism will likely conflict with this plugin. Please consider deactivating it by setting it to \"true\""); } @@ -164,11 +166,9 @@ public class NoCheat extends JavaPlugin implements CommandSender { private void setupCleanupTask() { - if(cleanUpTaskSetup) return; + if(cleanUpTaskId != -1) return; - cleanUpTaskSetup = true; - - Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() { + cleanUpTaskId = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() { @Override public void run() { @@ -176,12 +176,15 @@ public class NoCheat extends JavaPlugin implements CommandSender { } }, 5000, 5000); } + + private void teardownCleanupTask() { + if(cleanUpTaskId != -1) + Bukkit.getServer().getScheduler().cancelTask(cleanUpTaskId); + } private void setupServerLagMeasureTask() { - if(serverLagMeasureTaskSetup) return; - - serverLagMeasureTaskSetup = true; + if(serverLagMeasureTaskSetup != -1) return; Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() { @@ -194,6 +197,11 @@ public class NoCheat extends JavaPlugin implements CommandSender { } }, 10, 10); } + + private void teardownServerLagMeasureTask() { + if(serverLagMeasureTaskSetup == -1) + Bukkit.getServer().getScheduler().cancelTask(serverLagMeasureTaskSetup); + } /** * Get, if available, a reference to the Permissions-plugin diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheatData.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheatData.java index 5c3afca9..387aa6e2 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheatData.java +++ b/src/cc/co/evenprime/bukkit/nocheat/NoCheatData.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import cc.co.evenprime.bukkit.nocheat.data.AirbuildData; @@ -68,5 +69,30 @@ public class NoCheatData { } } } + + /** + * Go through the playerData HashMap and remove players that are no longer online + * from the map. This should be called in long, regular intervals (e.g. every 10 minutes) + * to keep the memory footprint of the plugin low + */ + public static void cancelPlayerDataTasks() { + synchronized(playerData) { + Iterator> it = playerData.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pairs = (Map.Entry)it.next(); + + int id; + id = pairs.getValue().airbuild != null ? pairs.getValue().airbuild.summaryTask : -1; + + if(id != -1) + Bukkit.getServer().getScheduler().cancelTask(id); + + id = pairs.getValue().moving != null ? pairs.getValue().moving.summaryTask : -1; + + if(id != -1) + Bukkit.getServer().getScheduler().cancelTask(id); + } + } + } } \ No newline at end of file diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java index e047d9ec..66c7a067 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java @@ -48,19 +48,19 @@ public class AirbuildCheck extends Check { final AirbuildData data = AirbuildData.get(event.getPlayer()); final Player p = event.getPlayer(); - if(data.summaryTask == null) { - data.summaryTask = new Runnable() { + if(data.summaryTask == -1) { + Runnable r = new Runnable() { @Override public void run() { summary(p, data); // deleting its own reference - data.summaryTask = null; + data.summaryTask = -1; } }; // Give a summary in 100 ticks ~ 1 second - plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.summaryTask, 100); + data.summaryTask = plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, r, 100); } data.perFiveSeconds++; diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java index 36a1546a..4ae6d1b0 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java @@ -355,8 +355,8 @@ public class MovingCheck extends Check { */ private void setupSummaryTask(final Player p, final MovingData data) { // Setup task to display summary later - if(data.summaryTask == null) { - data.summaryTask = new Runnable() { + if(data.summaryTask == -1) { + Runnable r = new Runnable() { @Override public void run() { @@ -365,7 +365,7 @@ public class MovingCheck extends Check { plugin.log(data.highestLogLevel, logString); } // deleting its own reference - data.summaryTask = null; + data.summaryTask = -1; data.violationsInARow[0] = 0; data.violationsInARow[1] = 0; @@ -374,7 +374,7 @@ public class MovingCheck extends Check { }; // Give a summary in x ticks. 20 ticks ~ 1 second - plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.summaryTask, ticksBeforeSummary); + data.summaryTask = plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, r, ticksBeforeSummary); } } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java index 4b4cb321..9e1e0a8b 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java @@ -49,6 +49,8 @@ public class SpeedhackCheck extends Check { // Should we check at all? if(skipCheck(player)) return; + + // Ignore events of players in vehicles (these can be the cause of event spam between server and client) // Ignore events if the player has positive y-Velocity (these can be the cause of event spam between server and client) if(player.isInsideVehicle() || player.getVelocity().getY() > 0.0D) { @@ -77,8 +79,6 @@ public class SpeedhackCheck extends Check { resetData(data, event.getFrom(), ticks); } else { - Action action[] = null; - final int low = (limits[0]+1) / 2; final int med = (limits[1]+1) / 2; final int high = (limits[2]+1) / 2; @@ -97,7 +97,7 @@ public class SpeedhackCheck extends Check { if(data.violationsInARowTotal >= violationsLimit) { data.violationsInARow[level]++; - action(action, event, data.violationsInARow[level], data); + action(actions[level], event, data.violationsInARow[level], data); } // Reset value for next check @@ -129,12 +129,12 @@ public class SpeedhackCheck extends Check { for(Action a : actions) { if(a.firstAfter <= violations) { - if(a.firstAfter == violations || a.repeat) { - if(a instanceof LogAction) { - String log = String.format(logMessage, event.getPlayer().getName(), data.eventsSinceLastCheck*2, limits[0]); - plugin.log(((LogAction)a).level, log); - } - else if(a instanceof CancelAction) { + if(a instanceof LogAction) { + String log = String.format(logMessage, event.getPlayer().getName(), data.eventsSinceLastCheck*2, limits[0]); + plugin.log(((LogAction)a).level, log); + } + else if(a.firstAfter == violations || a.repeat) { + if(a instanceof CancelAction) { resetPlayer(event, data); } else if(a instanceof CustomAction) { diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java b/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java index 29f6cd32..ee83b9f4 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java +++ b/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java @@ -14,6 +14,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import cc.co.evenprime.bukkit.nocheat.ConfigurationException; +import cc.co.evenprime.bukkit.nocheat.LogFileFormatter; import cc.co.evenprime.bukkit.nocheat.actions.Action; import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; import cc.co.evenprime.bukkit.nocheat.actions.LogAction; @@ -113,7 +114,8 @@ public class NoCheatConfiguration { root.add(speedhackNode); speedhackNode.add(new LongStringOption("logmessage", - SimpleYaml.getString("logging.filename", "%1$s sent %2$d move events, but only %3$d were allowed. Speedhack?", yamlContent))); + SimpleYaml.getString("speedhack.logmessage", "[player] sent [events] move events, but only [limit] were allowed. Speedhack?", yamlContent). + replace("[player]", "%1$s").replace("[events]", "%2$d").replace("[limit]", "%3$d"))); /*** SPEEDHACK LIMITS section ***/ { @@ -121,11 +123,11 @@ public class NoCheatConfiguration { speedhackNode.add(speedhackLimitsNode); speedhackLimitsNode.add(new IntegerOption("low", - SimpleYaml.getInt("speedhack.limits.low", 30, yamlContent))); + SimpleYaml.getInt("speedhack.limits.low", 22, yamlContent))); speedhackLimitsNode.add(new IntegerOption("med", - SimpleYaml.getInt("speedhack.limits.med", 45, yamlContent))); + SimpleYaml.getInt("speedhack.limits.med", 33, yamlContent))); speedhackLimitsNode.add(new IntegerOption("high", - SimpleYaml.getInt("speedhack.limits.high", 60, yamlContent))); + SimpleYaml.getInt("speedhack.limits.high", 44, yamlContent))); } /*** SPEEDHACK ACTIONS section ***/ @@ -148,9 +150,11 @@ public class NoCheatConfiguration { root.add(movingNode); movingNode.add(new LongStringOption("logmessage", - SimpleYaml.getString("moving.logmessage", "Moving violation: %1$s from %2$s (%4$.1f, %5$.1f, %6$.1f) to %3$s (%7$.1f, %8$.1f, %9$.1f)", yamlContent))); + SimpleYaml.getString("moving.logmessage", "Moving violation: [player] from [world] [from] to [to]", yamlContent). + replace("[player]", "%1$s").replace("[world]", "%2$s").replace("[from]", "(%4$.1f, %5$.1f, %6$.1f)").replace("[to]", "(%7$.1f, %8$.1f, %9$.1f)"))); movingNode.add(new LongStringOption("summarymessage", - SimpleYaml.getString("moving.summarymessage", "Moving summary of last ~%2$d seconds: %1$s total Violations: (%3$d,%4$d,%5$d)", yamlContent))); + SimpleYaml.getString("moving.summarymessage", "Moving summary of last ~[timeframe] seconds: [player] total Violations: [violations]", yamlContent). + replace("[timeframe]", "%2$d").replace("[player]", "%1$s").replace("[violations]", "(%3$d,%4$d,%5$d)"))); movingNode.add(new BooleanOption("allowflying", SimpleYaml.getBoolean("moving.allowflying", false, yamlContent))); movingNode.add(new BooleanOption("allowfakesneak", @@ -250,7 +254,7 @@ public class NoCheatConfiguration { try { fh = new FileHandler(getStringValue("logging.filename"), true); fh.setLevel(getLogLevelValue("logging.logtofile")); - fh.setFormatter(Logger.getLogger("Minecraft").getHandlers()[0].getFormatter()); + fh.setFormatter(new LogFileFormatter()); logger.addHandler(fh); } catch (Exception e) { diff --git a/src/cc/co/evenprime/bukkit/nocheat/data/AirbuildData.java b/src/cc/co/evenprime/bukkit/nocheat/data/AirbuildData.java index 2db6da9b..0555435b 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/data/AirbuildData.java +++ b/src/cc/co/evenprime/bukkit/nocheat/data/AirbuildData.java @@ -6,7 +6,7 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatData; public class AirbuildData { public int perFiveSeconds = 0; - public Runnable summaryTask = null; + public int summaryTask = -1; public static AirbuildData get(Player p) { diff --git a/src/cc/co/evenprime/bukkit/nocheat/data/MovingData.java b/src/cc/co/evenprime/bukkit/nocheat/data/MovingData.java index 882850b9..eebd2c5f 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/data/MovingData.java +++ b/src/cc/co/evenprime/bukkit/nocheat/data/MovingData.java @@ -15,7 +15,7 @@ public class MovingData { public double vertFreedom = 0.0D; public int vertFreedomCounter = 0; public Location setBackPoint = null; - public Runnable summaryTask = null; + public int summaryTask = -1; public Level highestLogLevel = null; public double maxYVelocity = 0.0D; public int sneakingFreedomCounter = 10;