Updated AntiSpam

This commit is contained in:
obvWolf
2024-02-21 16:43:29 -06:00
parent 18e0ad4c02
commit 78d6518bcd
15 changed files with 412 additions and 392 deletions

View File

@@ -137,10 +137,6 @@ public final class Sentinel extends JavaPlugin {
// Plugin startup logic
log.info("Starting Up! (%s)...".formatted(getDescription().getVersion()));
// Enable Functions
AntiSpam.enableAntiSpam();
ProfanityFilter.enableAntiSwear();
// Commands
new SentinelCommand().register();
new MessageCommand().register();

View File

@@ -7,12 +7,14 @@ import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import io.github.itzispyder.pdk.utils.misc.Cooldown;
import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Report;
import io.github.thetrouper.sentinel.server.functions.ReportFalsePositives;
import io.github.thetrouper.sentinel.server.util.Text;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.UUID;
@CommandRegistry(value = "sentinelcallback", permission = @Permission("sentinel.callbacks"), printStackTrace = true)
public class ChatClickCallback implements CustomCommand {
Cooldown<UUID> fpReportCooldown = new Cooldown<>();
@@ -24,7 +26,14 @@ public class ChatClickCallback implements CustomCommand {
if (fpReportCooldown.isOnCooldown(p.getUniqueId()) && !p.isOp()) {
p.sendMessage(Text.prefix(Sentinel.language.get("cooldown") + fpReportCooldown.getCooldown(p.getUniqueId())));
} else {
ReportFalsePositives.sendFalsePositiveReport(ReportFalsePositives.reports.get(args.get(1).toLong()));
long id = args.get(1).toLong();
Report send = ReportFalsePositives.reports.get(id);
if (send == null) {
p.sendMessage(Text.prefix(Sentinel.language.get("no-report")));
return;
}
p.sendMessage(Text.prefix(Sentinel.language.get("reporting-false-positive")));
ReportFalsePositives.sendFalsePositiveReport(send);
p.sendMessage(Text.prefix(Sentinel.language.get("false-positive-report-success")));
}
}

View File

@@ -1,13 +1,13 @@
package io.github.thetrouper.sentinel.data;
public class Emojis {
public static String space = "<:space:1125871914334818446>";
public static String rightSort = "<:rightSort:1125785837255270520>";
public static String arrowRight = "<:arrowRight:1125785471520354304>";
public static String rightDoubleArrow = "<:rightDoubleArrow:1125785800353783868>";
public static String space = "<:space:1210008300515762238>";
public static String rightSort = "<:rightSort:1210008337144479754>";
public static String rightArrow = "<:rightArrow:1210008295738179594>";
public static String rightDoubleArrow = "<:rightDoubleArrow:1210008296723976224>";
public static String activity = "<:activity:1125785527468167178>";
public static String alarm = "<:alarm:1125790301873770606>";
public static String target = "<:target:1125788461371232307>";
public static String alarm = "<:alarm:1210008289635475547>";
public static String target = "<:target:1210008303992701068>";
public static String bot = "<:bot:1125791121851826206>";
public static String cancel = "<:cancel:1125785769471127694>";
public static String creation = "<:creation:1125790610729730109>";
@@ -15,19 +15,19 @@ public class Emojis {
public static String kick = "<:kick:1125785612595761212>";
public static String members = "<:members:1125791101199077426>";
public static String mute = "<:mute:1125789032937435247>";
public static String noDM = "<:noDM:1125790359423824022>";
public static String noDM = "<:noDM:1210008293729370204>";
public static String owner = "<:owner:1125791175559876669>";
public static String potentialDanger = "<:potentialDanger:1125788513971998741>";
public static String roles = "<:roles:1125790513933594645>";
public static String separator = "<:separator:1125790817626357861>";
public static String splash = "<:splash:1125791213933563905>";
public static String success = "<:success:1125785728161419356>";
public static String success = "<:success:1210008354039275570>";
public static String suspicious = "<:suspicious:1125790709371371682>";
public static String trustedAdmin = "<:trustedAdmin:1125785574591180822>";
public static String trustedAdmin = "<:trustedAdmin:1210008362230743080>";
public static String upvoter = "<:upvoter:1125790659735977994>";
public static String vanity = "<:vanity:1125791060594004039>";
public static String webhook = "<:webhook:1125790545638330388>";
public static String failure = "<:failure:1125241087909429369>";
public static String nuke = "<:nuke:1125244368807280702>";
public static String member = "<:member:1125244044407218176>";
public static String failure = "<:failure:1210008290625462432>";
public static String nuke = "<:nuke:1210008294756712478>";
public static String member = "<:member:1210008291174785105>";
}

View File

@@ -3,7 +3,8 @@ package io.github.thetrouper.sentinel.data;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
public record Report(long id, AsyncPlayerChatEvent event, HashMap<String,String> stepsTaken) {
public record Report(long id, AsyncPlayerChatEvent event, LinkedHashMap<String,String> stepsTaken) {
}

View File

@@ -50,6 +50,8 @@ public class LanguageFile implements JsonSerializable<LanguageFile> {
put("unicode-notification", "§b§n%1$s§7 has triggered the anti-unicode.");
put("unicode-notification-hover", "§8]==-- §d§lSentinel §8--==[\n§bMessage: §f%1$s");
put("no-plugins-for-u", "§cThis server wishes to keep their plugins confidential.");
put("reporting-false-positive","Sending report to staff...");
put("no-report","§cThe report you requested either does not exist, or has expired!");
}};
public LanguageFile() {}

View File

@@ -22,9 +22,9 @@ public class MainConfig implements JsonSerializable<MainConfig> {
public String prefix = "§d§lSentinel §8» §7";
public String webhook = "https://discord.com/api/webhooks/id/token";
public String lang = "en-us.json";
public List<String> trustedPlayers = new ArrayList<>() {{
add("049460f7-21cb-42f5-8059-d42752bf406f");
}};
public List<String> trustedPlayers = List.of(
"049460f7-21cb-42f5-8059-d42752bf406f"
);
public boolean blockSpecific = true;
public boolean preventNBT = true;
public boolean preventCmdBlockPlace = true;
@@ -53,25 +53,30 @@ public class MainConfig implements JsonSerializable<MainConfig> {
"perms",
"perm",
"permission",
"permissions"
"permissions",
"pm",
"pluginmanager",
"rl",
"reload",
"plugman"
);
public boolean logDangerous = true;
public boolean logCmdBlocks = true;
public boolean logNBT = true;
public boolean logSpecific = false;
public List<String> logged = new ArrayList<>() {{
add("give");
add("item");
}};
public List<String> logged = List.of(
"give",
"item"
);
public boolean deop = true;
public boolean nbtPunish = false;
public boolean cmdBlockPunish = false;
public boolean commandPunish = false;
public boolean specificPunish = false;
public List<String> punishCommands = new ArrayList<>() {{
add("smite %player%");
add("ban %player% ]=- Sentinel -=[ You have been banned for attempting a dangerous action. If you believe this to be a mistake, please contact the server owner.");
}};
public List<String> punishCommands = List.of(
"smite %player%",
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
public boolean reopCommand = false;
public boolean pluginHider = true;
}

View File

@@ -14,84 +14,84 @@ public class SwearsConfig implements JsonSerializable<SwearsConfig> {
return file;
}
public List<String> swears = new ArrayList<>() {{
add("anal");
add("anus");
add("arse");
add("ass");
add("ballsack");
add("balls");
add("bastard");
add("bitch");
add("btch");
add("biatch");
add("blowjob");
add("bollock");
add("bollok");
add("boner");
add("boob");
add("bugger");
add("butt");
add("choad");
add("clitoris");
add("cock");
add("coon");
add("crap");
add("cum");
add("cunt");
add("dick");
add("dildo");
add("douchebag");
add("dyke");
add("feck");
add("fellate");
add("fellatio");
add("felching");
add("fuck");
add("fudgepacker");
add("flange");
add("gtfo");
add("hoe");
add("horny");
add("incest");
add("jerk");
add("jizz");
add("labia");
add("masturb");
add("muff");
add("nazi");
add("nipple");
add("nips");
add("nude");
add("pedophile");
add("penis");
add("piss");
add("poop");
add("porn");
add("prick");
add("prostit");
add("pube");
add("pussie");
add("pussy");
add("queer");
add("rape");
add("rapist");
add("retard");
add("rimjob");
add("scrotum");
add("sex");
add("shit");
add("slut");
add("spunk");
add("stfu");
add("suckmy");
add("tits");
add("tittie");
add("titty");
add("turd");
add("twat");
add("vagina");
add("wank");
add("whore");
}};
public List<String> swears = List.of(
"anal",
"anus",
"arse",
"ass",
"ballsack",
"balls",
"bastard",
"bitch",
"btch",
"biatch",
"blowjob",
"bollock",
"bollok",
"boner",
"boob",
"bugger",
"butt",
"choad",
"clitoris",
"cock",
"coon",
"crap",
"cum",
"cunt",
"dick",
"dildo",
"douchebag",
"dyke",
"feck",
"fellate",
"fellatio",
"felching",
"fuck",
"fudgepacker",
"flange",
"gtfo",
"hoe",
"horny",
"incest",
"jerk",
"jizz",
"labia",
"masturb",
"muff",
"nazi",
"nipple",
"nips",
"nude",
"pedophile",
"penis",
"piss",
"poop",
"porn",
"prick",
"prostit",
"pube",
"pussie",
"pussy",
"queer",
"rape",
"rapist",
"retard",
"rimjob",
"scrotum",
"sex",
"shit",
"slut",
"spunk",
"stfu",
"suckmy",
"tits",
"tittie",
"titty",
"turd",
"twat",
"vagina",
"wank",
"whore"
);
}

View File

@@ -1,6 +1,7 @@
package io.github.thetrouper.sentinel.events;
import io.github.itzispyder.pdk.events.CustomListener;
import io.github.itzispyder.pdk.utils.ArrayUtils;
import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Report;
import io.github.thetrouper.sentinel.server.functions.AdvancedBlockers;
@@ -26,6 +27,14 @@ public class ChatEvent implements CustomListener {
Report report = ReportFalsePositives.initializeReport(e);
ServerUtils.sendDebugMessage("""
Creating a chat report...
ID %s
Player %s
Message %s
Fields %s
""".formatted(report.id(),report.event().getPlayer(),report.event().getMessage(), report.stepsTaken().toString()));
handleEventIfNotBypassed(p,
"sentinel.chat.antiunicode.bypass",
Sentinel.mainConfig.chat.useAntiUnicode, "unicode",
@@ -52,16 +61,22 @@ public class ChatEvent implements CustomListener {
ProfanityFilter.handleProfanityFilter(event,report);
});
ServerUtils.sendDebugMessage("""
Adding a report to the list...
ID %s
Fields %s
""".formatted(report.id(), report.stepsTaken().toString()));
ReportFalsePositives.reports.put(report.id(),report);
AntiSpam.lastMessageMap.put(p, e.getMessage());
}
private static void handleEventIfNotBypassed(Player p, String permission, boolean isEnabled, String eventType, AsyncPlayerChatEvent e, Consumer<AsyncPlayerChatEvent> handler) {
if (!Sentinel.isTrusted(p) || !p.hasPermission(permission)) {
ServerUtils.sendDebugMessage("ChatEvent: Permission bypass failed, checking for " + eventType);
if (isEnabled) {
ServerUtils.sendDebugMessage("ChatEvent: " + eventType + " check enabled, continuing!");
handler.accept(e);
}
if (e.isCancelled()) return;
if (!isEnabled) return;
ServerUtils.sendDebugMessage("ChatEvent: " + eventType + " check enabled, continuing!");
handler.accept(e);
}
}
}

View File

@@ -6,8 +6,7 @@ import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Emojis;
import io.github.thetrouper.sentinel.data.FAT;
import io.github.thetrouper.sentinel.data.FilterSeverity;
import io.github.thetrouper.sentinel.server.functions.AdvancedBlockers;
import io.github.thetrouper.sentinel.server.functions.ReportFalsePositives;
import io.github.thetrouper.sentinel.data.Report;
import io.github.thetrouper.sentinel.server.util.ServerUtils;
import io.github.thetrouper.sentinel.server.util.Text;
import net.kyori.adventure.text.Component;
@@ -16,6 +15,7 @@ import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import static io.github.thetrouper.sentinel.server.functions.AntiSpam.heatMap;
@@ -24,118 +24,145 @@ import static io.github.thetrouper.sentinel.server.functions.ProfanityFilter.*;
public class FilterAction {
public static void filterPunish(AsyncPlayerChatEvent e, FAT type, Double similarity, FilterSeverity severity) {
String report = "This action is not reportable.";
TextComponent staffNotif = Component.text("");
TextComponent playerWarning = Component.text("");
public static void filterPunish(AsyncPlayerChatEvent e, FAT type, Double similarity, FilterSeverity severity, long reportID) {
long similar = Math.round(similarity);
long report = reportID;
Player offender = e.getPlayer();
switch (type) {
case BLOCK_UNICODE -> {
staffNotif = Component
.text(Text.prefix(Sentinel.language.get("unicode-notification")
.formatted(offender.getName())))
.hoverEvent(Component.text(Sentinel.language.get("unicode-notification-hover")
.formatted(e.getMessage())));
playerWarning = Component
.text(Text.prefix(Sentinel.language.get("unicode-warn")));
}
case BLOCK_URL -> {
staffNotif = Component
.text(Text.prefix(Sentinel.language.get("url-notification")
.formatted(offender.getName())))
.hoverEvent(Component.text(Sentinel.language.get("url-notification-hover")
.formatted(Text.color(Text.regexHighlighter(e.getMessage(),Sentinel.advConfig.urlRegex," &e> &n","&r &e<&f ")))));
playerWarning = Component
.text(Text.prefix(Sentinel.language.get("url-warn")));
}
case BLOCK_SPAM -> {
if (Sentinel.mainConfig.chat.antiSpam.clearChat) ServerUtils.sendCommand(Sentinel.mainConfig.chat.antiSpam.chatClearCommand);
staffNotif = Component
.text(Text.prefix(String.format(Sentinel.language.get("spam-notification"),
offender.getName(),
heatMap.get(offender),
Sentinel.mainConfig.chat.antiSpam.punishHeat
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("spam-notification-hover"),
lastMessageMap.get(offender),
e.getMessage(),
similarity
)));
playerWarning = Component.text(Text.prefix(Sentinel.language.get("spam-block-warn")));
}
case SPAM_PUNISH -> {
if (Sentinel.mainConfig.chat.antiSpam.clearChat) ServerUtils.sendCommand(Sentinel.mainConfig.chat.antiSpam.chatClearCommand);
staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("spam-mute-notification"),
offender.getName(),
heatMap.get(offender),
Sentinel.mainConfig.chat.antiSpam.punishHeat
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("spam-notification-hover"),
lastMessageMap.get(offender),
e.getMessage(),
similarity
)));
playerWarning = Component.text(Sentinel.language.get("spam-mute-warn"));
sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSpam.logSpam) sendDiscordLog(offender,e,type);
}
case BLOCK_SWEAR -> {
report = ReportFalsePositives.generateReport(e);
staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("profanity-block-notification"),
offender.getName(),
scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("severity-notification-hover"),
e.getMessage(),
highlightProfanity(fullSimplify(e.getMessage())),
severity.name()
)));
playerWarning = Component.text(Text.prefix(Sentinel.language.get("profanity-block-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")))
.clickEvent(ClickEvent.runCommand("sentinelcallback fpreport " + report));
}
case SWEAR_PUNISH -> {
report = ReportFalsePositives.generateReport(e);
staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("profanity-mute-notification"),
offender.getName(),
scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("severity-notification-hover"),
e.getMessage(),
highlightProfanity(fullSimplify(e.getMessage())),
severity.name()
)));
playerWarning = Component.text(Text.prefix(Sentinel.language.get("profanity-mute-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")));
sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSwear.logSwears) sendDiscordLog(offender,e,type);
}
case SLUR_PUNISH -> {
report = ReportFalsePositives.generateReport(e);
staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("slur-mute-notification"),
offender.getName(),
scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("severity-notification-hover"),
e.getMessage(),
highlightProfanity(fullSimplify(e.getMessage())),
severity.name()
)));
playerWarning = Component.text(Text.prefix(Sentinel.language.get("slur-mute-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")));
sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSwear.logSwears) sendDiscordLog(offender,e,type);
}
case BLOCK_UNICODE -> handleUnicodeBlock(e,offender,type,report);
case BLOCK_URL -> handleURLBlock(e,offender,type,report);
case BLOCK_SPAM -> handleSpamBlock(e,type,offender,report,similar);
case SPAM_PUNISH -> handleSpamPunish(e,type,offender,report,similar);
case BLOCK_SWEAR -> handleSwearBlock(e,type,offender,report,severity);
case SWEAR_PUNISH -> handleSwearPunish(e,type,offender,report,severity);
case SLUR_PUNISH -> handleSlur(e,type,offender,report,severity);
}
}
public static void handleUnicodeBlock(AsyncPlayerChatEvent e, Player offender, FAT type, long report) {
TextComponent staffNotif = Component
.text(Text.prefix(Sentinel.language.get("unicode-notification")
.formatted(offender.getName())))
.hoverEvent(Component.text(Sentinel.language.get("unicode-notification-hover")
.formatted(e.getMessage())));
TextComponent playerWarning = Component
.text(Text.prefix(Sentinel.language.get("unicode-warn")));
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
}
public static void handleURLBlock(AsyncPlayerChatEvent e, Player offender, FAT type, long report) {
TextComponent staffNotif = Component
.text(Text.prefix(Sentinel.language.get("url-notification")
.formatted(offender.getName())))
.hoverEvent(Component.text(Sentinel.language.get("url-notification-hover")
.formatted(Text.color(Text.regexHighlighter(e.getMessage(),Sentinel.advConfig.urlRegex," &e> &n","&r &e<&f ")))));
TextComponent playerWarning = Component
.text(Text.prefix(Sentinel.language.get("url-warn")));
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
}
public static void handleSpamBlock(AsyncPlayerChatEvent e, FAT type, Player offender, long report, double similarity) {
if (Sentinel.mainConfig.chat.antiSpam.clearChat) ServerUtils.sendCommand(Sentinel.mainConfig.chat.antiSpam.chatClearCommand);
TextComponent staffNotif = Component
.text(Text.prefix(String.format(Sentinel.language.get("spam-notification"),
offender.getName(),
heatMap.get(offender),
Sentinel.mainConfig.chat.antiSpam.punishHeat
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("spam-notification-hover"),
lastMessageMap.get(offender),
e.getMessage(),
similarity
)));
TextComponent playerWarning = Component.text(Text.prefix(Sentinel.language.get("spam-block-warn")));
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
}
public static void handleSpamPunish(AsyncPlayerChatEvent e, FAT type, Player offender, long report, double similarity) {
if (Sentinel.mainConfig.chat.antiSpam.clearChat) ServerUtils.sendCommand(Sentinel.mainConfig.chat.antiSpam.chatClearCommand);
TextComponent staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("spam-mute-notification"),
offender.getName(),
heatMap.get(offender),
Sentinel.mainConfig.chat.antiSpam.punishHeat
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("spam-notification-hover"),
lastMessageMap.get(offender),
e.getMessage(),
similarity
)));
TextComponent playerWarning = Component.text(Sentinel.language.get("spam-mute-warn"));
sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSpam.logSpam) sendDiscordLog(offender,e,type);
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
}
public static void handleSwearBlock(AsyncPlayerChatEvent e, FAT type, Player offender, long report, FilterSeverity severity) {
TextComponent staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("profanity-block-notification"),
offender.getName(),
scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("severity-notification-hover"),
e.getMessage(),
highlightProfanity(fullSimplify(e.getMessage())),
severity.name()
)));
TextComponent playerWarning = Component.text(Text.prefix(Sentinel.language.get("profanity-block-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")))
.clickEvent(ClickEvent.runCommand("sentinelcallback fpreport " + report));
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
}
public static void handleSwearPunish(AsyncPlayerChatEvent e, FAT type, Player offender, long report, FilterSeverity severity) {
TextComponent staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("profanity-mute-notification"),
offender.getName(),
scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("severity-notification-hover"),
e.getMessage(),
highlightProfanity(fullSimplify(e.getMessage())),
severity.name()
)));
TextComponent playerWarning = Component.text(Text.prefix(Sentinel.language.get("profanity-mute-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")));
sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSwear.logSwears) sendDiscordLog(offender,e,type);
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
}
public static void handleSlur(AsyncPlayerChatEvent e, FAT type, Player offender, long report, FilterSeverity severity) {
TextComponent staffNotif = Component.text(Text.prefix(String.format(Sentinel.language.get("slur-mute-notification"),
offender.getName(),
scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore
)))
.hoverEvent(Component.text(String.format(Sentinel.language.get("severity-notification-hover"),
e.getMessage(),
highlightProfanity(fullSimplify(e.getMessage())),
severity.name()
)));
TextComponent playerWarning = Component.text(Text.prefix(Sentinel.language.get("slur-mute-warn")))
.hoverEvent(Component.text(Sentinel.language.get("action-automatic-reportable")));
sendConsoleLog(offender,e,type);
if (Sentinel.mainConfig.chat.antiSwear.logSwears) sendDiscordLog(offender,e,type);
sendWarnings(e,type,offender, staffNotif, playerWarning,report);
}
public static void sendWarnings(AsyncPlayerChatEvent e, FAT type, Player offender, TextComponent staffNotif, TextComponent playerWarning, long report) {
if (type.getExecutedCommand() != null) {
ServerUtils.sendCommand(type.getExecutedCommand().replace("%player%", offender.getName()));
}
@@ -196,7 +223,7 @@ public class FilterAction {
case SPAM_PUNISH -> {
description.append(String.format("\n%1$s%2$sHeat: `%3$s/%4$s`",
Emojis.space,
Emojis.arrowRight,
Emojis.rightArrow,
heatMap.get(offender),
Sentinel.mainConfig.chat.antiSpam.punishHeat
));
@@ -209,7 +236,7 @@ public class FilterAction {
case SWEAR_PUNISH, SLUR_PUNISH -> {
description.append(String.format("\n%1$s%2$sScore: `%3$s/%4$s`",
Emojis.space,
Emojis.arrowRight,
Emojis.rightArrow,
scoreMap.get(offender),
Sentinel.mainConfig.chat.antiSwear.punishScore
));

View File

@@ -24,19 +24,22 @@ public class AdvancedBlockers {
}
public static void handleAntiUnicode(AsyncPlayerChatEvent e, Report report) {
if (e.isCancelled()) return;
String message = Text.removeFirstColor(e.getMessage());
report.stepsTaken().put("Anti-Unicode", "`%s`".formatted(message));
ServerUtils.sendDebugMessage("AdvBlocker: Checking for unicode: " + message);
String nonAllowed = message.replaceAll(Sentinel.advConfig.allowedCharRegex, "").trim();
if (nonAllowed.length() != 0) {
ServerUtils.sendDebugMessage("AdvBlocker: Caught Unicode: " + nonAllowed);
e.setCancelled(true);
report.stepsTaken().replace("Anti-Unicode", "`%s` %s".formatted(message, Emojis.alarm));
FilterAction.filterPunish(e,FAT.BLOCK_UNICODE,null,null);
FilterAction.filterPunish(e,FAT.BLOCK_UNICODE,null,null,report.id());
}
}
public static void handleSwearRegex(AsyncPlayerChatEvent e, Report report) {
if (e.isCancelled()) return;
String swearRegex = Sentinel.advConfig.swearRegex;
Pattern pattern = Pattern.compile(swearRegex, Pattern.CASE_INSENSITIVE);
@@ -44,16 +47,16 @@ public class AdvancedBlockers {
report.stepsTaken().put("Anti-Swear Regex", "`%s`".formatted(e.getMessage()));
String highlighted = Text.regexHighlighter(swearRegex,e.getMessage()," > "," < ");
if (matcher.find()) {
e.setCancelled(true);
String highlighted = Text.regexHighlighter(swearRegex,e.getMessage()," > "," < ");
report.stepsTaken().replace("Anti-Swear Regex", "`%s` %s".formatted(highlighted, Emojis.alarm));
FilterAction.filterPunish(e,FAT.SWEAR_PUNISH,null,FilterSeverity.HIGH);
FilterAction.filterPunish(e,FAT.SWEAR_PUNISH,null,FilterSeverity.HIGH,report.id());
}
}
public static void handleStrictRegex(AsyncPlayerChatEvent e, Report report) {
if (e.isCancelled()) return;
String strictRegex = Sentinel.advConfig.strictRegex;
Pattern pattern = Pattern.compile(strictRegex, Pattern.CASE_INSENSITIVE);
@@ -61,23 +64,27 @@ public class AdvancedBlockers {
report.stepsTaken().put("Strict Regex", "`%s`".formatted(e.getMessage()));
String highlighted = Text.regexHighlighter(strictRegex,e.getMessage()," > "," < ");
if (matcher.find()) {
e.setCancelled(true);
String highlighted = Text.regexHighlighter(strictRegex,e.getMessage()," > "," < ");
report.stepsTaken().replace("Strict Regex", "`%s` %s".formatted(highlighted, Emojis.alarm));
FilterAction.filterPunish(e, FAT.SLUR_PUNISH,null, FilterSeverity.SLUR);
FilterAction.filterPunish(e, FAT.SLUR_PUNISH,null, FilterSeverity.SLUR,report.id());
}
}
public static void handleAntiURL(AsyncPlayerChatEvent e, Report report) {
if (e.isCancelled()) return;
String urlRegex = Sentinel.advConfig.urlRegex;
Pattern pattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(e.getMessage());
ServerUtils.sendDebugMessage("AdvBlocker: Checking for URLs against regex `%1$s`:%2$s".formatted(urlRegex, e.getMessage()));
report.stepsTaken().replace("Anti-URL", "`%s` %s".formatted(e.getMessage(), Emojis.alarm));
report.stepsTaken().put("Anti-URL", "`%s`".formatted(
e.getMessage()
));
if (matcher.find()) {
e.setCancelled(true);
@@ -85,7 +92,7 @@ public class AdvancedBlockers {
ServerUtils.sendDebugMessage("AdvBlocker: Caught URL: " + highlighted);
report.stepsTaken().replace("Anti-URL", "`%s` %s".formatted(highlighted, Emojis.alarm));
FilterAction.filterPunish(e,FAT.BLOCK_URL,null,null);
FilterAction.filterPunish(e,FAT.BLOCK_URL,null,null,report.id());
}
}
}

View File

@@ -1,5 +1,6 @@
package io.github.thetrouper.sentinel.server.functions;
import io.github.itzispyder.pdk.utils.SchedulerUtils;
import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Emojis;
import io.github.thetrouper.sentinel.data.FAT;
@@ -15,67 +16,52 @@ import java.util.HashMap;
import java.util.Map;
public class AntiSpam {
public static Map<Player, Integer> heatMap;
public static Map<Player, String> lastMessageMap;
public static void enableAntiSpam() {
heatMap = new HashMap<>();
lastMessageMap = new HashMap<>();
}
public static Map<Player, Integer> heatMap = new HashMap<>();
public static Map<Player, String> lastMessageMap = new HashMap<>();
public static void handleAntiSpam(AsyncPlayerChatEvent e, Report report) {
Player p = e.getPlayer();
String message = Text.removeFirstColor(e.getMessage());
if (!lastMessageMap.containsKey(p)) {
lastMessageMap.put(p,"/* Placeholder Message from Sentinel */");
ServerUtils.sendDebugMessage("AntiSpam: " + p.getName() + " did not have a previous message, setting to placeholder!");
String lastMessage = lastMessageMap.getOrDefault(p,"/* Placeholder Message from Sentinel */");
int currentHeat = heatMap.getOrDefault(p,0);
double similarity = GPTUtils.calcSim(message, lastMessage);
int addHeat = Sentinel.mainConfig.chat.antiSpam.defaultGain;
ServerUtils.sendDebugMessage("AntiSpam: " + p.getName() + " has a heat of " + currentHeat + "/" + Sentinel.mainConfig.chat.antiSpam.punishHeat + ". Current Message: \"" + message + "\" Last message: \"" + lastMessage + "\"");
if (similarity > 90) {
addHeat = Sentinel.mainConfig.chat.antiSpam.highGain;
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 90% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.highGain);
} else if (similarity > 50) {
addHeat = Sentinel.mainConfig.chat.antiSpam.mediumGain;
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 50% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.mediumGain);
} else if (similarity > 25) {
addHeat = Sentinel.mainConfig.chat.antiSpam.lowGain;
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 25% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.lowGain);
}
if (!heatMap.containsKey(p)) {
heatMap.put(p,0);
ServerUtils.sendDebugMessage("AntiSpam: " + p.getName() + " did not have a heat, setting it to 0!");
}
report.stepsTaken().put("Anti-Spam", "Heat: %s\nMessage: `%s`".formatted(currentHeat,message));
if (lastMessageMap.containsKey(p)) {
String lastMessage = lastMessageMap.get(p);
double similarity = GPTUtils.calcSim(message, lastMessage);
ServerUtils.sendDebugMessage("AntiSpam: " + p.getName() + " has a heat of " + heatMap.get(p) + "/" + Sentinel.mainConfig.chat.antiSpam.punishHeat + ". Current Message: \"" + message + "\" Last message: \"" + lastMessage + "\"");
if (similarity > 90) {
heatMap.put(p, heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.highGain);
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 90% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.highGain);
} else if (similarity > 50) {
heatMap.put(p, heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.mediumGain);
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 50% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.mediumGain);
} else if (similarity > 25) {
heatMap.put(p, heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.lowGain);
ServerUtils.sendDebugMessage("AntiSpam: Similarity: " + similarity + ", is greater than 25% for " + p.getName() + ". Adding " + Sentinel.mainConfig.chat.antiSpam.lowGain);
}
}
report.stepsTaken().put("Anti-Spam", "Heat: %s\nMessage: `%s`".formatted(heatMap.get(p),message));
lastMessageMap.put(p, message);
if (heatMap.get(p) > Sentinel.mainConfig.chat.antiSpam.punishHeat) {
if (currentHeat > Sentinel.mainConfig.chat.antiSpam.punishHeat) {
e.setCancelled(true);
report.stepsTaken().replace("Anti-Spam", "Heat: %s\nMessage: `%s` %s".formatted(heatMap.get(p),message, Emojis.alarm));
FilterAction.filterPunish(e,FAT.SPAM_PUNISH,GPTUtils.calcSim(e.getMessage(),lastMessageMap.get(p)), null);
report.stepsTaken().replace("Anti-Spam", "Heat: %s\nMessage: `%s` %s".formatted(currentHeat,message, Emojis.alarm));
FilterAction.filterPunish(e,FAT.SPAM_PUNISH,GPTUtils.calcSim(e.getMessage(),lastMessage), null,report.id());
return;
}
if (heatMap.get(p) > Sentinel.mainConfig.chat.antiSpam.blockHeat) {
if (currentHeat > Sentinel.mainConfig.chat.antiSpam.blockHeat) {
e.setCancelled(true);
report.stepsTaken().replace("Anti-Spam", "Heat: %s\nMessage: `%s` %s".formatted(heatMap.get(p),message, Emojis.alarm));
FilterAction.filterPunish(e,FAT.BLOCK_SPAM, GPTUtils.calcSim(e.getMessage(),lastMessageMap.get(p)), null);
heatMap.put(p, heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.highGain);
report.stepsTaken().replace("Anti-Spam", "Heat: %s\nMessage: `%s` %s".formatted(currentHeat,message, Emojis.alarm));
FilterAction.filterPunish(e,FAT.BLOCK_SPAM, GPTUtils.calcSim(e.getMessage(),lastMessage), null,report.id());
heatMap.put(p, currentHeat + Sentinel.mainConfig.chat.antiSpam.highGain);
return;
}
heatMap.put(p,heatMap.get(p) + Sentinel.mainConfig.chat.antiSpam.defaultGain);
heatMap.put(p,currentHeat + addHeat);
}
public static void decayHeat() {
for (Player p : heatMap.keySet()) {
int heat = heatMap.get(p);
int heat = heatMap.getOrDefault(p,0);
if (heat > 0) {
heat = heat - Sentinel.mainConfig.chat.antiSpam.heatDecay;
heatMap.put(p, Math.max(0, heat));

View File

@@ -1,6 +1,7 @@
package io.github.thetrouper.sentinel.server.functions;
import io.github.thetrouper.sentinel.Sentinel;
import io.github.thetrouper.sentinel.data.Emojis;
import io.github.thetrouper.sentinel.data.FAT;
import io.github.thetrouper.sentinel.data.FilterSeverity;
import io.github.thetrouper.sentinel.data.Report;
@@ -15,15 +16,11 @@ import java.util.List;
import java.util.Map;
public class ProfanityFilter {
public static Map<Player, Integer> scoreMap;
public static Map<Player, Integer> scoreMap = new HashMap<>();
private static final List<String> swearBlacklist = Sentinel.swearConfig.swears;
private static final List<String> swearWhitelist = Sentinel.fpConfig.swearWhitelist;
private static final List<String> slurs = Sentinel.strictConfig.strict;
public static void enableAntiSwear() {
scoreMap = new HashMap<>();
}
public static void handleProfanityFilter(AsyncPlayerChatEvent event, Report report) {
Player player = event.getPlayer();
String message = Text.removeFirstColor(event.getMessage());
@@ -41,11 +38,11 @@ public class ProfanityFilter {
scoreMap.put(player, newScore);
if (newScore > Sentinel.mainConfig.chat.antiSwear.punishScore) {
FilterAction.filterPunish(event, FAT.SWEAR_PUNISH, null, severity);
FilterAction.filterPunish(event, FAT.SWEAR_PUNISH, null, severity,report.id());
return;
}
FilterAction.filterPunish(event, getFAT(severity), null, severity);
FilterAction.filterPunish(event, getFAT(severity), null, severity,report.id());
}
@@ -105,6 +102,7 @@ public class ProfanityFilter {
return removePeriodsAndSpaces(simplifiedText);
}
public static FilterSeverity checkSeverity(String text, Report report) {
FilterSeverity severity = FilterSeverity.SAFE;
// 1:
String lowercasedText = text.toLowerCase();
report.stepsTaken().put("Lowercased", lowercasedText);
@@ -116,8 +114,13 @@ public class ProfanityFilter {
ServerUtils.sendDebugMessage(("ProfanityFilter: Removed False positives: " + cleanedText));
// 3:
if (containsSwears(cleanedText)) return FilterSeverity.LOW;
if (containsSlurs(cleanedText)) return FilterSeverity.SLUR;
severity = checkProfanity(cleanedText,FilterSeverity.LOW);
if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Remove False Positives", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
// 4:
String convertedText = convertLeetSpeakCharacters(cleanedText);
@@ -125,42 +128,61 @@ public class ProfanityFilter {
ServerUtils.sendDebugMessage(("ProfanityFilter: Leet Converted: " + convertedText));
// 5:
if (containsSwears(convertedText)) return FilterSeverity.MEDIUM_LOW;
if (containsSlurs(cleanedText)) return FilterSeverity.SLUR;
severity = checkProfanity(convertedText,FilterSeverity.MEDIUM_LOW);
if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Convert LeetSpeak", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
// 6:
String strippedText = stripSpecialCharacters(convertedText);
report.stepsTaken().put("Remove Special Characters", strippedText);
ServerUtils.sendDebugMessage(("ProfanityFilter: Specials Removed: " + strippedText));
// 7:
if (containsSwears(strippedText)) return FilterSeverity.MEDIUM;
if (containsSlurs(strippedText)) return FilterSeverity.SLUR;
severity = checkProfanity(strippedText,FilterSeverity.MEDIUM);
if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Remove Special Characters", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
// 8:
String simplifiedText = simplifyRepeatingLetters(strippedText);
report.stepsTaken().put("Remove Repeats", simplifiedText);
ServerUtils.sendDebugMessage(("ProfanityFilter: Removed Repeating: " + simplifiedText));
// 9:
if (containsSwears(simplifiedText)) return FilterSeverity.MEDIUM_HIGH;
if (containsSlurs(simplifiedText)) return FilterSeverity.SLUR;
severity = checkProfanity(simplifiedText,FilterSeverity.MEDIUM_HIGH);
if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Remove Repeats", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
// 10:
String finalText = removePeriodsAndSpaces(simplifiedText);
report.stepsTaken().put("Remove Punctuation", finalText);
ServerUtils.sendDebugMessage(("ProfanityFilter: Remove Punctuation: " + finalText));
// 11:
if (containsSwears(finalText)) return FilterSeverity.HIGH;
if (containsSlurs(finalText)) return FilterSeverity.SLUR;
severity = checkProfanity(finalText,FilterSeverity.HIGH);
if (severity != FilterSeverity.SAFE) {
report.stepsTaken().replace("Remove Punctuation", "%s %s".formatted(
highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return severity;
}
return FilterSeverity.SAFE;
return severity;
}
public static boolean ContainsProfanity(String text) {
return containsSwears(text) || containsSlurs(text);
public static FilterSeverity checkProfanity(String text, FilterSeverity severity) {
if (containsSlurs(text)) return FilterSeverity.SLUR;
if (containsSwears(text)) return severity;
return FilterSeverity.SAFE;
}
private static boolean containsSwears(String text) {
ServerUtils.sendDebugMessage("ProfanityFilter: Checking for swears");

View File

@@ -9,53 +9,42 @@ import io.github.thetrouper.sentinel.data.Report;
import io.github.thetrouper.sentinel.server.util.Randomizer;
import io.github.thetrouper.sentinel.server.util.ServerUtils;
import io.github.thetrouper.sentinel.server.util.Text;
import it.unimi.dsi.fastutil.Hash;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class ReportFalsePositives {
public static Map<String,AsyncPlayerChatEvent> reportMap = new HashMap<>();
public static Map<Long,Report> reports = new HashMap<>();
public static Report initializeReport(AsyncPlayerChatEvent e) {
public static Report initializeReport(AsyncPlayerChatEvent event) {
final long reportID = Randomizer.generateID();
HashMap<String,String> steps = new HashMap<>();
steps.put("Original Message", e.getMessage());
return new Report(reportID,e,steps);
}
public static String generateReport(AsyncPlayerChatEvent e) {
final long reportLong = Randomizer.generateID();
final String reportID = Long.toString(reportLong);
ServerUtils.sendDebugMessage("FP Report: Generating chat filter report");
reportMap.put(reportID,e);
ServerUtils.sendDebugMessage(("FP Report: Generated chat filter report. ID:" + reportID + " Message: \"" + reportMap.get(reportID).getMessage() + "\" Expires in 60 seconds"));
LinkedHashMap<String,String> steps = new LinkedHashMap<>();
steps.put("Original Message", "`%s`".formatted(event.getMessage()));
SchedulerUtils.later(60000,()->{
reportMap.remove(reportID);
ServerUtils.sendDebugMessage("FP Report: Chat filter Report expired. ID: " + reportID);
reports.remove(reportID);
});
return reportID;
return new Report(reportID,event,steps);
}
public static void sendFalsePositiveReport(Report report) {
DiscordEmbed.Builder embed = DiscordEmbed.create()
.author(new DiscordEmbed.Author("Anti-Swear False Positive","",null))
.title("Flag Report:")
.title("A player has reported a false positive")
.desc(String.format("""
%1$sPlayer: %2$s %3$s\n
%4$s %5$sUUID: `%2$s`\n
%1$sPlayer: %2$s %3$s
%4$s %5$sUUID: `%6$s`
## **Filter Steps Taken:**
""",
Emojis.rightSort,
report.event().getPlayer().getName(),
Emojis.target,
Emojis.space,
Emojis.arrowRight
Emojis.rightArrow,
report.event().getPlayer().getUniqueId()
));
report.stepsTaken().forEach((key, value)->{
@@ -67,59 +56,7 @@ public class ReportFalsePositives {
.username("Sentinel Anti-Nuke | Logs")
.addEmbed(embed.build())
.send(Sentinel.mainConfig.plugin.webhook);
}
public static void sendFalsePositiveReport(String reportID) {
AsyncPlayerChatEvent e = reportMap.get(reportID);
String orig = e.getMessage();
String lowercasedText = orig.toLowerCase();
String remFP = ProfanityFilter.removeFalsePositives(lowercasedText);
String convertedLeet = ProfanityFilter.convertLeetSpeakCharacters(remFP);
String remSpecials = ProfanityFilter.stripSpecialCharacters(convertedLeet);
String simplifyRep = ProfanityFilter.simplifyRepeatingLetters(remSpecials);
String sanitized = ProfanityFilter. removePeriodsAndSpaces(simplifyRep);
try {
sendEmbed(e.getPlayer(),orig,lowercasedText,remFP,convertedLeet,remSpecials,simplifyRep,sanitized);
} catch (Exception ex) {
e.getPlayer().sendMessage(Text.prefix("Report Failed!"));
Sentinel.log.warning(ex.getMessage());
}
}
public static void sendEmbed(Player player,
String message,
String lowercased,
String remFP,
String convertedLeet,
String remSpecials,
String simplifyRep,
String sanitized) throws IOException {
ServerUtils.sendDebugMessage("Creating FalsePositive Webhook...");
DiscordWebhook.create()
.avatar("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/3lwit5nt.png")
.username("Sentinel Anti-Nuke | Logs")
.addEmbed(DiscordEmbed.create()
.author(new DiscordEmbed.Author("Anti-Swear False Positive","",null))
.title("Flag Report:")
.desc(String.format("%1$sPlayer: %2$s %3$s\n%4$s %5$sUUID: `%2$s`\n",
Emojis.rightSort,
player.getName(),
Emojis.target,
Emojis.space,
Emojis.arrowRight
))
.addField("Original Message", "`" + message + "` " + (ProfanityFilter.ContainsProfanity(message) ? Emojis.alarm : ""), false)
.addField("Lowercase", "`" + lowercased + "` " + (ProfanityFilter.ContainsProfanity(lowercased) ? Emojis.alarm : ""), false)
.addField("Removed FPs", "`" + remFP + "` " + (ProfanityFilter.ContainsProfanity(remFP) ? Emojis.alarm : ""), false)
.addField("Converted Leet", "`" + convertedLeet + "` " + (ProfanityFilter.ContainsProfanity(convertedLeet) ? Emojis.alarm : ""), false)
.addField("Removed Specials", "`" + remSpecials + "` " + (ProfanityFilter.ContainsProfanity(remSpecials) ? Emojis.alarm : ""), false)
.addField("Simplify Repeats", "`" + simplifyRep + "` " + (ProfanityFilter.ContainsProfanity(simplifyRep) ? Emojis.alarm : ""), false)
.addField("Fully Sanitized Message", ProfanityFilter.highlightProfanity(sanitized,"`", "`") + " " + Emojis.noDM, false)
.color(0x00FF00)
.thumbnail("https://crafatar.com/avatars/" + player.getUniqueId() + "?size=64&&overlay")
.build())
.build().send(Sentinel.mainConfig.plugin.webhook);
reports.remove(report.id());
}
}

View File

@@ -144,10 +144,8 @@ public class SystemCheck {
AntiSpam.handleAntiSpam(spam,ReportFalsePositives.initializeReport(spam));
});
String report = ReportFalsePositives.generateReport(falsePositive);
SchedulerUtils.later(20,()->{
ReportFalsePositives.sendFalsePositiveReport(report);
});
Message.messagePlayer(p,p,"Sentinel Automatic System check > Private Message");

View File

@@ -51,24 +51,39 @@ public class Text {
return input;
}
}
public static String replaceRepeatingLetters(String message) {
StringBuilder result = new StringBuilder();
char prevChar = '\0';
int count = 0;
public static String replaceRepeatingLetters(String input) {
if (input == null || input.isEmpty()) {
return input;
}
for (char c : message.toCharArray()) {
if (c == prevChar) {
StringBuilder simplifiedText = new StringBuilder();
char currentChar = input.charAt(0);
int count = 1;
for (int i = 1; i < input.length(); i++) {
char nextChar = input.charAt(i);
if (Character.toLowerCase(nextChar) == Character.toLowerCase(currentChar)) {
count++;
if (count <= 3) {
result.append(c);
}
} else {
prevChar = c;
simplifiedText.append(currentChar);
if (count > 1) {
simplifiedText.append(currentChar);
}
currentChar = nextChar;
count = 1;
result.append(c);
}
}
return result.toString();
simplifiedText.append(currentChar);
if (count > 1) {
simplifiedText.append(currentChar);
}
return simplifiedText.toString();
}
public static String fromLeetString(String s) {
Map<String, String> dictionary = Sentinel.advConfig.leetPatterns;