From 451ae2c2351ad283fe5b137c93bf3a8b32195df7 Mon Sep 17 00:00:00 2001 From: OPmasterLEO <98689894+OPmasterLEO@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:52:08 +0200 Subject: [PATCH 1/8] Folia Supported * Added folia support * Updated API * Small cleanup --- pom.xml | 42 +++++++++++---- .../chatfilter/chatfilter/ChatFilter.java | 52 +++++++++++++++++-- .../papers/chatfilter/chatfilter/Manager.java | 3 -- .../chatfilter/commands/ClearChatCommand.java | 1 - .../chatfilter/events/BooksListener.java | 1 - .../chatfilter/events/CommandListener.java | 2 - .../chatfilter/events/SignListener.java | 2 - .../chatfilter/shared/ChatFilters.java | 1 - src/main/resources/plugin.yml | 7 +-- 9 files changed, 84 insertions(+), 27 deletions(-) diff --git a/pom.xml b/pom.xml index 91f2d86..0317c55 100644 --- a/pom.xml +++ b/pom.xml @@ -5,8 +5,8 @@ 4.0.0 a4.papers.chatfilter - chatFilter - 1.1.8 + ChatFilter + 2.0.15 jar ChatFilter @@ -21,7 +21,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.14.0 ${java.version} ${java.version} @@ -30,7 +30,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.4 + 3.6.0 package @@ -39,7 +39,17 @@ false - C:\Users\A4pap\Desktop\Output\ChatFilter.jar + + + com.github.Anon8281:UniversalScheduler + + + + + com.github.Anon8281.universalScheduler + a4.papers.chatfilter.universalScheduler + + @@ -55,21 +65,31 @@ - spigotmc-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + papermc + https://repo.papermc.io/repository/maven-public/ sonatype https://oss.sonatype.org/content/groups/public/ + + jitpack.io + https://jitpack.io + - org.spigotmc - spigot-api - 1.18.1-R0.1-SNAPSHOT - provided + io.papermc.paper + paper-api + 1.21.8-R0.1-SNAPSHOT + provided + + + com.github.Anon8281 + UniversalScheduler + 0.1.7 + compile diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java index 5a20647..1816bc0 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java @@ -12,8 +12,13 @@ import a4.papers.chatfilter.chatfilter.shared.lang.LangManager; import a4.papers.chatfilter.chatfilter.shared.regexHandler.LoadFilters; import a4.papers.chatfilter.chatfilter.shared.regexHandler.RegexpGenerator; + +import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; +import com.github.Anon8281.universalScheduler.UniversalScheduler; + +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; + import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; @@ -38,8 +43,12 @@ import java.util.concurrent.Callable; import java.util.regex.Pattern; +@SuppressWarnings("deprecation") public class ChatFilter extends JavaPlugin { + private static TaskScheduler scheduler; + private static ChatFilter instance; + public ConsoleCommandSender consoleSender = Bukkit.getConsoleSender(); public ChatFilter chatFilter; public ChatFilters chatFilters; @@ -132,6 +141,10 @@ public void onEnable() { } catch (MalformedURLException e) { e.printStackTrace(); } + + scheduler = UniversalScheduler.getScheduler(this); + instance = this; + createCustomConfig(); loadVariables(); getCommand("chatfilter").setExecutor(new CommandMain(this)); @@ -236,9 +249,11 @@ public void loadVariables() { public String colour(String s) { if (manager.supported("hex")) { - return manager.colorStringHex(s); + return Manager.colorStringHex(s); } else { - return ChatColor.translateAlternateColorCodes('&', s); + return LegacyComponentSerializer.legacyAmpersand().serialize( + LegacyComponentSerializer.legacyAmpersand().deserialize(s) + ); } } @@ -349,4 +364,35 @@ public void reloadConfigs() throws Exception { wordConfig.load(wordConfigFile); unicodeConfig.load(unicodeConfigFile); } + + public static Object runTask(Runnable runnable) { + if (scheduler != null) { + return scheduler.runTask(runnable); + } else { + Bukkit.getScheduler().runTask(instance, runnable); + return null; + } + } + + public static Object runTaskLater(Runnable runnable, long delay) { + if (scheduler != null) { + return scheduler.runTaskLater(runnable, delay); + } else { + Bukkit.getScheduler().runTaskLater(instance, runnable, delay); + return null; + } + } + + public static Object runTaskTimer(Runnable runnable, long delay, long period) { + if (scheduler != null) { + return scheduler.runTaskTimer(runnable, delay, period); + } else { + Bukkit.getScheduler().runTaskTimer(instance, runnable, delay, period); + return null; + } + } + + public static TaskScheduler getScheduler() { + return scheduler; + } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java b/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java index 2124928..e777daf 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java @@ -2,10 +2,7 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.plugin.Plugin; -import java.awt.*; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/commands/ClearChatCommand.java b/src/main/java/a4/papers/chatfilter/chatfilter/commands/ClearChatCommand.java index 248bf9d..08f1f87 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/commands/ClearChatCommand.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/commands/ClearChatCommand.java @@ -2,7 +2,6 @@ import a4.papers.chatfilter.chatfilter.ChatFilter; import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; -import a4.papers.chatfilter.chatfilter.shared.lang.LangManager; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java index a555dc3..7c5c6d3 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java @@ -5,7 +5,6 @@ import a4.papers.chatfilter.chatfilter.shared.Result; import a4.papers.chatfilter.chatfilter.shared.Types; import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; -import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.Event; diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java index ee72395..7614bc6 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java @@ -10,9 +10,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventException; -import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.plugin.EventExecutor; diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java index 3358755..5f3a440 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java @@ -5,7 +5,6 @@ import a4.papers.chatfilter.chatfilter.shared.Result; import a4.papers.chatfilter.chatfilter.shared.Types; import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -14,7 +13,6 @@ import org.bukkit.event.block.SignChangeEvent; import org.bukkit.plugin.EventExecutor; -import java.util.List; public class SignListener implements EventExecutor, Listener { diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java index 26f4595..22d5a09 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java @@ -1,7 +1,6 @@ package a4.papers.chatfilter.chatfilter.shared; import a4.papers.chatfilter.chatfilter.ChatFilter; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.util.*; diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9849673..ce99f01 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,8 @@ -name: ChatFilter -version: 2.0.14 +name: ${project.name} +version: ${project.version} main: a4.papers.chatfilter.chatfilter.ChatFilter -api-version: 1.13 +api-version: 1.21 +folia-supported: true authors: [ A4_Papers ] description: Basic Regex chat, book and anvil filter commands: From 9489200033a501d83d7edc58c69774b94c3cebee Mon Sep 17 00:00:00 2001 From: OPmasterLEO <98689894+OPmasterLEO@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:57:17 +0200 Subject: [PATCH 2/8] Update README.md --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db7c83c..eab07b9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,49 @@ # ChatFilter -Chat Filter is a chat management plugin for reducing spam, swearing, advertisement of IPs and URLs. Stop repetition in chat and add as many swear words, IPs and URLs as you want to make sure your server chat is controlled! This plugin also filters books, signs, commands and anvils. +Chat Filter is a chat management plugin for reducing spam, swearing, advertisement of IPs and URLs. Stop repetition in chat and add as many swear words, IPs and URLs as you want to make sure your server chat is controlled! This plugin also filters books, signs, commands and anvils. More details below! + +## Features +- **Regex filtering:** Utilizes the use of regex to prevent bypassing of the filter. +- **Multiple Filters:** Filter words, IPs and URLs covering chat, anvils, signs, commands and books. +- **Unicode support:** Prevents the use of certain Unicode common with hacked clients. (hacker font) +- **Anti Spam:** Stop repetitive or similar messages aswell as excessive CAPS and character spam. (Player names exempt) +- **Punishments:** Execute commands when a player is caught by the filter. +- **Commands:** In-game regex generator for words, whitelisting of words, pause and clear chat. +- **Notify staff:** Alerts and highlights swearing and advertising to players with the correct permission. +- **Customizability:** All messages are fully modifiable - Hex compatible. +- **Preset words:** Over 55+ preset English words. +- **No bloat features:** ChatFilter has been made to stay simple and basic. +- **Languages files:** ChatFilter currently supports English, Danish, Chinese (Thanks to Zhaomengran) and Spanish. + +## Commands +- `/clearchat (/cf clear)` – Clears the chat. +- `/cf help` – Displays a list of the plugin’s commands. +- `/cf reload` – Reloads the plugin config. +- `/cf blacklist (ip/word) list/add/remove ` – Blacklists a chosen word or IP. (Will not allow this word/IP to go throught the filter) +- `/cf whitelist (ip/word) list/add/remove ` – Whitelists a chosen word or IP. (Will allow a string of characters/a word or IP to go through the filter) +- `/cf import` - Import plain text words +- `/cf pause` – Pause chat for players that do not have the bypass perm. + +## Permissions +- `chatfilter.reload` – Allows players to use /cf reload +- `chatfilter.blacklist` – Allows players to use /cf blacklist +- `chatfilter.whitelist` – Allows players to use /cf whitelist +- `chatfilter.blacklist.remove` – Allows players to use /cf whitelist remove +- `chatfilter.whitelist.remove` – Allows players to use /cf whitelist remove +- `chatfilter.view` – Allows players to to view what gets caught in the filter +- `chatfilter.pause` – Allows players to pause the chat +- `chatfilter.bypass` – Allows the player to bypass all filters(Chat, Signs, Books, Anvils, Decaps, pause chat and repeat messages) +- `chatfilter.bypass.chat` – Allows the player to bypass in chat +- `chatfilter.bypass.sign` – Allows the player to bypass on a sign +- `chatfilter.bypass.anvil` – Allows the player to bypass in a anvil +- `chatfilter.bypass.book` – Allows the player to bypass in books +- `chatfilter.bypass.command` – Allows the player to bypass in commands +- `chatfilter.bypass.repeat` – Allows the player to bypass repeat messages +- `chatfilter.bypass.caps` –Allows the player to bypass chat decapping +- `chatfilter.bypass.pause` – Allows the player to bypass paused chat +- `chatfilter.bypass.swear` – Allows the player to bypass all swear filters (chat ,books, commands etc) +- chatfilter.bypass.swear.` – Allows the player to bypass set config entries (chat ,books, commands etc) +- chatfilter.bypass.ip.` – Allows the player to bypass set config entries (chat ,books, commands etc) +chatfilter.bypass.ip` – Allows the player to bypass all ip filters (chat ,books, commands etc) + +# DISCLAIMER +This fork implements Folia with minimal code changes. \ No newline at end of file From d431473447a58959a69b26a608456a0882a4e2b2 Mon Sep 17 00:00:00 2001 From: OPmasterLEO <98689894+OPmasterLEO@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:04:53 +0200 Subject: [PATCH 3/8] Improve LegacyComponentSerializer calling create a static final instance to reuse: LegacyComponentSerializer --- .../java/a4/papers/chatfilter/chatfilter/ChatFilter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java index 1816bc0..f1fb3e5 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java @@ -48,6 +48,7 @@ public class ChatFilter extends JavaPlugin { private static TaskScheduler scheduler; private static ChatFilter instance; + private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacyAmpersand(); public ConsoleCommandSender consoleSender = Bukkit.getConsoleSender(); public ChatFilter chatFilter; @@ -251,8 +252,8 @@ public String colour(String s) { if (manager.supported("hex")) { return Manager.colorStringHex(s); } else { - return LegacyComponentSerializer.legacyAmpersand().serialize( - LegacyComponentSerializer.legacyAmpersand().deserialize(s) + return LEGACY_SERIALIZER.serialize( + LEGACY_SERIALIZER.deserialize(s) ); } } From 5de108ae9825e0b62068a832b4b0160dc94e2a29 Mon Sep 17 00:00:00 2001 From: OPmasterLEO <98689894+OPmasterLEO@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:07:19 +0200 Subject: [PATCH 4/8] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eab07b9..f51844b 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,9 @@ Chat Filter is a chat management plugin for reducing spam, swearing, advertiseme - `chatfilter.bypass.caps` –Allows the player to bypass chat decapping - `chatfilter.bypass.pause` – Allows the player to bypass paused chat - `chatfilter.bypass.swear` – Allows the player to bypass all swear filters (chat ,books, commands etc) -- chatfilter.bypass.swear.` – Allows the player to bypass set config entries (chat ,books, commands etc) -- chatfilter.bypass.ip.` – Allows the player to bypass set config entries (chat ,books, commands etc) -chatfilter.bypass.ip` – Allows the player to bypass all ip filters (chat ,books, commands etc) +- `chatfilter.bypass.swear.` – Allows the player to bypass set config entries (chat ,books, commands etc) +- `chatfilter.bypass.ip.` – Allows the player to bypass set config entries (chat ,books, commands etc) +- `chatfilter.bypass.ip` – Allows the player to bypass all ip filters (chat ,books, commands etc) # DISCLAIMER This fork implements Folia with minimal code changes. \ No newline at end of file From 15555f8e8f6aad05443098d7aabaac3c994d77f3 Mon Sep 17 00:00:00 2001 From: OPmasterLEO <98689894+OPmasterLEO@users.noreply.github.com> Date: Mon, 1 Dec 2025 20:40:38 +0100 Subject: [PATCH 5/8] Refactor and optimize chat filter commands and listeners Improves import and blacklist/whitelist commands for better argument handling and duplicate removal, refactors event listeners for clarity and performance, and optimizes string similarity and font detection logic. Updates Java version to 21 in pom.xml and introduces a compiled URL pattern for efficiency. Also cleans up imports and code structure across multiple files. --- pom.xml | 2 +- .../chatfilter/chatfilter/ChatFilter.java | 74 +++++---- .../papers/chatfilter/chatfilter/Manager.java | 10 +- .../chatfilter/commands/BlacklistCommand.java | 58 ++++--- .../chatfilter/commands/ImportCommand.java | 42 +++-- .../chatfilter/commands/WhitelistCommand.java | 34 +++- .../chatfilter/events/AnvilListener.java | 20 ++- .../chatfilter/events/BooksListener.java | 20 ++- .../chatfilter/events/CapsChatListener.java | 16 +- .../chatfilter/events/ChatDelayListener.java | 63 +++---- .../chatfilter/events/CommandListener.java | 75 +++++---- .../chatfilter/events/PauseChat.java | 31 ++-- .../chatfilter/events/RepeatCharListener.java | 12 +- .../chatfilter/events/SignListener.java | 20 ++- .../chatfilter/events/SwearChatListener.java | 17 +- .../chatfilter/shared/ChatFilters.java | 156 +++++++++++------- .../chatfilter/shared/LowerCaseReplace.java | 33 ++-- .../chatfilter/shared/StringSimilarity.java | 50 ++++-- .../chatfilter/shared/UnicodeWrapper.java | 12 ++ .../chatfilter/shared/lang/LangManager.java | 35 ++-- .../shared/regexHandler/LoadFilters.java | 19 +-- .../shared/regexHandler/RegexpGenerator.java | 12 +- 22 files changed, 474 insertions(+), 337 deletions(-) diff --git a/pom.xml b/pom.xml index 0317c55..931921f 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ ChatFilter - 1.8 + 21 UTF-8 diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java index f1fb3e5..9af9983 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java @@ -1,22 +1,13 @@ package a4.papers.chatfilter.chatfilter; -import a4.papers.chatfilter.chatfilter.commands.ClearChatCommand; -import a4.papers.chatfilter.chatfilter.commands.CommandHandler; -import a4.papers.chatfilter.chatfilter.commands.CommandMain; -import a4.papers.chatfilter.chatfilter.commands.TabComplete; -import a4.papers.chatfilter.chatfilter.events.*; -import a4.papers.chatfilter.chatfilter.shared.ChatFilters; -import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; -import a4.papers.chatfilter.chatfilter.shared.Types; -import a4.papers.chatfilter.chatfilter.shared.UnicodeWrapper; -import a4.papers.chatfilter.chatfilter.shared.lang.LangManager; -import a4.papers.chatfilter.chatfilter.shared.regexHandler.LoadFilters; -import a4.papers.chatfilter.chatfilter.shared.regexHandler.RegexpGenerator; - -import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; -import com.github.Anon8281.universalScheduler.UniversalScheduler; - -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; import org.bukkit.Bukkit; import org.bukkit.command.ConsoleCommandSender; @@ -33,15 +24,30 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.regex.Pattern; +import com.github.Anon8281.universalScheduler.UniversalScheduler; +import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; + +import a4.papers.chatfilter.chatfilter.commands.ClearChatCommand; +import a4.papers.chatfilter.chatfilter.commands.CommandHandler; +import a4.papers.chatfilter.chatfilter.commands.CommandMain; +import a4.papers.chatfilter.chatfilter.commands.TabComplete; +import a4.papers.chatfilter.chatfilter.events.AnvilListener; +import a4.papers.chatfilter.chatfilter.events.BooksListener; +import a4.papers.chatfilter.chatfilter.events.CapsChatListener; +import a4.papers.chatfilter.chatfilter.events.ChatDelayListener; +import a4.papers.chatfilter.chatfilter.events.CommandListener; +import a4.papers.chatfilter.chatfilter.events.PauseChat; +import a4.papers.chatfilter.chatfilter.events.RepeatCharListener; +import a4.papers.chatfilter.chatfilter.events.SignListener; +import a4.papers.chatfilter.chatfilter.events.SwearChatListener; +import a4.papers.chatfilter.chatfilter.shared.ChatFilters; +import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; +import a4.papers.chatfilter.chatfilter.shared.Types; +import a4.papers.chatfilter.chatfilter.shared.UnicodeWrapper; +import a4.papers.chatfilter.chatfilter.shared.lang.LangManager; +import a4.papers.chatfilter.chatfilter.shared.regexHandler.LoadFilters; +import a4.papers.chatfilter.chatfilter.shared.regexHandler.RegexpGenerator; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; @SuppressWarnings("deprecation") public class ChatFilter extends JavaPlugin { @@ -115,7 +121,8 @@ public class ChatFilter extends JavaPlugin { public String perWordOptionsString; public Pattern antiSpamPattern; - private Integer blockedInt = 1; + public Pattern urlPattern; + private int blockedInt = 1; private File wordConfigFile; private File advertConfigFile; private File whitelistConfigFile; @@ -126,6 +133,7 @@ public class ChatFilter extends JavaPlugin { private FileConfiguration unicodeConfig; + @Override public void onEnable() { regexWords = new HashMap<>(); regexAdvert = new HashMap<>(); @@ -187,12 +195,7 @@ public void onEnable() { metrics.addCustomChart(new Metrics.SimplePie("total_filters", () -> { return String.valueOf(regexWords.size() + regexAdvert.size()); })); - metrics.addCustomChart(new Metrics.SingleLineChart("block", new Callable() { - @Override - public Integer call() throws Exception { - return blockedInt; - } - })); + metrics.addCustomChart(new Metrics.SingleLineChart("block", () -> blockedInt)); } @Override @@ -244,6 +247,7 @@ public void loadVariables() { this.defaultIPCancelReplaceWith = getConfig().getString("default.ip.CancelChat.ReplaceWith"); this.defaultIPAction = getConfig().getStringList("default.ip.Action"); this.antiSpamPattern = Pattern.compile("(\\S)\\1{" + getConfig().getInt("antiSpam.aboveAmount") + ",}"); + this.urlPattern = Pattern.compile(this.URL_REGEX); this.perWordOptionsEnable = getConfig().getBoolean("perWordOptions.enabled"); this.perWordOptionsString = getConfig().getString("perWordOptions.nameOfList"); } @@ -295,7 +299,7 @@ public RegexpGenerator regexpGenerator() { } public void sendStaffMessage(String str) { - for (Player online : Bukkit.getServer().getOnlinePlayers()) { + for (Player online : Bukkit.getOnlinePlayers()) { if (online.hasPermission("chatfilter.view")) { online.sendMessage(str); } @@ -304,7 +308,7 @@ public void sendStaffMessage(String str) { public void sendConsole(Types type, String msg, Player p, String regexUsed, String pl) { if (!type.equals(Types.NOTYPE)) { - blockedInt = new Integer(blockedInt.intValue() + 1); + blockedInt++; consoleSender.sendMessage("------- Match Type: " + type.id + " ~ " + pl.toUpperCase()); consoleSender.sendMessage("Match: " + regexUsed); consoleSender.sendMessage("Catch > " + p.getName() + ": " + msg); diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java b/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java index e777daf..a37f682 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java @@ -1,14 +1,15 @@ package a4.papers.chatfilter.chatfilter; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; - import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + public class Manager { ChatFilter chatFilter; + private static final Pattern HEX_PATTERN = Pattern.compile("&#" + "([A-Fa-f0-9]{6})"); public Manager(ChatFilter instance) { chatFilter = instance; @@ -30,8 +31,7 @@ public boolean supported(String string) { } public static String colorStringHex(String msg) { - final Pattern hexPattern = Pattern.compile("&#" + "([A-Fa-f0-9]{6})"); - Matcher matcher = hexPattern.matcher(msg); + Matcher matcher = HEX_PATTERN.matcher(msg); StringBuffer buffer = new StringBuffer(msg.length() + 4 * 8); while (matcher.find()) { String group = matcher.group(1); diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/commands/BlacklistCommand.java b/src/main/java/a4/papers/chatfilter/chatfilter/commands/BlacklistCommand.java index 6ed40fc..b07d9fd 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/commands/BlacklistCommand.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/commands/BlacklistCommand.java @@ -1,22 +1,23 @@ package a4.papers.chatfilter.chatfilter.commands; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.ConfigurationSection; + import a4.papers.chatfilter.chatfilter.ChatFilter; +import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.ConfigurationSection; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; public class BlacklistCommand implements CommandExecutor { @@ -44,8 +45,8 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } if (args[2].equals("ip")) { List strlist = new ArrayList<>(); - for (String words : chatFilter.regexAdvert.keySet()) { - strlist.add(chatFilter.regexAdvert.get(words).getWord()); + for (FilterWrapper wrapper : chatFilter.regexAdvert.values()) { + strlist.add(wrapper.getWord()); } Collections.sort(strlist); sender.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.CMD_BLACKLIST_LIST_IP_2.s))); @@ -67,14 +68,16 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } if (args[2].equals("word")) { List strlist = new ArrayList<>(); - for (String stringlist : chatFilter.regexWords.keySet()) { - strlist.add(chatFilter.regexWords.get(stringlist).getWord()); + for (FilterWrapper wrapper : chatFilter.regexWords.values()) { + String word = wrapper.getWord(); + if (!strlist.contains(word)) { + strlist.add(word); + } } - List listWithoutDuplicates = strlist.stream().distinct().collect(Collectors.toList()); - Collections.sort(listWithoutDuplicates); + Collections.sort(strlist); if (chatFilter.manager.supported("text-component")) { ComponentBuilder message = new ComponentBuilder(""); - for (String words : listWithoutDuplicates) { + for (String words : strlist) { message.append(ChatColor.WHITE + " " + words + ", "); message.event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/cf blacklist remove word " + words)); message.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.CMD_BLACKLIST_LIST_WORD_1.s).replace("%word%", words))))); @@ -110,7 +113,12 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String return true; } if (args[2].equals("word") && args.length > 3) { - String ArgsString = String.join(" ", args).toLowerCase().replaceAll("blacklist remove word ", ""); + StringBuilder sb = new StringBuilder(); + for (int i = 3; i < args.length; i++) { + if (i > 3) sb.append(' '); + sb.append(args[i]); + } + String ArgsString = sb.toString().toLowerCase(); ConfigurationSection config = chatFilter.getWordConfig().getConfigurationSection("ChatFilter"); Set set = config.getKeys(false); if (!set.contains(ArgsString)) { @@ -153,7 +161,12 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String sender.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.CMD_BLACKLIST_ADD_IP_ARG.s))); return true; } else if (args[2].equals("word") && args.length > 3) { - String argsString = String.join(" ", args).toLowerCase().replace("blacklist add word ", ""); + StringBuilder sb = new StringBuilder(); + for (int i = 3; i < args.length; i++) { + if (i > 3) sb.append(' '); + sb.append(args[i]); + } + String argsString = sb.toString().toLowerCase(); if (matchStringAdd(argsString)) { sender.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.CMD_BLACKLIST_ADD_WORD_NO.s).replace("%word%", argsString))); } else { @@ -161,7 +174,12 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String chatFilter.getFilters().createWordFilter(argsString, sender.getName()); } } else if (args[2].equals("ip") && args.length > 3) { - String argsString = String.join(" ", args).toLowerCase().replaceAll("blacklist add ip ", ""); + StringBuilder sb = new StringBuilder(); + for (int i = 3; i < args.length; i++) { + if (i > 3) sb.append(' '); + sb.append(args[i]); + } + String argsString = sb.toString().toLowerCase(); sender.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.CMD_BLACKLIST_ADD_IP_ADDED.s).replace("%ip%", argsString))); chatFilter.getFilters().createAdvertFilter(argsString, sender.getName()); return true; diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/commands/ImportCommand.java b/src/main/java/a4/papers/chatfilter/chatfilter/commands/ImportCommand.java index 1f5a626..a4ea9eb 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/commands/ImportCommand.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/commands/ImportCommand.java @@ -1,15 +1,16 @@ package a4.papers.chatfilter.chatfilter.commands; -import a4.papers.chatfilter.chatfilter.ChatFilter; -import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; + import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; +import a4.papers.chatfilter.chatfilter.ChatFilter; +import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; public class ImportCommand implements CommandExecutor { @@ -32,18 +33,27 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } public void load(CommandSender sender) { - try { - File fileObj = new File(chatFilter.getDataFolder(), "data.txt"); - BufferedReader reader = new BufferedReader(new FileReader(fileObj)); - String l; - while ((l = reader.readLine()) != null) { - String word = l.replace(" ", ""); - chatFilter.getFilters().createWordFilter(word, "Imported by " + sender.getName()); - sender.sendMessage(word + ChatColor.GOLD + " Added to filter."); - } - reader.close(); - } catch (Throwable t) { + File fileObj = new File(chatFilter.getDataFolder(), "data.txt"); + if (!fileObj.exists()) { sender.sendMessage(ChatColor.RED + "data.txt file is not found"); + return; + } + + try (BufferedReader reader = new BufferedReader(new FileReader(fileObj))) { + String line; + int count = 0; + String importedBy = "Imported by " + sender.getName(); + + while ((line = reader.readLine()) != null) { + String word = line.trim().toLowerCase(); + if (!word.isEmpty() && word.length() > 1) { + chatFilter.getFilters().createWordFilter(word, importedBy); + count++; + } + } + sender.sendMessage(ChatColor.GOLD + "Successfully imported " + count + " words to filter."); + } catch (Exception e) { + sender.sendMessage(ChatColor.RED + "Error reading data.txt: " + e.getMessage()); } } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/commands/WhitelistCommand.java b/src/main/java/a4/papers/chatfilter/chatfilter/commands/WhitelistCommand.java index 71b1ced..a40e1b0 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/commands/WhitelistCommand.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/commands/WhitelistCommand.java @@ -1,5 +1,12 @@ package a4.papers.chatfilter.chatfilter.commands; +import java.util.Collections; +import java.util.List; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + import a4.papers.chatfilter.chatfilter.ChatFilter; import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; import net.md_5.bungee.api.ChatColor; @@ -7,12 +14,6 @@ import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; public class WhitelistCommand implements CommandExecutor { @@ -92,7 +93,12 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String return true; } if (args[2].equals("ip") && args.length > 3) { - String ArgsString = String.join(" ", args).toLowerCase().replaceAll("whitelist add ip ", ""); + StringBuilder sb = new StringBuilder(); + for (int i = 3; i < args.length; i++) { + if (i > 3) sb.append(' '); + sb.append(args[i]); + } + String ArgsString = sb.toString().toLowerCase(); List list = chatFilter.getWhitelistConfig().getStringList("bypassIP"); if (list.contains(ArgsString)) { sender.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.CMD_WHITELIST_ADD_IP_NO.s).replace("%ip%", ArgsString))); @@ -107,7 +113,12 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } } if (args[2].equals("word") && args.length > 3) { - String ArgsString = String.join(" ", args).toLowerCase().replaceAll("whitelist add word ", ""); + StringBuilder sb = new StringBuilder(); + for (int i = 3; i < args.length; i++) { + if (i > 3) sb.append(' '); + sb.append(args[i]); + } + String ArgsString = sb.toString().toLowerCase(); List list = chatFilter.getWhitelistConfig().getStringList("bypassWords"); if (list.contains(ArgsString)) { sender.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.CMD_WHITELIST_ADD_WORD_NO.s).replace("%word%", ArgsString))); @@ -141,7 +152,12 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String sender.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.NO_PERMISSION.s))); return true; } - String ArgsString = String.join(" ", args).toLowerCase().replaceAll("whitelist remove word ", ""); + StringBuilder sb = new StringBuilder(); + for (int i = 3; i < args.length; i++) { + if (i > 3) sb.append(' '); + sb.append(args[i]); + } + String ArgsString = sb.toString().toLowerCase(); List list = chatFilter.getWhitelistConfig().getStringList("bypassWords"); if (!list.contains(ArgsString)) { sender.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.CMD_WHITELIST_REMOVE_WORD_NO.s).replace("%word%", ArgsString))); diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/AnvilListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/AnvilListener.java index bb00024..e167f0e 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/AnvilListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/AnvilListener.java @@ -1,14 +1,11 @@ package a4.papers.chatfilter.chatfilter.events; -import a4.papers.chatfilter.chatfilter.ChatFilter; -import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; -import a4.papers.chatfilter.chatfilter.shared.Result; -import a4.papers.chatfilter.chatfilter.shared.Types; -import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; import org.bukkit.ChatColor; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; -import org.bukkit.event.*; +import org.bukkit.event.Event; +import org.bukkit.event.EventException; +import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.AnvilInventory; import org.bukkit.inventory.Inventory; @@ -17,6 +14,12 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.plugin.EventExecutor; +import a4.papers.chatfilter.chatfilter.ChatFilter; +import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; +import a4.papers.chatfilter.chatfilter.shared.Result; +import a4.papers.chatfilter.chatfilter.shared.Types; +import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; + public class AnvilListener implements EventExecutor, Listener { ChatFilter chatFilter; @@ -82,8 +85,9 @@ public void onInventoryClick(InventoryClickEvent event) { if (filterWrapper.getLogToConsole()) chatFilter.sendConsole(type, displayName, p, filterWrapper.getRegex(), "Anvil"); if (filterWrapper.getSendStaff()) { - for (String oneWord : chatFilter.getChatFilters().validResult(displayName, p).getStringArray()) { - displayName = displayName.replace(oneWord, chatFilter.colour(chatFilter.settingsSwearHighLight.replace("%catch%", oneWord))); + String highlightColored = chatFilter.colour(chatFilter.settingsSwearHighLight); + for (String oneWord : stringArray) { + displayName = displayName.replace(oneWord, highlightColored.replace("%catch%", oneWord)); } chatFilter.sendStaffMessage(chatFilter.colour(prefix + displayName)); } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java index 7c5c6d3..538117e 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java @@ -1,10 +1,9 @@ package a4.papers.chatfilter.chatfilter.events; -import a4.papers.chatfilter.chatfilter.ChatFilter; -import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; -import a4.papers.chatfilter.chatfilter.shared.Result; -import a4.papers.chatfilter.chatfilter.shared.Types; -import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -15,9 +14,11 @@ import org.bukkit.plugin.EventExecutor; import org.bukkit.scheduler.BukkitRunnable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import a4.papers.chatfilter.chatfilter.ChatFilter; +import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; +import a4.papers.chatfilter.chatfilter.shared.Result; +import a4.papers.chatfilter.chatfilter.shared.Types; +import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; public class BooksListener implements EventExecutor, Listener { ChatFilter chatFilter; @@ -98,9 +99,10 @@ public void run() { } if (filterWrapper.getSendStaff()) { chatFilter.sendStaffMessage(chatFilter.colour(prefix)); + String highlightColored = chatFilter.colour(chatFilter.settingsSwearHighLight); for (String page : bookPageMatch) { for (String oneWord : catchMatch) { - page = page.replace(oneWord, chatFilter.colour(chatFilter.settingsSwearHighLight.replace("%catch%", oneWord))); + page = page.replace(oneWord, highlightColored.replace("%catch%", oneWord)); } chatFilter.sendStaffMessage(page); } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/CapsChatListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/CapsChatListener.java index 755588b..a7efedb 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/CapsChatListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/CapsChatListener.java @@ -1,14 +1,14 @@ package a4.papers.chatfilter.chatfilter.events; -import a4.papers.chatfilter.chatfilter.ChatFilter; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.*; +import org.bukkit.event.Event; +import org.bukkit.event.EventException; +import org.bukkit.event.Listener; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.plugin.EventExecutor; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import a4.papers.chatfilter.chatfilter.ChatFilter; public class CapsChatListener implements EventExecutor, Listener { @@ -51,12 +51,6 @@ public void onPlayerCaps(AsyncPlayerChatEvent event) { } public boolean isURL(String str) { - boolean matched = false; - Pattern p = Pattern.compile(chatFilter.URL_REGEX); - Matcher m = p.matcher(str); - if (m.find()) { - matched = true; - } - return matched; + return chatFilter.urlPattern.matcher(str).find(); } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/ChatDelayListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/ChatDelayListener.java index 5d898f4..311bc16 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/ChatDelayListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/ChatDelayListener.java @@ -21,12 +21,19 @@ public class ChatDelayListener implements EventExecutor, Listener { public Map chatmsgs = new HashMap(); ChatFilter chatFilter; - private HashMap chatMSG = new HashMap<>(); - private HashMap cooldown = new HashMap<>(); + private BigDecimal similarityThreshold; public ChatDelayListener(ChatFilter instance) { chatFilter = instance; } + + private BigDecimal getSimilarityThreshold() { + if (similarityThreshold == null) { + String percent = chatFilter.percentage.trim().replace("%", ""); + similarityThreshold = new BigDecimal(percent).divide(BigDecimal.valueOf(100)); + } + return similarityThreshold; + } @Override public void execute(final Listener listener, final Event event) throws EventException { @@ -38,38 +45,38 @@ public void onPlayerSpam(AsyncPlayerChatEvent e) { if (!chatFilter.antiRepeatEnabled) { return; } - if (e.getPlayer().hasPermission("chatfilter.bypass") || e.getPlayer().hasPermission("chatfilter.bypass.repeat")) - return; + Player p = e.getPlayer(); + if (p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.repeat")) { + return; + } + UUID playerUUID = p.getUniqueId(); String msg = e.getMessage(); - chatmsgs.containsKey(playerUUID); + long currentTime = System.currentTimeMillis(); long configtime = chatFilter.repeatDelay * 1000L; - if (!p.hasPermission("chatfilter.bypass") || !e.getPlayer().hasPermission("chatfilter.bypass.repeat") && chatFilter.antiRepeatEnabled) { - if (chatmsgs.containsKey(playerUUID)) { - long time = chatmsgs.get(playerUUID).getLong(); - double sim = StringSimilarity.similarity(msg, chatmsgs.get(playerUUID).getString()); - BigDecimal d = new BigDecimal(chatFilter.percentage.trim().replace("%", "")).divide(BigDecimal.valueOf(100)); - if (sim > d.doubleValue()) { - if (time > System.currentTimeMillis()) { - e.setCancelled(true); - int remainingTime = Math.round((this.chatmsgs.get(playerUUID).getLong() - System.currentTimeMillis()) / 1000 * 10) / 10; - String timeString = ""; - if (remainingTime >= 2) { - timeString = remainingTime + " seconds"; - } else { - timeString = 1 + " second"; - } - p.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.chatRepeatMessage.s).replace("%time%", timeString))); - } else { - chatmsgs.put(playerUUID, new ChatData(msg, System.currentTimeMillis() + configtime)); - } - } else { - chatmsgs.remove(playerUUID); - } + + ChatData chatData = chatmsgs.get(playerUUID); + if (chatData == null) { + chatmsgs.put(playerUUID, new ChatData(msg, currentTime + configtime)); + return; + } + + long expiryTime = chatData.getLong(); + double sim = StringSimilarity.similarity(msg, chatData.getString()); + + if (sim > getSimilarityThreshold().doubleValue()) { + if (expiryTime > currentTime) { + e.setCancelled(true); + long remainingMs = expiryTime - currentTime; + int remainingTime = (int) Math.ceil(remainingMs / 1000.0); + String timeString = remainingTime >= 2 ? remainingTime + " seconds" : "1 second"; + p.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.chatRepeatMessage.s).replace("%time%", timeString))); } else { - chatmsgs.put(playerUUID, new ChatData(msg, System.currentTimeMillis() + configtime)); + chatmsgs.put(playerUUID, new ChatData(msg, currentTime + configtime)); } + } else { + chatmsgs.put(playerUUID, new ChatData(msg, currentTime + configtime)); } } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java index 7614bc6..ba3a0bc 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java @@ -1,11 +1,6 @@ package a4.papers.chatfilter.chatfilter.events; -import a4.papers.chatfilter.chatfilter.ChatFilter; -import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; -import a4.papers.chatfilter.chatfilter.shared.Result; -import a4.papers.chatfilter.chatfilter.shared.Types; -import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -14,6 +9,12 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.plugin.EventExecutor; +import a4.papers.chatfilter.chatfilter.ChatFilter; +import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; +import a4.papers.chatfilter.chatfilter.shared.Result; +import a4.papers.chatfilter.chatfilter.shared.Types; +import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; + public class CommandListener implements EventExecutor, Listener { ChatFilter chatFilter; @@ -28,17 +29,19 @@ public void execute(final Listener listener, final Event event) throws EventExce public void onPlayerCommand(PlayerCommandPreprocessEvent event) { Player p = event.getPlayer(); - String cmd = ChatColor.stripColor(event.getMessage().toLowerCase()); - String[] array = cmd.split(" "); if (p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.command")) return; - if (event.isCancelled()) - return; - if (!chatFilter.cmdCheck) + if (event.isCancelled() || !chatFilter.cmdCheck) return; - if (chatFilter.getConfig().getConfigurationSection("commands").getKeys(false).contains(array[0].replace("/", ""))) { - boolean swearconfig = chatFilter.getConfig().getBoolean("commands." + array[0].replace("/", "") + ".swear"); - boolean dnsconfig = chatFilter.getConfig().getBoolean("commands." + array[0].replace("/", "") + ".ip"); + + String cmd = ChatColor.stripColor(event.getMessage().toLowerCase()); + String[] array = cmd.split(" "); + String commandName = array[0].replace("/", ""); + + if (chatFilter.getConfig().getConfigurationSection("commands").getKeys(false).contains(commandName)) { + String configPath = "commands." + commandName; + boolean swearconfig = chatFilter.getConfig().getBoolean(configPath + ".swear"); + boolean dnsconfig = chatFilter.getConfig().getBoolean(configPath + ".ip"); String prefix = "Error"; String warnPlayerMessage = "Error"; @@ -47,31 +50,30 @@ public void onPlayerCommand(PlayerCommandPreprocessEvent event) { Types type = result.getType(); String[] stringArray = result.getStringArray(); FilterWrapper filterWrapper = result.getFilterWrapper(); - if (type == Types.SWEAR && !swearconfig) { - return; - } - if (type == Types.IP_DNS && !dnsconfig) { + if ((type == Types.SWEAR && !swearconfig) || (type == Types.IP_DNS && !dnsconfig)) { return; } + + String placeHolder = chatFilter.getLang().stringArrayToString(stringArray); + String playerName = p.getName(); + if (type == Types.SWEAR && swearconfig) { - prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdSwear.s).replace("%player%", p.getName()); - warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnSwearMessage.s).replace("%placeHolder%", (chatFilter.getLang().stringArrayToString(stringArray))); - } - if (type == Types.IP_DNS && dnsconfig) { - prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdIP.s).replace("%player%", p.getName()); - warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnIPMessage.s).replace("%placeHolder%", (chatFilter.getLang().stringArrayToString(stringArray))); - } - if (type == Types.IP_SWEAR && dnsconfig && !swearconfig) { - prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdIP.s).replace("%player%", p.getName()); - warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnIPMessage.s).replace("%placeHolder%", (chatFilter.getLang().stringArrayToString(stringArray))); - } - if (type == Types.IP_SWEAR && !dnsconfig && swearconfig) { - prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdSwear.s).replace("%player%", p.getName()); - warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnSwearMessage.s).replace("%placeHolder%", (chatFilter.getLang().stringArrayToString(stringArray))); - } - if (type == Types.IP_SWEAR && dnsconfig && swearconfig) { - prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdIPandSwear.s).replace("%player%", p.getName()); - warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnSwearAndIPMessage.s).replace("%placeHolder%", (chatFilter.getLang().stringArrayToString(stringArray))); + prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdSwear.s).replace("%player%", playerName); + warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnSwearMessage.s).replace("%placeHolder%", placeHolder); + } else if (type == Types.IP_DNS && dnsconfig) { + prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdIP.s).replace("%player%", playerName); + warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnIPMessage.s).replace("%placeHolder%", placeHolder); + } else if (type == Types.IP_SWEAR) { + if (dnsconfig && swearconfig) { + prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdIPandSwear.s).replace("%player%", playerName); + warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnSwearAndIPMessage.s).replace("%placeHolder%", placeHolder); + } else if (dnsconfig) { + prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdIP.s).replace("%player%", playerName); + warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnIPMessage.s).replace("%placeHolder%", placeHolder); + } else if (swearconfig) { + prefix = chatFilter.getLang().mapToString(EnumStrings.prefixCmdSwear.s).replace("%player%", playerName); + warnPlayerMessage = chatFilter.getLang().mapToString(EnumStrings.warnSwearMessage.s).replace("%placeHolder%", placeHolder); + } } if (filterWrapper.getCancelChat()) { event.setCancelled(true); @@ -92,8 +94,9 @@ public void onPlayerCommand(PlayerCommandPreprocessEvent event) { p.sendMessage(chatFilter.colour(warnPlayerMessage)); } if (filterWrapper.getSendStaff()) { + String highlightColored = chatFilter.colour(chatFilter.settingsSwearHighLight); for (String oneWord : stringArray) { - cmd = cmd.replace(oneWord, chatFilter.colour( chatFilter.colour(chatFilter.settingsSwearHighLight.replace("%catch%",oneWord)))); + cmd = cmd.replace(oneWord, highlightColored.replace("%catch%", oneWord)); } chatFilter.sendStaffMessage(chatFilter.colour(prefix + cmd)); } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/PauseChat.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/PauseChat.java index c49df61..a4f505a 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/PauseChat.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/PauseChat.java @@ -1,12 +1,18 @@ package a4.papers.chatfilter.chatfilter.events; -import a4.papers.chatfilter.chatfilter.ChatFilter; -import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; -import org.bukkit.event.*; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.EventException; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.plugin.EventExecutor; +import a4.papers.chatfilter.chatfilter.ChatFilter; +import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; + public class PauseChat implements EventExecutor, Listener { ChatFilter chatFilter; @@ -20,18 +26,17 @@ public void execute(final Listener listener, final Event event) throws EventExce @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerChatPause(AsyncPlayerChatEvent event) { - if (event.isCancelled()) + if (event.isCancelled() || !chatFilter.chatPause) + return; + + Player player = event.getPlayer(); + if (player.hasPermission("chatfilter.bypass") || player.hasPermission("chatfilter.pause") || player.hasPermission("chatfilter.bypass.pause")) { return; - if (chatFilter.chatPause) { - if (event.getPlayer().hasPermission("chatfilter.bypass") || event.getPlayer().hasPermission("chatfilter.pause") || event.getPlayer().hasPermission("chatfilter.bypass.pause")) { - } else { - event.setCancelled(true); - event.getPlayer().sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.denyMessagePause.s))); - chatFilter.logMsg("[Chat filter] (Paused chat) " + event.getPlayer().getDisplayName() + ": " + event.getMessage()); - } - } - + + event.setCancelled(true); + player.sendMessage(chatFilter.colour(chatFilter.getLang().mapToString(EnumStrings.denyMessagePause.s))); + chatFilter.logMsg("[Chat filter] (Paused chat) " + player.getDisplayName() + ": " + event.getMessage()); } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/RepeatCharListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/RepeatCharListener.java index af98cd0..a498466 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/RepeatCharListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/RepeatCharListener.java @@ -1,14 +1,12 @@ package a4.papers.chatfilter.chatfilter.events; -import a4.papers.chatfilter.chatfilter.ChatFilter; import org.bukkit.event.Event; import org.bukkit.event.EventException; import org.bukkit.event.Listener; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.plugin.EventExecutor; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import a4.papers.chatfilter.chatfilter.ChatFilter; public class RepeatCharListener implements EventExecutor, Listener { @@ -37,12 +35,6 @@ public void onPlayerCarSpam(AsyncPlayerChatEvent event) { } public boolean isURL(String str) { - boolean matched = false; - Pattern p = Pattern.compile(chatFilter.URL_REGEX); - Matcher m = p.matcher(str); - if (m.find()) { - matched = true; - } - return matched; + return chatFilter.urlPattern.matcher(str).find(); } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java index 5f3a440..9cf63b2 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java @@ -1,10 +1,5 @@ package a4.papers.chatfilter.chatfilter.events; -import a4.papers.chatfilter.chatfilter.ChatFilter; -import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; -import a4.papers.chatfilter.chatfilter.shared.Result; -import a4.papers.chatfilter.chatfilter.shared.Types; -import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -13,6 +8,12 @@ import org.bukkit.event.block.SignChangeEvent; import org.bukkit.plugin.EventExecutor; +import a4.papers.chatfilter.chatfilter.ChatFilter; +import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; +import a4.papers.chatfilter.chatfilter.shared.Result; +import a4.papers.chatfilter.chatfilter.shared.Types; +import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; + public class SignListener implements EventExecutor, Listener { @@ -84,9 +85,10 @@ public void onSignEvent(SignChangeEvent event) { if (filterWrapper.getSendStaff()) { chatFilter.sendStaffMessage(chatFilter.colour(prefix)); } + String highlightColored = chatFilter.colour(chatFilter.settingsSwearHighLight); if (!event.getLine(0).isEmpty()) { for (String oneWord : stringArray) { - line0 = line0.replace(oneWord.replace(" ", ""), chatFilter.colour(chatFilter.settingsSwearHighLight.replace("%catch%", oneWord))); + line0 = line0.replace(oneWord.replace(" ", ""), highlightColored.replace("%catch%", oneWord)); line0Sign = line0Sign.replace(oneWord, filterWrapper.getReplace()); } if (!broken && filterWrapper.getCancelChatReplace()) @@ -98,7 +100,7 @@ public void onSignEvent(SignChangeEvent event) { if (!event.getLine(1).isEmpty()) { for (String oneWord : stringArray) { - line1 = line1.replace(oneWord.replace(" ", ""), chatFilter.colour(chatFilter.settingsSwearHighLight.replace("%catch%", oneWord))); + line1 = line1.replace(oneWord.replace(" ", ""), highlightColored.replace("%catch%", oneWord)); line1Sign = line1Sign.replace(oneWord, filterWrapper.getReplace()); } if (!broken && filterWrapper.getCancelChatReplace()) @@ -109,7 +111,7 @@ public void onSignEvent(SignChangeEvent event) { } if (!event.getLine(2).isEmpty()) { for (String oneWord : stringArray) { - line2 = line2.replace(oneWord.replace(" ", ""), chatFilter.colour(chatFilter.settingsSwearHighLight.replace("%catch%", oneWord))); + line2 = line2.replace(oneWord.replace(" ", ""), highlightColored.replace("%catch%", oneWord)); line2Sign = line2Sign.replace(oneWord, filterWrapper.getReplace()); } if (!broken && filterWrapper.getCancelChatReplace()) @@ -120,7 +122,7 @@ public void onSignEvent(SignChangeEvent event) { } if (!event.getLine(3).isEmpty()) { for (String oneWord : stringArray) { - line3 = line3.replace(oneWord.replace(" ", ""), chatFilter.colour(chatFilter.settingsSwearHighLight.replace("%catch%", oneWord))); + line3 = line3.replace(oneWord.replace(" ", ""), highlightColored.replace("%catch%", oneWord)); line3Sign = line3Sign.replace(oneWord, filterWrapper.getReplace()); } if (!broken && filterWrapper.getCancelChatReplace()) diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java index f4e1071..a85f5e3 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java @@ -1,13 +1,6 @@ package a4.papers.chatfilter.chatfilter.events; -import a4.papers.chatfilter.chatfilter.ChatFilter; -import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; -import a4.papers.chatfilter.chatfilter.shared.LowerCaseReplace; -import a4.papers.chatfilter.chatfilter.shared.Result; -import a4.papers.chatfilter.chatfilter.shared.Types; -import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -16,6 +9,13 @@ import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.plugin.EventExecutor; +import a4.papers.chatfilter.chatfilter.ChatFilter; +import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; +import a4.papers.chatfilter.chatfilter.shared.LowerCaseReplace; +import a4.papers.chatfilter.chatfilter.shared.Result; +import a4.papers.chatfilter.chatfilter.shared.Types; +import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; + public class SwearChatListener implements EventExecutor, Listener { ChatFilter chatFilter; @@ -76,8 +76,9 @@ public void onPlayerSwear(AsyncPlayerChatEvent event) { if (filterWrapper.getWarnPlayer()) p.sendMessage(chatFilter.colour(warnPlayerMessage)); if (filterWrapper.getSendStaff()) { + String highlightColored = chatFilter.colour(chatFilter.settingsSwearHighLight); for (String oneWord : stringArray) { - chatMessage = chatMessage.replace(oneWord, chatFilter.colour(chatFilter.settingsSwearHighLight.replace("%catch%", oneWord))); + chatMessage = chatMessage.replace(oneWord, highlightColored.replace("%catch%", oneWord)); } chatFilter.sendStaffMessage(chatFilter.colour(prefix + chatMessage)); } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java index 22d5a09..c593af8 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java @@ -1,12 +1,17 @@ package a4.papers.chatfilter.chatfilter.shared; -import a4.papers.chatfilter.chatfilter.ChatFilter; -import org.bukkit.entity.Player; - -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.bukkit.entity.Player; + +import a4.papers.chatfilter.chatfilter.ChatFilter; + public class ChatFilters { ChatFilter chatFilter; @@ -16,118 +21,145 @@ public ChatFilters(ChatFilter instance) { } private String removeBypass(String s) { - List bypassItems = new ArrayList(chatFilter.byPassWords); - bypassItems.addAll(chatFilter.byPassDNS); - for (String removewording : bypassItems) { + for (String removewording : chatFilter.byPassWords) { + if (s.contains(removewording)) { + s = s.replace(removewording, " "); + } + } + for (String removewording : chatFilter.byPassDNS) { if (s.contains(removewording)) { - s = s.replaceAll(removewording, " "); + s = s.replace(removewording, " "); } } return s; } public Result validResult(String string, Player player) { + String lowercaseString = removeBypass(string.toLowerCase()); + boolean matched = false; boolean matchedSwear = false; boolean matchedIP = false; boolean matchedURL = false; String regex = ""; - Map regexMap = new HashMap<>(); - String lowercaseString = removeBypass(string.toLowerCase()); - Types type = Types.NOTYPE; - List groupWords = new ArrayList(); - List regexUsed = new ArrayList(); - if (!(player.hasPermission("chatfilter.bypass.swear"))) { + boolean canBypassSwear = player.hasPermission("chatfilter.bypass.swear"); + boolean canBypassIP = player.hasPermission("chatfilter.bypass.ip"); + boolean canBypassURL = player.hasPermission("chatfilter.bypass.url"); + + List groupWords = new ArrayList<>(); + List regexUsed = new ArrayList<>(); + + // Check swear words + if (!canBypassSwear && !chatFilter.wordRegexPattern.isEmpty()) { for (Pattern p : chatFilter.wordRegexPattern) { Matcher m = p.matcher(lowercaseString); while (m.find()) { - if (!player.hasPermission("chatfilter.bypass.swear." + m.group(0))) + String match = m.group(0); + if (!player.hasPermission("chatfilter.bypass.swear." + match)) { matched = true; - matchedSwear = true; - regex = p.pattern(); - regexUsed.add(p.pattern()); - if (!groupWords.contains(m.group(0))) { - groupWords.add(m.group(0)); + matchedSwear = true; + regex = p.pattern(); + regexUsed.add(regex); + if (!groupWords.contains(match)) { + groupWords.add(match); + } } } } } - if (!(player.hasPermission("chatfilter.bypass.ip"))) { + if (!canBypassIP && !chatFilter.advertRegexPattern.isEmpty()) { for (Pattern p : chatFilter.advertRegexPattern) { Matcher m = p.matcher(lowercaseString); while (m.find()) { - if (!player.hasPermission("chatfilter.bypass.ip." + m.group(0))) + String match = m.group(0); + if (!player.hasPermission("chatfilter.bypass.ip." + match)) { matched = true; - matchedIP = true; - regex = p.pattern(); - if (!groupWords.contains(m.group(0))) { - groupWords.add(m.group(0)); + matchedIP = true; + regex = p.pattern(); + if (!groupWords.contains(match)) { + groupWords.add(match); + } } } } } - if (!(player.hasPermission("chatfilter.bypass.url"))) { - if (!chatFilter.settingsAllowURL) { - Pattern p = Pattern.compile(chatFilter.URL_REGEX); - Matcher m = p.matcher(lowercaseString); - if (m.find()) { - matched = true; - matchedURL = true; - regex = chatFilter.URL_REGEX; - } + // Build regex map only when needed + Map regexMap = new HashMap<>(); + + // Check URL + if (!canBypassURL && !chatFilter.settingsAllowURL) { + Matcher m = chatFilter.urlPattern.matcher(lowercaseString); + if (m.find()) { + matched = true; + matchedURL = true; + regex = chatFilter.URL_REGEX; regexMap.put(chatFilter.URL_REGEX, new FilterWrapper("URL", Collections.singletonList("none"), chatFilter.URL_REGEX, true, false, "", false, true, false)); } } - if (matchedURL) { - matched = true; - type = Types.URL; - } + // Check font if (isFont(string)) { matched = true; - type = Types.FONT; regex = "unicode"; regexMap.put("unicode", new FilterWrapper("unicode", Collections.singletonList("none"), "unicode", true, false, "", true, true, true)); - - } - if (matchedSwear) { - type = Types.SWEAR; - } - if (matchedIP) { - type = Types.IP_DNS; } + + // Determine type + Types type; if (matchedSwear && matchedIP) { type = Types.IP_SWEAR; + } else if (matchedSwear) { + type = Types.SWEAR; + } else if (matchedIP) { + type = Types.IP_DNS; + } else if (matchedURL) { + type = Types.URL; + } else if (matched) { + type = Types.FONT; + } else { + type = Types.NOTYPE; } - String[] array = new String[groupWords.size()]; - groupWords.toArray(array); + String[] array = groupWords.toArray(new String[groupWords.size()]); regexMap.putAll(chatFilter.regexWords); regexMap.putAll(chatFilter.regexAdvert); return new Result(matched, array, type, regexMap.get(regex), regexUsed); } public boolean isFont(String string) { - boolean matchedFont = false; + if (!chatFilter.settingsBlockFancyChat || chatFilter.unicodeBlacklist.isEmpty()) { + return false; + } + + // Remove whitelisted characters first + String processedString = string; for (String s : chatFilter.unicodeWhitelist) { - if (string.contains(s)) { - string = string.replace(s, ""); + if (processedString.contains(s)) { + processedString = processedString.replace(s, ""); } } - if (chatFilter.settingsBlockFancyChat) { - for (String s : chatFilter.unicodeBlacklist.keySet()) { - int UrangeLow = Integer.parseInt(chatFilter.unicodeBlacklist.get(s).getStart(), 16); - int UrangeHigh = Integer.parseInt(chatFilter.unicodeBlacklist.get(s).getEnd(), 16); - for (int iLetter = 0; iLetter < string.length(); iLetter++) { - int cp = string.codePointAt(iLetter); - if (cp >= UrangeLow && cp <= UrangeHigh) { - matchedFont = true; - } + + // Early exit if string is now empty + if (processedString.isEmpty()) { + return false; + } + + // Check unicode ranges + for (UnicodeWrapper wrapper : chatFilter.unicodeBlacklist.values()) { + int urangeLow = wrapper.getStartInt(); + int urangeHigh = wrapper.getEndInt(); + + int length = processedString.length(); + for (int i = 0; i < length; ) { + int cp = processedString.codePointAt(i); + if (cp >= urangeLow && cp <= urangeHigh) { + return true; } + i += Character.charCount(cp); } } - return matchedFont; + return false; } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/LowerCaseReplace.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/LowerCaseReplace.java index 31cb0e9..6230a8f 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/LowerCaseReplace.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/LowerCaseReplace.java @@ -4,20 +4,29 @@ public class LowerCaseReplace { public static String replace(String source, String target, String replacement) { - StringBuilder sbSource = new StringBuilder(source); - StringBuilder sbSourceLower = new StringBuilder(source.toLowerCase()); + if (source == null || target == null || replacement == null) { + return source; + } + String searchString = target.toLowerCase(); - - int idx = 0; - while((idx = sbSourceLower.indexOf(searchString, idx)) != -1) { - sbSource.replace(idx, idx + searchString.length(), replacement); - sbSourceLower.replace(idx, idx + searchString.length(), replacement); - idx+= replacement.length(); + String sourceLower = source.toLowerCase(); + + int idx = sourceLower.indexOf(searchString); + if (idx == -1) { + return source; } - sbSourceLower.setLength(0); - sbSourceLower.trimToSize(); - sbSourceLower = null; - + + StringBuilder sbSource = new StringBuilder(source.length()); + int lastIdx = 0; + + while (idx != -1) { + sbSource.append(source, lastIdx, idx); + sbSource.append(replacement); + lastIdx = idx + searchString.length(); + idx = sourceLower.indexOf(searchString, lastIdx); + } + sbSource.append(source, lastIdx, source.length()); + return sbSource.toString(); } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/StringSimilarity.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/StringSimilarity.java index 0d6b242..5338820 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/StringSimilarity.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/StringSimilarity.java @@ -3,6 +3,10 @@ public class StringSimilarity { public static double similarity(String s1, String s2) { + if (s1.equals(s2)) { + return 1.0; + } + String longer = s1, shorter = s2; if (s1.length() < s2.length()) { longer = s2; @@ -12,31 +16,45 @@ public static double similarity(String s1, String s2) { if (longerLength == 0) { return 1.0; } + + int lengthDiff = longerLength - shorter.length(); + if (lengthDiff > longerLength / 2) { + return (double)(longerLength - lengthDiff) / longerLength; + } + return (longerLength - editDistance(longer, shorter)) / (double) longerLength; } public static int editDistance(String s1, String s2) { - s1 = s1.toLowerCase(); - s2 = s2.toLowerCase(); - - int[] costs = new int[s2.length() + 1]; - for (int i = 0; i <= s1.length(); i++) { + // Convert to lowercase once + String s1Lower = s1.toLowerCase(); + String s2Lower = s2.toLowerCase(); + + int len1 = s1Lower.length(); + int len2 = s2Lower.length(); + + // Early exit for empty strings + if (len1 == 0) return len2; + if (len2 == 0) return len1; + + int[] costs = new int[len2 + 1]; + for (int i = 0; i <= len1; i++) { int lastValue = i; - for (int j = 0; j <= s2.length(); j++) { - if (i == 0) costs[j] = j; - else { - if (j > 0) { - int newValue = costs[j - 1]; - if (s1.charAt(i - 1) != s2.charAt(j - 1)) - newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1; - costs[j - 1] = lastValue; - lastValue = newValue; + for (int j = 0; j <= len2; j++) { + if (i == 0) { + costs[j] = j; + } else if (j > 0) { + int newValue = costs[j - 1]; + if (s1Lower.charAt(i - 1) != s2Lower.charAt(j - 1)) { + newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1; } + costs[j - 1] = lastValue; + lastValue = newValue; } } - if (i > 0) costs[s2.length()] = lastValue; + if (i > 0) costs[len2] = lastValue; } - return costs[s2.length()]; + return costs[len2]; } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/UnicodeWrapper.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/UnicodeWrapper.java index 9253ad9..8123325 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/UnicodeWrapper.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/UnicodeWrapper.java @@ -4,10 +4,14 @@ public class UnicodeWrapper { private final String start; private final String end; + private final int startInt; + private final int endInt; public UnicodeWrapper(String start, String end) { this.start = start; this.end = end; + this.startInt = Integer.parseInt(start, 16); + this.endInt = Integer.parseInt(end, 16); } public String getStart() { @@ -17,5 +21,13 @@ public String getStart() { public String getEnd() { return this.end; } + + public int getStartInt() { + return this.startInt; + } + + public int getEndInt() { + return this.endInt; + } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/lang/LangManager.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/lang/LangManager.java index 15c2a34..9cb727f 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/lang/LangManager.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/lang/LangManager.java @@ -1,12 +1,16 @@ package a4.papers.chatfilter.chatfilter.shared.lang; -import a4.papers.chatfilter.chatfilter.ChatFilter; - import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.*; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +import a4.papers.chatfilter.chatfilter.ChatFilter; public class LangManager { @@ -26,16 +30,18 @@ public String mapToString(String s) { } public String stringArrayToString(String[] strArr) { - StringBuilder sb = new StringBuilder(); - String prefix = ""; - for (String str : strArr) - if (strArr.length > 1) { - sb.append(prefix); - prefix = ", "; - sb.append(str.replace(" ", "")); - } else { - sb.append(str.replace(" ", "")); - } + if (strArr.length == 0) { + return ""; + } + if (strArr.length == 1) { + return strArr[0].replace(" ", ""); + } + + StringBuilder sb = new StringBuilder(strArr.length * 10); + sb.append(strArr[0].replace(" ", "")); + for (int i = 1; i < strArr.length; i++) { + sb.append(", ").append(strArr[i].replace(" ", "")); + } return sb.toString(); } @@ -54,7 +60,7 @@ public void loadLang() throws MalformedURLException { } Map convertResourceBundleToMap(ResourceBundle resource) { - Map map = new HashMap(); + Map map = new HashMap<>(); Enumeration keys = resource.getKeys(); while (keys.hasMoreElements()) { String key = keys.nextElement(); @@ -94,6 +100,7 @@ private void setupLanguageFiles() { if (!lang_plFile.exists()) { chatFilter.saveResource("messages_pl.properties", false); } + break; case "da": locale = DanishLocale; File lang_daFile = new File(chatFilter.getDataFolder().getAbsolutePath(), "messages_da.properties"); diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/regexHandler/LoadFilters.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/regexHandler/LoadFilters.java index bf3f769..7deff73 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/regexHandler/LoadFilters.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/regexHandler/LoadFilters.java @@ -1,12 +1,13 @@ package a4.papers.chatfilter.chatfilter.shared.regexHandler; +import java.util.List; +import java.util.regex.Pattern; + +import org.bukkit.configuration.ConfigurationSection; + import a4.papers.chatfilter.chatfilter.ChatFilter; import a4.papers.chatfilter.chatfilter.shared.FilterWrapper; import a4.papers.chatfilter.chatfilter.shared.UnicodeWrapper; -import org.bukkit.configuration.ConfigurationSection; - -import java.util.List; -import java.util.regex.Pattern; public class LoadFilters { @@ -155,13 +156,11 @@ public void reloadFilters() { } public void regexCompile() { - for (String StringMatchedDNS : chatFilter.regexAdvert.keySet()) { - Pattern p = Pattern.compile(StringMatchedDNS); - chatFilter.advertRegexPattern.add(p); + for (String pattern : chatFilter.regexAdvert.keySet()) { + chatFilter.advertRegexPattern.add(Pattern.compile(pattern)); } - for (String StringMatchedWords : chatFilter.regexWords.keySet()) { - Pattern p = Pattern.compile(StringMatchedWords); - chatFilter.wordRegexPattern.add(p); + for (String pattern : chatFilter.regexWords.keySet()) { + chatFilter.wordRegexPattern.add(Pattern.compile(pattern)); } } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/regexHandler/RegexpGenerator.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/regexHandler/RegexpGenerator.java index 1294814..00a4e23 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/regexHandler/RegexpGenerator.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/regexHandler/RegexpGenerator.java @@ -10,7 +10,7 @@ public RegexpGenerator(ChatFilter instance) { } public String generateRegexp(String s) { - StringBuilder stringBuilder = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(s.length() * 15); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); String chars = String.valueOf(c); @@ -43,9 +43,11 @@ public String generateRegexp(String s) { } String toLeetSpeak(String speak) { - StringBuilder sb = new StringBuilder(speak.length()); - if (chatFilter.enableLeetSpeak) - for (char c : speak.toCharArray()) { + if (!chatFilter.enableLeetSpeak) { + return speak; + } + StringBuilder sb = new StringBuilder(speak.length() * 2); + for (char c : speak.toCharArray()) { switch (c) { case 'a': sb.append("@|a|4"); @@ -129,7 +131,7 @@ String toLeetSpeak(String speak) { sb.append(c); break; } - } + } return sb.toString(); } } From 3b31b2a13ded65ad8b898aa90a0682b6cd84988c Mon Sep 17 00:00:00 2001 From: OPmasterLEO <98689894+OPmasterLEO@users.noreply.github.com> Date: Fri, 16 Jan 2026 22:34:49 +0100 Subject: [PATCH 6/8] Add option to block non-English letters in chat --- .../chatfilter/chatfilter/ChatFilter.java | 2 ++ .../chatfilter/events/SwearChatListener.java | 17 +++++++++++++++ .../chatfilter/shared/ChatFilters.java | 21 +++++++++++++++++++ src/main/resources/config.yml | 3 +++ 4 files changed, 43 insertions(+) diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java index 9af9983..8016ea3 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java @@ -85,6 +85,7 @@ public class ChatFilter extends JavaPlugin { public boolean CommandsOnSwearAndAdvertisesEnabled; public boolean settingsAllowURL; public boolean settingsBlockFancyChat; + public boolean settingsBlockCustomSybols; public boolean CommandsOnFontEnabled; public boolean deCap; public boolean chatPause = false; @@ -216,6 +217,7 @@ public void loadVariables() { this.CommandsOnSwearAndAdvertisesCommand = getConfig().getString("CommandsOnSwearAndAdvertises.command"); this.settingsAllowURL = getConfig().getBoolean("settings.allowURL"); this.settingsBlockFancyChat = getConfig().getBoolean("settings.blockFancyChat"); + this.settingsBlockCustomSybols = getConfig().getBoolean("settings.blockCustomSybols"); this.settingsSwearHighLight = getConfig().getString("settings.swearHighLight"); this.cmdCheck = getConfig().getBoolean("checkCommands"); this.capsAmount = getConfig().getInt("settings.capsAmount"); diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java index a85f5e3..a2d5886 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java @@ -15,6 +15,8 @@ import a4.papers.chatfilter.chatfilter.shared.Result; import a4.papers.chatfilter.chatfilter.shared.Types; import a4.papers.chatfilter.chatfilter.shared.lang.EnumStrings; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; public class SwearChatListener implements EventExecutor, Listener { @@ -41,6 +43,21 @@ public void onPlayerSwear(AsyncPlayerChatEvent event) { return; if (chatFilter.chatPause) return; + // Early check for non-English letters if enabled (after bypass/pause checks) + if (chatFilter.settingsBlockCustomSybols) { + String rawMessage = ChatColor.stripColor(event.getMessage()); + if (chatFilter.getChatFilters().containsNonEnglishLetters(rawMessage)) { + String deny = "&cYour message was not sent due to containing disallowed characters."; + p.sendMessage(chatFilter.colour(deny)); + try { + p.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(chatFilter.colour(deny))); + } catch (Throwable ignored) { + // Fallback silently if actionbar is unavailable + } + event.setCancelled(true); + return; + } + } Result result = chatFilter.getChatFilters().validResult(chatMessage, p); if (result.getResult()) { Types type = result.getType(); diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java index c593af8..22f2592 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java @@ -162,4 +162,25 @@ public boolean isFont(String string) { } return false; } + + public boolean containsNonEnglishLetters(String string) { + if (!chatFilter.settingsBlockCustomSybols) { + return false; + } + if (string == null || string.isEmpty()) { + return false; + } + int length = string.length(); + for (int i = 0; i < length;) { + int cp = string.codePointAt(i); + // Only consider letters; allow digits, symbols, whitespace + if (Character.isLetter(cp)) { + if (!((cp >= 'A' && cp <= 'Z') || (cp >= 'a' && cp <= 'z'))) { + return true; + } + } + i += Character.charCount(cp); + } + return false; + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 39ce42d..0b156ca 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -58,6 +58,9 @@ settings: # Block fancy text? Often used with hacked clients. blockFancyChat: true + # Block non-English letters (allow numbers and symbols) + blockCustomSybols: true + # Prevent same or repeated messages antiRepeatEnabled: true From 8f61acd3bd546568f626bb48f8100360b241d015 Mon Sep 17 00:00:00 2001 From: OPmasterLEO <98689894+OPmasterLEO@users.noreply.github.com> Date: Sun, 8 Feb 2026 17:51:42 +0100 Subject: [PATCH 7/8] Migrate build from Maven to Gradle (Kotlin DSL) --- .gitignore | 4 ++ build.gradle.kts | 51 +++++++++++++++++++ pom.xml | 95 ----------------------------------- settings.gradle.kts | 8 +++ src/main/resources/plugin.yml | 4 +- 5 files changed, 65 insertions(+), 97 deletions(-) create mode 100644 build.gradle.kts delete mode 100644 pom.xml create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore index 4788b4b..689d6fe 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,10 @@ # IntelliJ out/ +# Gradle +.gradle/ +build/ + # Compiled class file *.class diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..c806b2a --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,51 @@ +plugins { + java + id("com.gradleup.shadow") version "9.3.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.19" +} + +group = "a4.papers.chatfilter" +version = "2.0.15" + +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + +repositories { + mavenCentral() + maven("https://repo.papermc.io/repository/maven-public/") + maven("https://oss.sonatype.org/content/groups/public/") + maven("https://jitpack.io") +} + +dependencies { + paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT") + implementation("com.github.Anon8281:UniversalScheduler:0.1.7") +} + +tasks { + compileJava { + options.encoding = "UTF-8" + } + + processResources { + filesMatching("plugin.yml") { + expand("version" to project.version) + } + } + + shadowJar { + archiveClassifier.set("") // Produces plain jar + // Use runtimeClasspath instead of implementation to fix Gradle 8+ issue + configurations = listOf(project.configurations.runtimeClasspath.get()) + relocate( + "com.github.Anon8281.universalScheduler", + "a4.papers.chatfilter.universalScheduler" + ) + } + + build { + dependsOn(shadowJar) + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 931921f..0000000 --- a/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - 4.0.0 - - a4.papers.chatfilter - ChatFilter - 2.0.15 - jar - - ChatFilter - - - 21 - UTF-8 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.14.0 - - ${java.version} - ${java.version} - - - - org.apache.maven.plugins - maven-shade-plugin - 3.6.0 - - - package - - shade - - - false - - - com.github.Anon8281:UniversalScheduler - - - - - com.github.Anon8281.universalScheduler - a4.papers.chatfilter.universalScheduler - - - - - - - - - - src/main/resources - true - - - - - - - papermc - https://repo.papermc.io/repository/maven-public/ - - - sonatype - https://oss.sonatype.org/content/groups/public/ - - - jitpack.io - https://jitpack.io - - - - - - io.papermc.paper - paper-api - 1.21.8-R0.1-SNAPSHOT - provided - - - com.github.Anon8281 - UniversalScheduler - 0.1.7 - compile - - - diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..9ca48bb --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,8 @@ +rootProject.name = "ChatFilter" + +pluginManagement { + repositories { + gradlePluginPortal() + maven("https://repo.papermc.io/repository/maven-public/") + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ce99f01..351a25e 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ -name: ${project.name} -version: ${project.version} +name: ChatFilter +version: ${version} main: a4.papers.chatfilter.chatfilter.ChatFilter api-version: 1.21 folia-supported: true From f287a53617d94dc3982122414142b50b09ad68d2 Mon Sep 17 00:00:00 2001 From: OPmasterLEO <98689894+OPmasterLEO@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:02:18 +0100 Subject: [PATCH 8/8] Add op bypass checks; refactor color parsing --- .../chatfilter/chatfilter/ChatFilter.java | 8 ++++---- .../papers/chatfilter/chatfilter/Manager.java | 17 ++++++++++------- .../chatfilter/events/AnvilListener.java | 11 ++++++----- .../chatfilter/events/BooksListener.java | 2 +- .../chatfilter/events/CapsChatListener.java | 11 ++++++----- .../chatfilter/events/ChatDelayListener.java | 3 +-- .../chatfilter/events/CommandListener.java | 3 +-- .../chatfilter/chatfilter/events/PauseChat.java | 3 +-- .../chatfilter/events/RepeatCharListener.java | 3 ++- .../chatfilter/events/SignListener.java | 2 +- .../chatfilter/events/SwearChatListener.java | 3 +-- .../chatfilter/shared/ChatFilters.java | 7 ++++--- 12 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java index 8016ea3..f152ae6 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/ChatFilter.java @@ -256,11 +256,11 @@ public void loadVariables() { public String colour(String s) { if (manager.supported("hex")) { - return Manager.colorStringHex(s); + String result = Manager.colorStringHex(s); + return result; } else { - return LEGACY_SERIALIZER.serialize( - LEGACY_SERIALIZER.deserialize(s) - ); + String deserialized = LEGACY_SERIALIZER.serialize(LEGACY_SERIALIZER.deserialize(s)); + return deserialized; } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java b/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java index a37f682..87547cc 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/Manager.java @@ -32,15 +32,18 @@ public boolean supported(String string) { public static String colorStringHex(String msg) { Matcher matcher = HEX_PATTERN.matcher(msg); - StringBuffer buffer = new StringBuffer(msg.length() + 4 * 8); + StringBuilder buffer = new StringBuilder(msg.length() + 4 * 8); + int lastEnd = 0; while (matcher.find()) { + buffer.append(msg, lastEnd, matcher.start()); String group = matcher.group(1); - matcher.appendReplacement(buffer, COLOR_CHAR + "x" - + COLOR_CHAR + group.charAt(0) + COLOR_CHAR + group.charAt(1) - + COLOR_CHAR + group.charAt(2) + COLOR_CHAR + group.charAt(3) - + COLOR_CHAR + group.charAt(4) + COLOR_CHAR + group.charAt(5) - ); + buffer.append(COLOR_CHAR).append("x") + .append(COLOR_CHAR).append(group.charAt(0)).append(COLOR_CHAR).append(group.charAt(1)) + .append(COLOR_CHAR).append(group.charAt(2)).append(COLOR_CHAR).append(group.charAt(3)) + .append(COLOR_CHAR).append(group.charAt(4)).append(COLOR_CHAR).append(group.charAt(5)); + lastEnd = matcher.end(); } - return ChatColor.translateAlternateColorCodes('&', matcher.appendTail(buffer).toString()); + buffer.append(msg.substring(lastEnd)); + return ChatColor.translateAlternateColorCodes('&', buffer.toString()); } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/AnvilListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/AnvilListener.java index e167f0e..8f54058 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/AnvilListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/AnvilListener.java @@ -33,12 +33,14 @@ public void execute(final Listener listener, final Event event) throws EventExce } public void onInventoryClick(InventoryClickEvent event) { - if (event.getWhoClicked().hasPermission("chatfilter.bypass") || event.getWhoClicked().hasPermission("chatfilter.bypass.anvil")) + HumanEntity ent = event.getWhoClicked(); + if (!(ent instanceof Player)) { + return; + } + Player p = (Player) ent; + if (p.isOp() || p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.anvil")) return; if (!event.isCancelled()) { - HumanEntity ent = event.getWhoClicked(); - if (ent instanceof Player) { - Player p = (Player) ent; Inventory inv = event.getInventory(); if (inv instanceof AnvilInventory) { InventoryView view = event.getView(); @@ -98,7 +100,6 @@ public void onInventoryClick(InventoryClickEvent event) { } } } - } } } } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java index 538117e..276ea7a 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/BooksListener.java @@ -33,7 +33,7 @@ public void execute(final Listener listener, final Event event) throws EventExce public void onBookEvent(PlayerEditBookEvent event) { Player p = event.getPlayer(); - if (event.getPlayer().hasPermission("chatfilter.bypass") || event.getPlayer().hasPermission("chatfilter.bypass.book")) + if (p.isOp() || p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.book")) return; List catchMatch = new ArrayList<>(); List bookPageMatch = new ArrayList<>(); diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/CapsChatListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/CapsChatListener.java index a7efedb..6d48a07 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/CapsChatListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/CapsChatListener.java @@ -26,7 +26,8 @@ public void execute(final Listener listener, final Event event) throws EventExce public void onPlayerCaps(AsyncPlayerChatEvent event) { String msg = event.getMessage(); if (chatFilter.deCap) { - if (event.getPlayer().hasPermission("chatfilter.bypass") || event.getPlayer().hasPermission("chatfilter.bypass.caps")) + Player player = event.getPlayer(); + if (player.isOp() || player.hasPermission("chatfilter.bypass") || player.hasPermission("chatfilter.bypass.caps")) return; if (isURL(msg)) return; @@ -39,11 +40,11 @@ public void onPlayerCaps(AsyncPlayerChatEvent event) { msg = msg.charAt(0) + msg.substring(1).toLowerCase(); } String newmsg = msg; - for (Player p : Bukkit.getOnlinePlayers()) { - String player = p.getName(); + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + String playerName = onlinePlayer.getName(); - if (msg.toLowerCase().contains(player.toLowerCase())) { - newmsg = newmsg.replace(player.toLowerCase(), player); + if (msg.toLowerCase().contains(playerName.toLowerCase())) { + newmsg = newmsg.replace(playerName.toLowerCase(), playerName); } } event.setMessage(newmsg); diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/ChatDelayListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/ChatDelayListener.java index 311bc16..f92892b 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/ChatDelayListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/ChatDelayListener.java @@ -1,6 +1,5 @@ package a4.papers.chatfilter.chatfilter.events; - import a4.papers.chatfilter.chatfilter.ChatFilter; import a4.papers.chatfilter.chatfilter.shared.ChatData; import a4.papers.chatfilter.chatfilter.shared.StringSimilarity; @@ -47,7 +46,7 @@ public void onPlayerSpam(AsyncPlayerChatEvent e) { } Player p = e.getPlayer(); - if (p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.repeat")) { + if (p.isOp() || p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.repeat")) { return; } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java index ba3a0bc..b65e07c 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/CommandListener.java @@ -1,6 +1,5 @@ package a4.papers.chatfilter.chatfilter.events; - import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -29,7 +28,7 @@ public void execute(final Listener listener, final Event event) throws EventExce public void onPlayerCommand(PlayerCommandPreprocessEvent event) { Player p = event.getPlayer(); - if (p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.command")) + if (p.isOp() || p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.command")) return; if (event.isCancelled() || !chatFilter.cmdCheck) return; diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/PauseChat.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/PauseChat.java index a4f505a..5bf87a2 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/PauseChat.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/PauseChat.java @@ -1,6 +1,5 @@ package a4.papers.chatfilter.chatfilter.events; - import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventException; @@ -30,7 +29,7 @@ public void onPlayerChatPause(AsyncPlayerChatEvent event) { return; Player player = event.getPlayer(); - if (player.hasPermission("chatfilter.bypass") || player.hasPermission("chatfilter.pause") || player.hasPermission("chatfilter.bypass.pause")) { + if (player.isOp() || player.hasPermission("chatfilter.bypass") || player.hasPermission("chatfilter.pause") || player.hasPermission("chatfilter.bypass.pause")) { return; } diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/RepeatCharListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/RepeatCharListener.java index a498466..a3dff2a 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/RepeatCharListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/RepeatCharListener.java @@ -24,7 +24,8 @@ public void execute(final Listener listener, final Event event) throws EventExce public void onPlayerCarSpam(AsyncPlayerChatEvent event) { String msg = event.getMessage(); if (chatFilter.antiSpamEnabled) { - if (event.getPlayer().hasPermission("chatfilter.bypass") || event.getPlayer().hasPermission("chatfilter.bypass.characters")) { + org.bukkit.entity.Player player = event.getPlayer(); + if (player.isOp() || player.hasPermission("chatfilter.bypass") || player.hasPermission("chatfilter.bypass.characters")) { return; } if (isURL(msg)) { diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java index 9cf63b2..930ff56 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/SignListener.java @@ -30,7 +30,7 @@ public void execute(final Listener listener, final Event event) throws EventExce public void onSignEvent(SignChangeEvent event) { Player p = event.getPlayer(); - if (p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.sign")) { + if (p.isOp() || p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.sign")) { return; } boolean broken = false; diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java b/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java index a2d5886..3cc0848 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/events/SwearChatListener.java @@ -1,6 +1,5 @@ package a4.papers.chatfilter.chatfilter.events; - import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -37,7 +36,7 @@ public void onPlayerSwear(AsyncPlayerChatEvent event) { String chatMessage = ChatColor.stripColor(event.getMessage()).toLowerCase(); String prefix = ""; String warnPlayerMessage = ""; - if (p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.chat")) + if (p.isOp() || p.hasPermission("chatfilter.bypass") || p.hasPermission("chatfilter.bypass.chat")) return; if (event.isCancelled()) return; diff --git a/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java b/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java index 22f2592..dc01a2f 100644 --- a/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java +++ b/src/main/java/a4/papers/chatfilter/chatfilter/shared/ChatFilters.java @@ -42,9 +42,10 @@ public Result validResult(String string, Player player) { boolean matchedIP = false; boolean matchedURL = false; String regex = ""; - boolean canBypassSwear = player.hasPermission("chatfilter.bypass.swear"); - boolean canBypassIP = player.hasPermission("chatfilter.bypass.ip"); - boolean canBypassURL = player.hasPermission("chatfilter.bypass.url"); + boolean isOp = player.isOp(); + boolean canBypassSwear = isOp || player.hasPermission("chatfilter.bypass.swear"); + boolean canBypassIP = isOp || player.hasPermission("chatfilter.bypass.ip"); + boolean canBypassURL = isOp || player.hasPermission("chatfilter.bypass.url"); List groupWords = new ArrayList<>(); List regexUsed = new ArrayList<>();