More spaces.

This commit is contained in:
asofold 2014-11-04 00:20:18 +01:00
parent 8b43e5e5f1
commit 1f2f18a748
4 changed files with 331 additions and 332 deletions

View File

@ -13,7 +13,6 @@ import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.components.MCAccessHolder; import fr.neatmonster.nocheatplus.components.MCAccessHolder;
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager; import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
import fr.neatmonster.nocheatplus.hooks.NCPHookManager; import fr.neatmonster.nocheatplus.hooks.NCPHookManager;
import fr.neatmonster.nocheatplus.logging.LogUtil;
import fr.neatmonster.nocheatplus.players.DataManager; import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.players.ExecutionHistory; import fr.neatmonster.nocheatplus.players.ExecutionHistory;
import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.TickTask;
@ -103,7 +102,7 @@ public abstract class Check implements MCAccessHolder{
* @return true, if the event should be cancelled * @return true, if the event should be cancelled
*/ */
protected boolean executeActions(final ViolationData violationData){ protected boolean executeActions(final ViolationData violationData){
return executeActions(violationData, true); return executeActions(violationData, true);
} }
/** /**
@ -116,7 +115,7 @@ public abstract class Check implements MCAccessHolder{
*/ */
protected boolean executeActions(final ViolationData violationData, final boolean isMainThread) { protected boolean executeActions(final ViolationData violationData, final boolean isMainThread) {
// Dispatch the VL processing to the hook manager (now thread safe). // Dispatch the VL processing to the hook manager (now thread safe).
if (NCPHookManager.shouldCancelVLProcessing(violationData)) 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;
@ -124,13 +123,13 @@ public abstract class Check implements MCAccessHolder{
final boolean hasCancel = violationData.hasCancel(); final boolean hasCancel = violationData.hasCancel();
if (isMainThread) if (isMainThread)
return violationData.executeActions(); return violationData.executeActions();
else else
// Always schedule to add to ViolationHistory. // Always schedule to add to ViolationHistory.
TickTask.requestActionsExecution(violationData); TickTask.requestActionsExecution(violationData);
// (Design change: Permission checks are moved to cached permissions, lazily updated.) // (Design change: Permission checks are moved to cached permissions, lazily updated.)
return hasCancel; return hasCancel;
} }
/** /**
@ -141,9 +140,9 @@ public abstract class Check implements MCAccessHolder{
* @return * @return
*/ */
protected Map<ParameterName, String> getParameterMap(final ViolationData violationData){ protected Map<ParameterName, String> getParameterMap(final ViolationData violationData){
final Map<ParameterName, String> params = new HashMap<ParameterName, String>(); final Map<ParameterName, String> params = new HashMap<ParameterName, String>();
// (Standard parameters like player, vl, check name are filled in in ViolationData.getParameter!) // (Standard parameters like player, vl, check name are filled in in ViolationData.getParameter!)
return params; return params;
} }
/** /**
@ -180,14 +179,14 @@ public abstract class Check implements MCAccessHolder{
return !NCPExemptionManager.isExempted(player, type); return !NCPExemptionManager.isExempted(player, type);
} }
@Override @Override
public void setMCAccess(MCAccess mcAccess) { public void setMCAccess(MCAccess mcAccess) {
this.mcAccess = mcAccess; this.mcAccess = mcAccess;
} }
@Override @Override
public MCAccess getMCAccess() { public MCAccess getMCAccess() {
return mcAccess; return mcAccess;
} }
} }

View File

@ -26,7 +26,7 @@ public abstract class ACheckConfig implements ICheckConfig {
*/ */
public ACheckConfig(final ConfigFile config, final String pathPrefix){ public ACheckConfig(final ConfigFile config, final String pathPrefix){
this(config, pathPrefix, null); this(config, pathPrefix, null);
} }
/** /**
* *
@ -42,10 +42,10 @@ public abstract class ACheckConfig implements ICheckConfig {
this.cachePermissions = cachePermissions; this.cachePermissions = cachePermissions;
} }
@Override @Override
public String[] getCachePermissions() { public String[] getCachePermissions() {
return cachePermissions; return cachePermissions;
} }
@Override @Override
public boolean getDebug() { public boolean getDebug() {

View File

@ -17,23 +17,23 @@ import fr.neatmonster.nocheatplus.utilities.ColorUtil;
public class Captcha extends Check implements ICaptcha{ public class Captcha extends Check implements ICaptcha{
public Captcha() { public Captcha() {
super(CheckType.CHAT_CAPTCHA); super(CheckType.CHAT_CAPTCHA);
} }
/** The random number generator. */ /** The random number generator. */
private final Random random = new Random(); private final Random random = new Random();
@Override @Override
public void checkCaptcha(Player player, String message, ChatConfig cc, ChatData data, boolean isMainThread) { public void checkCaptcha(Player player, String message, ChatConfig cc, ChatData data, boolean isMainThread) {
// Correct answer to the captcha? // Correct answer to the captcha?
if (message.equals(data.captchaGenerated)) { if (message.equals(data.captchaGenerated)) {
// Yes, clear their data and do not worry anymore about them. // Yes, clear their data and do not worry anymore about them.
data.reset(); data.reset();
data.captchaStarted = false; data.captchaStarted = false;
player.sendMessage(ColorUtil.replaceColors(cc.captchaSuccess)); player.sendMessage(ColorUtil.replaceColors(cc.captchaSuccess));
} else { } else {
// Increment their tries number counter. // Increment their tries number counter.
data.captchTries++; data.captchTries++;
data.captchaVL ++; data.captchaVL ++;
// Have they failed too man times? // Have they failed too man times?
@ -45,58 +45,58 @@ public class Captcha extends Check implements ICaptcha{
// Display the question again (if not kicked). // Display the question again (if not kicked).
if (player.isOnline()) { if (player.isOnline()) {
sendCaptcha(player, cc, data); sendCaptcha(player, cc, data);
} }
} }
} }
@Override @Override
public void sendNewCaptcha(Player player, ChatConfig cc, ChatData data) { public void sendNewCaptcha(Player player, ChatConfig cc, ChatData data) {
// Display a captcha to the player. // Display a captcha to the player.
generateCaptcha(cc, data, true); generateCaptcha(cc, data, true);
sendCaptcha(player, cc, data); sendCaptcha(player, cc, data);
data.captchaStarted = true; data.captchaStarted = true;
} }
@Override @Override
public void generateCaptcha(ChatConfig cc, ChatData data, boolean reset) { public void generateCaptcha(ChatConfig cc, ChatData data, boolean reset) {
if (reset) data.captchTries = 0; if (reset) data.captchTries = 0;
final char[] chars = new char[cc.captchaLength]; final char[] chars = new char[cc.captchaLength];
for (int i = 0; i < cc.captchaLength; i++) for (int i = 0; i < cc.captchaLength; i++)
chars[i] = cc.captchaCharacters.charAt(random chars[i] = cc.captchaCharacters.charAt(random
.nextInt(cc.captchaCharacters.length())); .nextInt(cc.captchaCharacters.length()));
data.captchaGenerated = new String(chars); data.captchaGenerated = new String(chars);
} }
@Override @Override
public void resetCaptcha(Player player){ public void resetCaptcha(Player player){
ChatData data = ChatData.getData(player); ChatData data = ChatData.getData(player);
synchronized (data) { synchronized (data) {
resetCaptcha(ChatConfig.getConfig(player), data); resetCaptcha(ChatConfig.getConfig(player), data);
} }
} }
@Override @Override
public void resetCaptcha(ChatConfig cc, ChatData data){ public void resetCaptcha(ChatConfig cc, ChatData data){
data.captchTries = 0; data.captchTries = 0;
if (shouldCheckCaptcha(cc, data) || shouldStartCaptcha(cc, data)){ if (shouldCheckCaptcha(cc, data) || shouldStartCaptcha(cc, data)){
generateCaptcha(cc, data, true); generateCaptcha(cc, data, true);
} }
} }
@Override @Override
public void sendCaptcha(Player player, ChatConfig cc, ChatData data) { public void sendCaptcha(Player player, ChatConfig cc, ChatData data) {
player.sendMessage(ColorUtil.replaceColors(cc.captchaQuestion.replace("[captcha]", player.sendMessage(ColorUtil.replaceColors(cc.captchaQuestion.replace("[captcha]",
data.captchaGenerated))); data.captchaGenerated)));
} }
@Override @Override
public boolean shouldStartCaptcha(ChatConfig cc, ChatData data) { public boolean shouldStartCaptcha(ChatConfig cc, ChatData data) {
return cc.captchaCheck && !data.captchaStarted && !data.hasCachedPermission(Permissions.CHAT_CAPTCHA); return cc.captchaCheck && !data.captchaStarted && !data.hasCachedPermission(Permissions.CHAT_CAPTCHA);
} }
@Override @Override
public boolean shouldCheckCaptcha(ChatConfig cc, ChatData data) { public boolean shouldCheckCaptcha(ChatConfig cc, ChatData data) {
return cc.captchaCheck && data.captchaStarted && !data.hasCachedPermission(Permissions.CHAT_CAPTCHA); return cc.captchaCheck && data.captchaStarted && !data.hasCachedPermission(Permissions.CHAT_CAPTCHA);
} }
} }

View File

@ -31,140 +31,140 @@ import fr.neatmonster.nocheatplus.utilities.StringUtil;
*/ */
public class Text extends Check implements INotifyReload { public class Text extends Check implements INotifyReload {
private LetterEngine engine = null; private LetterEngine engine = null;
/** Not really cancelled but above threshold for actions. */ /** Not really cancelled but above threshold for actions. */
private String lastCancelledMessage = ""; private String lastCancelledMessage = "";
private long lastCancelledTime = 0; private long lastCancelledTime = 0;
private String lastGlobalMessage = ""; private String lastGlobalMessage = "";
private long lastGlobalTime = 0; private long lastGlobalTime = 0;
public Text() { public Text() {
super(CheckType.CHAT_TEXT); super(CheckType.CHAT_TEXT);
init(); init();
} }
/** /**
* Start analysis. * Start analysis.
* @param player * @param player
* The player who issued the message. * The player who issued the message.
* @param message * @param message
* The message to check. * The message to check.
* @param captcha * @param captcha
* Used for starting captcha on failure, if configured so. * Used for starting captcha on failure, if configured so.
* @param alreadyCancelled * @param alreadyCancelled
* @return * @return
*/ */
public boolean check(final Player player, final String message, final ICaptcha captcha, boolean isMainThread, final boolean alreadyCancelled) { public boolean check(final Player player, final String message, final ICaptcha captcha, boolean isMainThread, final boolean alreadyCancelled) {
final ChatConfig cc = ChatConfig.getConfig(player); final ChatConfig cc = ChatConfig.getConfig(player);
final ChatData data = ChatData.getData(player); final ChatData data = ChatData.getData(player);
synchronized (data) { synchronized (data) {
return unsafeCheck(player, message, captcha, cc, data, isMainThread, alreadyCancelled); return unsafeCheck(player, message, captcha, cc, data, isMainThread, alreadyCancelled);
} }
} }
private void init() { private void init() {
// Set some things from the global config. // Set some things from the global config.
final ConfigFile config = ConfigManager.getConfigFile(); final ConfigFile config = ConfigManager.getConfigFile();
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI(); final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
if (engine != null) { if (engine != null) {
engine.clear(); engine.clear();
api.removeComponent(engine); api.removeComponent(engine);
} }
engine = new LetterEngine(config); engine = new LetterEngine(config);
api.addComponent(engine); api.addComponent(engine);
} }
@Override @Override
public void onReload() { public void onReload() {
synchronized(engine) { synchronized(engine) {
engine.clear(); engine.clear();
} }
init(); init();
} }
/** /**
* Check without further synchronization. * Check without further synchronization.
* @param player * @param player
* @param message * @param message
* @param captcha * @param captcha
* @param cc * @param cc
* @param data * @param data
* @param isMainThread * @param isMainThread
* @param alreadyCancelled * @param alreadyCancelled
* @return * @return
*/ */
private boolean unsafeCheck(final Player player, final String message, final ICaptcha captcha, private boolean unsafeCheck(final Player player, final String message, final ICaptcha captcha,
final ChatConfig cc, final ChatData data, boolean isMainThread, final boolean alreadyCancelled) { final ChatConfig cc, final ChatData data, boolean isMainThread, final boolean alreadyCancelled) {
// Test captcha. // Test captcha.
// TODO: Skip captcha for "handleaschat" commands? [controversial potential] // TODO: Skip captcha for "handleaschat" commands? [controversial potential]
if (captcha.shouldCheckCaptcha(cc, data)) { if (captcha.shouldCheckCaptcha(cc, data)) {
captcha.checkCaptcha(player, message, cc, data, isMainThread); captcha.checkCaptcha(player, message, cc, data, isMainThread);
return true; return true;
} else if (alreadyCancelled) { } else if (alreadyCancelled) {
// Skip checking. // Skip checking.
return true; return true;
} }
// Take time once: // Take time once:
final long time = System.currentTimeMillis(); final long time = System.currentTimeMillis();
final String lcMessage = message.trim().toLowerCase(); final String lcMessage = message.trim().toLowerCase();
boolean cancel = false; boolean cancel = false;
boolean debug = cc.textDebug || cc.debug; boolean debug = cc.textDebug || cc.debug;
final List<String> debugParts; final List<String> debugParts;
if (debug) { if (debug) {
debugParts = new LinkedList<String>(); debugParts = new LinkedList<String>();
debugParts.add("[NoCheatPlus][chat.text] Message ("+player.getName()+"/"+message.length()+"): "); debugParts.add("[NoCheatPlus][chat.text] Message ("+player.getName()+"/"+message.length()+"): ");
} }
else debugParts = null; else debugParts = null;
// Update the frequency interval weights. // Update the frequency interval weights.
data.chatFrequency.update(time); data.chatFrequency.update(time);
// Score for this message (violation score). // Score for this message (violation score).
float score = 0; float score = 0;
final MessageLetterCount letterCounts = new MessageLetterCount(message); final MessageLetterCount letterCounts = new MessageLetterCount(message);
final int msgLen = message.length(); final int msgLen = message.length();
// (Following: random/made up criteria.) // (Following: random/made up criteria.)
// TODO: Create tests for all methods with wordlists, fake chat (refactor for that). // TODO: Create tests for all methods with wordlists, fake chat (refactor for that).
// Full message processing. ------------ // Full message processing. ------------
// Upper case. // Upper case.
if (letterCounts.fullCount.upperCase > msgLen / 3) { if (letterCounts.fullCount.upperCase > msgLen / 3) {
final float wUpperCase = 0.6f * letterCounts.fullCount.getUpperCaseRatio(); final float wUpperCase = 0.6f * letterCounts.fullCount.getUpperCaseRatio();
score += wUpperCase * cc.textMessageUpperCase; score += wUpperCase * cc.textMessageUpperCase;
} }
// Letters vs. word length. // Letters vs. word length.
if (msgLen > 4) { if (msgLen > 4) {
final float fullRep = letterCounts.fullCount.getLetterCountRatio(); final float fullRep = letterCounts.fullCount.getLetterCountRatio();
// Long messages: very small and very big are bad ! // Long messages: very small and very big are bad !
final float wRepetition = (float) msgLen / 15.0f * Math.abs(0.5f - fullRep); final float wRepetition = (float) msgLen / 15.0f * Math.abs(0.5f - fullRep);
score += wRepetition * cc.textMessageLetterCount; score += wRepetition * cc.textMessageLetterCount;
// Number of words vs. length of message // Number of words vs. length of message
final float fnWords = (float) letterCounts.words.length / (float) msgLen; final float fnWords = (float) letterCounts.words.length / (float) msgLen;
if (fnWords > 0.75f) { // TODO: balance or configure or remove ? if (fnWords > 0.75f) { // TODO: balance or configure or remove ?
score += fnWords * cc.textMessagePartition; score += fnWords * cc.textMessagePartition;
} }
} }
final CombinedData cData = CombinedData.getData(player); final CombinedData cData = CombinedData.getData(player);
final long timeout = 8000; // TODO: maybe set dynamically in data. final long timeout = 8000; // TODO: maybe set dynamically in data.
// Repetition of last message. // Repetition of last message.
if (cc.textMsgRepeatSelf != 0f && time - data.chatLastTime < timeout) { if (cc.textMsgRepeatSelf != 0f && time - data.chatLastTime < timeout) {
if (StringUtil.isSimilar(lcMessage, data.chatLastMessage, 0.8f)) { if (StringUtil.isSimilar(lcMessage, data.chatLastMessage, 0.8f)) {
final float timeWeight = (float) (timeout - (time - data.chatLastTime)) / (float) timeout; final float timeWeight = (float) (timeout - (time - data.chatLastTime)) / (float) timeout;
@ -179,147 +179,147 @@ public class Text extends Check implements INotifyReload {
} }
} }
// Repetition of last cancelled message. // Repetition of last cancelled message.
if (cc.textMsgRepeatCancel != 0f && time - lastCancelledTime < timeout) { if (cc.textMsgRepeatCancel != 0f && time - lastCancelledTime < timeout) {
if (StringUtil.isSimilar(lcMessage, lastCancelledMessage, 0.8f)) { if (StringUtil.isSimilar(lcMessage, lastCancelledMessage, 0.8f)) {
final float timeWeight = (float) (timeout - (time - lastCancelledTime)) / (float) timeout; final float timeWeight = (float) (timeout - (time - lastCancelledTime)) / (float) timeout;
score += cc.textMsgRepeatCancel * timeWeight; score += cc.textMsgRepeatCancel * timeWeight;
} }
} }
// Chat quickly after join. // Chat quickly after join.
if (cc.textMsgAfterJoin != 0f && time - cData.lastJoinTime < timeout) { if (cc.textMsgAfterJoin != 0f && time - cData.lastJoinTime < timeout) {
final float timeWeight = (float) (timeout - (time - cData.lastJoinTime)) / (float) timeout; final float timeWeight = (float) (timeout - (time - cData.lastJoinTime)) / (float) timeout;
score += cc.textMsgAfterJoin * timeWeight; score += cc.textMsgAfterJoin * timeWeight;
} }
// Chat without moving. // Chat without moving.
if (cc.textMsgNoMoving != 0f && time - cData.lastMoveTime > timeout) { if (cc.textMsgNoMoving != 0f && time - cData.lastMoveTime > timeout) {
score += cc.textMsgNoMoving; score += cc.textMsgNoMoving;
} }
// Per word checks. ------------------- // Per word checks. -------------------
float wWords = 0.0f; float wWords = 0.0f;
final float avwLen = (float) msgLen / (float) letterCounts.words.length; final float avwLen = (float) msgLen / (float) letterCounts.words.length;
for (final WordLetterCount word: letterCounts.words) { for (final WordLetterCount word: letterCounts.words) {
float wWord = 0.0f; float wWord = 0.0f;
final int wLen = word.word.length(); final int wLen = word.word.length();
// TODO: ? used letters vs. word length. // TODO: ? used letters vs. word length.
// Length of word vs. av. word length. // Length of word vs. av. word length.
final float fLenAv = Math.abs(avwLen - (float) wLen) / avwLen; final float fLenAv = Math.abs(avwLen - (float) wLen) / avwLen;
wWord += fLenAv * cc.textMessageLengthAv; wWord += fLenAv * cc.textMessageLengthAv;
// Length of word vs. message length; // Length of word vs. message length;
final float fLenMsg = (float) wLen / (float) msgLen; final float fLenMsg = (float) wLen / (float) msgLen;
wWord += fLenMsg * cc.textMessageLengthMsg; wWord += fLenMsg * cc.textMessageLengthMsg;
// Not letter: // Not letter:
float notLetter = word.getNotLetterRatio(); float notLetter = word.getNotLetterRatio();
notLetter *= notLetter; notLetter *= notLetter;
wWord += notLetter * cc.textMessageNoLetter; wWord += notLetter * cc.textMessageNoLetter;
wWord *= wWord; // TODO: quadratic ? (configurable) wWord *= wWord; // TODO: quadratic ? (configurable)
wWords += wWord; wWords += wWord;
} }
wWords /= (float) letterCounts.words.length; wWords /= (float) letterCounts.words.length;
score += wWords; score += wWords;
if (debug && score > 0f) debugParts.add("Simple score: " + StringUtil.fdec3.format(score)); if (debug && score > 0f) debugParts.add("Simple score: " + StringUtil.fdec3.format(score));
// Engine: // Engine:
// TODO: more fine grained sync ! // TODO: more fine grained sync !
float wEngine = 0f; float wEngine = 0f;
final Map<String, Float> engMap; final Map<String, Float> engMap;
synchronized (engine) { synchronized (engine) {
engMap = engine.process(letterCounts, player.getName(), cc, data); engMap = engine.process(letterCounts, player.getName(), cc, data);
// TODO: more fine grained sync !s // TODO: more fine grained sync !s
// TODO: different methods (add or max or add+max or something else). // TODO: different methods (add or max or add+max or something else).
for (final Float res : engMap.values()) { for (final Float res : engMap.values()) {
if (cc.textEngineMaximum) wEngine = Math.max(wEngine, res.floatValue()); if (cc.textEngineMaximum) wEngine = Math.max(wEngine, res.floatValue());
else wEngine += res.floatValue(); else wEngine += res.floatValue();
} }
} }
score += wEngine; score += wEngine;
// Wrapping it up. -------------------- // Wrapping it up. --------------------
// Add weight to frequency counts. // Add weight to frequency counts.
final float normalScore = Math.max(cc.textFreqNormMin, score); final float normalScore = Math.max(cc.textFreqNormMin, score);
data.chatFrequency.add(time, normalScore); data.chatFrequency.add(time, normalScore);
final float accumulated = cc.textFreqNormWeight * data.chatFrequency.score(cc.textFreqNormFactor); final float accumulated = cc.textFreqNormWeight * data.chatFrequency.score(cc.textFreqNormFactor);
final boolean normalViolation = accumulated > cc.textFreqNormLevel; final boolean normalViolation = accumulated > cc.textFreqNormLevel;
final float shortTermScore = Math.max(cc.textFreqShortTermMin, score); final float shortTermScore = Math.max(cc.textFreqShortTermMin, score);
data.chatShortTermFrequency.add(time, shortTermScore); data.chatShortTermFrequency.add(time, shortTermScore);
// TODO: very short term (1st bucket) or do it indirectly. // TODO: very short term (1st bucket) or do it indirectly.
final float shortTermAccumulated = cc.textFreqShortTermWeight * data.chatShortTermFrequency.score(cc.textFreqShortTermFactor); final float shortTermAccumulated = cc.textFreqShortTermWeight * data.chatShortTermFrequency.score(cc.textFreqShortTermFactor);
final boolean shortTermViolation = shortTermAccumulated > cc.textFreqShortTermLevel; final boolean shortTermViolation = shortTermAccumulated > cc.textFreqShortTermLevel;
if (normalViolation || shortTermViolation) { if (normalViolation || shortTermViolation) {
lastCancelledMessage = lcMessage; lastCancelledMessage = lcMessage;
lastCancelledTime = time; lastCancelledTime = time;
final double added; final double added;
if (shortTermViolation) { if (shortTermViolation) {
added = (shortTermAccumulated - cc.textFreqShortTermLevel)/ 3.0; added = (shortTermAccumulated - cc.textFreqShortTermLevel)/ 3.0;
} else { } else {
added = (accumulated - cc.textFreqNormLevel) / 10.0; added = (accumulated - cc.textFreqNormLevel) / 10.0;
} }
data.textVL += added; data.textVL += added;
if (captcha.shouldStartCaptcha(cc, data)) { if (captcha.shouldStartCaptcha(cc, data)) {
captcha.sendNewCaptcha(player, cc, data); captcha.sendNewCaptcha(player, cc, data);
cancel = true; cancel = true;
} }
else{ else{
if (shortTermViolation) { if (shortTermViolation) {
if (executeActions(player, data.textVL, added, cc.textFreqShortTermActions, isMainThread)) { if (executeActions(player, data.textVL, added, cc.textFreqShortTermActions, isMainThread)) {
cancel = true; cancel = true;
} }
} }
else if (normalViolation) { else if (normalViolation) {
if (executeActions(player, data.textVL, added, cc.textFreqNormActions, isMainThread)) { if (executeActions(player, data.textVL, added, cc.textFreqNormActions, isMainThread)) {
cancel = true; cancel = true;
} }
} }
} }
} }
else if (cc.chatWarningCheck && time - data.chatWarningTime > cc.chatWarningTimeout && (100f * accumulated / cc.textFreqNormLevel > cc.chatWarningLevel || 100f * shortTermAccumulated / cc.textFreqShortTermLevel > cc.chatWarningLevel)) { else if (cc.chatWarningCheck && time - data.chatWarningTime > cc.chatWarningTimeout && (100f * accumulated / cc.textFreqNormLevel > cc.chatWarningLevel || 100f * shortTermAccumulated / cc.textFreqShortTermLevel > cc.chatWarningLevel)) {
NCPAPIProvider.getNoCheatPlusAPI().sendMessageOnTick(player.getName(), ColorUtil.replaceColors(cc.chatWarningMessage)); NCPAPIProvider.getNoCheatPlusAPI().sendMessageOnTick(player.getName(), ColorUtil.replaceColors(cc.chatWarningMessage));
data.chatWarningTime = time; data.chatWarningTime = time;
} }
else { else {
data.textVL *= 0.95; data.textVL *= 0.95;
if (cc.textAllowVLReset && normalScore < 2.0f * cc.textFreqNormWeight && shortTermScore < 2.0f * cc.textFreqShortTermWeight) { if (cc.textAllowVLReset && normalScore < 2.0f * cc.textFreqNormWeight && shortTermScore < 2.0f * cc.textFreqShortTermWeight) {
// Reset the VL. // Reset the VL.
// TODO: maybe elaborate on resetting conditions (after some timeout just divide by two or so?). // TODO: maybe elaborate on resetting conditions (after some timeout just divide by two or so?).
data.textVL = 0.0; data.textVL = 0.0;
} }
} }
if (debug) { if (debug) {
final List<String> keys = new LinkedList<String>(engMap.keySet()); final List<String> keys = new LinkedList<String>(engMap.keySet());
Collections.sort(keys); Collections.sort(keys);
for (String key : keys) { for (String key : keys) {
Float s = engMap.get(key); Float s = engMap.get(key);
if (s.floatValue() > 0.0f) if (s.floatValue() > 0.0f)
debugParts.add(key + ":" + StringUtil.fdec3.format(s)); debugParts.add(key + ":" + StringUtil.fdec3.format(s));
} }
if (wEngine > 0.0f) if (wEngine > 0.0f)
debugParts.add("Engine score (" + (cc.textEngineMaximum?"max":"sum") + "): " + StringUtil.fdec3.format(wEngine)); debugParts.add("Engine score (" + (cc.textEngineMaximum?"max":"sum") + "): " + StringUtil.fdec3.format(wEngine));
debugParts.add("Final score: " + StringUtil.fdec3.format(score)); debugParts.add("Final score: " + StringUtil.fdec3.format(score));
debugParts.add("Normal: min=" + StringUtil.fdec3.format(cc.textFreqNormMin) +", weight=" + StringUtil.fdec3.format(cc.textFreqNormWeight) + " => accumulated=" + StringUtil.fdec3.format(accumulated)); debugParts.add("Normal: min=" + StringUtil.fdec3.format(cc.textFreqNormMin) +", weight=" + StringUtil.fdec3.format(cc.textFreqNormWeight) + " => accumulated=" + StringUtil.fdec3.format(accumulated));
debugParts.add("Short-term: min=" + StringUtil.fdec3.format(cc.textFreqShortTermMin) +", weight=" + StringUtil.fdec3.format(cc.textFreqShortTermWeight) + " => accumulated=" + StringUtil.fdec3.format(shortTermAccumulated)); debugParts.add("Short-term: min=" + StringUtil.fdec3.format(cc.textFreqShortTermMin) +", weight=" + StringUtil.fdec3.format(cc.textFreqShortTermWeight) + " => accumulated=" + StringUtil.fdec3.format(shortTermAccumulated));
debugParts.add("vl: " + StringUtil.fdec3.format(data.textVL)); debugParts.add("vl: " + StringUtil.fdec3.format(data.textVL));
LogUtil.scheduleLogInfo(debugParts, " | "); LogUtil.scheduleLogInfo(debugParts, " | ");
debugParts.clear(); debugParts.clear();
} }
lastGlobalMessage = data.chatLastMessage = lcMessage; lastGlobalMessage = data.chatLastMessage = lcMessage;
lastGlobalTime = data.chatLastTime = time; lastGlobalTime = data.chatLastTime = time;
return cancel; return cancel;
} }
@Override @Override
protected Map<ParameterName, String> getParameterMap(final ViolationData violationData) { protected Map<ParameterName, String> getParameterMap(final ViolationData violationData) {
final Map<ParameterName, String> parameters = super.getParameterMap(violationData); final Map<ParameterName, String> parameters = super.getParameterMap(violationData);
parameters.put(ParameterName.IP, violationData.player.getAddress().toString().substring(1).split(":")[0]); parameters.put(ParameterName.IP, violationData.player.getAddress().toString().substring(1).split(":")[0]);