mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-02-09 16:21:49 +01:00
Add "globalchat" check skeleton - currently only monitors 30 seconds
chat frequency per player, delegate to captcha or actions, configurable paramters.
This commit is contained in:
parent
8c7ade7034
commit
4508bc30e0
@ -54,6 +54,7 @@ public enum CheckType {
|
||||
CHAT(ChatConfig.factory, ChatData.factory),
|
||||
CHAT_COLOR(CHAT, Permissions.CHAT_COLOR),
|
||||
CHAT_NOPWNAGE(CHAT, Permissions.CHAT_NOPWNAGE),
|
||||
CHAT_GLOBALCHAT(CHAT, Permissions.CHAT_GLOBALCHAT),
|
||||
|
||||
FIGHT(FightConfig.factory, FightData.factory),
|
||||
FIGHT_ANGLE(FIGHT, Permissions.FIGHT_ANGLE),
|
||||
|
@ -69,6 +69,12 @@ public class ChatConfig implements CheckConfig {
|
||||
|
||||
public final boolean colorCheck;
|
||||
public final ActionList colorActions;
|
||||
|
||||
public final boolean globalChatCheck;
|
||||
public double globalChatFrequencyFactor;
|
||||
public final double globalChatFrequencyWeight;
|
||||
public final double globalChatLevel;
|
||||
public final ActionList globalChatActions;
|
||||
|
||||
public final boolean noPwnageCheck;
|
||||
public final List<String> noPwnageExclusions;
|
||||
@ -135,6 +141,12 @@ public class ChatConfig implements CheckConfig {
|
||||
public ChatConfig(final ConfigFile data) {
|
||||
colorCheck = data.getBoolean(ConfPaths.CHAT_COLOR_CHECK);
|
||||
colorActions = data.getActionList(ConfPaths.CHAT_COLOR_ACTIONS, Permissions.CHAT_COLOR);
|
||||
|
||||
globalChatCheck = data.getBoolean(ConfPaths.CHAT_GLOBALCHAT_CHECK);
|
||||
globalChatFrequencyFactor = data.getDouble(ConfPaths.CHAT_GLOBALCHAT_FREQUENCY_FACTOR);
|
||||
globalChatFrequencyWeight = data.getDouble(ConfPaths.CHAT_GLOBALCHAT_FREQUENCY_WEIGHT);
|
||||
globalChatLevel = data.getDouble(ConfPaths.CHAT_GLOBALCHAT_LEVEL);
|
||||
globalChatActions = data.getActionList(ConfPaths.CHAT_GLOBALCHAT_ACTIONS, Permissions.CHAT_GLOBALCHAT);
|
||||
|
||||
noPwnageCheck = data.getBoolean(ConfPaths.CHAT_NOPWNAGE_CHECK);
|
||||
noPwnageExclusions = data.getStringList(ConfPaths.CHAT_NOPWNAGE_EXCLUSIONS);
|
||||
@ -201,6 +213,8 @@ public class ChatConfig implements CheckConfig {
|
||||
switch (checkType) {
|
||||
case CHAT_COLOR:
|
||||
return colorCheck;
|
||||
case CHAT_GLOBALCHAT:
|
||||
return globalChatCheck;
|
||||
case CHAT_NOPWNAGE:
|
||||
return noPwnageCheck;
|
||||
default:
|
||||
|
@ -7,6 +7,7 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckData;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckDataFactory;
|
||||
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
|
||||
|
||||
/*
|
||||
* MM'""""'YMM dP dP M""""""'YMM dP
|
||||
@ -49,7 +50,11 @@ public class ChatData implements CheckData {
|
||||
// Violation levels.
|
||||
public double captchaVL;
|
||||
public double colorVL;
|
||||
public double globalChatVL;
|
||||
public double noPwnageVL;
|
||||
|
||||
// Data of the globalchat check.
|
||||
public final ActionFrequency globalChatFrequency = new ActionFrequency(10, 3000);
|
||||
|
||||
// Data of the no pwnage check.
|
||||
public int noPwnageCaptchTries;
|
||||
|
@ -34,6 +34,9 @@ public class ChatListener implements Listener {
|
||||
|
||||
/** The no pwnage check. */
|
||||
private final NoPwnage noPwnage = new NoPwnage();
|
||||
|
||||
/** Global chat check (experiment: alternative / supplement). */
|
||||
private final GlobalChat globalChat = new GlobalChat();
|
||||
|
||||
/**
|
||||
* We listen to PlayerChat events for obvious reasons.
|
||||
@ -60,7 +63,10 @@ public class ChatListener implements Listener {
|
||||
// Then the no pwnage check.
|
||||
if (noPwnage.check(player, event.getMessage(), false))
|
||||
event.setCancelled(true);
|
||||
// player.kickPlayer(CheckUtils.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage));
|
||||
else if (globalChat.check(player, event.getMessage(), (ICaptcha) noPwnage))
|
||||
// Only check those that got through.
|
||||
// (ICaptcha to start captcha if desired.)
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,7 +121,6 @@ public class ChatListener implements Listener {
|
||||
// Then the no pwnage check.
|
||||
if (noPwnage.check(player, event.getMessage(), true))
|
||||
event.setCancelled(true);
|
||||
// player.kickPlayer(CheckUtils.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
|
67
src/fr/neatmonster/nocheatplus/checks/chat/GlobalChat.java
Normal file
67
src/fr/neatmonster/nocheatplus/checks/chat/GlobalChat.java
Normal file
@ -0,0 +1,67 @@
|
||||
package fr.neatmonster.nocheatplus.checks.chat;
|
||||
|
||||
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.
|
||||
* @author mc_dev
|
||||
*
|
||||
*/
|
||||
public class GlobalChat extends Check{
|
||||
|
||||
public GlobalChat() {
|
||||
super(CheckType.CHAT_GLOBALCHAT);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player
|
||||
* @param message
|
||||
* @param captcha Used for starting captcha on failure.
|
||||
* @return
|
||||
*/
|
||||
public boolean check(final Player player, final String message, final ICaptcha captcha) {
|
||||
// Take time once:
|
||||
final long time = System.currentTimeMillis();
|
||||
|
||||
final ChatConfig cc = ChatConfig.getConfig(player);
|
||||
|
||||
// Checking the player, actually.
|
||||
if (!cc.isEnabled(type) || NCPExemptionManager.isExempted(player, type))
|
||||
return false;
|
||||
|
||||
final ChatData data = ChatData.getData(player);
|
||||
|
||||
boolean cancel = false;
|
||||
|
||||
data.globalChatFrequency.add(time);
|
||||
double score = cc.globalChatFrequencyWeight * data.globalChatFrequency.getScore(cc.globalChatFrequencyFactor);
|
||||
if (score < 2.0 * cc.globalChatFrequencyWeight)
|
||||
// Reset the VL.
|
||||
data.globalChatVL = 0.0;
|
||||
|
||||
// TODO Core checks....
|
||||
|
||||
if (score > cc.globalChatLevel){
|
||||
if (captcha.shouldStartCaptcha(cc, data)){
|
||||
captcha.sendNewCaptcha(player, cc, data);
|
||||
cancel = true;
|
||||
}
|
||||
else{
|
||||
data.globalChatVL += score / 10.0;
|
||||
if (executeActionsThreadSafe(player, data.globalChatVL, score, cc.globalChatActions, Permissions.CHAT_GLOBALCHAT))
|
||||
cancel = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
data.globalChatVL *= 0.95;
|
||||
|
||||
return cancel;
|
||||
}
|
||||
|
||||
}
|
@ -138,6 +138,14 @@ public abstract class ConfPaths {
|
||||
private static final String CHAT_COLOR = CHAT + "color.";
|
||||
public static final String CHAT_COLOR_CHECK = CHAT_COLOR + "active";
|
||||
public static final String CHAT_COLOR_ACTIONS = CHAT_COLOR + "actions";
|
||||
|
||||
public static final String CHAT_GLOBALCHAT = CHAT + "globalchat.";
|
||||
public static final String CHAT_GLOBALCHAT_CHECK = CHAT_GLOBALCHAT + "active";
|
||||
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";
|
||||
public static final String CHAT_GLOBALCHAT_LEVEL = CHAT_GLOBALCHAT + "level";
|
||||
public static final String CHAT_GLOBALCHAT_ACTIONS = CHAT_GLOBALCHAT + "actions";
|
||||
|
||||
private static final String CHAT_NOPWNAGE = CHAT + "nopwnage.";
|
||||
public static final String CHAT_NOPWNAGE_CHECK = CHAT_NOPWNAGE + "active";
|
||||
|
@ -124,6 +124,12 @@ public class DefaultConfig extends ConfigFile {
|
||||
*/
|
||||
set(ConfPaths.CHAT_COLOR_CHECK, true);
|
||||
set(ConfPaths.CHAT_COLOR_ACTIONS, "log:color:0:1:if cancel");
|
||||
|
||||
set(ConfPaths.CHAT_GLOBALCHAT_CHECK, true);
|
||||
set(ConfPaths.CHAT_GLOBALCHAT_FREQUENCY_FACTOR, 0.8D);
|
||||
set(ConfPaths.CHAT_GLOBALCHAT_FREQUENCY_WEIGHT, 6.0D);
|
||||
set(ConfPaths.CHAT_GLOBALCHAT_LEVEL, 30D);
|
||||
set(ConfPaths.CHAT_GLOBALCHAT_ACTIONS, "log:globalchat:0:5:if cancel");
|
||||
|
||||
set(ConfPaths.CHAT_NOPWNAGE_CHECK, true);
|
||||
set(ConfPaths.CHAT_NOPWNAGE_EXCLUSIONS, new ArrayList<String>());
|
||||
@ -318,6 +324,7 @@ public class DefaultConfig extends ConfigFile {
|
||||
+ "tried to move from [locationfrom] to [locationto] over a distance of [distance] block(s)" + end);
|
||||
set(ConfPaths.STRINGS + ".freach", start + "tried to attack entity out of reach" + end);
|
||||
set(ConfPaths.STRINGS + ".fspeed", start + "tried to attack more than [limit] times per second" + end);
|
||||
set(ConfPaths.STRINGS + ".globalchat", start + "potentially annoying chat" + end);
|
||||
set(ConfPaths.STRINGS + ".godmode", start + "avoided taking damage or lagging" + end);
|
||||
set(ConfPaths.STRINGS + ".instantbow", start + "fires bow to fast" + end);
|
||||
set(ConfPaths.STRINGS + ".instanteat", start + "eats food [food] too fast" + end);
|
||||
|
@ -81,6 +81,7 @@ public class Permissions {
|
||||
*/
|
||||
private static final String CHAT = CHECKS + ".chat";
|
||||
public static final String CHAT_COLOR = CHAT + ".color";
|
||||
public static final String CHAT_GLOBALCHAT = CHAT + ".globalchat";
|
||||
public static final String CHAT_NOPWNAGE = CHAT + ".nopwnage";
|
||||
public static final String CHAT_NOPWNAGE_CAPTCHA = CHAT_NOPWNAGE + ".captcha";
|
||||
|
||||
|
@ -0,0 +1,85 @@
|
||||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
/**
|
||||
* Keep track of frequency of some action,
|
||||
* sort into buckets, representing time intervals,
|
||||
* TODO: find a better name.
|
||||
* @author mc_dev
|
||||
*
|
||||
*/
|
||||
public class ActionFrequency {
|
||||
|
||||
/** Reference time for filling in. */
|
||||
long time = 0;
|
||||
|
||||
final int[] buckets;
|
||||
|
||||
final long durBucket;
|
||||
|
||||
public ActionFrequency(final int nBuckets, final long durBucket){
|
||||
this.buckets = new int[nBuckets];
|
||||
this.durBucket = durBucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and add.
|
||||
* @param ts
|
||||
*/
|
||||
public void add(final long now){
|
||||
update(now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update without adding, also updates time.
|
||||
* @param now
|
||||
*/
|
||||
public void update(final long now) {
|
||||
final long diff = now - time;
|
||||
final int shift = (int) ((float) diff / (float) durBucket);
|
||||
if (shift == 0){
|
||||
// No update, just fill in.
|
||||
buckets[0] ++;
|
||||
return;
|
||||
}
|
||||
else if (shift >= buckets.length){
|
||||
// Clear and fill in (beyond range).
|
||||
clear(now);
|
||||
buckets[0] ++;
|
||||
return;
|
||||
}
|
||||
// Update buckets.
|
||||
for (int i = 0; i < buckets.length - shift; i++){
|
||||
buckets[buckets.length - (i + 1)] = buckets[buckets.length - (i + 1 + shift)];
|
||||
}
|
||||
for (int i = 0; i < shift; i++){
|
||||
buckets[i] = 0;
|
||||
}
|
||||
buckets[0] ++;
|
||||
// Set time according to bucket duration (!).
|
||||
time += durBucket * shift;
|
||||
}
|
||||
|
||||
public void clear(final long now) {
|
||||
for (int i = 0; i < buckets.length; i++){
|
||||
buckets[i] = 0;
|
||||
}
|
||||
time = now;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a weighted sum score, weight for bucket i: w(i) = factor^i.
|
||||
* @param factor
|
||||
* @return
|
||||
*/
|
||||
public double getScore(final double factor){
|
||||
double res = buckets[0];
|
||||
double cf = factor;
|
||||
for (int i = 1; i < buckets.length; i++){
|
||||
res += cf * buckets[i];
|
||||
cf *= factor;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user