Skip to content

Commit 1386cfb

Browse files
Add comprehensive filtering and muting features
PistonFilter: - Sign, book, anvil, and command filtering - Unicode/special character filtering with configurable ranges - Message cooldown, anti-caps, and character repetition limits - Whitelist system for bypassing filters - Staff notifications for blocked messages - Chat pause and clear commands PistonMute: - Warning system with configurable expiry and auto-escalation - Progressive punishment templates (swearing, spam, advertising, harassment) - Mute reasons and detailed mute information - Punishment history tracking - Staff immunity/hierarchy system (immune and weight modes) - Notes system for players - Command logging to punishments.log - Command blocking for muted players - Alt account detection and tracking - Offline player muting support - Mute list and mute info commands Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent dcb563c commit 1386cfb

42 files changed

Lines changed: 6215 additions & 64 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

PistonFilter/src/main/java/net/pistonmaster/pistonfilter/PistonFilter.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77
import net.md_5.bungee.api.ChatColor;
88
import net.pistonmaster.pistonfilter.commands.FilterCommand;
99
import net.pistonmaster.pistonfilter.config.PistonFilterConfig;
10+
import net.pistonmaster.pistonfilter.listeners.AnvilListener;
11+
import net.pistonmaster.pistonfilter.listeners.BookListener;
1012
import net.pistonmaster.pistonfilter.listeners.ChatListener;
13+
import net.pistonmaster.pistonfilter.listeners.CommandListener;
14+
import net.pistonmaster.pistonfilter.listeners.SignListener;
15+
import net.pistonmaster.pistonfilter.managers.ChatPauseManager;
1116
import net.pistonmaster.pistonutils.update.GitHubUpdateChecker;
1217
import net.pistonmaster.pistonutils.update.SemanticVersion;
1318
import org.bstats.bukkit.Metrics;
@@ -30,6 +35,9 @@ public class PistonFilter extends JavaPlugin {
3035
@Getter
3136
private PistonFilterConfig pluginConfig;
3237

38+
@Getter
39+
private final ChatPauseManager chatPauseManager = new ChatPauseManager();
40+
3341
@Override
3442
public void onEnable() {
3543
Logger log = getLogger();
@@ -47,6 +55,10 @@ public void onEnable() {
4755

4856
log.info(ChatColor.AQUA + "Registering listeners");
4957
getServer().getPluginManager().registerEvents(new ChatListener(this), this);
58+
getServer().getPluginManager().registerEvents(new SignListener(this), this);
59+
getServer().getPluginManager().registerEvents(new BookListener(this), this);
60+
getServer().getPluginManager().registerEvents(new AnvilListener(this), this);
61+
getServer().getPluginManager().registerEvents(new CommandListener(this), this);
5062

5163
log.info(ChatColor.AQUA + "Loading metrics");
5264
new Metrics(this, 11561);

PistonFilter/src/main/java/net/pistonmaster/pistonfilter/commands/FilterCommand.java

Lines changed: 121 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44
import net.md_5.bungee.api.ChatColor;
55
import net.pistonmaster.pistonfilter.PistonFilter;
66
import net.pistonmaster.pistonfilter.config.PistonFilterConfig;
7+
import org.bukkit.Bukkit;
78
import org.bukkit.command.Command;
89
import org.bukkit.command.CommandExecutor;
910
import org.bukkit.command.CommandSender;
1011
import org.bukkit.command.TabExecutor;
12+
import org.bukkit.entity.Player;
1113
import org.bukkit.util.StringUtil;
1214

1315
import java.util.ArrayList;
1416
import java.util.Collections;
1517
import java.util.List;
18+
import java.util.Locale;
1619
import java.util.stream.Stream;
1720

1821
@RequiredArgsConstructor
@@ -21,44 +24,146 @@ public class FilterCommand implements CommandExecutor, TabExecutor {
2124

2225
@Override
2326
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
24-
if (sender.hasPermission("pistonfilter.admin") && args.length > 0) {
25-
if ("reload".equalsIgnoreCase(args[0])) {
27+
if (args.length == 0) {
28+
sendHelp(sender);
29+
return true;
30+
}
31+
32+
String subCommand = args[0].toLowerCase(Locale.ROOT);
33+
34+
switch (subCommand) {
35+
case "reload" -> {
36+
if (!sender.hasPermission("pistonfilter.admin")) {
37+
sender.sendMessage(ChatColor.RED + "You don't have permission to use this command.");
38+
return true;
39+
}
2640
plugin.loadConfig();
2741
sender.sendMessage(ChatColor.GOLD + "Reloaded the config!");
2842
}
29-
30-
if ("add".equalsIgnoreCase(args[0]) && args.length > 1) {
43+
case "add" -> {
44+
if (!sender.hasPermission("pistonfilter.admin")) {
45+
sender.sendMessage(ChatColor.RED + "You don't have permission to use this command.");
46+
return true;
47+
}
48+
if (args.length < 2) {
49+
sender.sendMessage(ChatColor.RED + "Usage: /filter add <text>");
50+
return true;
51+
}
3152
PistonFilterConfig config = plugin.getPluginConfig();
32-
3353
List<String> newBannedText = Stream.concat(config.bannedText.stream(), Stream.of(args[1])).toList();
3454
config.bannedText = newBannedText;
35-
3655
plugin.saveConfig(config);
37-
3856
sender.sendMessage(ChatColor.GOLD + "Successfully added the config entry!");
3957
}
58+
case "pause" -> {
59+
if (!sender.hasPermission("pistonfilter.pausechat")) {
60+
sender.sendMessage(ChatColor.RED + "You don't have permission to use this command.");
61+
return true;
62+
}
63+
if (plugin.getChatPauseManager().pause()) {
64+
sender.sendMessage(ChatColor.GREEN + "Chat has been paused.");
65+
notifyStaffChatPaused(sender, true);
66+
} else {
67+
sender.sendMessage(ChatColor.YELLOW + "Chat is already paused.");
68+
}
69+
}
70+
case "unpause", "resume" -> {
71+
if (!sender.hasPermission("pistonfilter.pausechat")) {
72+
sender.sendMessage(ChatColor.RED + "You don't have permission to use this command.");
73+
return true;
74+
}
75+
if (plugin.getChatPauseManager().unpause()) {
76+
sender.sendMessage(ChatColor.GREEN + "Chat has been resumed.");
77+
notifyStaffChatPaused(sender, false);
78+
} else {
79+
sender.sendMessage(ChatColor.YELLOW + "Chat is not paused.");
80+
}
81+
}
82+
case "clearchat", "clear" -> {
83+
if (!sender.hasPermission("pistonfilter.clearchat")) {
84+
sender.sendMessage(ChatColor.RED + "You don't have permission to use this command.");
85+
return true;
86+
}
87+
clearChat();
88+
sender.sendMessage(ChatColor.GREEN + "Chat has been cleared.");
89+
}
90+
default -> sendHelp(sender);
4091
}
4192

42-
return false;
93+
return true;
94+
}
95+
96+
private void sendHelp(CommandSender sender) {
97+
sender.sendMessage(ChatColor.GOLD + "PistonFilter Commands:");
98+
if (sender.hasPermission("pistonfilter.admin")) {
99+
sender.sendMessage(ChatColor.YELLOW + "/filter reload" + ChatColor.GRAY + " - Reload the config");
100+
sender.sendMessage(ChatColor.YELLOW + "/filter add <text>" + ChatColor.GRAY + " - Add banned text");
101+
}
102+
if (sender.hasPermission("pistonfilter.pausechat")) {
103+
sender.sendMessage(ChatColor.YELLOW + "/filter pause" + ChatColor.GRAY + " - Pause chat");
104+
sender.sendMessage(ChatColor.YELLOW + "/filter unpause" + ChatColor.GRAY + " - Resume chat");
105+
}
106+
if (sender.hasPermission("pistonfilter.clearchat")) {
107+
sender.sendMessage(ChatColor.YELLOW + "/filter clearchat" + ChatColor.GRAY + " - Clear chat");
108+
}
109+
}
110+
111+
private void notifyStaffChatPaused(CommandSender executor, boolean paused) {
112+
PistonFilterConfig config = plugin.getPluginConfig();
113+
String message = paused ? config.chatPausedStaffMessage : config.chatUnpausedStaffMessage;
114+
message = ChatColor.translateAlternateColorCodes('&', message.replace("%player%", executor.getName()));
115+
116+
for (Player player : Bukkit.getOnlinePlayers()) {
117+
if (player.hasPermission("pistonfilter.notify") && !player.equals(executor)) {
118+
player.sendMessage(message);
119+
}
120+
}
121+
}
122+
123+
private void clearChat() {
124+
PistonFilterConfig config = plugin.getPluginConfig();
125+
int lines = config.clearChatLines;
126+
127+
StringBuilder blankLines = new StringBuilder();
128+
for (int i = 0; i < lines; i++) {
129+
blankLines.append("\n");
130+
}
131+
String clearMessage = blankLines.toString();
132+
133+
for (Player player : Bukkit.getOnlinePlayers()) {
134+
// Don't clear chat for staff who have the bypass permission
135+
if (!player.hasPermission("pistonfilter.clearchat.bypass")) {
136+
player.sendMessage(clearMessage);
137+
}
138+
}
43139
}
44140

45141
@Override
46142
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
47143
if (args.length == 1) {
48-
List<String> suggestion = new ArrayList<>();
144+
List<String> suggestions = new ArrayList<>();
49145

50-
suggestion.add("add");
51-
suggestion.add("reload");
146+
if (sender.hasPermission("pistonfilter.admin")) {
147+
suggestions.add("add");
148+
suggestions.add("reload");
149+
}
150+
if (sender.hasPermission("pistonfilter.pausechat")) {
151+
suggestions.add("pause");
152+
suggestions.add("unpause");
153+
suggestions.add("resume");
154+
}
155+
if (sender.hasPermission("pistonfilter.clearchat")) {
156+
suggestions.add("clearchat");
157+
suggestions.add("clear");
158+
}
52159

53160
List<String> completions = new ArrayList<>();
54-
55-
StringUtil.copyPartialMatches(args[0], suggestion, completions);
56-
161+
StringUtil.copyPartialMatches(args[0], suggestions, completions);
57162
Collections.sort(completions);
58163

59164
return completions;
60-
} else {
61-
return new ArrayList<>();
62165
}
166+
167+
return new ArrayList<>();
63168
}
64169
}

0 commit comments

Comments
 (0)