Add commands to check like chat to globalchat, add experimental counts.

This commit is contained in:
asofold 2012-09-01 15:37:05 +02:00
parent c58c086e39
commit 87d2894fcf
6 changed files with 145 additions and 12 deletions

View File

@ -1,8 +1,10 @@
package fr.neatmonster.nocheatplus.checks.chat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.entity.Player;
@ -71,6 +73,7 @@ public class ChatConfig implements CheckConfig {
public final ActionList colorActions;
public final boolean globalChatCheck;
public final Set<String> globalChatCommands;
public final float globalChatFrequencyFactor;
public final float globalChatFrequencyWeight;
public final double globalChatLevel;
@ -143,6 +146,13 @@ public class ChatConfig implements CheckConfig {
colorActions = data.getActionList(ConfPaths.CHAT_COLOR_ACTIONS, Permissions.CHAT_COLOR);
globalChatCheck = data.getBoolean(ConfPaths.CHAT_GLOBALCHAT_CHECK);
final List<String> commands = data.getStringList(ConfPaths.CHAT_GLOBALCHAT_COMMANDS);
globalChatCommands = new HashSet<String>();
if (commands != null){
for (String cmd : commands){
globalChatCommands.add(cmd.trim().toLowerCase());
}
}
globalChatFrequencyFactor = (float) data.getDouble(ConfPaths.CHAT_GLOBALCHAT_FREQUENCY_FACTOR);
globalChatFrequencyWeight = (float) data.getDouble(ConfPaths.CHAT_GLOBALCHAT_FREQUENCY_WEIGHT);
globalChatLevel = data.getDouble(ConfPaths.CHAT_GLOBALCHAT_LEVEL);

View File

@ -63,7 +63,7 @@ public class ChatListener implements Listener {
// Then the no pwnage check.
if (noPwnage.check(player, event.getMessage(), false))
event.setCancelled(true);
else if (globalChat.check(player, event.getMessage(), (ICaptcha) noPwnage))
else if (globalChat.check(player, event.getMessage(), (ICaptcha) noPwnage, false))
// Only check those that got through.
// (ICaptcha to start captcha if desired.)
event.setCancelled(true);
@ -93,10 +93,12 @@ public class ChatListener implements Listener {
* |_|
*/
final Player player = event.getPlayer();
final String command = event.getMessage().split(" ")[0].substring(1).toLowerCase();
final String command = event.getMessage().trim().split(" ")[0].substring(1).toLowerCase();
final ChatConfig cc = ChatConfig.getConfig(player);
// Protect some commands to prevent players for seeing which plugins are installed.
if (ChatConfig.getConfig(player).protectPlugins)
if (cc.protectPlugins)
if ((command.equalsIgnoreCase("plugins") || command.equalsIgnoreCase("pl")
|| command.equalsIgnoreCase("version") || command.equalsIgnoreCase("ver"))
&& !player.hasPermission(Permissions.ADMINISTRATION_PLUGINS)) {
@ -108,7 +110,7 @@ public class ChatListener implements Listener {
}
// Prevent /op and /deop commands from being used in chat.
if (ChatConfig.getConfig(player).opInConsoleOnly && (command.equals("op") || command.equals("deop"))) {
if (cc.opInConsoleOnly && (command.equals("op") || command.equals("deop"))) {
event.getPlayer().sendMessage(
ChatColor.RED + "I'm sorry, but this command can't be executed in chat. Use the console instead!");
event.setCancelled(true);
@ -121,6 +123,8 @@ public class ChatListener implements Listener {
// Then the no pwnage check.
if (noPwnage.check(player, event.getMessage(), true))
event.setCancelled(true);
else if ((cc.globalChatCommands.contains(command) || cc.globalChatCommands.contains("/"+command)) && globalChat.check(player, event.getMessage(), noPwnage, true))
event.setCancelled(true);
}
/**

View File

@ -5,7 +5,6 @@ import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
import fr.neatmonster.nocheatplus.players.Permissions;
/**
* Some alternative more or less advanced analysis methods.
@ -28,18 +27,18 @@ public class GlobalChat extends Check{
* Used for starting captcha on failure, if configured so.
* @return
*/
public boolean check(final Player player, final String message, final ICaptcha captcha) {
public boolean check(final Player player, final String message, final ICaptcha captcha, boolean isMainThread) {
final ChatConfig cc = ChatConfig.getConfig(player);
// Checking the player, actually.
if (!cc.isEnabled(type) || NCPExemptionManager.isExempted(player, type))
if (isMainThread && !isEnabled(player)) return false;
if (!isMainThread && (!cc.isEnabled(type) || NCPExemptionManager.isExempted(player, type)))
return false;
final ChatData data = ChatData.getData(player);
synchronized (data) {
return unsafeCheck(player, message, captcha, cc, data);
return unsafeCheck(player, message, captcha, cc, data, isMainThread);
}
}
@ -50,10 +49,11 @@ public class GlobalChat extends Check{
* @param captcha
* @param cc
* @param data
* @param isMainThread
* @return
*/
private boolean unsafeCheck(final Player player, final String message, final ICaptcha captcha,
final ChatConfig cc, final ChatData data) {
final ChatConfig cc, final ChatData data, boolean isMainThread) {
// Take time once:
final long time = System.currentTimeMillis();
@ -68,6 +68,23 @@ public class GlobalChat extends Check{
// Weight of this chat message.
float weight = 1.0f;
final MessageLetterCount letterCounts = new MessageLetterCount(message);
final int length = message.length();
// Upper case.
if (length > 8 && letterCounts.fullCount.upperCase > length / 4){
weight += 0.6 * letterCounts.fullCount.getUpperCaseRatio();
}
// ? for words individually ?
// Repetition of characters.
if (length > 4){
final float fullRep = letterCounts.fullCount.getLetterRatio();
score += (float) length / 15.0 * Math.abs(0.5 - fullRep); // Very small and very big are bad !
}
// TODO Core checks....
// Add weight to frequency counts.
@ -81,13 +98,14 @@ public class GlobalChat extends Check{
}
else{
data.globalChatVL += score / 10.0;
if (executeActionsThreadSafe(player, data.globalChatVL, score, cc.globalChatActions, Permissions.CHAT_GLOBALCHAT))
if (executeActionsThreadSafe(player, data.globalChatVL, score, cc.globalChatActions, isMainThread))
cancel = true;
}
}
else
data.globalChatVL *= 0.95;
return cancel;
}

View File

@ -0,0 +1,96 @@
package fr.neatmonster.nocheatplus.checks.chat;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Letter count for a message and sub words, including upper case count.<br>
* NOTE: this is a pretty heavy implementation for testing purposes.
* @author mc_dev
*
*/
public class MessageLetterCount {
/**
* Letter count for a word.
* @author mc_dev
*
*/
public static final class WordLetterCount{
public final String word;
public final Map<Character, Integer> counts;
public final int upperCase;
public WordLetterCount(final String word){
this.word = word;
char[] a = word.toCharArray();
// Preserve insertion order.
counts = new LinkedHashMap<Character, Integer>(a.length);
int upperCase = 0;
for (int i = 0; i < a.length; i++){
final char c = a[i];
final Character key;
if (Character.isUpperCase(c)){
upperCase ++;
key = Character.toLowerCase(c);
}
else key = c;
final Integer count = counts.remove(key);
if (count == null) counts.put(key, 1);
else counts.put(key, count.intValue() + 1);
}
this.upperCase = upperCase;
}
public float getLetterRatio(){
return (float) counts.size() / (float) word.length();
}
public float getUpperCaseRatio(){
return (float) upperCase / (float) word.length();
}
}
public final String message;
public final String split;
public final WordLetterCount[] words;
public final WordLetterCount fullCount;
/**
* Constructor for splitting by a space.
* @param message
*/
public MessageLetterCount(final String message){
this(message, " ");
}
/**
*
* @param message
* @param split
*/
public MessageLetterCount(final String message, final String split){
this.message = message;
this.split = split;
final String[] parts = message.split(split);
words = new WordLetterCount[parts.length];
fullCount = new WordLetterCount(message);
// (Do not store 60 times "a".)
final Map<String, WordLetterCount> done = new HashMap<String, MessageLetterCount.WordLetterCount>(words.length);
for (int i = 0; i < parts.length; i++){
final String word = parts[i];
if (done.containsKey(word)){
words[i] = done.get(word);
continue;
}
done.put(word, words[i] = new WordLetterCount(word));
}
done.clear();
}
}

View File

@ -141,6 +141,7 @@ public abstract class ConfPaths {
public static final String CHAT_GLOBALCHAT = CHAT + "globalchat.";
public static final String CHAT_GLOBALCHAT_CHECK = CHAT_GLOBALCHAT + "active";
public static final String CHAT_GLOBALCHAT_COMMANDS = CHAT_GLOBALCHAT + "commands";
public static final String CHAT_GLOBALCHAT_FREQUENCY = CHAT_GLOBALCHAT + "frequency.";
public static final String CHAT_GLOBALCHAT_FREQUENCY_WEIGHT = CHAT_GLOBALCHAT_FREQUENCY + "weight";
public static final String CHAT_GLOBALCHAT_FREQUENCY_FACTOR = CHAT_GLOBALCHAT_FREQUENCY + "factor";

View File

@ -1,6 +1,8 @@
package fr.neatmonster.nocheatplus.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
/*
* M""""""'YMM .8888b dP dP MM'""""'YMM .8888b oo
@ -126,6 +128,8 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.CHAT_COLOR_ACTIONS, "log:color:0:1:if cancel");
set(ConfPaths.CHAT_GLOBALCHAT_CHECK, true);
set(ConfPaths.CHAT_GLOBALCHAT_COMMANDS, new LinkedList<String>(Arrays.asList(
new String[]{"/me"})));
set(ConfPaths.CHAT_GLOBALCHAT_FREQUENCY_FACTOR, 0.8D);
set(ConfPaths.CHAT_GLOBALCHAT_FREQUENCY_WEIGHT, 6.0D);
set(ConfPaths.CHAT_GLOBALCHAT_LEVEL, 30D);