Cleaned some stuff...

This commit is contained in:
NeatMonster 2012-08-14 19:19:39 +02:00
parent 96a7f493f8
commit 55ec451d64
17 changed files with 240 additions and 279 deletions

View File

@ -1,5 +1,7 @@
package fr.neatmonster.nocheatplus.actions; package fr.neatmonster.nocheatplus.actions;
import fr.neatmonster.nocheatplus.checks.ViolationData;
/* /*
* MMP"""""""MM dP oo * MMP"""""""MM dP oo
* M' .mmmm MM 88 * M' .mmmm MM 88
@ -46,4 +48,13 @@ public abstract class Action {
this.delay = delay; this.delay = delay;
this.repeat = repeat; this.repeat = repeat;
} }
/**
* Execute the action.
*
* @param violationData
* the violation data
* @return true, if successful
*/
public abstract boolean execute(final ViolationData violationData);
} }

View File

@ -4,7 +4,6 @@ import java.util.ArrayList;
import fr.neatmonster.nocheatplus.actions.Action; import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.ViolationData; 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. * Get a string with all the wildcards replaced with data from the violation data.
* *
* @param check
* the check
* @param violationData * @param violationData
* the violation data * the violation data
* @return the message * @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. // Should be big enough most of the time.
final StringBuilder log = new StringBuilder(100); final StringBuilder log = new StringBuilder(100);
@ -68,7 +65,7 @@ public abstract class ActionWithParameters extends Action {
if (part instanceof String) if (part instanceof String)
log.append((String) part); log.append((String) part);
else else
log.append(check.getParameter((ParameterName) part, violationData)); log.append(violationData.check.getParameter((ParameterName) part, violationData));
return log.toString(); return log.toString();
} }

View File

@ -1,6 +1,7 @@
package fr.neatmonster.nocheatplus.actions.types; package fr.neatmonster.nocheatplus.actions.types;
import fr.neatmonster.nocheatplus.actions.Action; import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.checks.ViolationData;
/* /*
* MM'""""'YMM dP MMP"""""""MM dP oo * MM'""""'YMM dP MMP"""""""MM dP oo
@ -24,6 +25,14 @@ public class CancelAction extends Action {
super("cancel", 0, 0); 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) /* (non-Javadoc)
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */

View File

@ -1,6 +1,8 @@
package fr.neatmonster.nocheatplus.actions.types; 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; import fr.neatmonster.nocheatplus.checks.ViolationData;
/* /*
@ -42,18 +44,21 @@ public class CommandAction extends ActionWithParameters {
super(name, delay, repeat, command); super(name, delay, repeat, command);
} }
/** /* (non-Javadoc)
* Fill in the placeholders (stuff that looks like '[something]') with information, make a nice String out of it * @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData)
* 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.
*/ */
public String getCommand(final Check check, final ViolationData violationData) { @Override
return super.getMessage(check, violationData); 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;
} }
/** /**

View File

@ -1,6 +1,7 @@
package fr.neatmonster.nocheatplus.actions.types; package fr.neatmonster.nocheatplus.actions.types;
import fr.neatmonster.nocheatplus.actions.Action; import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.checks.ViolationData;
/* /*
* M""""""'YMM MMP"""""""MM dP oo * M""""""'YMM MMP"""""""MM dP oo
@ -31,6 +32,14 @@ public class DummyAction extends Action {
this.definition = definition; 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) /* (non-Javadoc)
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */

View File

