diff --git a/src/fr/neatmonster/nocheatplus/actions/Action.java b/src/fr/neatmonster/nocheatplus/actions/Action.java index c04b7aa8..43e7a9ad 100644 --- a/src/fr/neatmonster/nocheatplus/actions/Action.java +++ b/src/fr/neatmonster/nocheatplus/actions/Action.java @@ -1,5 +1,7 @@ package fr.neatmonster.nocheatplus.actions; +import fr.neatmonster.nocheatplus.checks.ViolationData; + /* * MMP"""""""MM dP oo * M' .mmmm MM 88 @@ -46,4 +48,13 @@ public abstract class Action { this.delay = delay; this.repeat = repeat; } + + /** + * Execute the action. + * + * @param violationData + * the violation data + * @return true, if successful + */ + public abstract boolean execute(final ViolationData violationData); } diff --git a/src/fr/neatmonster/nocheatplus/actions/types/ActionWithParameters.java b/src/fr/neatmonster/nocheatplus/actions/types/ActionWithParameters.java index 57adc4a7..8497b74d 100644 --- a/src/fr/neatmonster/nocheatplus/actions/types/ActionWithParameters.java +++ b/src/fr/neatmonster/nocheatplus/actions/types/ActionWithParameters.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import fr.neatmonster.nocheatplus.actions.Action; import fr.neatmonster.nocheatplus.actions.ParameterName; -import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.ViolationData; /* @@ -54,13 +53,11 @@ public abstract class ActionWithParameters extends Action { /** * Get a string with all the wildcards replaced with data from the violation data. * - * @param check - * the check * @param violationData * the violation data * @return the message */ - protected String getMessage(final Check check, final ViolationData violationData) { + protected String getMessage(final ViolationData violationData) { // Should be big enough most of the time. final StringBuilder log = new StringBuilder(100); @@ -68,7 +65,7 @@ public abstract class ActionWithParameters extends Action { if (part instanceof String) log.append((String) part); else - log.append(check.getParameter((ParameterName) part, violationData)); + log.append(violationData.check.getParameter((ParameterName) part, violationData)); return log.toString(); } diff --git a/src/fr/neatmonster/nocheatplus/actions/types/CancelAction.java b/src/fr/neatmonster/nocheatplus/actions/types/CancelAction.java index f2466b2b..4dffdb41 100644 --- a/src/fr/neatmonster/nocheatplus/actions/types/CancelAction.java +++ b/src/fr/neatmonster/nocheatplus/actions/types/CancelAction.java @@ -1,6 +1,7 @@ package fr.neatmonster.nocheatplus.actions.types; import fr.neatmonster.nocheatplus.actions.Action; +import fr.neatmonster.nocheatplus.checks.ViolationData; /* * MM'""""'YMM dP MMP"""""""MM dP oo @@ -24,6 +25,14 @@ public class CancelAction extends Action { super("cancel", 0, 0); } + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData) + */ + @Override + public boolean execute(final ViolationData data) { + return true; + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ diff --git a/src/fr/neatmonster/nocheatplus/actions/types/CommandAction.java b/src/fr/neatmonster/nocheatplus/actions/types/CommandAction.java index 86af75ea..1864d5be 100644 --- a/src/fr/neatmonster/nocheatplus/actions/types/CommandAction.java +++ b/src/fr/neatmonster/nocheatplus/actions/types/CommandAction.java @@ -1,6 +1,8 @@ package fr.neatmonster.nocheatplus.actions.types; -import fr.neatmonster.nocheatplus.checks.Check; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandException; + import fr.neatmonster.nocheatplus.checks.ViolationData; /* @@ -42,18 +44,21 @@ public class CommandAction extends ActionWithParameters { super(name, delay, repeat, command); } - /** - * Fill in the placeholders (stuff that looks like '[something]') with information, make a nice String out of it - * that can be directly used as a command in the console. - * - * @param check - * The check that is used to fill in missing . - * @param violationData - * the violation data - * @return The complete, ready to use, command. + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData) */ - public String getCommand(final Check check, final ViolationData violationData) { - return super.getMessage(check, violationData); + @Override + public boolean execute(final ViolationData violationData) { + final String command = super.getMessage(violationData); + try { + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command); + } catch (final CommandException e) { + System.out.println("[NoCheatPlus] Failed to execute the command '" + command + "': " + e.getMessage() + + ", please check if everything is setup correct."); + } catch (final Exception e) { + // I don't care in this case, your problem if your command fails. + } + return false; } /** diff --git a/src/fr/neatmonster/nocheatplus/actions/types/DummyAction.java b/src/fr/neatmonster/nocheatplus/actions/types/DummyAction.java index 8a6e697a..a9abce78 100644 --- a/src/fr/neatmonster/nocheatplus/actions/types/DummyAction.java +++ b/src/fr/neatmonster/nocheatplus/actions/types/DummyAction.java @@ -1,6 +1,7 @@ package fr.neatmonster.nocheatplus.actions.types; import fr.neatmonster.nocheatplus.actions.Action; +import fr.neatmonster.nocheatplus.checks.ViolationData; /* * M""""""'YMM MMP"""""""MM dP oo @@ -31,6 +32,14 @@ public class DummyAction extends Action { this.definition = definition; } + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData) + */ + @Override + public boolean execute(final ViolationData violationData) { + return false; + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ diff --git a/src/fr/neatmonster/nocheatplus/actions/types/LogAction.java b/src/fr/neatmonster/nocheatplus/actions/types/LogAction.java index fd3b4a06..18edaaca 100644 --- a/src/fr/neatmonster/nocheatplus/actions/types/LogAction.java +++ b/src/fr/neatmonster/nocheatplus/actions/types/LogAction.java @@ -1,7 +1,15 @@ package fr.neatmonster.nocheatplus.actions.types; -import fr.neatmonster.nocheatplus.checks.Check; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + import fr.neatmonster.nocheatplus.checks.ViolationData; +import fr.neatmonster.nocheatplus.config.ConfPaths; +import fr.neatmonster.nocheatplus.config.ConfigFile; +import fr.neatmonster.nocheatplus.config.ConfigManager; +import fr.neatmonster.nocheatplus.players.Permissions; +import fr.neatmonster.nocheatplus.utilities.CheckUtils; /* * M""MMMMMMMM MMP"""""""MM dP oo @@ -53,44 +61,26 @@ public class LogAction extends ActionWithParameters { this.toFile = toFile; } - /** - * Parse the final log message out of various data from the player and check that triggered the action. - * - * @param player - * The player that is used as a source for the log message. - * @param check - * The check that is used as a source for the log message. - * @return the log message + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData) */ - public String getLogMessage(final Check check, final ViolationData violationData) { - return super.getMessage(check, violationData); - } - - /** - * Should the message be shown in chat? - * - * @return true, if yes - */ - public boolean toChat() { - return toChat; - } - - /** - * Should the message be shown in the console? - * - * @return true, if yes - */ - public boolean toConsole() { - return toConsole; - } - - /** - * Should the message be written to the logfile? - * - * @return true, if yes - */ - public boolean toFile() { - return toFile; + @Override + public boolean execute(final ViolationData violationData) { + final ConfigFile configurationFile = ConfigManager.getConfigFile(); + if (configurationFile.getBoolean(ConfPaths.LOGGING_ACTIVE) + && !violationData.player.hasPermission(violationData.actions.permissionSilent)) { + final String message = super.getMessage(violationData); + if (toChat && configurationFile.getBoolean(ConfPaths.LOGGING_LOGTOINGAMECHAT)) + for (final Player otherPlayer : Bukkit.getServer().getOnlinePlayers()) + if (otherPlayer.hasPermission(Permissions.ADMINISTRATION_NOTIFY)) + otherPlayer.sendMessage(ChatColor.RED + "NCP: " + ChatColor.WHITE + + CheckUtils.replaceColors(message)); + if (toConsole && configurationFile.getBoolean(ConfPaths.LOGGING_LOGTOCONSOLE)) + System.out.println("[NoCheatPlus] " + CheckUtils.removeColors(message)); + if (toFile && configurationFile.getBoolean(ConfPaths.LOGGING_LOGTOFILE)) + CheckUtils.fileLogger.info(CheckUtils.removeColors(message)); + } + return false; } /** diff --git a/src/fr/neatmonster/nocheatplus/checks/Check.java b/src/fr/neatmonster/nocheatplus/checks/Check.java index e7356107..cd4efcbc 100644 --- a/src/fr/neatmonster/nocheatplus/checks/Check.java +++ b/src/fr/neatmonster/nocheatplus/checks/Check.java @@ -2,26 +2,15 @@ package fr.neatmonster.nocheatplus.checks; import java.util.HashMap; import java.util.Map; -import java.util.logging.Logger; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandException; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.actions.Action; import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.actions.types.ActionList; -import fr.neatmonster.nocheatplus.actions.types.CancelAction; -import fr.neatmonster.nocheatplus.actions.types.CommandAction; -import fr.neatmonster.nocheatplus.actions.types.DummyAction; -import fr.neatmonster.nocheatplus.actions.types.LogAction; -import fr.neatmonster.nocheatplus.config.ConfPaths; -import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.hooks.NCPHookManager; import fr.neatmonster.nocheatplus.players.ExecutionHistory; -import fr.neatmonster.nocheatplus.players.Permissions; /* * MM'""""'YMM dP dP @@ -36,9 +25,9 @@ import fr.neatmonster.nocheatplus.players.Permissions; * The Class Check. */ public abstract class Check { - protected static Map histories = new HashMap(); - private static Logger fileLogger = null; + /** The execution histories of each check. */ + protected static Map histories = new HashMap(); /** * Gets the player's history. @@ -53,42 +42,6 @@ public abstract class Check { return histories.get(player.getName()); } - /** - * Removes the colors of a message. - * - * @param text - * the text - * @return the string - */ - public static String removeColors(String text) { - for (final ChatColor c : ChatColor.values()) - text = text.replace("&" + c.getChar(), ""); - return text; - } - - /** - * Replace colors of a message. - * - * @param text - * the text - * @return the string - */ - public static String replaceColors(String text) { - for (final ChatColor c : ChatColor.values()) - text = text.replace("&" + c.getChar(), c.toString()); - return text; - } - - /** - * Sets the file logger. - * - * @param logger - * the new file logger - */ - public static void setFileLogger(final Logger logger) { - fileLogger = logger; - } - /** The type. */ protected final CheckType type; @@ -126,45 +79,26 @@ public abstract class Check { */ protected boolean executeActions(final ViolationData violationData) { try { - boolean special = false; - final Player player = violationData.player; - - // Check a bypass permission: + // Check a bypass permission. if (violationData.bypassPermission != null) - if (player.hasPermission(violationData.bypassPermission)) + if (violationData.player.hasPermission(violationData.bypassPermission)) return false; - final ActionList actionList = violationData.actions; - final double violationLevel = violationData.VL; - // Dispatch the VL processing to the hook manager. - if (NCPHookManager.shouldCancelVLProcessing(violationData.check.type, player)) + if (NCPHookManager.shouldCancelVLProcessing(violationData)) // One of the hooks has decided to cancel the VL processing, return false. return false; - // Get the to be executed actions. - final Action[] actions = actionList.getActions(violationLevel); - final long time = System.currentTimeMillis() / 1000L; - for (final Action ac : actions) - if (getHistory(player).executeAction(violationData.check.type.getName(), ac, time)) + boolean cancel = false; + for (final Action action : violationData.getActions()) + if (getHistory(violationData.player).executeAction(violationData, action, time)) // The execution history said it really is time to execute the action, find out what it is and do // what is needed. + cancel = cancel || action.execute(violationData); - // TODO: Check design: maybe ac.execute(this) without the instance checks ? - - if (ac instanceof LogAction && !player.hasPermission(actionList.permissionSilent)) - executeLogAction((LogAction) ac, violationData.check, violationData); - else if (ac instanceof CancelAction) - special = true; - else if (ac instanceof CommandAction) - executeConsoleCommand((CommandAction) ac, violationData.check, violationData); - else if (ac instanceof DummyAction) { - // Do nothing, it's a dummy action after all. - } - - return special; + return cancel; } catch (final Exception e) { e.printStackTrace(); } @@ -203,58 +137,6 @@ public abstract class Check { return event.getCancel(); } - /** - * Execute a console command. - * - * @param action - * the action - * @param check - * the check - * @param violationData - * the violation data - */ - private void executeConsoleCommand(final CommandAction action, final Check check, final ViolationData violationData) { - final String command = action.getCommand(check, violationData); - - try { - Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command); - } catch (final CommandException e) { - System.out.println("[NoCheatPlus] Failed to execute the command '" + command + "': " + e.getMessage() - + ", please check if everything is setup correct."); - } catch (final Exception e) { - // I don't care in this case, your problem if your command fails. - } - } - - /** - * Execute a log action. - * - * @param logAction - * the log action - * @param check - * the check - * @param violationData - * the violation data - */ - private void executeLogAction(final LogAction logAction, final Check check, final ViolationData violationData) { - final ConfigFile configurationFile = ConfigManager.getConfigFile(); - if (!configurationFile.getBoolean(ConfPaths.LOGGING_ACTIVE)) - return; - - final String message = logAction.getLogMessage(check, violationData); - if (configurationFile.getBoolean(ConfPaths.LOGGING_LOGTOCONSOLE) && logAction.toConsole()) - // Console logs are not colored. - System.out.println("[NoCheatPlus] " + removeColors(message)); - if (configurationFile.getBoolean(ConfPaths.LOGGING_LOGTOINGAMECHAT) && logAction.toChat()) - for (final Player otherPlayer : Bukkit.getServer().getOnlinePlayers()) - if (otherPlayer.hasPermission(Permissions.ADMINISTRATION_NOTIFY)) - // Chat logs are potentially colored. - otherPlayer.sendMessage(replaceColors(ChatColor.RED + "NCP: " + ChatColor.WHITE + message)); - if (configurationFile.getBoolean(ConfPaths.LOGGING_LOGTOFILE) && logAction.toFile()) - // File logs are not colored. - fileLogger.info(removeColors(message)); - } - /** * Replace a parameter for commands or log actions with an actual value. Individual checks should override this to * get their own parameters handled too. @@ -272,9 +154,8 @@ public abstract class Check { return violationData.player.getName(); else if (wildcard == ParameterName.VIOLATIONS) { try { - return "" + Math.round(violationData.VL); + return "" + Math.round(violationData.violationLevel); } catch (final Exception e) { - Bukkit.broadcastMessage("getParameter " + type.getName()); e.printStackTrace(); } return ""; @@ -282,6 +163,15 @@ public abstract class Check { return "The author was lazy and forgot to define " + wildcard + "."; } + /** + * Gets the type of the check. + * + * @return the type + */ + public CheckType getType() { + return type; + } + /** * Checks if this check is enabled for the specified player. * diff --git a/src/fr/neatmonster/nocheatplus/checks/CheckType.java b/src/fr/neatmonster/nocheatplus/checks/CheckType.java index b59757a5..e3fb338b 100644 --- a/src/fr/neatmonster/nocheatplus/checks/CheckType.java +++ b/src/fr/neatmonster/nocheatplus/checks/CheckType.java @@ -195,8 +195,6 @@ public enum CheckType { * @return true, if the check is enabled */ public final boolean isEnabled(final Player player) { - // if (configFactory == null) return true; // TODO: maybe leave this out. return configFactory.getConfig(player).isEnabled(this); } - } \ No newline at end of file diff --git a/src/fr/neatmonster/nocheatplus/checks/ViolationData.java b/src/fr/neatmonster/nocheatplus/checks/ViolationData.java index a61ba08b..f3e8fd0c 100644 --- a/src/fr/neatmonster/nocheatplus/checks/ViolationData.java +++ b/src/fr/neatmonster/nocheatplus/checks/ViolationData.java @@ -2,6 +2,7 @@ package fr.neatmonster.nocheatplus.checks; import org.bukkit.entity.Player; +import fr.neatmonster.nocheatplus.actions.Action; import fr.neatmonster.nocheatplus.actions.types.ActionList; /* @@ -21,6 +22,12 @@ import fr.neatmonster.nocheatplus.actions.types.ActionList; */ public class ViolationData { + /** The actions to be executed. */ + public final ActionList actions; + + /** The bypassing permission. */ + public final String bypassPermission; + /** The check. */ public final Check check; @@ -28,13 +35,7 @@ public class ViolationData { public final Player player; /** The violation level. */ - public final double VL; - - /** The actions to be executed. */ - public final ActionList actions; - - /** The bypassing permission. */ - public final String bypassPermission; + public final double violationLevel; /** * Instantiates a new violation data. @@ -43,13 +44,13 @@ public class ViolationData { * the check * @param player * the player - * @param VL - * the vL + * @param violationLevel + * the violation level * @param actions * the actions */ - public ViolationData(final Check check, final Player player, final double VL, final ActionList actions) { - this(check, player, VL, actions, null); + public ViolationData(final Check check, final Player player, final double violationLevel, final ActionList actions) { + this(check, player, violationLevel, actions, null); } /** @@ -59,20 +60,28 @@ public class ViolationData { * the check * @param player * the player - * @param VL - * the vL + * @param violationLevel + * the violation level * @param actions * the actions * @param bypassPermission * the permission to bypass the execution, if not null */ - public ViolationData(final Check check, final Player player, final double VL, final ActionList actions, + public ViolationData(final Check check, final Player player, final double violationLevel, final ActionList actions, final String bypassPermission) { this.check = check; this.player = player; - this.VL = VL; + this.violationLevel = violationLevel; this.actions = actions; this.bypassPermission = bypassPermission; } + /** + * Gets the actions. + * + * @return the actions + */ + public Action[] getActions() { + return actions.getActions(violationLevel); + } } diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/ChatData.java b/src/fr/neatmonster/nocheatplus/checks/chat/ChatData.java index d3b5dfe6..f6229ac3 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/ChatData.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/ChatData.java @@ -54,7 +54,6 @@ public class ChatData implements CheckData { // Data of the no pwnage check. public int noPwnageCaptchTries; public String noPwnageGeneratedCaptcha; - public boolean noPwnageHasFilledCaptcha; public boolean noPwnageHasStartedCaptcha; public long noPwnageJoinTime; public Location noPwnageLastLocation; @@ -70,7 +69,6 @@ public class ChatData implements CheckData { * Clear the data of the no pwnage check. */ public synchronized void clearNoPwnageData() { - // TODO: re-think this sync [keep related to ChatData/NoPwnage/Color used lock.] noPwnageCaptchTries = noPwnageReloginWarnings = 0; noPwnageJoinTime = noPwnageLastMessageTime = noPwnageLastMovedTime = noPwnageLastWarningTime = noPwnageLeaveTime = noPwnageReloginWarningTime = 0L; noPwnageGeneratedCaptcha = noPwnageLastMessage = ""; diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java b/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java index 6b8151ce..2b4c0228 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java @@ -10,8 +10,8 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; -import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.players.Permissions; +import fr.neatmonster.nocheatplus.utilities.CheckUtils; /* * MM'""""'YMM dP dP M""MMMMMMMM oo dP @@ -59,7 +59,7 @@ public class ChatListener implements Listener { // Then the no pwnage check. if (noPwnage.check(player, event, false)) - player.kickPlayer(Check.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage)); + player.kickPlayer(CheckUtils.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage)); } /** @@ -90,7 +90,8 @@ public class ChatListener implements Listener { // Protect some commands to prevent players for seeing which plugins are installed. if (ChatConfig.getConfig(player).protectPlugins - && (command.equals("plugins") || command.equals("pl") || command.equals("?")) + && (command.equals("?") || command.equals("about") || command.equals("help") + || command.equals("plugins") || command.equals("pl")) && !player.hasPermission(Permissions.ADMINISTRATION_PLUGINS)) { event.getPlayer().sendMessage( ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. " @@ -112,7 +113,7 @@ public class ChatListener implements Listener { // Then the no pwnage check. if (noPwnage.check(player, event, true)) - player.kickPlayer(Check.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage)); + player.kickPlayer(CheckUtils.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage)); } /** diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java index 89220241..ab0b9203 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java @@ -163,49 +163,68 @@ public class NoPwnage extends Check { */ private boolean unsafeCheck(final Player player, final PlayerEvent event, final boolean isMainThread, final ChatConfig cc, final ChatData data) { + boolean[] results = null; + if (event instanceof AsyncPlayerChatEvent) { + final AsyncPlayerChatEvent e = (AsyncPlayerChatEvent) event; + results = unsafeCheck(player, e.getMessage(), isMainThread, cc, data); + e.setCancelled(results[0]); + } else if (event instanceof PlayerCommandPreprocessEvent) { + final PlayerCommandPreprocessEvent e = (PlayerCommandPreprocessEvent) event; + results = unsafeCheck(player, e.getMessage(), isMainThread, cc, data); + e.setCancelled(results[0]); + } + return results[1]; + } + + /** + * Only to be called form synchronized code. + * + * @param player + * the player + * @param message + * the message + * @param isMainThread + * the is main thread + * @param cc + * the cc + * @param data + * the data + * @return the boolean[] + */ + private boolean[] unsafeCheck(final Player player, final String message, final boolean isMainThread, + final ChatConfig cc, final ChatData data) { data.noPwnageVL = 0D; boolean cancel = false; + boolean kick = false; - String message = ""; - if (event instanceof AsyncPlayerChatEvent) - message = ((AsyncPlayerChatEvent) event).getMessage(); - else if (event instanceof PlayerCommandPreprocessEvent) - message = ((PlayerCommandPreprocessEvent) event).getMessage(); - final boolean isCommand = event instanceof PlayerCommandPreprocessEvent; final long now = System.currentTimeMillis(); - if (!data.noPwnageHasFilledCaptcha) - if (cc.noPwnageCaptchaCheck && data.noPwnageHasStartedCaptcha) { - // Correct answer to the captcha? - if (message.equals(data.noPwnageGeneratedCaptcha)) { - // Yes, clear his data and do not worry anymore about him. - data.clearNoPwnageData(); - data.noPwnageHasFilledCaptcha = true; - player.sendMessage(replaceColors(cc.noPwnageCaptchaSuccess)); - } else { - // Does he failed too much times? - if (data.noPwnageCaptchTries > cc.noPwnageCaptchaTries) - // Find out if we need to ban the player or not. - // TODO: extra captcha actions / VL ? - cancel = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, isMainThread); + if (cc.noPwnageCaptchaCheck && data.noPwnageHasStartedCaptcha) { + // Correct answer to the captcha? + if (message.equals(data.noPwnageGeneratedCaptcha)) { + // Yes, clear his data and do not worry anymore about him. + data.clearNoPwnageData(); + data.noPwnageHasStartedCaptcha = false; + player.sendMessage(CheckUtils.replaceColors(cc.noPwnageCaptchaSuccess)); + } else { + // Does he failed too much times? + if (data.noPwnageCaptchTries > cc.noPwnageCaptchaTries) + // Find out if we need to ban the player or not. + kick = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, isMainThread); - // Increment his tries number counter. - data.noPwnageCaptchTries++; + // Increment his tries number counter. + data.noPwnageCaptchTries++; - // Display the question again. - player.sendMessage(replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]", - data.noPwnageGeneratedCaptcha))); - } - - // Cancel the event and return. - if (event instanceof AsyncPlayerChatEvent) - ((AsyncPlayerChatEvent) event).setCancelled(true); - else if (event instanceof PlayerCommandPreprocessEvent) - ((PlayerCommandPreprocessEvent) event).setCancelled(true); - return cancel; + // Display the question again. + player.sendMessage(CheckUtils.replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]", + data.noPwnageGeneratedCaptcha))); } + // Cancel the message and maybe event. + return new boolean[] {true, kick}; + } + if (data.noPwnageLastLocation == null) data.noPwnageLastLocation = player.getLocation(); else if (!data.noPwnageLastLocation.equals(player.getLocation())) { @@ -215,7 +234,7 @@ public class NoPwnage extends Check { // NoPwnage will remember the last message that caused someone to get banned. If a player repeats that // message within "timeout" milliseconds, the suspicion will be increased by "weight". - if (!isCommand && cc.noPwnageBannedCheck && now - lastBanCausingMessageTime < cc.noPwnageBannedTimeout + if (cc.noPwnageBannedCheck && now - lastBanCausingMessageTime < cc.noPwnageBannedTimeout && CheckUtils.isSimilar(message, lastBanCausingMessage, 0.8f)) data.noPwnageVL += cc.noPwnageBannedWeight; @@ -226,7 +245,7 @@ public class NoPwnage extends Check { // NoPwnage will check if a player repeats a message that has been sent by another player just before, // within "timeout". If he does, suspicion will be increased by "weight". - if (!isCommand && cc.noPwnageGlobalCheck && now - lastGlobalMessageTime < cc.noPwnageGlobalTimeout + if (cc.noPwnageGlobalCheck && now - lastGlobalMessageTime < cc.noPwnageGlobalTimeout && CheckUtils.isSimilar(message, lastGlobalMessage, 0.8f)) data.noPwnageVL += cc.noPwnageGlobalWeight; @@ -237,7 +256,7 @@ public class NoPwnage extends Check { // NoPwnage will check if a player repeats his messages within the "timeout" timeframe. Even if the message // is a bit different, it will be counted as being a repetition. The suspicion is increased by "weight". - if (!isCommand && cc.noPwnageRepeatCheck && now - data.noPwnageLastMessageTime < cc.noPwnageRepeatTimeout + if (cc.noPwnageRepeatCheck && now - data.noPwnageLastMessageTime < cc.noPwnageRepeatTimeout && CheckUtils.isSimilar(message, data.noPwnageLastMessage, 0.8f)) data.noPwnageVL += cc.noPwnageRepeatWeight; @@ -258,34 +277,29 @@ public class NoPwnage extends Check { } if (cc.noPwnageWarnPlayerCheck && data.noPwnageVL > cc.noPwnageWarnLevel && !warned) { - player.sendMessage(replaceColors(cc.noPwnageWarnPlayerMessage)); + player.sendMessage(CheckUtils.replaceColors(cc.noPwnageWarnPlayerMessage)); data.noPwnageLastWarningTime = now; } else if (data.noPwnageVL > cc.noPwnageLevel) if (cc.noPwnageCaptchaCheck && !data.noPwnageHasStartedCaptcha) { // Display a captcha to the player. + data.noPwnageGeneratedCaptcha = ""; for (int i = 0; i < cc.noPwnageCaptchaLength; i++) data.noPwnageGeneratedCaptcha += cc.noPwnageCaptchaCharacters.charAt(random .nextInt(cc.noPwnageCaptchaCharacters.length())); - player.sendMessage(replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]", + player.sendMessage(CheckUtils.replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]", data.noPwnageGeneratedCaptcha))); data.noPwnageHasStartedCaptcha = true; - if (event instanceof AsyncPlayerChatEvent) - ((AsyncPlayerChatEvent) event).setCancelled(true); - else if (event instanceof PlayerCommandPreprocessEvent) - ((PlayerCommandPreprocessEvent) event).setCancelled(true); + cancel = true; } else { lastBanCausingMessage = message; data.noPwnageLastWarningTime = lastBanCausingMessageTime = now; if (cc.noPwnageWarnOthersCheck) - Bukkit.broadcastMessage(replaceColors(cc.noPwnageWarnOthersMessage.replace("[player]", + Bukkit.broadcastMessage(CheckUtils.replaceColors(cc.noPwnageWarnOthersMessage.replace("[player]", player.getName()))); - if (event instanceof AsyncPlayerChatEvent) - ((AsyncPlayerChatEvent) event).setCancelled(true); - else if (event instanceof PlayerCommandPreprocessEvent) - ((PlayerCommandPreprocessEvent) event).setCancelled(true); + cancel = true; // Find out if we need to ban the player or not. - cancel = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, isMainThread); + kick = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, isMainThread); } // Store the message and some other data. @@ -294,7 +308,7 @@ public class NoPwnage extends Check { lastGlobalMessage = message; lastGlobalMessageTime = now; - return cancel; + return new boolean[] {cancel, kick}; } /** @@ -320,12 +334,11 @@ public class NoPwnage extends Check { if (now - data.noPwnageReloginWarningTime > cc.noPwnageReloginWarningTimeout) data.noPwnageReloginWarnings = 0; if (data.noPwnageReloginWarnings < cc.noPwnageReloginWarningNumber) { - player.sendMessage(replaceColors(cc.noPwnageReloginWarningMessage)); + player.sendMessage(CheckUtils.replaceColors(cc.noPwnageReloginWarningMessage)); data.noPwnageReloginWarningTime = now; data.noPwnageReloginWarnings++; } else if (now - data.noPwnageReloginWarningTime < cc.noPwnageReloginWarningTimeout) // Find out if we need to ban the player or not. - // TODO: extra actions / VL ? cancel = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, true); } diff --git a/src/fr/neatmonster/nocheatplus/config/ConfigManager.java b/src/fr/neatmonster/nocheatplus/config/ConfigManager.java index 858b894d..deb3363a 100644 --- a/src/fr/neatmonster/nocheatplus/config/ConfigManager.java +++ b/src/fr/neatmonster/nocheatplus/config/ConfigManager.java @@ -15,7 +15,7 @@ import java.util.logging.LogRecord; import java.util.logging.Logger; import fr.neatmonster.nocheatplus.NoCheatPlus; -import fr.neatmonster.nocheatplus.checks.Check; +import fr.neatmonster.nocheatplus.utilities.CheckUtils; /* * MM'""""'YMM .8888b oo M"""""`'"""`YM @@ -182,7 +182,7 @@ public class ConfigManager { e.printStackTrace(); } - Check.setFileLogger(logger); + CheckUtils.fileLogger = logger; // Try to find world-specific configuration files. final HashMap worldFiles = new HashMap(); diff --git a/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java b/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java index 1160f70e..e3ca352a 100644 --- a/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java +++ b/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java @@ -132,11 +132,11 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_CHECK, true); set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_CHARACTERS, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); - set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_LENGTH, 4); + set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_LENGTH, 6); set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_QUESTION, "&cPlease type '&6[captcha]&c' to continue sending messages/commands."); set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_SUCCESS, "&aOK, it sounds like you're not a spambot."); - set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_TRIES, 20); + set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_TRIES, 3); set(ConfPaths.CHAT_NOPWNAGE_FIRST_CHECK, true); set(ConfPaths.CHAT_NOPWNAGE_FIRST_TIMEOUT, 3000L); @@ -301,8 +301,8 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.STRINGS + ".color", start + "sent colored chat message" + end); set(ConfPaths.STRINGS + ".critical", start + "tried to do a critical hit but wasn't technically jumping" + end); set(ConfPaths.STRINGS + ".drop", start + "tried to drop more items than allowed" + end); - set(ConfPaths.STRINGS + ".fastbreak", start + "tried to break too much blocks" + end); - set(ConfPaths.STRINGS + ".fastplace", start + "tried to place too much blocks" + end); + set(ConfPaths.STRINGS + ".fastbreak", start + "tried to break too many blocks" + end); + set(ConfPaths.STRINGS + ".fastplace", start + "tried to place too many blocks" + end); set(ConfPaths.STRINGS + ".fdirection", start + "tried to hit an entity out of line of sight" + end); set(ConfPaths.STRINGS + ".flyshort", start + "tried to move unexpectedly" + end); set(ConfPaths.STRINGS + ".flylong", start diff --git a/src/fr/neatmonster/nocheatplus/hooks/NCPHookManager.java b/src/fr/neatmonster/nocheatplus/hooks/NCPHookManager.java index eec6633f..3c38e04d 100644 --- a/src/fr/neatmonster/nocheatplus/hooks/NCPHookManager.java +++ b/src/fr/neatmonster/nocheatplus/hooks/NCPHookManager.java @@ -13,6 +13,7 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.checks.ViolationData; /* * M"""""""`YM MM'""""'YMM MM"""""""`YM M""MMMMM""MM dP @@ -265,7 +266,7 @@ public final class NCPHookManager { */ private static final void logHookFailure(final CheckType checkType, final Player player, final NCPHook hook, final Throwable t) { - // TODO: Might accumulate failure rate and only log every so and so seconds or disable hook if spamming (leads + // TODO: might accumulate failure rate and only log every so and so seconds or disable hook if spamming (leads // to NCP spam though)? final StringBuilder builder = new StringBuilder(1024); builder.append("[NoCheatPlus] Hook " + getHookDescription(hook) + " encountered an unexpected exception:\n"); @@ -403,14 +404,12 @@ public final class NCPHookManager { * the player that fails the check * @return if we should cancel the VL processing */ - public static final boolean shouldCancelVLProcessing(final CheckType checkType, final Player player) { + public static final boolean shouldCancelVLProcessing(final ViolationData violationData) { // Checks for hooks registered for this event, parent groups or ALL will be inserted into the list. - // Return true as soon as one hook returns true. - - // Test hooks, if present: - final List hooksCheck = hooksByChecks.get(checkType); + // Return true as soon as one hook returns true. Test hooks, if present. + final List hooksCheck = hooksByChecks.get(violationData.check.getType()); if (hooksCheck != null) - if (applyHooks(checkType, player, hooksCheck)) + if (applyHooks(violationData.check.getType(), violationData.player, hooksCheck)) return true; return false; } diff --git a/src/fr/neatmonster/nocheatplus/players/ExecutionHistory.java b/src/fr/neatmonster/nocheatplus/players/ExecutionHistory.java index d0244f52..db1a827f 100644 --- a/src/fr/neatmonster/nocheatplus/players/ExecutionHistory.java +++ b/src/fr/neatmonster/nocheatplus/players/ExecutionHistory.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Map; import fr.neatmonster.nocheatplus.actions.Action; +import fr.neatmonster.nocheatplus.checks.ViolationData; /* * MM""""""""`M dP oo @@ -82,9 +83,9 @@ public class ExecutionHistory { * the length */ private void clearTimes(final long start, long length) { - if (length <= 0) - return; // Nothing to do (yet). + // Nothing to do (yet). + return; if (length > executionTimes.length) length = executionTimes.length; @@ -144,25 +145,24 @@ public class ExecutionHistory { * Returns true, if the action should be executed, because all time criteria have been met. Will add a entry with * the time to a list which will influence further requests, so only use once and remember the result. * - * @param check - * the check + * @param violationData + * the violation data * @param action * the action * @param time * a time IN SECONDS * @return true, if successful */ - public boolean executeAction(final String check, final Action action, final long time) { + public boolean executeAction(final ViolationData violationData, final Action action, final long time) { + final String check = violationData.check.getType().getName(); Map executionHistory = executionHistories.get(check); - if (executionHistory == null) { executionHistory = new HashMap(); executionHistories.put(check, executionHistory); } ExecutionHistoryEntry entry = executionHistory.get(action); - if (entry == null) { entry = new ExecutionHistoryEntry(60); executionHistory.put(action, entry); diff --git a/src/fr/neatmonster/nocheatplus/utilities/CheckUtils.java b/src/fr/neatmonster/nocheatplus/utilities/CheckUtils.java index c7bd3ee6..43a6e3e0 100644 --- a/src/fr/neatmonster/nocheatplus/utilities/CheckUtils.java +++ b/src/fr/neatmonster/nocheatplus/utilities/CheckUtils.java @@ -1,5 +1,8 @@ package fr.neatmonster.nocheatplus.utilities; +import java.util.logging.Logger; + +import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -9,6 +12,9 @@ import org.bukkit.util.Vector; */ public class CheckUtils { + /** The file logger. */ + public static Logger fileLogger = null; + /** * Check if a player looks at a target of a specific size, with a specific precision value (roughly). * @@ -152,4 +158,30 @@ public class CheckUtils { return p[n]; } + + /** + * Removes the colors of a message. + * + * @param text + * the text + * @return the string + */ + public static String removeColors(String text) { + for (final ChatColor c : ChatColor.values()) + text = text.replace("&" + c.getChar(), ""); + return text; + } + + /** + * Replace colors of a message. + * + * @param text + * the text + * @return the string + */ + public static String replaceColors(String text) { + for (final ChatColor c : ChatColor.values()) + text = text.replace("&" + c.getChar(), c.toString()); + return text; + } }