diff --git a/src/main/java/me/hsgamer/muteplus/MutePlus.java b/src/main/java/me/hsgamer/muteplus/MutePlus.java index 702f51f..79d6dc0 100644 --- a/src/main/java/me/hsgamer/muteplus/MutePlus.java +++ b/src/main/java/me/hsgamer/muteplus/MutePlus.java @@ -8,9 +8,11 @@ import me.hsgamer.muteplus.command.GlobalUnmuteCommand; import me.hsgamer.muteplus.command.MuteCommand; import me.hsgamer.muteplus.command.UnmuteCommand; +import me.hsgamer.muteplus.config.MainConfig; import me.hsgamer.muteplus.config.MessageConfig; import me.hsgamer.muteplus.hook.YATPAHook; import me.hsgamer.muteplus.listener.ChatListener; +import me.hsgamer.muteplus.listener.CommandListener; import me.hsgamer.muteplus.manager.GlobalMuteManager; import me.hsgamer.muteplus.manager.PlayerMuteManager; @@ -20,6 +22,7 @@ public final class MutePlus extends BasePlugin { private final GlobalMuteManager globalMuteManager = new GlobalMuteManager(this); private final PlayerMuteManager playerMuteManager = new PlayerMuteManager(this); + private final MainConfig mainConfig = ConfigGenerator.newInstance(MainConfig.class, new BukkitConfig(this), true, true); private final MessageConfig messageConfig = ConfigGenerator.newInstance(MessageConfig.class, new BukkitConfig(this, "messages.yml")); @Override @@ -38,6 +41,7 @@ public void enable() { registerCommand(new GlobalUnmuteCommand(this)); registerListener(new ChatListener(this)); + registerListener(new CommandListener(this)); if (YATPAHook.isAvailable()) { registerListener(new YATPAHook(this)); @@ -63,6 +67,10 @@ public PlayerMuteManager getPlayerMuteManager() { return playerMuteManager; } + public MainConfig getMainConfig() { + return mainConfig; + } + public MessageConfig getMessageConfig() { return messageConfig; } diff --git a/src/main/java/me/hsgamer/muteplus/config/MainConfig.java b/src/main/java/me/hsgamer/muteplus/config/MainConfig.java new file mode 100644 index 0000000..db7cad8 --- /dev/null +++ b/src/main/java/me/hsgamer/muteplus/config/MainConfig.java @@ -0,0 +1,42 @@ +package me.hsgamer.muteplus.config; + +import me.hsgamer.hscore.config.annotation.ConfigPath; +import me.hsgamer.muteplus.config.converter.CommandFetcherConverter; +import me.hsgamer.muteplus.config.converter.StringListConverter; +import me.hsgamer.muteplus.fetcher.CommandFetcher; +import me.hsgamer.muteplus.fetcher.impl.SimpleCommandFetcher; + +import java.util.Arrays; +import java.util.List; + +public interface MainConfig { + @ConfigPath({"filter-command", "enabled"}) + default boolean isFilterCommandEnabled() { + return true; + } + + @ConfigPath(value = {"filter-command", "player"}, converter = CommandFetcherConverter.class) + default List getPlayerCommandFetcher() { + return Arrays.asList( + new SimpleCommandFetcher("/tpa"), + new SimpleCommandFetcher("/tpahere"), + new SimpleCommandFetcher("/w"), + new SimpleCommandFetcher("/whisper"), + new SimpleCommandFetcher("/msg"), + new SimpleCommandFetcher("/tell") + ); + } + + @ConfigPath(value = {"filter-command", "global"}, converter = StringListConverter.class) + default List getGlobalCommand() { + return Arrays.asList( + "/r", + "/reply" + ); + } + + default boolean matchGlobalCommand(String command) { + String[] split = command.split(" "); + return getGlobalCommand().stream().anyMatch(s -> s.equalsIgnoreCase(split[0])); + } +} diff --git a/src/main/java/me/hsgamer/muteplus/config/MessageConfig.java b/src/main/java/me/hsgamer/muteplus/config/MessageConfig.java index d40a9d9..4cf10e5 100644 --- a/src/main/java/me/hsgamer/muteplus/config/MessageConfig.java +++ b/src/main/java/me/hsgamer/muteplus/config/MessageConfig.java @@ -28,6 +28,11 @@ default String playerOnly() { return "&cYou must be a player to do this"; } + @ConfigPath("command-denied") + default String commandDenied() { + return "&cYou cannot use this command while muted"; + } + @ConfigPath("yatpa.cancel") default String yatpaCancel() { return "&cYou cannot request teleport while muted"; diff --git a/src/main/java/me/hsgamer/muteplus/config/converter/CommandFetcherConverter.java b/src/main/java/me/hsgamer/muteplus/config/converter/CommandFetcherConverter.java new file mode 100644 index 0000000..19293de --- /dev/null +++ b/src/main/java/me/hsgamer/muteplus/config/converter/CommandFetcherConverter.java @@ -0,0 +1,70 @@ +package me.hsgamer.muteplus.config.converter; + +import me.hsgamer.hscore.common.CollectionUtils; +import me.hsgamer.hscore.config.annotation.converter.Converter; +import me.hsgamer.muteplus.fetcher.impl.PatternCommandFetcher; +import me.hsgamer.muteplus.fetcher.impl.SimpleCommandFetcher; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CommandFetcherConverter implements Converter { + private final Pattern regexFetcherPattern = Pattern.compile("pattern(\\(\\d+\\))?\\s*:\\s*(.+)\\s*"); + + @Override + public Object convert(Object raw) { + if (raw == null) return null; + return CollectionUtils.createStringListFromObject(raw) + .stream() + .flatMap(string -> { + Matcher matcher = regexFetcherPattern.matcher(string); + if (matcher.matches()) { + String patternString = matcher.group(2); + String targetGroup = matcher.group(1); + if (targetGroup == null || targetGroup.isEmpty()) { + targetGroup = "1"; + } + + Pattern pattern; + try { + pattern = Pattern.compile(patternString); + } catch (Exception e) { + return Stream.empty(); + } + + try { + int parsedTargetGroup = Integer.parseInt(targetGroup); + return Stream.of(new PatternCommandFetcher(pattern, parsedTargetGroup)); + } catch (Exception e) { + return Stream.empty(); + } + } else { + return Stream.of(new SimpleCommandFetcher(string)); + } + }) + .collect(Collectors.toList()); + } + + @Override + public Object convertToRaw(Object value) { + if (value instanceof List) { + List list = (List) value; + return list.stream() + .flatMap(fetcher -> { + if (fetcher instanceof PatternCommandFetcher) { + PatternCommandFetcher patternCommandFetcher = (PatternCommandFetcher) fetcher; + return Stream.of("pattern(" + patternCommandFetcher.getTargetGroup() + "): " + patternCommandFetcher.getPatternString()); + } else if (fetcher instanceof SimpleCommandFetcher) { + SimpleCommandFetcher simpleCommandFetcher = (SimpleCommandFetcher) fetcher; + return Stream.of(simpleCommandFetcher.getCommand()); + } + return Stream.empty(); + }) + .collect(Collectors.toList()); + } + return null; + } +} diff --git a/src/main/java/me/hsgamer/muteplus/config/converter/StringListConverter.java b/src/main/java/me/hsgamer/muteplus/config/converter/StringListConverter.java new file mode 100644 index 0000000..4a7e956 --- /dev/null +++ b/src/main/java/me/hsgamer/muteplus/config/converter/StringListConverter.java @@ -0,0 +1,17 @@ +package me.hsgamer.muteplus.config.converter; + +import me.hsgamer.hscore.common.CollectionUtils; +import me.hsgamer.hscore.config.annotation.converter.Converter; + +public class StringListConverter implements Converter { + @Override + public Object convert(Object raw) { + if (raw == null) return null; + return CollectionUtils.createStringListFromObject(raw); + } + + @Override + public Object convertToRaw(Object value) { + return value; + } +} diff --git a/src/main/java/me/hsgamer/muteplus/fetcher/CommandFetcher.java b/src/main/java/me/hsgamer/muteplus/fetcher/CommandFetcher.java new file mode 100644 index 0000000..9774bbc --- /dev/null +++ b/src/main/java/me/hsgamer/muteplus/fetcher/CommandFetcher.java @@ -0,0 +1,7 @@ +package me.hsgamer.muteplus.fetcher; + +import java.util.Optional; + +public interface CommandFetcher { + Optional getPlayer(String command); +} diff --git a/src/main/java/me/hsgamer/muteplus/fetcher/CommandResult.java b/src/main/java/me/hsgamer/muteplus/fetcher/CommandResult.java new file mode 100644 index 0000000..b74a2c4 --- /dev/null +++ b/src/main/java/me/hsgamer/muteplus/fetcher/CommandResult.java @@ -0,0 +1,34 @@ +package me.hsgamer.muteplus.fetcher; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; + +import java.util.Optional; + +public class CommandResult { + private final boolean present; + private final String playerName; + + public CommandResult(String playerName) { + this.present = !playerName.isEmpty(); + this.playerName = playerName; + } + + public boolean isPresent() { + return present; + } + + public String getPlayerName() { + return playerName; + } + + public Optional getPlayer() { + //noinspection deprecation + OfflinePlayer player = Bukkit.getOfflinePlayer(playerName); + if (player.hasPlayedBefore()) { + return Optional.of(player); + } else { + return Optional.empty(); + } + } +} diff --git a/src/main/java/me/hsgamer/muteplus/fetcher/impl/PatternCommandFetcher.java b/src/main/java/me/hsgamer/muteplus/fetcher/impl/PatternCommandFetcher.java new file mode 100644 index 0000000..60c2948 --- /dev/null +++ b/src/main/java/me/hsgamer/muteplus/fetcher/impl/PatternCommandFetcher.java @@ -0,0 +1,48 @@ +package me.hsgamer.muteplus.fetcher.impl; + +import me.hsgamer.muteplus.fetcher.CommandFetcher; +import me.hsgamer.muteplus.fetcher.CommandResult; + +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PatternCommandFetcher implements CommandFetcher { + private final Pattern pattern; + private final int targetGroup; + + public PatternCommandFetcher(Pattern pattern, int targetGroup) { + this.pattern = pattern; + this.targetGroup = targetGroup; + } + + @Override + public Optional getPlayer(String command) { + Matcher matcher = pattern.matcher(command); + if (!matcher.matches()) { + return Optional.empty(); + } + + String player = ""; + try { + player = matcher.group(targetGroup); + player = player == null ? "" : player; + } catch (Exception ignored) { + // IGNORED + } + + return Optional.of(new CommandResult(player)); + } + + public Pattern getPattern() { + return pattern; + } + + public String getPatternString() { + return pattern.pattern(); + } + + public int getTargetGroup() { + return targetGroup; + } +} diff --git a/src/main/java/me/hsgamer/muteplus/fetcher/impl/SimpleCommandFetcher.java b/src/main/java/me/hsgamer/muteplus/fetcher/impl/SimpleCommandFetcher.java new file mode 100644 index 0000000..6c428b1 --- /dev/null +++ b/src/main/java/me/hsgamer/muteplus/fetcher/impl/SimpleCommandFetcher.java @@ -0,0 +1,31 @@ +package me.hsgamer.muteplus.fetcher.impl; + +import me.hsgamer.muteplus.fetcher.CommandFetcher; +import me.hsgamer.muteplus.fetcher.CommandResult; + +import java.util.Optional; + +public class SimpleCommandFetcher implements CommandFetcher { + private final String command; + + public SimpleCommandFetcher(String command) { + this.command = command; + } + + @Override + public Optional getPlayer(String command) { + if (!command.startsWith(this.command)) return Optional.empty(); + + String playerName = ""; + String[] args = command.split(" "); + if (args.length >= 2) { + playerName = args[1]; + } + + return Optional.of(new CommandResult(playerName)); + } + + public String getCommand() { + return command; + } +} diff --git a/src/main/java/me/hsgamer/muteplus/listener/CommandListener.java b/src/main/java/me/hsgamer/muteplus/listener/CommandListener.java new file mode 100644 index 0000000..b648d98 --- /dev/null +++ b/src/main/java/me/hsgamer/muteplus/listener/CommandListener.java @@ -0,0 +1,58 @@ +package me.hsgamer.muteplus.listener; + +import me.hsgamer.hscore.bukkit.utils.MessageUtils; +import me.hsgamer.muteplus.MutePlus; +import me.hsgamer.muteplus.fetcher.CommandResult; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; + +import java.util.Locale; +import java.util.Optional; + +public class CommandListener implements Listener { + private final MutePlus plugin; + + public CommandListener(MutePlus plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onCommand(PlayerCommandPreprocessEvent event) { + Player player = event.getPlayer(); + String command = event.getMessage().toLowerCase(Locale.ROOT); + + if (!plugin.getMainConfig().isFilterCommandEnabled()) { + return; + } + + if (plugin.getGlobalMuteManager().isMuted(player.getUniqueId()) && plugin.getMainConfig().matchGlobalCommand(command)) { + MessageUtils.sendMessage(player.getUniqueId(), plugin.getMessageConfig().commandDenied()); + event.setCancelled(true); + return; + } + + Optional optionalCommandResult = plugin.getMainConfig().getPlayerCommandFetcher().stream() + .map(fetcher -> fetcher.getPlayer(command)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + if (!optionalCommandResult.isPresent()) { + return; + } + CommandResult result = optionalCommandResult.get(); + + Optional optionalPlayer = result.getPlayer(); + if (!optionalPlayer.isPresent()) { + return; + } + + OfflinePlayer target = optionalPlayer.get(); + if (plugin.getGlobalMuteManager().isMuted(target.getUniqueId()) || plugin.getPlayerMuteManager().isMuted(player.getUniqueId(), target.getUniqueId())) { + MessageUtils.sendMessage(player.getUniqueId(), plugin.getMessageConfig().commandDenied()); + event.setCancelled(true); + } + } +}