@ -1,7 +1,15 @@
package fr.neatmonster.nocheatplus.actions.types; 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.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 * M""MMMMMMMM MMP"""""""MM dP oo
@ -53,44 +61,26 @@ public class LogAction extends ActionWithParameters {
this.toFile = toFile; this.toFile = toFile;
} }
/** /* (non-Javadoc)
* Parse the final log message out of various data from the player and check that triggered the action. * @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData)
*
* @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
*/ */
public String getLogMessage(final Check check, final ViolationData violationData) { @Override
return super.getMessage(check, violationData); 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;
/**
* 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;
} }
/** /**

View File

@ -2,26 +2,15 @@ package fr.neatmonster.nocheatplus.checks;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandException;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.actions.Action; import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.actions.types.ActionList; 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.hooks.NCPHookManager;
import fr.neatmonster.nocheatplus.players.ExecutionHistory; import fr.neatmonster.nocheatplus.players.ExecutionHistory;
import fr.neatmonster.nocheatplus.players.Permissions;
/* /*
* MM'""""'YMM dP dP * MM'""""'YMM dP dP
@ -36,9 +25,9 @@ import fr.neatmonster.nocheatplus.players.Permissions;
* The Class Check. * The Class Check.
*/ */
public abstract class Check { public abstract class Check {
protected static Map<String, ExecutionHistory> histories = new HashMap<String, ExecutionHistory>();
private static Logger fileLogger = null; /** The execution histories of each check. */
protected static Map<String, ExecutionHistory> histories = new HashMap<String, ExecutionHistory>();
/** /**
* Gets the player's history. * Gets the player's history.
@ -53,42 +42,6 @@ public abstract class Check {
return histories.get(player.getName()); 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. */ /** The type. */
protected final CheckType type; protected final CheckType type;
@ -126,45 +79,26 @@ public abstract class Check {
*/ */
protected boolean executeActions(final ViolationData violationData) { protected boolean executeActions(final ViolationData violationData) {
try { try {
boolean special = false; // Check a bypass permission.
final Player player = violationData.player;
// Check a bypass permission:
if (violationData.bypassPermission != null) if (violationData.bypassPermission != null)
if (player.hasPermission(violationData.bypassPermission)) if (violationData.player.hasPermission(violationData.bypassPermission))
return false; return false;
final ActionList actionList = violationData.actions;
final double violationLevel = violationData.VL;
// Dispatch the VL processing to the hook manager. // 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. // One of the hooks has decided to cancel the VL processing, return false.
return false; return false;
// Get the to be executed actions.
final Action[] actions = actionList.getActions(violationLevel);
final long time = System.currentTimeMillis() / 1000L; final long time = System.currentTimeMillis() / 1000L;
for (final Action ac : actions) boolean cancel = false;
if (getHistory(player).executeAction(violationData.check.type.getName(), ac, time)) 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 // The execution history said it really is time to execute the action, find out what it is and do
// what is needed. // what is needed.
cancel = cancel || action.execute(violationData);
// TODO: Check design: maybe ac.execute(this) without the instance checks ? return cancel;
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;
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -203,58 +137,6 @@ public abstract class Check {
return event.getCancel(); 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 * Replace a parameter for commands or log actions with an actual value. Individual checks should override this to
* get their own parameters handled too. * get their own parameters handled too.
@ -272,9 +154,8 @@ public abstract class Check {
return violationData.player.getName(); return violationData.player.getName();
else if (wildcard == ParameterName.VIOLATIONS) { else if (wildcard == ParameterName.VIOLATIONS) {
try { try {
return "" + Math.round(violationData.VL); return "" + Math.round(violationData.violationLevel);
} catch (final Exception e) { } catch (final Exception e) {
Bukkit.broadcastMessage("getParameter " + type.getName());
e.printStackTrace(); e.printStackTrace();
} }
return ""; return "";
@ -282,6 +163,15 @@ public abstract class Check {
return "The author was lazy and forgot to define " + wildcard + "."; 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. * Checks if this check is enabled for the specified player.
* *

View File

@ -195,8 +195,6 @@ public enum CheckType {
* @return true, if the check is enabled * @return true, if the check is enabled
*/ */
public final boolean isEnabled(final Player player) { public final boolean isEnabled(final Player player) {
// if (configFactory == null) return true; // TODO: maybe leave this out.
return configFactory.getConfig(player).isEnabled(this); return configFactory.getConfig(player).isEnabled(this);
} }
} }

View File

@ -2,6 +2,7 @@ package fr.neatmonster.nocheatplus.checks;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.types.ActionList; import fr.neatmonster.nocheatplus.actions.types.ActionList;
/* /*
@ -21,6 +22,12 @@ import fr.neatmonster.nocheatplus.actions.types.ActionList;
*/ */
public class ViolationData { public class ViolationData {
/** The actions to be executed. */
public final ActionList actions;
/** The bypassing permission. */
public final String bypassPermission;
/** The check. */ /** The check. */
public final Check check; public final Check check;
@ -28,13 +35,7 @@ public class ViolationData {
public final Player player; public final Player player;
/** The violation level. */ /** The violation level. */
public final double VL; public final double violationLevel;
/** The actions to be executed. */
public final ActionList actions;
/** The bypassing permission. */
public final String bypassPermission;
/** /**
* Instantiates a new violation data. * Instantiates a new violation data.
@ -43,13 +44,13 @@ public class ViolationData {
* the check * the check
* @param player * @param player
* the player * the player
* @param VL * @param violationLevel
* the vL * the violation level
* @param actions * @param actions
* the actions * the actions
*/ */
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) {
this(check, player, VL, actions, null); this(check, player, violationLevel, actions, null);
} }
/** /**
@ -59,20 +60,28 @@ public class ViolationData {
* the check * the check
* @param player * @param player
* the player * the player
* @param VL * @param violationLevel
* the vL * the violation level
* @param actions * @param actions
* the actions * the actions
* @param bypassPermission * @param bypassPermission
* the permission to bypass the execution, if not null * 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) { final String bypassPermission) {
this.check = check; this.check = check;
this.player = player; this.player = player;
this.VL = VL; this.violationLevel = violationLevel;
this.actions = actions; this.actions = actions;
this.bypassPermission = bypassPermission; this.bypassPermission = bypassPermission;
} }
/**
* Gets the actions.
*
* @return the actions
*/
public Action[] getActions() {
return actions.getActions(violationLevel);
}
} }

View File

@ -54,7 +54,6 @@ public class ChatData implements CheckData {
// Data of the no pwnage check. // Data of the no pwnage check.
public int noPwnageCaptchTries; public int noPwnageCaptchTries;
public String noPwnageGeneratedCaptcha; public String noPwnageGeneratedCaptcha;
public boolean noPwnageHasFilledCaptcha;
public boolean noPwnageHasStartedCaptcha; public boolean noPwnageHasStartedCaptcha;
public long noPwnageJoinTime; public long noPwnageJoinTime;
public Location noPwnageLastLocation; public Location noPwnageLastLocation;
@ -70,7 +69,6 @@ public class ChatData implements CheckData {
* Clear the data of the no pwnage check. * Clear the data of the no pwnage check.
*/ */
public synchronized void clearNoPwnageData() { public synchronized void clearNoPwnageData() {
// TODO: re-think this sync [keep related to ChatData/NoPwnage/Color used lock.]
noPwnageCaptchTries = noPwnageReloginWarnings = 0; noPwnageCaptchTries = noPwnageReloginWarnings = 0;
noPwnageJoinTime = noPwnageLastMessageTime = noPwnageLastMovedTime = noPwnageLastWarningTime = noPwnageLeaveTime = noPwnageReloginWarningTime = 0L; noPwnageJoinTime = noPwnageLastMessageTime = noPwnageLastMovedTime = noPwnageLastWarningTime = noPwnageLeaveTime = noPwnageReloginWarningTime = 0L;
noPwnageGeneratedCaptcha = noPwnageLastMessage = ""; noPwnageGeneratedCaptcha = noPwnageLastMessage = "";

View File

@ -10,8 +10,8 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result; import org.bukkit.event.player.PlayerLoginEvent.Result;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.players.Permissions; import fr.neatmonster.nocheatplus.players.Permissions;
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
/* /*
* MM'""""'YMM dP dP M""MMMMMMMM oo dP * MM'""""'YMM dP dP M""MMMMMMMM oo dP
@ -59,7 +59,7 @@ public class ChatListener implements Listener {
// Then the no pwnage check. // Then the no pwnage check.
if (noPwnage.check(player, event, false)) 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. // Protect some commands to prevent players for seeing which plugins are installed.
if (ChatConfig.getConfig(player).protectPlugins 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)) { && !player.hasPermission(Permissions.ADMINISTRATION_PLUGINS)) {
event.getPlayer().sendMessage( event.getPlayer().sendMessage(
ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. " 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. // Then the no pwnage check.
if (noPwnage.check(player, event, true)) if (noPwnage.check(player, event, true))
player.kickPlayer(Check.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage)); player.kickPlayer(CheckUtils.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage));
} }
/** /**

View File

@ -163,47 +163,66 @@ public class NoPwnage extends Check {
*/ */
private boolean unsafeCheck(final Player player, final PlayerEvent event, final boolean isMainThread, private boolean unsafeCheck(final Player player, final PlayerEvent event, final boolean isMainThread,
final ChatConfig cc, final ChatData data) { 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; data.noPwnageVL = 0D;
boolean cancel = false; 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(); final long now = System.currentTimeMillis();
if (!data.noPwnageHasFilledCaptcha)
if (cc.noPwnageCaptchaCheck && data.noPwnageHasStartedCaptcha) { if (cc.noPwnageCaptchaCheck && data.noPwnageHasStartedCaptcha) {
// Correct answer to the captcha? // Correct answer to the captcha?
if (message.equals(data.noPwnageGeneratedCaptcha)) { if (message.equals(data.noPwnageGeneratedCaptcha)) {
// Yes, clear his data and do not worry anymore about him. // Yes, clear his data and do not worry anymore about him.
data.clearNoPwnageData(); data.clearNoPwnageData();
data.noPwnageHasFilledCaptcha = true; data.noPwnageHasStartedCaptcha = false;
player.sendMessage(replaceColors(cc.noPwnageCaptchaSuccess)); player.sendMessage(CheckUtils.replaceColors(cc.noPwnageCaptchaSuccess));
} else { } else {
// Does he failed too much times? // Does he failed too much times?
if (data.noPwnageCaptchTries > cc.noPwnageCaptchaTries) if (data.noPwnageCaptchTries > cc.noPwnageCaptchaTries)
// Find out if we need to ban the player or not. // Find out if we need to ban the player or not.
// TODO: extra captcha actions / VL ? kick = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, isMainThread);
cancel = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, isMainThread);
// Increment his tries number counter. // Increment his tries number counter.
data.noPwnageCaptchTries++; data.noPwnageCaptchTries++;
// Display the question again. // Display the question again.
player.sendMessage(replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]", player.sendMessage(CheckUtils.replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]",
data.noPwnageGeneratedCaptcha))); data.noPwnageGeneratedCaptcha)));
} }
// Cancel the event and return. // Cancel the message and maybe event.
if (event instanceof AsyncPlayerChatEvent) return new boolean[] {true, kick};
((AsyncPlayerChatEvent) event).setCancelled(true);
else if (event instanceof PlayerCommandPreprocessEvent)
((PlayerCommandPreprocessEvent) event).setCancelled(true);
return cancel;
} }
if (data.noPwnageLastLocation == null) if (data.noPwnageLastLocation == null)
@ -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 // 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". // 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)) && CheckUtils.isSimilar(message, lastBanCausingMessage, 0.8f))
data.noPwnageVL += cc.noPwnageBannedWeight; 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, // 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". // 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)) && CheckUtils.isSimilar(message, lastGlobalMessage, 0.8f))
data.noPwnageVL += cc.noPwnageGlobalWeight; 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 // 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". // 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)) && CheckUtils.isSimilar(message, data.noPwnageLastMessage, 0.8f))
data.noPwnageVL += cc.noPwnageRepeatWeight; data.noPwnageVL += cc.noPwnageRepeatWeight;
@ -258,34 +277,29 @@ public class NoPwnage extends Check {
} }
if (cc.noPwnageWarnPlayerCheck && data.noPwnageVL > cc.noPwnageWarnLevel && !warned) { if (cc.noPwnageWarnPlayerCheck && data.noPwnageVL > cc.noPwnageWarnLevel && !warned) {
player.sendMessage(replaceColors(cc.noPwnageWarnPlayerMessage)); player.sendMessage(CheckUtils.replaceColors(cc.noPwnageWarnPlayerMessage));
data.noPwnageLastWarningTime = now; data.noPwnageLastWarningTime = now;
} else if (data.noPwnageVL > cc.noPwnageLevel) } else if (data.noPwnageVL > cc.noPwnageLevel)
if (cc.noPwnageCaptchaCheck && !data.noPwnageHasStartedCaptcha) { if (cc.noPwnageCaptchaCheck && !data.noPwnageHasStartedCaptcha) {
// Display a captcha to the player. // Display a captcha to the player.
data.noPwnageGeneratedCaptcha = "";
for (int i = 0; i < cc.noPwnageCaptchaLength; i++) for (int i = 0; i < cc.noPwnageCaptchaLength; i++)
data.noPwnageGeneratedCaptcha += cc.noPwnageCaptchaCharacters.charAt(random data.noPwnageGeneratedCaptcha += cc.noPwnageCaptchaCharacters.charAt(random
.nextInt(cc.noPwnageCaptchaCharacters.length())); .nextInt(cc.noPwnageCaptchaCharacters.length()));
player.sendMessage(replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]", player.sendMessage(CheckUtils.replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]",
data.noPwnageGeneratedCaptcha))); data.noPwnageGeneratedCaptcha)));
data.noPwnageHasStartedCaptcha = true; data.noPwnageHasStartedCaptcha = true;
if (event instanceof AsyncPlayerChatEvent) cancel = true;
((AsyncPlayerChatEvent) event).setCancelled(true);
else if (event instanceof PlayerCommandPreprocessEvent)
((PlayerCommandPreprocessEvent) event).setCancelled(true);
} else { } else {
lastBanCausingMessage = message; lastBanCausingMessage = message;
data.noPwnageLastWarningTime = lastBanCausingMessageTime = now; data.noPwnageLastWarningTime = lastBanCausingMessageTime = now;
if (cc.noPwnageWarnOthersCheck) if (cc.noPwnageWarnOthersCheck)
Bukkit.broadcastMessage(replaceColors(cc.noPwnageWarnOthersMessage.replace("[player]", Bukkit.broadcastMessage(CheckUtils.replaceColors(cc.noPwnageWarnOthersMessage.replace("[player]",
player.getName()))); player.getName())));
if (event instanceof AsyncPlayerChatEvent) cancel = true;
((AsyncPlayerChatEvent) event).setCancelled(true);
else if (event instanceof PlayerCommandPreprocessEvent)
((PlayerCommandPreprocessEvent) event).setCancelled(true);
// Find out if we need to ban the player or not. // 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. // Store the message and some other data.
@ -294,7 +308,7 @@ public class NoPwnage extends Check {
lastGlobalMessage = message; lastGlobalMessage = message;
lastGlobalMessageTime = now; lastGlobalMessageTime = now;
return cancel; return new boolean[] {cancel, kick};
} }
/** /**
@ -320,12 +334,11 @@ public class NoPwnage extends Check {
if (now - data.noPwnageReloginWarningTime > cc.noPwnageReloginWarningTimeout) if (now - data.noPwnageReloginWarningTime > cc.noPwnageReloginWarningTimeout)
data.noPwnageReloginWarnings = 0; data.noPwnageReloginWarnings = 0;
if (data.noPwnageReloginWarnings < cc.noPwnageReloginWarningNumber) { if (data.noPwnageReloginWarnings < cc.noPwnageReloginWarningNumber) {
player.sendMessage(replaceColors(cc.noPwnageReloginWarningMessage)); player.sendMessage(CheckUtils.replaceColors(cc.noPwnageReloginWarningMessage));
data.noPwnageReloginWarningTime = now; data.noPwnageReloginWarningTime = now;
data.noPwnageReloginWarnings++; data.noPwnageReloginWarnings++;
} else if (now - data.noPwnageReloginWarningTime < cc.noPwnageReloginWarningTimeout) } else if (now - data.noPwnageReloginWarningTime < cc.noPwnageReloginWarningTimeout)
// Find out if we need to ban the player or not. // Find out if we need to ban the player or not.
// TODO: extra actions / VL ?
cancel = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, true); cancel = executeActionsThreadSafe(player, data.noPwnageVL, cc.noPwnageActions, true);
} }

View File

@ -15,7 +15,7 @@ import java.util.logging.LogRecord;
import java.util.logging.Logger; import java.util.logging.Logger;
import fr.neatmonster.nocheatplus.NoCheatPlus; import fr.neatmonster.nocheatplus.NoCheatPlus;
import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.utilities.CheckUtils;
/* /*
* MM'""""'YMM .8888b oo M"""""`'"""`YM * MM'""""'YMM .8888b oo M"""""`'"""`YM
@ -182,7 +182,7 @@ public class ConfigManager {
e.printStackTrace(); e.printStackTrace();
} }
Check.setFileLogger(logger); CheckUtils.fileLogger = logger;
// Try to find world-specific configuration files. // Try to find world-specific configuration files.
final HashMap<String, File> worldFiles = new HashMap<String, File>(); final HashMap<String, File> worldFiles = new HashMap<String, File>();

View File

@ -132,11 +132,11 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_CHECK, true); set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_CHECK, true);
set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_CHARACTERS, set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_CHARACTERS,
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_LENGTH, 4); set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_LENGTH, 6);
set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_QUESTION, set(ConfPaths.CHAT_NOPWNAGE_CAPTCHA_QUESTION,
"&cPlease type '&6[captcha]&c' to continue sending messages/commands."); "&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_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_CHECK, true);
set(ConfPaths.CHAT_NOPWNAGE_FIRST_TIMEOUT, 3000L); 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 + ".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 + ".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 + ".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 + ".fastbreak", start + "tried to break too many blocks" + end);
set(ConfPaths.STRINGS + ".fastplace", start + "tried to place too much 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 + ".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 + ".flyshort", start + "tried to move unexpectedly" + end);
set(ConfPaths.STRINGS + ".flylong", start set(ConfPaths.STRINGS + ".flylong", start

View File

@ -13,6 +13,7 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
/* /*
* M"""""""`YM MM'""""'YMM MM"""""""`YM M""MMMMM""MM dP * 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, private static final void logHookFailure(final CheckType checkType, final Player player, final NCPHook hook,
final Throwable t) { 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)? // to NCP spam though)?
final StringBuilder builder = new StringBuilder(1024); final StringBuilder builder = new StringBuilder(1024);
builder.append("[NoCheatPlus] Hook " + getHookDescription(hook) + " encountered an unexpected exception:\n"); 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 * the player that fails the check
* @return if we should cancel the VL processing * @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. // 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. // Return true as soon as one hook returns true. Test hooks, if present.
final List<NCPHook> hooksCheck = hooksByChecks.get(violationData.check.getType());
// Test hooks, if present:
final List<NCPHook> hooksCheck = hooksByChecks.get(checkType);
if (hooksCheck != null) if (hooksCheck != null)
if (applyHooks(checkType, player, hooksCheck)) if (applyHooks(violationData.check.getType(), violationData.player, hooksCheck))
return true; return true;
return false; return false;
} }

View File

@ -4,6 +4,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import fr.neatmonster.nocheatplus.actions.Action; import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.checks.ViolationData;
/* /*
* MM""""""""`M dP oo * MM""""""""`M dP oo
@ -82,9 +83,9 @@ public class ExecutionHistory {
* the length * the length
*/ */
private void clearTimes(final long start, long length) { private void clearTimes(final long start, long length) {
if (length <= 0) if (length <= 0)
return; // Nothing to do (yet). // Nothing to do (yet).
return;
if (length > executionTimes.length) if (length > executionTimes.length)
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 * 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. * the time to a list which will influence further requests, so only use once and remember the result.
* *
* @param check * @param violationData
* the check * the violation data
* @param action * @param action
* the action * the action
* @param time * @param time
* a time IN SECONDS * a time IN SECONDS
* @return true, if successful * @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<Action, ExecutionHistoryEntry> executionHistory = executionHistories.get(check); Map<Action, ExecutionHistoryEntry> executionHistory = executionHistories.get(check);
if (executionHistory == null) { if (executionHistory == null) {
executionHistory = new HashMap<Action, ExecutionHistoryEntry>(); executionHistory = new HashMap<Action, ExecutionHistoryEntry>();
executionHistories.put(check, executionHistory); executionHistories.put(check, executionHistory);
} }
ExecutionHistoryEntry entry = executionHistory.get(action); ExecutionHistoryEntry entry = executionHistory.get(action);
if (entry == null) { if (entry == null) {
entry = new ExecutionHistoryEntry(60); entry = new ExecutionHistoryEntry(60);
executionHistory.put(action, entry); executionHistory.put(action, entry);

View File

@ -1,5 +1,8 @@
package fr.neatmonster.nocheatplus.utilities; package fr.neatmonster.nocheatplus.utilities;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -9,6 +12,9 @@ import org.bukkit.util.Vector;
*/ */
public class CheckUtils { 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). * 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]; 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;
}
} }