From cd99a787181095a7cd02fdce238cdf921c3c97d9 Mon Sep 17 00:00:00 2001 From: Evenprime Date: Mon, 18 Jul 2011 17:18:26 +0200 Subject: [PATCH] Added new Permissions support, and defined permissions in plugin.yml Added Tips-and-Tricks on startup --- plugin.yml | 47 +- .../bukkit/nocheat/CustomCommandSender.java | 106 +++ .../evenprime/bukkit/nocheat/DataManager.java | 70 +- .../co/evenprime/bukkit/nocheat/NoCheat.java | 833 +++++++++--------- .../bukkit/nocheat/checks/AirbuildCheck.java | 2 + .../bukkit/nocheat/checks/MovingCheck.java | 4 + .../nocheat/config/NoCheatConfiguration.java | 3 + .../bukkit/nocheat/data/PermissionData.java | 4 +- .../nocheat/wizard/gui/Explainations.java | 5 + 9 files changed, 634 insertions(+), 440 deletions(-) create mode 100644 src/cc/co/evenprime/bukkit/nocheat/CustomCommandSender.java diff --git a/plugin.yml b/plugin.yml index 5fd3aba3..062c074c 100644 --- a/plugin.yml +++ b/plugin.yml @@ -3,7 +3,7 @@ name: NoCheat author: Evenprime main: cc.co.evenprime.bukkit.nocheat.NoCheat -version: 1.10a +version: 1.11 softdepend: [ Permissions, CraftIRC ] @@ -14,4 +14,47 @@ commands: / Example: / | Displays version, enabled checks and bugfixes Example: / -p | Get your permissions, * = check disabled globally - Example: / -p [player] | Get permissions of the player, * = check disabled globally \ No newline at end of file + Example: / -p [player] | Get permissions of the player, * = check disabled globally + +permissions: + nocheat.all: + description: Allow the player to do everything (except for getting log messages) + children: + nocheat.moving: true + nocheat.speedhack: true + nocheat.airbuild: true + nocheat.bogusitems: true + nocheat.nuke: true + nocheat.flying: true + nocheat.fakesneak: true + nocheat.fastswim: true + nocheat.moving: + description: Allow to player to move/fly without getting checked at all + default: op + nocheat.speedhack: + description: Don't observe the number of move events sent by the player + default: op + nocheat.airbuild: + description: Allow placing blocks against air/in midair + default: op + nocheat.bogusitems: + description: Allow the use of items with invalid values e.g. negative stacksize + default: op + nocheat.nuke: + description: Allow breaking of blocks that are not in the field of view of the player + default: op + nocheat.notify: + description: Receive log messages in chat + default: op + nocheat.flying: + description: Allow the player to fly at normal walking speed + default: op + nocheat.fakesneak: + description: Allow the player to sneak at normal walking speed + default: op + nocheat.fastswim: + description: Allow the player to swim at normal walking speed + default: op + + + \ No newline at end of file diff --git a/src/cc/co/evenprime/bukkit/nocheat/CustomCommandSender.java b/src/cc/co/evenprime/bukkit/nocheat/CustomCommandSender.java new file mode 100644 index 00000000..f39000bf --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/CustomCommandSender.java @@ -0,0 +1,106 @@ +package cc.co.evenprime.bukkit.nocheat; + +import java.util.Set; + +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.Plugin; + +public class CustomCommandSender implements CommandSender { + + private final Server server; + + public CustomCommandSender(Server server) { + this.server = server; + } + + @Override + public boolean isPermissionSet(String name) { + // Just pretend that we have a permission, no matter which one + return true; + } + + @Override + public boolean isPermissionSet(Permission perm) { + // Just pretend that we have a permission, no matter which one + return true; + } + + @Override + public boolean hasPermission(String name) { + // Just pretend that we have a permission, no matter which one + return true; + } + + @Override + public boolean hasPermission(Permission perm) { + // Just pretend that we have a permission, no matter which one + return true; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String name, + boolean value) { + // Whatever it is, I don't care + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin) { + // Whatever it is, I don't care + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String name, + boolean value, int ticks) { + // Whatever it is, I don't care + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, int ticks) { + // Whatever it is, I don't care + return null; + } + + @Override + public void removeAttachment(PermissionAttachment attachment) { + // Whatever it is, I don't care + } + + @Override + public void recalculatePermissions() { + // Nothing to calculate + } + + @Override + public Set getEffectivePermissions() { + // Nothing + return null; + } + + @Override + public void setOp(boolean value) { + // Nothing + } + + @Override + public void sendMessage(String message) { + // we don't receive messages + } + + @Override + public boolean isOp() { + // We declare ourselves to be OP to be allowed to do more commands + return true; + } + + @Override + public Server getServer() { + return server; + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/DataManager.java b/src/cc/co/evenprime/bukkit/nocheat/DataManager.java index 72a116dd..58577bfb 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/DataManager.java +++ b/src/cc/co/evenprime/bukkit/nocheat/DataManager.java @@ -32,8 +32,12 @@ public class DataManager { Iterator> it = playerData.entrySet().iterator(); while (it.hasNext()) { Map.Entry pairs = (Map.Entry)it.next(); - if(!pairs.getKey().isOnline()) - it.remove(); + if(!pairs.getKey().isOnline()) { + // Cancel all referenced tasks before removing the entry + cancelTasks(pairs.getValue()); + it.remove(); + } + } } } @@ -127,37 +131,39 @@ public class DataManager { synchronized(playerData) { Iterator> it = playerData.entrySet().iterator(); while (it.hasNext()) { - Map.Entry pairs = (Map.Entry)it.next(); - - AirbuildData d = pairs.getValue().airbuild; - - if(d != null) { - int id = d.summaryTask; - - if(id != -1) { - Bukkit.getServer().getScheduler().cancelTask(id); - } - else { - // To prevent accidentially creating a new one while cleaning up - d.summaryTask = 1; - } - } - - MovingData d2 = pairs.getValue().moving; - - if(d2 != null) { - int id = d2.summaryTask; - - if(id != -1) { - Bukkit.getServer().getScheduler().cancelTask(id); - } - else { - // To prevent accidentially creating a new one while cleaning up - d2.summaryTask = 1; - } - } + cancelTasks(it.next().getValue()); } } } - + + private void cancelTasks(NoCheatData data) { + + AirbuildData d = data.airbuild; + + if(d != null) { + int id = d.summaryTask; + + if(id != -1) { + Bukkit.getServer().getScheduler().cancelTask(id); + } + else { + // To prevent accidentially creating a new one while cleaning up + d.summaryTask = 1; + } + } + + MovingData d2 = data.moving; + + if(d2 != null) { + int id = d2.summaryTask; + + if(id != -1) { + Bukkit.getServer().getScheduler().cancelTask(id); + } + else { + // To prevent accidentially creating a new one while cleaning up + d2.summaryTask = 1; + } + } + } } diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java index 7485c47a..43536741 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java +++ b/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java @@ -1,6 +1,5 @@ package cc.co.evenprime.bukkit.nocheat; - import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -35,417 +34,443 @@ import org.bukkit.plugin.Plugin; * * NoCheat * - * Check various player events for their plausibility and log/deny them based on configuration + * Check various player events for their plausibility and log/deny them based on + * configuration * * @author Evenprime */ -public class NoCheat extends JavaPlugin implements CommandSender { +public class NoCheat extends JavaPlugin { - private MovingCheck movingCheck; - private SpeedhackCheck speedhackCheck; - private AirbuildCheck airbuildCheck; - private BogusitemsCheck bogusitemsCheck; - - private Check[] checks; - - private NoCheatConfiguration config; - - private long exceptionWithPermissions = 0; - - private int cleanUpTaskId = -1; - private int serverLagMeasureTaskSetup = -1; - - private int serverTicks = 0; - private long serverLagInMilliSeconds = 0; - private long lastServerTime = 0; - - // Permissions, if available - private PermissionHandler permissions; + private MovingCheck movingCheck; + private SpeedhackCheck speedhackCheck; + private AirbuildCheck airbuildCheck; + private BogusitemsCheck bogusitemsCheck; - // CraftIRC, if available - private CraftIRC irc; - private boolean allowFlightSet; + private Check[] checks; - private Level chatLevel; - private Level ircLevel; - private Level consoleLevel; - private String ircTag; - private NukeCheck nukeCheck; + private NoCheatConfiguration config; + private boolean useNewPermissionSystem = false; - private DataManager dataManager; - - public NoCheat() { + private long exceptionWithPermissions = 0; - } + private int cleanUpTaskId = -1; + private int serverLagMeasureTaskSetup = -1; - @Override - public boolean onCommand(CommandSender sender, Command command, String commandLabel, String[] args) - { - if(args.length == 0) { - sender.sendMessage("NC: Using "+ ((permissions == null) ? "isOp()" : "Permissions") + ". Activated checks/bugfixes: " + getActiveChecksAsString() + ". Total time used for moving check so far: " + (movingCheck.statisticElapsedTimeNano / 1000000L + " ms. Average time per move event: " + (movingCheck.statisticElapsedTimeNano/1000L)/movingCheck.statisticTotalEvents + " us")); - return true; - } - else if(args.length == 1 && args[0] != null && args[0].trim().equals("-p")) { - if(sender instanceof Player) { - Player p = (Player) sender; - - sender.sendMessage("NC: You have permissions: " + getPermissionsForPlayerAsString(p)); - return true; - } - else { - sender.sendMessage("NC: You have to be a player to use this command"); - return true; - } - } - else if(args.length == 2 && args[0] != null && args[0].trim().equals("-p")) { - Player p = getServer().getPlayer(args[1]); + private int serverTicks = 0; + private long serverLagInMilliSeconds = 0; + private long lastServerTime = 0; - if(p != null) { - sender.sendMessage("NC: "+p.getName() + " has permissions: " + getPermissionsForPlayerAsString(p)); - return true; - } - else { - sender.sendMessage("NC: Player " + args[1] + " was not found."); - return true; - } - } - - return false; - } - - - - public void onDisable() { - - PluginDescriptionFile pdfFile = this.getDescription(); - - if(config != null) - config.cleanup(); - - try { - teardownCleanupTask(); - teardownServerLagMeasureTask(); - - dataManager.cancelPlayerDataTasks(); - } - catch(Exception e) { /* Can't do much in case of error here... */ } - Logger.getLogger("Minecraft").info( "[NoCheat] version [" + pdfFile.getVersion() + "] is disabled."); - } - - public void onEnable() { - - dataManager = new DataManager(); - // parse the nocheat.yml config file - setupConfig(); - - movingCheck = new MovingCheck(this, config); - speedhackCheck = new SpeedhackCheck(this, config); - airbuildCheck = new AirbuildCheck(this, config); - bogusitemsCheck = new BogusitemsCheck(this, config); - nukeCheck = new NukeCheck(this, config); - - // just for convenience - checks = new Check[] { movingCheck, speedhackCheck, airbuildCheck, bogusitemsCheck, nukeCheck }; - - 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\""); - } - - PluginDescriptionFile pdfFile = this.getDescription(); - - // Get, if available, the Permissions and irc plugin - setupPermissions(); - setupIRC(); - - Logger.getLogger("Minecraft").info( "[NoCheat] version [" + pdfFile.getVersion() + "] is enabled with the following checks: "+getActiveChecksAsString()); - - setupCleanupTask(); - - setupServerLagMeasureTask(); - } - - public DataManager getDataManager() { - return dataManager; - } - - private void setupCleanupTask() { - - if(cleanUpTaskId != -1) return; - - try { - cleanUpTaskId = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() { - - @Override - public void run() { - dataManager.cleanPlayerDataCollection(); - } - }, 5000, 5000); - } - catch(Exception e) { - // It's not THAT important, so if it fails for whatever reason, just let it be. - } - } - - private void teardownCleanupTask() { - if(cleanUpTaskId != -1) - Bukkit.getServer().getScheduler().cancelTask(cleanUpTaskId); - } - - private void setupServerLagMeasureTask() { - - if(serverLagMeasureTaskSetup != -1) return; - - serverLagMeasureTaskSetup = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() { - - @Override - public void run() { - serverTicks += 10; - long time = System.currentTimeMillis(); - serverLagInMilliSeconds = Math.abs((time - lastServerTime - 500)*2); - lastServerTime = time; - } - }, 10, 10); - } - - private void teardownServerLagMeasureTask() { - if(serverLagMeasureTaskSetup != -1) - Bukkit.getServer().getScheduler().cancelTask(serverLagMeasureTaskSetup); - } - - /** - * Get, if available, a reference to the Permissions-plugin - */ - private void setupPermissions() { - - Plugin permissionsPlugin = this.getServer().getPluginManager().getPlugin("Permissions"); - - if (this.permissions == null) { - if (permissionsPlugin != null) { - this.permissions = ((Permissions) permissionsPlugin).getHandler(); - } else { - PluginDescriptionFile pdfFile = this.getDescription(); - Logger.getLogger("Minecraft").warning("[NoCheat] version [" + pdfFile.getVersion() + "] couldn't find Permissions plugin. Fallback to 'isOp()' equals 'nocheat.*'"); - } - } - } - - /** - * Get, if available, a reference to the Permissions-plugin - */ - private void setupIRC() { - CraftIRC p = null; - - Plugin test = this.getServer().getPluginManager().getPlugin("CraftIRC"); - - if(test != null && test instanceof CraftIRC) { - p = (CraftIRC)test; - } - - if(p == null) { - PluginDescriptionFile pdfFile = this.getDescription(); - Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] couldn't find CrafTIRC plugin. Disabling logging to IRC."); - } - - irc = p; - } - - /** - * Log a violation message to all locations declared in the config file - * @param message - */ - public void log(Level l, String message) { - if(l != null && message != null) { - message = "NC: " + message; - config.logger.log(l, message); - logToConsole(l, message); - logToChat(l, message); - logToIRC(l, message); - - } - } - - private void logToChat(Level l, String message) { - if(chatLevel.intValue() <= l.intValue()) { - for(Player player : getServer().getOnlinePlayers()) { - if(hasPermission(player, PermissionData.PERMISSION_NOTIFY, false)) { - player.sendMessage("["+l.getName()+"] " + message); - } - } - } - } - - private void logToIRC(Level l, String message) { - if(irc != null && ircLevel.intValue() <= l.intValue()) { - irc.sendMessageToTag("["+l.getName()+"] " + message , ircTag); - } - } - - private void logToConsole(Level l, String message) { - if( consoleLevel.intValue() <= l.intValue()) { - Logger.getLogger("Minecraft").log(l, message); - } - } - - - public boolean hasPermission(Player player, int permission, boolean checkOPs) { - - if(player == null) return false; - - try { - if(permissions == null) { - if(checkOPs) { - // OPs don't get special treatment - return false; - } - else { - return player.isOp(); - } - } - else { - PermissionData data = dataManager.getPermissionData(player); - long time = System.currentTimeMillis(); - if(data.lastUpdate[permission] + 10000 < time) { - data.lastUpdate[permission] = time; - data.cache[permission] = permissions.has(player, PermissionData.permissionNames[permission]); - } - return data.cache[permission]; - } - } - catch(Throwable e) { - if(this.exceptionWithPermissions + 60000 < System.currentTimeMillis()) { - // Prevent spam and recursion by definitely doing this only once - this.exceptionWithPermissions = System.currentTimeMillis(); - - String logtext = "Asking Permissions-Plugin if "+player.getName()+" has permission "+PermissionData.permissionNames[permission]+" caused an Exception "+ e.getMessage() + ". Please review your permissions config file. This message is displayed at most once every 60 seconds."; - log(Level.SEVERE, logtext); - for(StackTraceElement s : e.getStackTrace()) { - config.logger.log(Level.SEVERE, s.toString()); - } - } - return false; - } - } - - /** - * Read the config file - */ - private void setupConfig() { - if(this.config == null) - this.config = new NoCheatConfiguration(new File(NoCheatConfiguration.configFile), new File(NoCheatConfiguration.descriptionsFile)); - else - this.config.config(new File(NoCheatConfiguration.configFile), new File(NoCheatConfiguration.descriptionsFile)); - - config.setupFileLogger(); - - try { - this.chatLevel = config.getLogLevelValue("logging.logtochat"); - this.ircLevel = config.getLogLevelValue("logging.logtoirc"); - this.consoleLevel = config.getLogLevelValue("logging.logtoconsole"); - this.ircTag = config.getStringValue("logging.logtoirctag"); - } catch (ConfigurationException e) { - this.setEnabled(false); - } - - try { - BufferedReader reader = new BufferedReader(new FileReader(new File("server.properties"))); - - allowFlightSet = true; - String s = null; - - while((s = reader.readLine()) != null) { - if(s.startsWith("allow-flight=false")) { - allowFlightSet = false; - } - - } - } catch (Exception e) { - e.printStackTrace(); - // ignore errors - } - } - - - private String getActiveChecksAsString() { - - String s = ""; - - for(Check c : checks) { - s = s + (c.isActive() ? c.getName() + " " : ""); - } - - s = s + (movingCheck.isActive() && !movingCheck.allowFlying ? "flying " : ""); - s = s + (movingCheck.isActive() && !movingCheck.allowFakeSneak ? "fakesneak " : ""); - s = s + (movingCheck.isActive() && !movingCheck.allowFastSwim ? "fastswim " : ""); - - return s; - } - - - private String getPermissionsForPlayerAsString(Player p) { - - String s = ""; - - for(Check c : checks) { - s = s + (!c.isActive() ? c.getName() + "* " : (c.skipCheck(p) ? c.getName() + " " : "")); - } - - s = s + (!movingCheck.isActive() || movingCheck.allowFlying ? "flying* " : (hasPermission(p, PermissionData.PERMISSION_FLYING, movingCheck.checkOPs) ? "flying " : "")); - s = s + (!movingCheck.isActive() || movingCheck.allowFakeSneak ? "fakesneak* " : (hasPermission(p, PermissionData.PERMISSION_FAKESNEAK, movingCheck.checkOPs) ? "fakesneak " : "")); - s = s + (!movingCheck.isActive() || movingCheck.allowFastSwim ? "fastswim* " : (hasPermission(p, PermissionData.PERMISSION_FASTSWIM, movingCheck.checkOPs) ? "fastswim " : "")); - - s = s + (hasPermission(p, PermissionData.PERMISSION_NOTIFY, false) ? "notify " : ""); - - return s; - } - - public int getServerTicks() { - return serverTicks; - } - - public long getServerLag() { - return this.serverLagInMilliSeconds; - } - - public void handleCustomAction(CustomAction a, Player player) { - - String command = a.command.replace("[player]", player.getName()); - try { - String[] commandParts = command.split(" ", 2); - String commandName = commandParts[0]; - PluginCommand com = Bukkit.getServer().getPluginCommand(commandName); - - // If there's a plugin that can handle it - if(com != null) { - if(commandParts.length > 1) { // Command + parameters - String[] commandArgs = commandParts[1].split(" "); - com.execute(this, commandName, commandArgs); - } - else { - String[] commandArgs = new String[0]; - com.execute(this, commandName, commandArgs); - } - } - else - { - // The standard server should do it - Bukkit.getServer().dispatchCommand(this, command); - } - } - catch(Exception e) { - this.log(Level.WARNING, "NoCheat couldn't execute custom server command: \""+command+"\""); - } - } - - @Override - public void sendMessage(String message) { - // we don't receive messages - - } - - @Override - public boolean isOp() { - // We declare ourselves to be OP to be allowed to do more commands - return true; - } -} \ No newline at end of file + // Permissions, if available + private PermissionHandler permissions; + + // CraftIRC, if available + private CraftIRC irc; + private boolean allowFlightSet; + + private Level chatLevel; + private Level ircLevel; + private Level consoleLevel; + private String ircTag; + private NukeCheck nukeCheck; + + private DataManager dataManager; + + private CustomCommandSender sender; + private boolean showStartupMessages = true; + + public NoCheat() { + + } + + public String[] getMessagesOfTheDay() { + + return new String[] {"NoCheat now supports the new Bukkit-Permission system. You can activate it in the config file.", "There will be a change in the near future to how movement in CraftBukkit works, which will break NoCheats moving-check(s) completely, causing tons of false positives. Be careful if you tend to run bleeding edge builds of CraftBukkit.", "This version of NoCheat was written for CraftBukkit RB 1000, but may still work for some older or newer versions.", "You can find detailed information about all configuration options of NoCheat in the file \"descriptions.txt\" in your \"plugins/NoCheat\" folder", "You can deactivate these Messages in the config file, if they annoy you."}; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String commandLabel, String[] args) { + + if(args.length == 0) { + sender.sendMessage("NC: Using " + ((permissions == null) ? "isOp()" : "Permissions") + ". Activated checks/bugfixes: " + getActiveChecksAsString() + ". Total time used for moving check so far: " + (movingCheck.statisticElapsedTimeNano / 1000000L + " ms. Average time per move event: " + (movingCheck.statisticElapsedTimeNano / 1000L) / movingCheck.statisticTotalEvents + " us")); + return true; + } else if(args.length == 1 && args[0] != null && args[0].trim().equals("-p")) { + if(sender instanceof Player) { + Player p = (Player) sender; + + sender.sendMessage("NC: You have permissions: " + getPermissionsForPlayerAsString(p)); + return true; + } else { + sender.sendMessage("NC: You have to be a player to use this command"); + return true; + } + } else if(args.length == 2 && args[0] != null && args[0].trim().equals("-p")) { + Player p = getServer().getPlayer(args[1]); + + if(p != null) { + sender.sendMessage("NC: " + p.getName() + " has permissions: " + getPermissionsForPlayerAsString(p)); + return true; + } else { + sender.sendMessage("NC: Player " + args[1] + " was not found."); + return true; + } + } + + return false; + } + + public void onDisable() { + + PluginDescriptionFile pdfFile = this.getDescription(); + + if(config != null) + config.cleanup(); + + try { + dataManager.cancelPlayerDataTasks(); + + teardownCleanupTask(); + teardownServerLagMeasureTask(); + } catch(Exception e) { /* Can't do much in case of error here... */ + } + Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] is disabled."); + } + + public void onEnable() { + + dataManager = new DataManager(); + + sender = new CustomCommandSender(getServer()); + // parse the nocheat.yml config file + setupConfig(); + + movingCheck = new MovingCheck(this, config); + speedhackCheck = new SpeedhackCheck(this, config); + airbuildCheck = new AirbuildCheck(this, config); + bogusitemsCheck = new BogusitemsCheck(this, config); + nukeCheck = new NukeCheck(this, config); + + // just for convenience + checks = new Check[] {movingCheck, speedhackCheck, airbuildCheck, bogusitemsCheck, nukeCheck}; + + 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\""); + } + + for(String s : getMessagesOfTheDay()) { + if(showStartupMessages) + Logger.getLogger("Minecraft").info("(NoCheat) Did you know? " + s); + } + + PluginDescriptionFile pdfFile = this.getDescription(); + + // Get, if available, the Permissions and irc plugin + if(!useNewPermissionSystem) { + setupPermissions(); + } + setupIRC(); + + Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] is enabled with the following checks: " + getActiveChecksAsString()); + + setupCleanupTask(); + + setupServerLagMeasureTask(); + } + + public DataManager getDataManager() { + + return dataManager; + } + + private void setupCleanupTask() { + + if(cleanUpTaskId != -1) { + return; + } + try { + cleanUpTaskId = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() { + + @Override + public void run() { + + try { + if(getDataManager() != null) { + getDataManager().cleanPlayerDataCollection(); + } + } catch(Exception e) {} + } + }, 5000, 5000); + } catch(Exception e) { + // It's not THAT important, so if it fails for whatever reason, just + // let it be. + } + } + + private void teardownCleanupTask() { + + if(cleanUpTaskId != -1) { + Bukkit.getServer().getScheduler().cancelTask(cleanUpTaskId); + } + } + + private void setupServerLagMeasureTask() { + + if(serverLagMeasureTaskSetup != -1) { + return; + } + + serverLagMeasureTaskSetup = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() { + + @Override + public void run() { + + serverTicks += 10; + long time = System.currentTimeMillis(); + serverLagInMilliSeconds = Math.abs((time - lastServerTime - 500) * 2); + lastServerTime = time; + + } + }, 10, 10); + } + + private void teardownServerLagMeasureTask() { + + if(serverLagMeasureTaskSetup != -1) { + Bukkit.getServer().getScheduler().cancelTask(serverLagMeasureTaskSetup); + } + } + + /** + * Get, if available, a reference to the Permissions-plugin + */ + private void setupPermissions() { + + Plugin permissionsPlugin = this.getServer().getPluginManager().getPlugin("Permissions"); + + if(this.permissions == null) { + if(permissionsPlugin != null) { + this.permissions = ((Permissions) permissionsPlugin).getHandler(); + } else { + PluginDescriptionFile pdfFile = this.getDescription(); + Logger.getLogger("Minecraft").warning("[NoCheat] version [" + pdfFile.getVersion() + "] couldn't find Permissions plugin. Fallback to 'isOp()' equals 'nocheat.*'"); + } + } + } + + /** + * Get, if available, a reference to the Permissions-plugin + */ + private void setupIRC() { + + CraftIRC p = null; + + Plugin test = this.getServer().getPluginManager().getPlugin("CraftIRC"); + + if(test != null && test instanceof CraftIRC) { + p = (CraftIRC) test; + } + + if(p == null) { + PluginDescriptionFile pdfFile = this.getDescription(); + Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] couldn't find CrafTIRC plugin. Disabling logging to IRC."); + } + + irc = p; + } + + /** + * Log a violation message to all locations declared in the config file + * + * @param message + */ + public void log(Level l, String message) { + + if(l != null && message != null) { + message = "NC: " + message; + config.logger.log(l, message); + logToConsole(l, message); + logToChat(l, message); + logToIRC(l, message); + + } + } + + private void logToChat(Level l, String message) { + + if(chatLevel.intValue() <= l.intValue()) { + for(Player player : getServer().getOnlinePlayers()) { + if(hasPermission(player, PermissionData.PERMISSION_NOTIFY, false)) { + player.sendMessage("[" + l.getName() + "] " + message); + } + } + } + } + + private void logToIRC(Level l, String message) { + + if(irc != null && ircLevel.intValue() <= l.intValue()) { + irc.sendMessageToTag("[" + l.getName() + "] " + message, ircTag); + } + } + + private void logToConsole(Level l, String message) { + + if(consoleLevel.intValue() <= l.intValue()) { + Logger.getLogger("Minecraft").log(l, message); + } + } + + public boolean hasPermission(Player player, int permission, boolean ignoreOPstatus) { + + if(player == null) + return false; + + if(useNewPermissionSystem) { + //System.out.println("New permissions system asked for " + PermissionData.permissionNames[permission] + " got " + player.hasPermission(PermissionData.permissionNames[permission])); + return player.hasPermission(PermissionData.permissionNames[permission]); + } + + try { + if(permissions == null) { + if(ignoreOPstatus) { + // OPs don't get special treatment + return false; + } else { + return player.isOp(); + } + } else { + PermissionData data = dataManager.getPermissionData(player); + long time = System.currentTimeMillis(); + if(data.lastUpdate[permission] + 10000 < time) { + data.lastUpdate[permission] = time; + data.cache[permission] = permissions.has(player, PermissionData.permissionNames[permission]); + } + return data.cache[permission]; + } + } catch(Throwable e) { + if(this.exceptionWithPermissions + 60000 < System.currentTimeMillis()) { + // Prevent spam and recursion by definitely doing this only once + this.exceptionWithPermissions = System.currentTimeMillis(); + + String logtext = "Asking Permissions-Plugin if " + player.getName() + " has permission " + PermissionData.permissionNames[permission] + " caused an Exception " + e.getMessage() + ". Please review your permissions config file. This message is displayed at most once every 60 seconds."; + log(Level.SEVERE, logtext); + for(StackTraceElement s : e.getStackTrace()) { + config.logger.log(Level.SEVERE, s.toString()); + } + } + return false; + } + } + + /** + * Read the config file + */ + private void setupConfig() { + + if(this.config == null) + this.config = new NoCheatConfiguration(new File(NoCheatConfiguration.configFile), new File(NoCheatConfiguration.descriptionsFile)); + else + this.config.config(new File(NoCheatConfiguration.configFile), new File(NoCheatConfiguration.descriptionsFile)); + + config.setupFileLogger(); + + try { + this.chatLevel = config.getLogLevelValue("logging.logtochat"); + this.ircLevel = config.getLogLevelValue("logging.logtoirc"); + this.consoleLevel = config.getLogLevelValue("logging.logtoconsole"); + this.ircTag = config.getStringValue("logging.logtoirctag"); + this.useNewPermissionSystem = this.config.getBooleanValue("newpermsystem"); + this.showStartupMessages = this.config.getBooleanValue("showinfomessages"); + } catch(ConfigurationException e) { + e.printStackTrace(); + this.setEnabled(false); + } + + try { + BufferedReader reader = new BufferedReader(new FileReader(new File("server.properties"))); + + allowFlightSet = true; + String s = null; + + while((s = reader.readLine()) != null) { + if(s.startsWith("allow-flight=false")) { + allowFlightSet = false; + } + + } + } catch(Exception e) { + e.printStackTrace(); + // ignore errors + } + + } + + private String getActiveChecksAsString() { + + String s = ""; + + for(Check c : checks) { + s = s + (c.isActive() ? c.getName() + " " : ""); + } + + s = s + (movingCheck.isActive() && !movingCheck.allowFlying ? "flying " : ""); + s = s + (movingCheck.isActive() && !movingCheck.allowFakeSneak ? "fakesneak " : ""); + s = s + (movingCheck.isActive() && !movingCheck.allowFastSwim ? "fastswim " : ""); + + return s; + } + + private String getPermissionsForPlayerAsString(Player p) { + + String s = ""; + + for(Check c : checks) { + s = s + (!c.isActive() ? c.getName() + "* " : (c.skipCheck(p) ? c.getName() + " " : "")); + } + + s = s + (!movingCheck.isActive() || movingCheck.allowFlying ? "flying* " : (hasPermission(p, PermissionData.PERMISSION_FLYING, movingCheck.checkOPs) ? "flying " : "")); + s = s + (!movingCheck.isActive() || movingCheck.allowFakeSneak ? "fakesneak* " : (hasPermission(p, PermissionData.PERMISSION_FAKESNEAK, movingCheck.checkOPs) ? "fakesneak " : "")); + s = s + (!movingCheck.isActive() || movingCheck.allowFastSwim ? "fastswim* " : (hasPermission(p, PermissionData.PERMISSION_FASTSWIM, movingCheck.checkOPs) ? "fastswim " : "")); + + s = s + (hasPermission(p, PermissionData.PERMISSION_NOTIFY, false) ? "notify " : ""); + + return s; + } + + public int getServerTicks() { + + return serverTicks; + } + + public long getServerLag() { + + return this.serverLagInMilliSeconds; + } + + public void handleCustomAction(CustomAction a, Player player) { + + String command = a.command.replace("[player]", player.getName()); + try { + String[] commandParts = command.split(" ", 2); + String commandName = commandParts[0]; + PluginCommand com = Bukkit.getServer().getPluginCommand(commandName); + + // If there's a plugin that can handle it + if(com != null) { + if(commandParts.length > 1) { // Command + parameters + String[] commandArgs = commandParts[1].split(" "); + com.execute(sender, commandName, commandArgs); + } else { + String[] commandArgs = new String[0]; + com.execute(sender, commandName, commandArgs); + } + } else { + // The standard server should do it + Bukkit.getServer().dispatchCommand(sender, command); + } + } catch(Exception e) { + this.log(Level.WARNING, "NoCheat couldn't execute custom server command: \"" + command + "\""); + } + } + +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java index 9fbb6e30..489fc50c 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java @@ -53,9 +53,11 @@ public class AirbuildCheck extends Check { @Override public void run() { + try { summary(p, data); // deleting its own reference data.summaryTask = -1; + }catch(Exception e) {} } }; diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java index 6172736d..a9309a2e 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java @@ -223,6 +223,8 @@ public class MovingCheck extends Check { @Override public void run() { + + try { if(data.highestLogLevel != null) { String logString = String.format(summaryMessage, p.getName(), ticksBeforeSummary/20, data.violationsInARow[0], data.violationsInARow[1],data.violationsInARow[2]); plugin.log(data.highestLogLevel, logString); @@ -235,6 +237,8 @@ public class MovingCheck extends Check { data.violationsInARow[0] = 0; data.violationsInARow[1] = 0; data.violationsInARow[2] = 0; + } + catch(Exception e) { } } }; diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java b/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java index 3d7871fb..e349ff0a 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java +++ b/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java @@ -91,6 +91,9 @@ public class NoCheatConfiguration { loggingNode.add(new ShortStringOption("logtoirctag", SimpleYaml.getString("logging.logtoirctag", "nocheat", yamlContent))); } + + root.add(new BooleanOption("newpermsystem", SimpleYaml.getBoolean("newpermsystem", false, yamlContent))); + root.add(new BooleanOption("showinfomessages", SimpleYaml.getBoolean("showinfomessages", true, yamlContent))); /*** ACTIVE section ***/ { diff --git a/src/cc/co/evenprime/bukkit/nocheat/data/PermissionData.java b/src/cc/co/evenprime/bukkit/nocheat/data/PermissionData.java index dcf76457..c7d5cd3b 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/data/PermissionData.java +++ b/src/cc/co/evenprime/bukkit/nocheat/data/PermissionData.java @@ -11,10 +11,10 @@ public class PermissionData { public static final int PERMISSION_FLYING = 1; public static final int PERMISSION_SPEEDHACK = 2; public static final int PERMISSION_AIRBUILD = 3; - public static final int PERMISSION_BEDTELEPORT = 4; + public static final int PERMISSION_BEDTELEPORT = 4; // No longer used public static final int PERMISSION_BOGUSITEMS = 5; public static final int PERMISSION_NOTIFY = 6; - public static final int PERMISSION_ITEMDUPE = 7; + public static final int PERMISSION_ITEMDUPE = 7; // No longer used public static final int PERMISSION_FAKESNEAK = 8; public static final int PERMISSION_FASTSWIM = 9; public static final int PERMISSION_NUKE = 10; diff --git a/src/cc/co/evenprime/bukkit/nocheat/wizard/gui/Explainations.java b/src/cc/co/evenprime/bukkit/nocheat/wizard/gui/Explainations.java index f940a80a..d5432691 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/wizard/gui/Explainations.java +++ b/src/cc/co/evenprime/bukkit/nocheat/wizard/gui/Explainations.java @@ -37,6 +37,11 @@ public class Explainations { "blocks that are outside his field of sight, he'll get kicked from the server.\n" + "This is only a temporary solution (and will probably not hold for long), but it's better than nothing, I guess..."); + set("newpermsystem", "If activated, NoCheat will fully rely on the new Permission system of Bukkit, introduced with build 1000.\n" + + "This only makes sense if you also have a permission plugin that is capable of managing permissions in the new system."); + set("showinfomessages", "If activated, NoCheat will give useful advice and information on startup, about recent changes and potential \n" + + "problems with your servers configuration or conflicts with other plugins."); + set("logging.filename", "Determines where the various messages by NoCheat are stored at, if logging to file is activated."); set("logging.logtofile", "Determine what severeness messages need to have to be printed to the logfile.\n" + "The values that can be used are:\n" +