LoChat/src/main/java/com/loki/lochat/managers/AntiSpamManager.java

128 lines
3.9 KiB
Java

package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class AntiSpamManager {
private final LoChat plugin;
private final Map<UUID, String> lastMessages = new ConcurrentHashMap<>();
private final Map<UUID, Long> lastMessageTime = new ConcurrentHashMap<>();
public AntiSpamManager(LoChat plugin) {
this.plugin = plugin;
}
public enum SpamResult {
ALLOWED,
TOO_MANY_CAPS,
REPEAT_CHARS,
SIMILAR_MESSAGE
}
public SpamResult checkMessage(UUID player, String message) {
if (!plugin.getConfigManager().isAntiSpamEnabled()) {
return SpamResult.ALLOWED;
}
// Проверка CAPS
if (hasTooManyCaps(message)) {
return SpamResult.TOO_MANY_CAPS;
}
// Проверка повторяющихся символов
if (hasRepeatChars(message)) {
return SpamResult.REPEAT_CHARS;
}
// Проверка похожих сообщений
if (isSimilarMessage(player, message)) {
return SpamResult.SIMILAR_MESSAGE;
}
// Сохраняем сообщение
lastMessages.put(player, message.toLowerCase());
lastMessageTime.put(player, System.currentTimeMillis());
return SpamResult.ALLOWED;
}
private boolean hasTooManyCaps(String message) {
if (message.length() < 5) return false;
int maxPercent = plugin.getConfigManager().getMaxCapsPercent();
long upperCount = message.chars().filter(Character::isUpperCase).count();
long letterCount = message.chars().filter(Character::isLetter).count();
if (letterCount == 0) return false;
int percent = (int) ((upperCount * 100) / letterCount);
return percent > maxPercent;
}
private boolean hasRepeatChars(String message) {
int maxRepeat = plugin.getConfigManager().getMaxRepeatChars();
int count = 1;
char lastChar = 0;
for (char c : message.toCharArray()) {
if (c == lastChar) {
count++;
if (count > maxRepeat) return true;
} else {
count = 1;
lastChar = c;
}
}
return false;
}
private boolean isSimilarMessage(UUID player, String message) {
String lastMsg = lastMessages.get(player);
Long lastTime = lastMessageTime.get(player);
if (lastMsg == null || lastTime == null) return false;
int delay = plugin.getConfigManager().getSimilarMessageDelay();
long elapsed = (System.currentTimeMillis() - lastTime) / 1000;
if (elapsed > delay) return false;
// Проверка схожести (простая)
return message.toLowerCase().equals(lastMsg) ||
similarity(message.toLowerCase(), lastMsg) > 0.8;
}
private double similarity(String s1, String s2) {
int maxLen = Math.max(s1.length(), s2.length());
if (maxLen == 0) return 1.0;
int distance = levenshteinDistance(s1, s2);
return 1.0 - ((double) distance / maxLen);
}
private int levenshteinDistance(String s1, String s2) {
int[][] dp = new int[s1.length() + 1][s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) dp[i][0] = i;
for (int j = 0; j <= s2.length(); j++) dp[0][j] = j;
for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
int cost = s1.charAt(i - 1) == s2.charAt(j - 1) ? 0 : 1;
dp[i][j] = Math.min(Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + cost);
}
}
return dp[s1.length()][s2.length()];
}
public void clearPlayer(UUID player) {
lastMessages.remove(player);
lastMessageTime.remove(player);
}
}