diff --git a/pom.xml b/pom.xml index 85d2675..f128934 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ simplexity SimplePMs - 2.3.1 + 2.4.0 jar SimplePMs @@ -90,5 +90,10 @@ 2.11.6 provided + + com.zaxxer + HikariCP + 6.3.0 + diff --git a/src/main/java/simplexity/simplepms/SimplePMs.java b/src/main/java/simplexity/simplepms/SimplePMs.java index 36492fa..c62e689 100644 --- a/src/main/java/simplexity/simplepms/SimplePMs.java +++ b/src/main/java/simplexity/simplepms/SimplePMs.java @@ -1,8 +1,8 @@ package simplexity.simplepms; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import simplexity.simplepms.commands.Block; @@ -14,50 +14,85 @@ import simplexity.simplepms.commands.SocialSpy; import simplexity.simplepms.commands.Unblock; import simplexity.simplepms.config.ConfigHandler; -import simplexity.simplepms.listeners.LoginListener; +import simplexity.simplepms.listeners.JoinListener; import simplexity.simplepms.listeners.PreCommandListener; import simplexity.simplepms.listeners.QuitListener; +import simplexity.simplepms.logic.Constants; +import simplexity.simplepms.saving.SqlHandler; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - +@SuppressWarnings("UnstableApiUsage") public final class SimplePMs extends JavaPlugin { private static Plugin instance; private static final MiniMessage miniMessage = MiniMessage.miniMessage(); private static boolean papiEnabled = false; - private static final HashSet players = new HashSet<>(); - private static final HashSet spyingPlayers = new HashSet<>(); private static ConsoleCommandSender consoleSender; - public static HashSet getPlayers() { - return players; - } - - public static Set getSpyingPlayers() { - return spyingPlayers; - } @Override public void onEnable() { instance = this; - registerCommands(); - this.getServer().getPluginManager().registerEvents(new LoginListener(), this); - this.getServer().getPluginManager().registerEvents(new QuitListener(), this); - this.getServer().getPluginManager().registerEvents(new PreCommandListener(), this); - if (this.getServer().getPluginManager().getPlugin("PlaceholderAPI") != null) { + consoleSender = getServer().getConsoleSender(); + if (getServer().getPluginManager().getPlugin("PlaceholderAPI") != null) { papiEnabled = true; - } else { - this.getLogger().info("You do not have PlaceholderAPI loaded on your server. Any PlaceholderAPI placeholders used in this plugin's messages, will not work."); } - consoleSender = this.getServer().getConsoleSender(); - this.saveDefaultConfig(); + SqlHandler.getInstance().init(); + loadConfigStuff(); + registerListeners(); + registerCommands(); + registerPermissions(); + } + + private void registerListeners() { + getServer().getPluginManager().registerEvents(new QuitListener(), this); + getServer().getPluginManager().registerEvents(new PreCommandListener(), this); + getServer().getPluginManager().registerEvents(new JoinListener(), this); + } + + private void loadConfigStuff() { + saveDefaultConfig(); getConfig().options().copyDefaults(true); saveConfig(); ConfigHandler.getInstance().loadConfigValues(); } + private void registerCommands() { + getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> { + commands.registrar().register(PrivateMessage.createCommand()); + commands.registrar().register(PrivateMessage.createTellAlias()); + commands.registrar().register(PrivateMessage.createWhisperAlias()); + commands.registrar().register(Reply.createCommand()); + commands.registrar().register(Reply.createAlias()); + commands.registrar().register(Block.createCommand()); + commands.registrar().register(Unblock.createCommand()); + commands.registrar().register(MessageToggle.createCommand()); + commands.registrar().register(SocialSpy.createCommand()); + commands.registrar().register(SocialSpy.createAlias()); + commands.registrar().register(Reload.createCommand()); + commands.registrar().register(Blocklist.createCommand()); + }); + } + + private void registerPermissions() { + getServer().getPluginManager().addPermission(Constants.MESSAGE_BASIC); + getServer().getPluginManager().addPermission(Constants.MESSAGE_ADMIN); + getServer().getPluginManager().addPermission(Constants.MESSAGE_SEND); + getServer().getPluginManager().addPermission(Constants.MESSAGE_RECEIVE); + getServer().getPluginManager().addPermission(Constants.MESSAGE_TOGGLE); + getServer().getPluginManager().addPermission(Constants.MESSAGE_BLOCK); + getServer().getPluginManager().addPermission(Constants.PLUGIN_RELOAD); + getServer().getPluginManager().addPermission(Constants.ADMIN_OVERRIDE); + getServer().getPluginManager().addPermission(Constants.ADMIN_SOCIAL_SPY); + getServer().getPluginManager().addPermission(Constants.ADMIN_CONSOLE_SPY); + getServer().getPluginManager().addPermission(Constants.BYPASS_SOCIAL_SPY); + getServer().getPluginManager().addPermission(Constants.BYPASS_COMMAND_SPY); + } + + @Override + public void onDisable() { + SqlHandler.getInstance().shutdownConnection(); + } + public static MiniMessage getMiniMessage() { return miniMessage; } @@ -74,15 +109,4 @@ public static ConsoleCommandSender getPMConsoleSender() { return consoleSender; } - private void registerCommands() { - Objects.requireNonNull(this.getCommand("msg")).setExecutor(new PrivateMessage()); - Objects.requireNonNull(this.getCommand("reply")).setExecutor(new Reply()); - Objects.requireNonNull(this.getCommand("socialspy")).setExecutor(new SocialSpy()); - Objects.requireNonNull(this.getCommand("spmreload")).setExecutor(new Reload()); - Objects.requireNonNull(this.getCommand("block")).setExecutor(new Block()); - Objects.requireNonNull(this.getCommand("unblock")).setExecutor(new Unblock()); - Objects.requireNonNull(this.getCommand("blocklist")).setExecutor(new Blocklist()); - Objects.requireNonNull(this.getCommand("msgtoggle")).setExecutor(new MessageToggle()); - } - } diff --git a/src/main/java/simplexity/simplepms/commands/Block.java b/src/main/java/simplexity/simplepms/commands/Block.java index 455b270..6cd3c3a 100644 --- a/src/main/java/simplexity/simplepms/commands/Block.java +++ b/src/main/java/simplexity/simplepms/commands/Block.java @@ -1,45 +1,70 @@ package simplexity.simplepms.commands; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; +import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import simplexity.simplepms.config.Message; -import simplexity.simplepms.logic.Util; -import simplexity.simplepms.objects.PlayerBlock; -import simplexity.simplepms.saving.Cache; - -import java.util.Arrays; - -public class Block implements CommandExecutor { - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - sender.sendRichMessage(Message.ONLY_PLAYER.getMessage()); - return false; - } - if (args.length == 0) { - player.sendRichMessage(Message.NO_USER_PROVIDED.getMessage()); - return false; - } - String playerToBlockString = args[0]; - Player playerToBlock = Util.getInstance().getPlayer(playerToBlockString); - if (playerToBlock == null) { - sender.sendRichMessage(Message.RECIPIENT_NOT_EXIST.getMessage(), - Placeholder.parsed("name", playerToBlockString)); - return false; - } - String blockReason = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); - PlayerBlock playerBlock = new PlayerBlock( - player.getUniqueId(), - playerToBlock.getName(), - playerToBlock.getUniqueId(), - blockReason); - Cache.addBlockedUser(player.getUniqueId(), playerBlock); - player.sendRichMessage(Message.BLOCKED_PLAYER.getMessage(), - Placeholder.parsed("name", playerToBlockString)); - return true; +import simplexity.simplepms.commands.arguments.OfflinePlayerArgument; +import simplexity.simplepms.commands.util.Exceptions; +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.logic.BlockHandler; +import simplexity.simplepms.logic.Constants; + +@SuppressWarnings("UnstableApiUsage") +public class Block { + + public static LiteralCommandNode createCommand() { + OfflinePlayerArgument offlinePlayerArg = new OfflinePlayerArgument(); + + return Commands.literal("block") + .requires(Block::canExecute) + .then(Commands.argument("target", offlinePlayerArg) + .suggests(offlinePlayerArg::suggestOnlinePlayers) + .executes(Block::execute) + .then(Commands.argument("reason", StringArgumentType.greedyString()) + .executes(Block::executeWithReason))).build(); + } + + private static boolean canExecute(CommandSourceStack css) { + if (!(css.getSender() instanceof Player)) return false; + return css.getSender().hasPermission(Constants.MESSAGE_BLOCK); + } + + private static int execute(CommandContext ctx) throws CommandSyntaxException { + CommandSender sender = ctx.getSource().getSender(); + if (!(sender instanceof Player playerSender)) throw Exceptions.ERROR_MUST_BE_PLAYER.create(); + OfflinePlayer target = ctx.getArgument("target", OfflinePlayer.class); + BlockHandler.addBlockedPlayer(playerSender, target, null); + sendSuccessMessage(playerSender, target); + return Command.SINGLE_SUCCESS; + } + + private static int executeWithReason(CommandContext ctx) throws CommandSyntaxException { + CommandSender sender = ctx.getSource().getSender(); + if (!(sender instanceof Player playerSender)) throw Exceptions.ERROR_MUST_BE_PLAYER.create(); + OfflinePlayer target = ctx.getArgument("target", OfflinePlayer.class); + String reason = ctx.getArgument("reason", String.class); + BlockHandler.addBlockedPlayer(playerSender, target, reason); + sendSuccessMessage(playerSender, target); + return Command.SINGLE_SUCCESS; + } + + private static void sendSuccessMessage(@NotNull Player sender, @NotNull OfflinePlayer blockedPlayer) { + String blockedPlayerName = blockedPlayer.getName(); + if (blockedPlayerName == null) blockedPlayerName = "[NO NAME FOUND]"; // Attempting to make intellij shut up + sender.sendRichMessage( + LocaleMessage.BLOCKED_PLAYER.getMessage(), + Placeholder.parsed("name", blockedPlayerName) + ); + } + } diff --git a/src/main/java/simplexity/simplepms/commands/Blocklist.java b/src/main/java/simplexity/simplepms/commands/Blocklist.java index d1074e3..de8f826 100644 --- a/src/main/java/simplexity/simplepms/commands/Blocklist.java +++ b/src/main/java/simplexity/simplepms/commands/Blocklist.java @@ -1,49 +1,56 @@ package simplexity.simplepms.commands; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; import simplexity.simplepms.SimplePMs; -import simplexity.simplepms.config.Message; -import simplexity.simplepms.objects.PlayerBlock; +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.logic.Constants; import simplexity.simplepms.saving.Cache; +import simplexity.simplepms.saving.objects.PlayerBlock; import java.util.List; import java.util.UUID; -public class Blocklist implements CommandExecutor { +@SuppressWarnings("UnstableApiUsage") +public class Blocklist { - private final MiniMessage miniMessage = SimplePMs.getMiniMessage(); + private static final MiniMessage miniMessage = SimplePMs.getMiniMessage(); - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - sender.sendMessage(Message.ONLY_PLAYER.getMessage()); - return false; - } - UUID uuid = player.getUniqueId(); - List blockList = Cache.getBlockList(uuid); - if (blockList == null || blockList.isEmpty()) { - player.sendRichMessage(Message.BLOCKLIST_EMPTY.getMessage()); - return true; - } - Component message = miniMessage.deserialize(Message.BLOCKLIST_HEADER.getMessage()); - for (PlayerBlock block : blockList) { - message = message.appendNewline(); - message = message.append(miniMessage.deserialize( - Message.BLOCKLIST_NAME.getMessage(), - Placeholder.parsed("name", block.blockedPlayerName()) - )); - if (block.blockReason() == null || block.blockReason().isEmpty()) continue; - message = message.append(miniMessage.deserialize(Message.BLOCKLIST_REASON.getMessage(), - Placeholder.parsed("reason", block.blockReason()))); - } - sender.sendMessage(message); - return true; + public static LiteralCommandNode createCommand() { + return Commands.literal("blocklist") + .requires(Blocklist::canExecute) + .executes(ctx -> { + Player player = (Player) ctx.getSource().getSender(); + UUID uuid = player.getUniqueId(); + List blockList = Cache.getBlockList(uuid); + if (blockList == null || blockList.isEmpty()) { + player.sendRichMessage(LocaleMessage.BLOCKLIST_EMPTY.getMessage()); + return Command.SINGLE_SUCCESS; + } + Component message = miniMessage.deserialize(LocaleMessage.BLOCKLIST_HEADER.getMessage()); + for (PlayerBlock block : blockList) { + message = message.appendNewline(); + message = message.append(miniMessage.deserialize( + LocaleMessage.BLOCKLIST_NAME.getMessage(), + Placeholder.parsed("name", block.getBlockedPlayerName()) + )); + if (block.getBlockReason() == null || block.getBlockReason().isEmpty()) continue; + message = message.append(miniMessage.deserialize(LocaleMessage.BLOCKLIST_REASON.getMessage(), + Placeholder.parsed("reason", block.getBlockReason()))); + } + player.sendMessage(message); + return Command.SINGLE_SUCCESS; + }).build(); + } + + private static boolean canExecute(CommandSourceStack css) { + if (!(css.getSender() instanceof Player)) return false; + return css.getSender().hasPermission(Constants.MESSAGE_BLOCK); } } diff --git a/src/main/java/simplexity/simplepms/commands/MessageToggle.java b/src/main/java/simplexity/simplepms/commands/MessageToggle.java index 4bb8f4f..381d0d8 100644 --- a/src/main/java/simplexity/simplepms/commands/MessageToggle.java +++ b/src/main/java/simplexity/simplepms/commands/MessageToggle.java @@ -1,33 +1,40 @@ package simplexity.simplepms.commands; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import simplexity.simplepms.config.Message; -import simplexity.simplepms.objects.PlayerSettings; +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.logic.Constants; import simplexity.simplepms.saving.Cache; -import simplexity.simplepms.saving.SqlHandler; +import simplexity.simplepms.saving.objects.PlayerSettings; import java.util.UUID; -public class MessageToggle implements CommandExecutor { - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { - if (!(sender instanceof Player player)) { - sender.sendRichMessage(Message.ONLY_PLAYER.getMessage()); - return false; - } - UUID uuid = player.getUniqueId(); - PlayerSettings playerSettings = Cache.getPlayerSettings(uuid); - if (playerSettings.messagesDisabled()) { - Cache.updateMessageSettings(uuid, false); - player.sendRichMessage(Message.MESSAGES_ENABLED.getMessage()); - return true; - } - Cache.updateMessageSettings(uuid, true); - player.sendRichMessage(Message.MESSAGES_DISABLED.getMessage()); - return true; +@SuppressWarnings("UnstableApiUsage") +public class MessageToggle { + + public static LiteralCommandNode createCommand() { + return Commands.literal("msgtoggle") + .requires(MessageToggle::canExecute) + .executes(ctx -> { + Player sender = (Player) ctx.getSource().getSender(); + UUID playerUuid = sender.getUniqueId(); + PlayerSettings playerSettings = Cache.getPlayerSettings(playerUuid); + if (playerSettings.areMessagesDisabled()) { + Cache.updateMessageSettings(playerUuid, false); + sender.sendRichMessage(LocaleMessage.MESSAGES_ENABLED.getMessage()); + return Command.SINGLE_SUCCESS; + } + Cache.updateMessageSettings(playerUuid, true); + sender.sendRichMessage(LocaleMessage.MESSAGES_DISABLED.getMessage()); + return Command.SINGLE_SUCCESS; + }).build(); + } + + public static boolean canExecute(CommandSourceStack css) { + if (!(css.getSender() instanceof Player)) return false; + return css.getSender().hasPermission(Constants.MESSAGE_TOGGLE); } } diff --git a/src/main/java/simplexity/simplepms/commands/PrivateMessage.java b/src/main/java/simplexity/simplepms/commands/PrivateMessage.java index e5c57a8..977de2a 100644 --- a/src/main/java/simplexity/simplepms/commands/PrivateMessage.java +++ b/src/main/java/simplexity/simplepms/commands/PrivateMessage.java @@ -1,48 +1,68 @@ package simplexity.simplepms.commands; -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.Command; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import simplexity.simplepms.config.Message; -import simplexity.simplepms.logic.PreProcessing; - -import java.util.Arrays; -import java.util.List; - -public class PrivateMessage implements TabExecutor { - - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if (args.length < 1) { - sender.sendRichMessage(Message.NO_RECIPIENT_PROVIDED.getMessage()); - return false; - } - if (args.length < 2) { - sender.sendRichMessage(Message.BLANK_MESSAGE.getMessage()); - return false; - } - CommandSender target = PreProcessing.getInstance().getTarget(args); - if (target == null) { - sender.sendRichMessage(Message.RECIPIENT_NOT_EXIST.getMessage(), - Placeholder.unparsed("name", args[0])); - return false; - } - if (PreProcessing.getInstance().messagingBlocked(sender, target, args[0])) { - return false; - } - String message = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); - PreProcessing.getInstance().callPMEvent(sender, target, message); - return true; +import simplexity.simplepms.commands.arguments.Target; +import simplexity.simplepms.commands.arguments.TargetArgument; +import simplexity.simplepms.commands.util.MessageChecks; +import simplexity.simplepms.logic.Constants; +import simplexity.simplepms.logic.PMHandler; + +@SuppressWarnings("UnstableApiUsage") +public class PrivateMessage { + + + public static LiteralCommandNode createCommand() { + return Commands.literal("msg") + .requires(PrivateMessage::canExecute) + .then(targetArg() + .then(messageArg())).build(); } + public static LiteralCommandNode createTellAlias() { + return Commands.literal("tell") + .requires(PrivateMessage::canExecute) + .then(targetArg() + .then(messageArg())).build(); + } - @Override - public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if (args.length > 1) return List.of(); - return null; + public static LiteralCommandNode createWhisperAlias() { + return Commands.literal("w") + .requires(PrivateMessage::canExecute) + .then(targetArg() + .then(messageArg())).build(); } + + private static RequiredArgumentBuilder targetArg() { + TargetArgument targetArg = new TargetArgument(); + return Commands.argument("target", targetArg) + .suggests(targetArg::suggestOnlinePlayers); + } + + private static RequiredArgumentBuilder messageArg() { + return Commands.argument("message", StringArgumentType.greedyString()) + .executes(PrivateMessage::execute); + } + + private static boolean canExecute(CommandSourceStack css) { + return css.getSender().hasPermission(Constants.MESSAGE_SEND); + } + + private static int execute(CommandContext ctx) throws CommandSyntaxException { + CommandSender sender = ctx.getSource().getSender(); + Target argTarget = ctx.getArgument("target", Target.class); + CommandSender target = argTarget.sender(); + MessageChecks.userChecks(sender, target, argTarget.providedName()); + String message = ctx.getArgument("message", String.class); + PMHandler.handlePrivateMessage(sender, target, message); + return Command.SINGLE_SUCCESS; + } + } diff --git a/src/main/java/simplexity/simplepms/commands/Reload.java b/src/main/java/simplexity/simplepms/commands/Reload.java index b98e7c9..9cc8677 100644 --- a/src/main/java/simplexity/simplepms/commands/Reload.java +++ b/src/main/java/simplexity/simplepms/commands/Reload.java @@ -1,19 +1,27 @@ package simplexity.simplepms.commands; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; import simplexity.simplepms.config.ConfigHandler; -import simplexity.simplepms.config.Message; - -public class Reload implements CommandExecutor { - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - ConfigHandler.getInstance().loadConfigValues(); - sender.sendRichMessage(Message.RELOADED.getMessage()); - return true; - } +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.logic.Constants; +import simplexity.simplepms.saving.SqlHandler; +@SuppressWarnings("UnstableApiUsage") +public class Reload { + public static LiteralCommandNode createCommand() { + return Commands.literal("spmreload") + .requires(css -> css.getSender().hasPermission(Constants.PLUGIN_RELOAD)) + .executes(ctx -> { + CommandSender sender = ctx.getSource().getSender(); + ConfigHandler.getInstance().loadConfigValues(); + SqlHandler.getInstance().reloadDatabase(); + sender.sendRichMessage(LocaleMessage.RELOADED.getMessage()); + return Command.SINGLE_SUCCESS; + }).build(); + } } diff --git a/src/main/java/simplexity/simplepms/commands/Reply.java b/src/main/java/simplexity/simplepms/commands/Reply.java index 4a9a27f..4b386d2 100644 --- a/src/main/java/simplexity/simplepms/commands/Reply.java +++ b/src/main/java/simplexity/simplepms/commands/Reply.java @@ -1,37 +1,51 @@ package simplexity.simplepms.commands; -import org.bukkit.command.Command; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import simplexity.simplepms.config.Message; -import simplexity.simplepms.logic.PreProcessing; - -import java.util.List; - -public class Reply implements TabExecutor { - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if (args.length < 1) { - sender.sendRichMessage(Message.BLANK_MESSAGE.getMessage()); - return false; - } - CommandSender recipient = PreProcessing.lastMessaged.get(sender); - if (recipient == null) { - sender.sendRichMessage(Message.CANNOT_REPLY.getMessage()); - return false; - } - if (PreProcessing.getInstance().messagingBlocked(sender, recipient, recipient.getName())) { - return false; - } - String message = String.join(" ", args); - PreProcessing.getInstance().callPMEvent(sender, recipient, message); - return true; +import simplexity.simplepms.commands.util.Exceptions; +import simplexity.simplepms.commands.util.MessageChecks; +import simplexity.simplepms.logic.Constants; +import simplexity.simplepms.logic.PMHandler; + +@SuppressWarnings("UnstableApiUsage") +public class Reply { + + public static LiteralCommandNode createCommand() { + return Commands.literal("reply") + .requires(Reply::canExecute) + .then(messageArg()).build(); } - @Override - public @Nullable List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { - return List.of(); + public static LiteralCommandNode createAlias() { + return Commands.literal("r") + .requires(Reply::canExecute) + .then(messageArg()).build(); } + + private static boolean canExecute(CommandSourceStack css) { + return css.getSender().hasPermission(Constants.MESSAGE_SEND); + } + + private static RequiredArgumentBuilder messageArg() { + return Commands.argument("message", StringArgumentType.greedyString()) + .executes(Reply::execute); + } + + private static int execute(CommandContext ctx) throws CommandSyntaxException { + CommandSender sender = ctx.getSource().getSender(); + CommandSender target = PMHandler.lastMessaged.get(sender); + if (target == null) throw Exceptions.ERROR_NOBODY_TO_REPLY_TO.create(); + MessageChecks.userChecks(sender, target, target.getName()); + String message = ctx.getArgument("message", String.class); + PMHandler.handlePrivateMessage(sender, target, message); + return Command.SINGLE_SUCCESS; + } + } diff --git a/src/main/java/simplexity/simplepms/commands/SocialSpy.java b/src/main/java/simplexity/simplepms/commands/SocialSpy.java index 631a976..8e805a7 100644 --- a/src/main/java/simplexity/simplepms/commands/SocialSpy.java +++ b/src/main/java/simplexity/simplepms/commands/SocialSpy.java @@ -1,39 +1,52 @@ package simplexity.simplepms.commands; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import simplexity.simplepms.SimplePMs; -import simplexity.simplepms.config.Message; -import simplexity.simplepms.objects.PlayerSettings; +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.logic.Constants; import simplexity.simplepms.saving.Cache; -import simplexity.simplepms.saving.SqlHandler; +import simplexity.simplepms.saving.objects.PlayerSettings; import java.util.UUID; -public class SocialSpy implements CommandExecutor { +@SuppressWarnings({"UnstableApiUsage", "SameReturnValue"}) +public class SocialSpy { + public static LiteralCommandNode createCommand() { + return Commands.literal("socialspy") + .requires(SocialSpy::canExecute) + .executes(SocialSpy::execute).build(); + } - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - sender.sendRichMessage(Message.ONLY_PLAYER.getMessage()); - return false; - } + public static LiteralCommandNode createAlias() { + return Commands.literal("ss") + .requires(SocialSpy::canExecute) + .executes(SocialSpy::execute).build(); + } + + private static boolean canExecute(CommandSourceStack css) { + if (!(css.getSender() instanceof Player)) return false; + return css.getSender().hasPermission(Constants.ADMIN_SOCIAL_SPY); + } + + private static int execute(CommandContext ctx) { + Player player = (Player) ctx.getSource().getSender(); UUID uuid = player.getUniqueId(); - PlayerSettings settings = SqlHandler.getInstance().getSettings(uuid); - if (settings == null || settings.socialSpyEnabled()) { + PlayerSettings settings = Cache.getPlayerSettings(uuid); + if (settings == null || settings.isSocialSpyEnabled()) { Cache.updateSocialSpySettings(uuid, false); - sender.sendRichMessage(Message.SOCIAL_SPY_DISABLED.getMessage()); - SimplePMs.getSpyingPlayers().remove(player); - return true; + player.sendRichMessage(LocaleMessage.SOCIAL_SPY_DISABLED.getMessage()); + Cache.getSpyingPlayers().remove(player); + return Command.SINGLE_SUCCESS; } Cache.updateSocialSpySettings(uuid, true); - sender.sendRichMessage(Message.SOCIAL_SPY_ENABLED.getMessage()); - SimplePMs.getSpyingPlayers().add(player); - return true; + player.sendRichMessage(LocaleMessage.SOCIAL_SPY_ENABLED.getMessage()); + Cache.getSpyingPlayers().add(player); + return Command.SINGLE_SUCCESS; } } diff --git a/src/main/java/simplexity/simplepms/commands/Unblock.java b/src/main/java/simplexity/simplepms/commands/Unblock.java index 4ce9b78..072aaf3 100644 --- a/src/main/java/simplexity/simplepms/commands/Unblock.java +++ b/src/main/java/simplexity/simplepms/commands/Unblock.java @@ -1,61 +1,71 @@ package simplexity.simplepms.commands; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import simplexity.simplepms.config.Message; -import simplexity.simplepms.objects.PlayerBlock; +import simplexity.simplepms.commands.util.Exceptions; +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.logic.Constants; +import simplexity.simplepms.logic.UnblockHandler; import simplexity.simplepms.saving.Cache; +import simplexity.simplepms.saving.objects.PlayerBlock; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; -public class Unblock implements TabExecutor { - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - sender.sendRichMessage(Message.ONLY_PLAYER.getMessage()); - return false; - } - if (args.length == 0) { - player.sendRichMessage(Message.NO_USER_PROVIDED.getMessage()); - return false; - } - String blockString = args[0]; - List playerBlockList = Cache.getBlockList(player.getUniqueId()); - PlayerBlock blockedPlayer = getBlockedPlayer(blockString, playerBlockList); - if (blockedPlayer == null) { - player.sendRichMessage(Message.PLAYER_NOT_BLOCKED.getMessage()); - return false; - } - Cache.removeBlockedUser(player.getUniqueId(), blockedPlayer); - player.sendRichMessage(Message.NO_LONGER_BLOCKING.getMessage(), - Placeholder.parsed("name", blockString)); - return true; +@SuppressWarnings("UnstableApiUsage") +public class Unblock { + + public static LiteralCommandNode createCommand() { + + return Commands.literal("unblock") + .requires(Unblock::canExecute) + .then(Commands.argument("target", StringArgumentType.word()) + .suggests(Unblock::suggestBlockedUsers) + .executes(Unblock::execute)).build(); } - private PlayerBlock getBlockedPlayer(String playerBlocked, List playerBlockList) { - for (PlayerBlock playerBlock : playerBlockList) { - if (playerBlock.blockedPlayerName().equals(playerBlocked)) { - return playerBlock; - } - } - return null; + private static boolean canExecute(CommandSourceStack css) { + if (!(css.getSender() instanceof Player)) return false; + return css.getSender().hasPermission(Constants.MESSAGE_BLOCK); } - @Override - public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - return null; - } - ArrayList blocked = new ArrayList<>(); - for (PlayerBlock block : Cache.getBlockList(player.getUniqueId())) { - blocked.add(block.blockedPlayerName()); + private static int execute(CommandContext ctx) throws CommandSyntaxException { + CommandSender sender = ctx.getSource().getSender(); + if (!(sender instanceof Player playerSender)) throw Exceptions.ERROR_MUST_BE_PLAYER.create(); + String target = ctx.getArgument("target", String.class); + UnblockHandler.removeBlockedPlayer(playerSender, target); + sendSuccessMessage(playerSender, target); + return Command.SINGLE_SUCCESS; + } + + private static void sendSuccessMessage(Player sender, String name) { + sender.sendRichMessage( + LocaleMessage.NO_LONGER_BLOCKING.getMessage(), + Placeholder.parsed("name", name) + ); + } + + private static CompletableFuture suggestBlockedUsers(final CommandContext ctx, final SuggestionsBuilder builder) { + CommandSender sender = ctx.getSource().getSender(); + if (!(sender instanceof Player playerSender)) return builder.buildFuture(); + List blockedPlayers = Cache.getBlockList(playerSender.getUniqueId()); + if (blockedPlayers.isEmpty()) return builder.buildFuture(); + for (PlayerBlock block : blockedPlayers) { + builder.suggest(block.getBlockedPlayerName(), + MessageComponentSerializer.message().serialize(Component.text(block.getBlockReason()))); } - return blocked; + return builder.buildFuture(); } } diff --git a/src/main/java/simplexity/simplepms/commands/arguments/OfflinePlayerArgument.java b/src/main/java/simplexity/simplepms/commands/arguments/OfflinePlayerArgument.java new file mode 100644 index 0000000..46c783b --- /dev/null +++ b/src/main/java/simplexity/simplepms/commands/arguments/OfflinePlayerArgument.java @@ -0,0 +1,80 @@ +package simplexity.simplepms.commands.arguments; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import simplexity.simplepms.commands.util.Exceptions; +import simplexity.simplepms.config.ConfigHandler; + +import java.util.concurrent.CompletableFuture; + + +@SuppressWarnings("UnstableApiUsage") +public class OfflinePlayerArgument implements CustomArgumentType { + + @Override + public @NotNull OfflinePlayer parse(@NotNull StringReader reader) throws CommandSyntaxException { + String playerName = reader.readString(); + OfflinePlayer[] offlinePlayers = Bukkit.getOfflinePlayers(); + OfflinePlayer offlinePlayer = null; + for (OfflinePlayer player : offlinePlayers) { + if (player.getName() == null || player.getName().isEmpty()) continue; + if (player.getName().equalsIgnoreCase(playerName)) { + offlinePlayer = player; + break; + } + } + if (offlinePlayer == null || !offlinePlayer.hasPlayedBefore()) + throw Exceptions.ERROR_INVALID_USER.create(playerName); + return offlinePlayer; + } + + @Override + public @NotNull ArgumentType getNativeType() { + return StringArgumentType.greedyString(); + } + + /** + * Provides suggestions for players based on the online player list. + * Will also provide a hover-able element that shows their current nickname. + * + * @param context Command Context + * @param builder SuggestionsBuilder object for adding suggestions to + * @param For Paper, generally CommandSourceStack + * @return Suggestions as a CompletableFuture + */ + public @NotNull CompletableFuture suggestOnlinePlayers(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) { + if (!(context.getSource() instanceof CommandSourceStack css)) return builder.buildFuture(); + CommandSender sender = css.getSender(); + Player playerSender = null; + if (sender instanceof Player) playerSender = (Player) sender; + for (Player player : Bukkit.getOnlinePlayers()) { + if (playerSender != null) { + if (!playerSender.canSee(player) && + !ConfigHandler.getInstance().canPlayersSendToHiddenPlayers()) continue; + } + String suggestion = player.getName(); + if (suggestion.toLowerCase().contains(builder.getRemainingLowerCase())) { + builder.suggest( + suggestion, + MessageComponentSerializer.message().serialize( + player.displayName() + ) + ); + } + } + return builder.buildFuture(); + } +} diff --git a/src/main/java/simplexity/simplepms/commands/arguments/Target.java b/src/main/java/simplexity/simplepms/commands/arguments/Target.java new file mode 100644 index 0000000..52d6abd --- /dev/null +++ b/src/main/java/simplexity/simplepms/commands/arguments/Target.java @@ -0,0 +1,6 @@ +package simplexity.simplepms.commands.arguments; + +import org.bukkit.command.CommandSender; + +public record Target(CommandSender sender, String providedName) { +} diff --git a/src/main/java/simplexity/simplepms/commands/arguments/TargetArgument.java b/src/main/java/simplexity/simplepms/commands/arguments/TargetArgument.java new file mode 100644 index 0000000..1f48525 --- /dev/null +++ b/src/main/java/simplexity/simplepms/commands/arguments/TargetArgument.java @@ -0,0 +1,75 @@ +package simplexity.simplepms.commands.arguments; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import simplexity.simplepms.SimplePMs; +import simplexity.simplepms.commands.util.Exceptions; +import simplexity.simplepms.config.ConfigHandler; + +import java.util.concurrent.CompletableFuture; + +@SuppressWarnings("UnstableApiUsage") +public class TargetArgument implements CustomArgumentType { + + private static final CommandSender consoleSender = SimplePMs.getPMConsoleSender(); + + @Override + public @NotNull Target parse(@NotNull StringReader reader) throws CommandSyntaxException { + String targetName = reader.readString(); + if (ConfigHandler.getInstance().getValidNamesForConsole().contains(targetName.toLowerCase())) + return new Target(consoleSender, targetName); + Player targetPlayer = Bukkit.getPlayerExact(targetName); + if (targetPlayer != null) return new Target(targetPlayer, targetName); + throw Exceptions.ERROR_INVALID_USER.create(targetName); + } + + @Override + public @NotNull ArgumentType getNativeType() { + return StringArgumentType.word(); + } + + + /** + * Provides suggestions for players based on the online player list. + * Will also provide a hover-able element that shows their current nickname. + * + * @param context Command Context + * @param builder SuggestionsBuilder object for adding suggestions to + * @param For Paper, generally CommandSourceStack + * @return Suggestions as a CompletableFuture + */ + public @NotNull CompletableFuture suggestOnlinePlayers(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) { + if (!(context.getSource() instanceof CommandSourceStack css)) return builder.buildFuture(); + CommandSender sender = css.getSender(); + Player playerSender = null; + if (sender instanceof Player) playerSender = (Player) sender; + for (Player player : Bukkit.getOnlinePlayers()) { + if (playerSender != null) { + if (!playerSender.canSee(player) && + !ConfigHandler.getInstance().canPlayersSendToHiddenPlayers()) continue; + } + String suggestion = player.getName(); + if (suggestion.toLowerCase().contains(builder.getRemainingLowerCase())) { + builder.suggest( + suggestion, + MessageComponentSerializer.message().serialize( + player.displayName() + ) + ); + } + } + return builder.buildFuture(); + } +} diff --git a/src/main/java/simplexity/simplepms/commands/util/Exceptions.java b/src/main/java/simplexity/simplepms/commands/util/Exceptions.java new file mode 100644 index 0000000..e696907 --- /dev/null +++ b/src/main/java/simplexity/simplepms/commands/util/Exceptions.java @@ -0,0 +1,72 @@ +package simplexity.simplepms.commands.util; + +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import simplexity.simplepms.SimplePMs; +import simplexity.simplepms.config.LocaleMessage; + +@SuppressWarnings("UnstableApiUsage") +public class Exceptions { + + private static final MiniMessage miniMessage = SimplePMs.getMiniMessage(); + + public static final DynamicCommandExceptionType ERROR_INVALID_USER = new DynamicCommandExceptionType(input -> + MessageComponentSerializer.message().serialize( + miniMessage.deserialize( + LocaleMessage.ERROR_RECIPIENT_NOT_EXIST.getMessage(), + Placeholder.unparsed("name", input.toString()) + ) + )); + + public static final SimpleCommandExceptionType ERROR_YOUR_MESSAGES_ARE_DISABLED = new SimpleCommandExceptionType( + MessageComponentSerializer.message().serialize( + miniMessage.deserialize( + LocaleMessage.ERROR_YOUR_MESSAGES_CURRENTLY_DISABLED.getMessage() + ) + ) + ); + + public static final SimpleCommandExceptionType ERROR_TARGET_CANNOT_RECEIVE_MESSAGE = new SimpleCommandExceptionType( + MessageComponentSerializer.message().serialize( + miniMessage.deserialize( + LocaleMessage.ERROR_TARGET_CANNOT_RECEIVE_MESSAGE.getMessage() + ) + ) + ); + + public static final SimpleCommandExceptionType ERROR_CANNOT_MESSAGE_SOMEONE_YOU_HAVE_BLOCKED = new SimpleCommandExceptionType( + MessageComponentSerializer.message().serialize( + miniMessage.deserialize( + LocaleMessage.ERROR_CANNOT_MESSAGE_SOMEONE_YOU_BLOCKED.getMessage() + ) + ) + ); + + public static final SimpleCommandExceptionType ERROR_NOBODY_TO_REPLY_TO = new SimpleCommandExceptionType( + MessageComponentSerializer.message().serialize( + miniMessage.deserialize( + LocaleMessage.ERROR_CANNOT_REPLY.getMessage() + ) + ) + ); + + public static final SimpleCommandExceptionType ERROR_MUST_BE_PLAYER = new SimpleCommandExceptionType( + MessageComponentSerializer.message().serialize( + miniMessage.deserialize( + LocaleMessage.ERROR_NOT_A_PLAYER.getMessage() + ) + ) + ); + + public static final SimpleCommandExceptionType ERROR_NOT_BLOCKING_ANYONE_BY_THIS_NAME = new SimpleCommandExceptionType( + MessageComponentSerializer.message().serialize( + miniMessage.deserialize( + LocaleMessage.PLAYER_NOT_BLOCKED.getMessage() + ) + ) + ); + +} diff --git a/src/main/java/simplexity/simplepms/commands/util/MessageChecks.java b/src/main/java/simplexity/simplepms/commands/util/MessageChecks.java new file mode 100644 index 0000000..48b191e --- /dev/null +++ b/src/main/java/simplexity/simplepms/commands/util/MessageChecks.java @@ -0,0 +1,78 @@ +package simplexity.simplepms.commands.util; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import simplexity.simplepms.config.ConfigHandler; +import simplexity.simplepms.logic.Constants; +import simplexity.simplepms.saving.Cache; +import simplexity.simplepms.saving.objects.PlayerBlock; +import simplexity.simplepms.saving.objects.PlayerSettings; + +import java.util.List; + +public class MessageChecks { + + + public static void userChecks(CommandSender initiator, CommandSender target, String providedName) throws CommandSyntaxException { + if (initiator instanceof Player playerInitiator) { + ownMessagesDisabledCheck(playerInitiator); + if (target instanceof Player playerTarget) { + initiatorBlockedTargetCheck(playerInitiator, playerTarget); + if (!initiator.hasPermission(Constants.ADMIN_OVERRIDE)) { + targetCanGetMessageCheck(playerTarget); + targetBlockedInitiatorCheck(playerInitiator, playerTarget); + vanishCheck(playerInitiator, playerTarget, providedName); + } + } else { + canSendToConsole(providedName); + } + } + } + + private static void vanishCheck(Player initiator, Player target, String providedName) throws CommandSyntaxException { + if (ConfigHandler.getInstance().canPlayersSendToHiddenPlayers()) return; + if (!initiator.canSee(target)) throw Exceptions.ERROR_INVALID_USER.create(providedName); + } + + private static void ownMessagesDisabledCheck(Player initiatingPlayer) throws CommandSyntaxException { + PlayerSettings settings = Cache.getPlayerSettings(initiatingPlayer.getUniqueId()); + if (settings == null) return; + if (settings.areMessagesDisabled()) throw Exceptions.ERROR_YOUR_MESSAGES_ARE_DISABLED.create(); + } + + private static void targetCanGetMessageCheck(Player targetPlayer) throws CommandSyntaxException { + if (!targetPlayer.hasPermission(Constants.MESSAGE_RECEIVE)) + throw Exceptions.ERROR_TARGET_CANNOT_RECEIVE_MESSAGE.create(); + PlayerSettings settings = Cache.getPlayerSettings(targetPlayer.getUniqueId()); + if (settings == null) return; + if (settings.areMessagesDisabled()) throw Exceptions.ERROR_TARGET_CANNOT_RECEIVE_MESSAGE.create(); + } + + private static void targetBlockedInitiatorCheck(Player initiatingPlayer, Player targetPlayer) throws CommandSyntaxException { + if (userBlocked(targetPlayer, initiatingPlayer)) throw Exceptions.ERROR_TARGET_CANNOT_RECEIVE_MESSAGE.create(); + } + + private static void initiatorBlockedTargetCheck(Player initiatingPlayer, Player targetPlayer) throws CommandSyntaxException { + if (userBlocked(initiatingPlayer, targetPlayer)) + throw Exceptions.ERROR_CANNOT_MESSAGE_SOMEONE_YOU_HAVE_BLOCKED.create(); + } + + private static void canSendToConsole(String providedName) throws CommandSyntaxException { + if (!ConfigHandler.getInstance().canPlayersSendToConsole()) + throw Exceptions.ERROR_INVALID_USER.create(providedName); + } + + private static boolean userBlocked(Player blocklistPlayer, Player potentialBlock) { + List playerBlocks = Cache.blockList.get(blocklistPlayer.getUniqueId()); + if (playerBlocks == null) { + return false; + } + for (PlayerBlock playerBlock : playerBlocks) { + if (playerBlock.getBlockedPlayerUUID().equals(potentialBlock.getUniqueId())) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/simplexity/simplepms/config/ConfigHandler.java b/src/main/java/simplexity/simplepms/config/ConfigHandler.java index dfdd0e0..8940e2d 100644 --- a/src/main/java/simplexity/simplepms/config/ConfigHandler.java +++ b/src/main/java/simplexity/simplepms/config/ConfigHandler.java @@ -1,9 +1,11 @@ package simplexity.simplepms.config; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.Sound; import org.bukkit.configuration.file.FileConfiguration; +import org.jetbrains.annotations.NotNull; import simplexity.simplepms.SimplePMs; -import simplexity.simplepms.saving.SqlHandler; import java.util.ArrayList; import java.util.HashSet; @@ -21,20 +23,22 @@ public static ConfigHandler getInstance() { private final Logger logger = SimplePMs.getInstance().getLogger(); private boolean mysqlEnabled, playersSendToConsole, playersSendToHiddenPlayers, consoleHasSocialSpy, commandSpyEnabled, consoleHasCommandSpy, receiveSoundEnabled, sendSoundEnabled, spySoundEnabled; - private Sound receiveSound, sendSound, spySound; + private NamespacedKey receiveSound = Registry.SOUNDS.getKey(Sound.BLOCK_NOTE_BLOCK_XYLOPHONE); + private NamespacedKey sendSound = Registry.SOUNDS.getKey(Sound.ENTITY_ALLAY_ITEM_THROWN); + private NamespacedKey spySound = Registry.SOUNDS.getKey(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM); private float receivePitch, receiveVolume, sendPitch, sendVolume, spyPitch, spyVolume; private String mysqlIp, mysqlName, mysqlUsername, mysqlPassword, normalFormat, socialSpyFormat; - private List validNamesForConsole = new ArrayList<>(); + private final List validNamesForConsole = new ArrayList<>(); private final HashSet commandsToSpy = new HashSet<>(); public void loadConfigValues() { SimplePMs.getInstance().reloadConfig(); FileConfiguration config = SimplePMs.getInstance().getConfig(); - SqlHandler.getInstance().init(); LocaleHandler.getInstance().reloadLocale(); - validNamesForConsole.clear(); List commands = config.getStringList("command-spy.commands"); + List consoleNames = config.getStringList("valid-console-names"); updateHashSet(commandsToSpy, commands); + validateConsoleNames(consoleNames); normalFormat = config.getString("format.normal", ""); socialSpyFormat = config.getString("format.social-spy", ""); mysqlEnabled = config.getBoolean("mysql.enabled", false); @@ -45,7 +49,6 @@ public void loadConfigValues() { mysqlPassword = config.getString("mysql.password", "badpassword!"); playersSendToConsole = config.getBoolean("allow-messaging.console", true); playersSendToHiddenPlayers = config.getBoolean("allow-messaging.hidden-players", false); - validNamesForConsole = config.getStringList("valid-console-names"); consoleHasSocialSpy = config.getBoolean("console-has-social-spy", true); consoleHasCommandSpy = config.getBoolean("console-has-command-spy", false); receiveSoundEnabled = config.getBoolean("sounds.received.enabled", false); @@ -62,48 +65,53 @@ private void updateHashSet(HashSet set, List list) { } private void loadReceiveSoundInfo(FileConfiguration config) { - String soundString = config.getString("sounds.received.sound", "BLOCK_NOTE_BLOCK_XYLOPHONE"); - receiveSound = getValidSound(soundString, Sound.BLOCK_NOTE_BLOCK_XYLOPHONE); + String soundString = config.getString("sounds.received.sound", "minecraft:block.note_block.xylophone"); + receiveSound = getValidSound(soundString, Registry.SOUNDS.getKey(Sound.BLOCK_NOTE_BLOCK_XYLOPHONE)); receivePitch = getValidFloat(config.getDouble("sounds.received.pitch", 1.8)); receiveVolume = getValidFloat(config.getDouble("sounds.received.volume", 0.5)); } - private void loadSendSoundInfo(FileConfiguration config){ - String soundString = config.getString("sounds.sent.sound", "ENTITY_ALLAY_ITEM_THROWN"); - sendSound = getValidSound(soundString, Sound.ENTITY_ALLAY_ITEM_THROWN); + private void loadSendSoundInfo(FileConfiguration config) { + String soundString = config.getString("sounds.sent.sound", "minecraft:entity.allay.item_thrown"); + sendSound = getValidSound(soundString, Registry.SOUNDS.getKey(Sound.ENTITY_ALLAY_ITEM_THROWN)); sendPitch = getValidFloat(config.getDouble("sounds.sent.pitch", 1.8)); sendVolume = getValidFloat(config.getDouble("sounds.sent.volume", 0.5)); } - private void loadSpySoundInfo(FileConfiguration config){ - String soundString = config.getString("sounds.spy.sound", "ENTITY_ITEM_FRAME_ROTATE_ITEM"); - spySound = getValidSound(soundString, Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM); + private void loadSpySoundInfo(FileConfiguration config) { + String soundString = config.getString("sounds.spy.sound", "minecraft:entity.item_frame.rotate_item"); + spySound = getValidSound(soundString, Registry.SOUNDS.getKey(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM)); spyPitch = getValidFloat(config.getDouble("sounds.spy.pitch", 1.8)); spyVolume = getValidFloat(config.getDouble("sounds.spy.volume", 0.5)); } - private Sound getValidSound(String soundString, Sound defaultSound){ - Sound sound; - try { - sound = Sound.valueOf(soundString); - } catch (IllegalArgumentException exception) { - String warning = Message.SOUND_NOT_VALID.getMessage().replace("%sound-string%", soundString); - String warning2 = Message.USING_DEFAULT_SOUND.getMessage().replace("%default-sound%", defaultSound.name()); + private NamespacedKey getValidSound(String soundString, NamespacedKey defaultSound) { + NamespacedKey key = NamespacedKey.fromString(soundString); + if (key == null || Registry.SOUNDS.get(key) == null) { + String warning = LocaleMessage.LOG_ERROR_SOUND_NOT_VALID.getMessage().replace("%sound-string%", soundString); + String warning2 = LocaleMessage.LOG_ERROR_USING_DEFAULT_SOUND.getMessage().replace("%default-sound%", defaultSound.getKey()); logger.warning(warning); logger.warning(warning2); - sound = defaultSound; + return defaultSound; } - return sound; + return key; } - private float getValidFloat(double numberToCheck){ + private float getValidFloat(double numberToCheck) { if (numberToCheck <= 2 && numberToCheck >= 0) return (float) numberToCheck; - String warning = Message.OUT_OF_RANGE.getMessage().replace("%number%", String.valueOf(numberToCheck)); + String warning = LocaleMessage.LOG_ERROR_FLOAT_OUT_OF_RANGE.getMessage().replace("%number%", String.valueOf(numberToCheck)); logger.warning(warning); - logger.warning(Message.USING_DEFAULT_NUMBER.getMessage()); + logger.warning(LocaleMessage.LOG_ERROR_USING_DEFAULT_FLOAT.getMessage()); return 1.0f; } + private void validateConsoleNames(List list) { + validNamesForConsole.clear(); + for (String name : list) { + validNamesForConsole.add(name.toLowerCase()); + } + } + public boolean isMysqlEnabled() { return mysqlEnabled; @@ -153,15 +161,15 @@ public boolean isCommandSpyEnabled() { return commandSpyEnabled; } - public boolean receivingMessagePlaysSound(){ + public boolean receivingMessagePlaysSound() { return receiveSoundEnabled; } - public boolean sendingMessagePlaysSound(){ + public boolean sendingMessagePlaysSound() { return sendSoundEnabled; } - public boolean messagePlaysSoundForSpy(){ + public boolean messagePlaysSoundForSpy() { return spySoundEnabled; } @@ -173,15 +181,18 @@ public String getSocialSpyFormat() { return socialSpyFormat; } - public Sound getReceiveSound() { + @NotNull + public NamespacedKey getReceiveSound() { return receiveSound; } - public Sound getSendSound() { + @NotNull + public NamespacedKey getSendSound() { return sendSound; } - public Sound getSpySound() { + @NotNull + public NamespacedKey getSpySound() { return spySound; } diff --git a/src/main/java/simplexity/simplepms/config/LocaleHandler.java b/src/main/java/simplexity/simplepms/config/LocaleHandler.java index ee60fff..2d6363e 100644 --- a/src/main/java/simplexity/simplepms/config/LocaleHandler.java +++ b/src/main/java/simplexity/simplepms/config/LocaleHandler.java @@ -52,16 +52,16 @@ public void reloadLocale() { private void populateLocale() { - Set missing = new HashSet<>(Arrays.asList(Message.values())); - for (Message message : Message.values()) { - if (locale.contains(message.getPath())) { - message.setMessage(locale.getString(message.getPath())); - missing.remove(message); + Set missing = new HashSet<>(Arrays.asList(LocaleMessage.values())); + for (LocaleMessage localeMessage : LocaleMessage.values()) { + if (locale.contains(localeMessage.getPath())) { + localeMessage.setMessage(locale.getString(localeMessage.getPath())); + missing.remove(localeMessage); } } - for (Message message : missing) { - locale.set(message.getPath(), message.getMessage()); + for (LocaleMessage localeMessage : missing) { + locale.set(localeMessage.getPath(), localeMessage.getMessage()); } diff --git a/src/main/java/simplexity/simplepms/config/LocaleMessage.java b/src/main/java/simplexity/simplepms/config/LocaleMessage.java new file mode 100644 index 0000000..6499972 --- /dev/null +++ b/src/main/java/simplexity/simplepms/config/LocaleMessage.java @@ -0,0 +1,63 @@ +package simplexity.simplepms.config; + +public enum LocaleMessage { + CONSOLE_SENDER_NAME("console.name", "[Server]"), + CONSOLE_NAME_SOCIAL_SPY("console.social-spy-name", "[Server]"), + RELOADED("plugin.reloaded", "SimplePMs Config has been reloaded"), + BLOCKED_PLAYER("plugin.blocking.successful", "You will no longer receive messages from "), + PLAYER_NOT_BLOCKED("plugin.blocking.not-blocked", "You do not have this player blocked"), + NO_LONGER_BLOCKING("plugin.blocking.removed", "You are no longer blocking "), + FORMAT_SENT("plugin.format.sent", "[You → ] "), + FORMAT_RECEIVED("plugin.format.received", "[ → You] "), + FORMAT_SOCIAL_SPY("plugin.format.social-spy", "[Spy] → » "), + FORMAT_COMMAND_SPY("plugin.format.command-spy", "[Spy] used []"), + SOCIAL_SPY_ENABLED("plugin.social-spy.enabled", "[<#989898>PM-Spy] PM Spy has been enabled"), + SOCIAL_SPY_DISABLED("plugin.social-spy.disabled", "[<#989898>PM-Spy] PM Spy has been disabled"), + MESSAGES_ENABLED("plugin.message.toggle-enabled", "You are now allowing direct messages"), + MESSAGES_DISABLED("plugin.message.toggle-disabled", "You are no longer allowing direct messages"), + BLOCKLIST_HEADER("plugin.block-list.header", "Block List"), + BLOCKLIST_NAME("plugin.block-list.name", "• "), + BLOCKLIST_REASON("plugin.block-list.reason", " (Reason: )"), + BLOCKLIST_EMPTY("plugin.block-list.empty", "You are not blocking anybody"), + ERROR_NOT_A_PLAYER("error.only-player", "You must be a player to execute this command."), + ERROR_NO_PERMISSION("error.no-permission", "You do not have permission to do this"), + ERROR_NO_RECIPIENT_PROVIDED("error.no-recipient-provided", "You must provide a valid recipient for your message"), + ERROR_NO_USER_PROVIDED("error.no-user-provided", "You must provide a valid user"), + ERROR_BLANK_MESSAGE("error.blank-message", "You cannot send someone a blank message"), + ERROR_RECIPIENT_NOT_EXIST("error.recipient-not-exist", "The user either does not exist, or is not online"), + ERROR_TARGET_CANNOT_RECEIVE_MESSAGE("error.cannot-receive-message", "Sorry, looks like that player cannot receive messages right now"), + ERROR_CANNOT_REPLY("error.cannot-reply", "There is nobody to reply to, sorry. Try /msg [name] instead"), + ERROR_YOUR_MESSAGES_CURRENTLY_DISABLED("error.your-messages-currently-disabled", "Sorry, you cannot send a message to someone while your messages are disabled."), + ERROR_CANNOT_MESSAGE_SOMEONE_YOU_BLOCKED("error.cannot-message-someone-you-blocked", "Sorry, you cannot message someone you currently have blocked."), + ERROR_CANNOT_MESSAGE_CONSOLE("error.cannot-message-console", "Sorry, you cannot message the server"), + ERROR_SOMETHING_WENT_WRONG("error.something-wrong", "Sorry, something went wrong, please check console for more information"), + ERROR_NAME_NOT_FOUND("error.name-not-found", "Name not found"), + LOG_ERROR_SOUND_NOT_VALID("console-error.sound-not-valid", "Warning! The sound you have input: '%sound-string%' is invalid! " + + "Sounds must now be in namespaced-key format, you can find the namespaced versions here: " + + "https://jd.papermc.io/paper/1.21.5/io/papermc/paper/registry/keys/SoundEventKeys.html"), + LOG_ERROR_USING_DEFAULT_SOUND("console-error.using-default-sound", "Using %default-sound% until a valid sound is provided"), + LOG_ERROR_FLOAT_OUT_OF_RANGE("console-error.float-out-of-range", "The number %number% is out of range! Volume and pitch values must be a number between 0 and 2!"), + LOG_ERROR_USING_DEFAULT_FLOAT("console-error.using-default-float", "Setting to 1.0 until a valid value is provided"); + + + private final String path; + private String message; + + LocaleMessage(String path, String message) { + this.path = path; + this.message = message; + } + + public String getPath() { + return path; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + +} diff --git a/src/main/java/simplexity/simplepms/config/Message.java b/src/main/java/simplexity/simplepms/config/Message.java deleted file mode 100644 index 8aa1c6a..0000000 --- a/src/main/java/simplexity/simplepms/config/Message.java +++ /dev/null @@ -1,60 +0,0 @@ -package simplexity.simplepms.config; - -public enum Message { - CONSOLE_SENDER_NAME("console.name", "[Server]"), - CONSOLE_NAME_SOCIAL_SPY("console.social-spy-name", "[Server]"), - RELOADED("plugin.reloaded", "SimplePMs Config has been reloaded"), - BLOCKED_PLAYER("plugin.blocking.successful", "You will no longer receive messages from "), - PLAYER_NOT_BLOCKED("plugin.blocking.not-blocked", "You do not have this player blocked"), - NO_LONGER_BLOCKING("plugin.blocking.removed", "You are no longer blocking "), - FORMAT_SENT("plugin.format.sent", "[You → ] "), - FORMAT_RECEIVED("plugin.format.received", "[ → You] "), - FORMAT_SOCIAL_SPY("plugin.format.social-spy", "[Spy] → » "), - FORMAT_COMMAND_SPY("plugin.format.command-spy", "[Spy] used []"), - SOCIAL_SPY_ENABLED("plugin.social-spy.enabled", "[<#989898>PM-Spy] PM Spy has been enabled"), - SOCIAL_SPY_DISABLED("plugin.social-spy.disabled", "[<#989898>PM-Spy] PM Spy has been disabled"), - MESSAGES_ENABLED("plugin.message.toggle-enabled", "You are now allowing direct messages"), - MESSAGES_DISABLED("plugin.message.toggle-disabled", "You are no longer allowing direct messages"), - BLOCKLIST_HEADER("plugin.block-list.header", "Block List"), - BLOCKLIST_NAME("plugin.block-list.name", "• "), - BLOCKLIST_REASON("plugin.block-list.reason", " (Reason: )"), - BLOCKLIST_EMPTY("plugin.block-list.empty", "You are not blocking anybody"), - ONLY_PLAYER("error.only-player", "You must be a player to execute this command."), - NO_PERMISSION("error.no-permission", "You do not have permission to do this"), - NO_RECIPIENT_PROVIDED("error.no-recipient-provided", "You must provide a valid recipient for your message"), - NO_USER_PROVIDED("error.no-user-provided", "You must provide a valid user"), - BLANK_MESSAGE("error.blank-message", "You cannot send someone a blank message"), - RECIPIENT_NOT_EXIST("error.recipient-not-exist", "The user either does not exist, or is not online"), - TARGET_CANNOT_RECIEVE_MESSAGE("error.cannot-receive-message", "Sorry, looks like that player cannot receive messages right now"), - CANNOT_REPLY("error.cannot-reply", "There is nobody to reply to, sorry. Try /msg [name] instead"), - YOUR_MESSAGES_CURRENTLY_DISABLED("error.your-messages-currently-disabled", "Sorry, you cannot send a message to someone while your messages are disabled."), - CANNOT_MESSAGE_SOMEONE_YOU_BLOCKED("error.cannot-message-someone-you-blocked", "Sorry, you cannot message someone you currently have blocked."), - CANNOT_MESSAGE_CONSOLE("error.cannot-message-console", "Sorry, you cannot message the server"), - SOMETHING_WENT_WRONG("error.something-wrong", "Sorry, something went wrong, please check console for more information"), - SOUND_NOT_VALID("console-error.sound-not-valid", "Warning! The sound you have input: '%sound-string%' is invalid! Please be sure you use a sound that is listed on https://jd.papermc.io/paper/1.21.4/org/bukkit/Sound.html"), - USING_DEFAULT_SOUND("console-error.using-default-sound", "Using %default-sound% until a valid sound is provided"), - OUT_OF_RANGE("console-error.float-out-of-range", "The number %number% is out of range! Volume and pitch values must be a number between 0 and 2!"), - USING_DEFAULT_NUMBER("console-error.using-default-float", "Setting to 1.0 until a valid value is provided"); - - - private final String path; - private String message; - - Message(String path, String message) { - this.path = path; - this.message = message; - } - - public String getPath() { - return path; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - -} diff --git a/src/main/java/simplexity/simplepms/events/BlockUserEvent.java b/src/main/java/simplexity/simplepms/events/BlockUserEvent.java new file mode 100644 index 0000000..d2ddf64 --- /dev/null +++ b/src/main/java/simplexity/simplepms/events/BlockUserEvent.java @@ -0,0 +1,159 @@ +package simplexity.simplepms.events; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.util.UUID; + +@SuppressWarnings("unused") +public class BlockUserEvent extends Event implements Cancellable { + private boolean cancelled; + private UUID initiatorUuid; + private UUID blockedPlayerUuid; + private String blockedPlayerName; + private String blockReason; + + private static final HandlerList handlers = new HandlerList(); + + public BlockUserEvent(@NotNull UUID initiatorUuid, @NotNull UUID blockedPlayerUuid, @NotNull String blockedPlayerName, @Nullable String blockReason) { + this.initiatorUuid = initiatorUuid; + this.blockedPlayerUuid = blockedPlayerUuid; + this.blockedPlayerName = blockedPlayerName; + this.blockReason = blockReason; + } + + + /** + * Gets whether this event has been cancelled + * + * @return boolean Cancelled + */ + + @Override + public boolean isCancelled() { + return cancelled; + } + + /** + * Sets whether this event should be cancelled + * + * @param cancel boolean + */ + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + /** + * Gets the handlerList for this event + * + * @return HandlerList + */ + + public @NotNull HandlerList getHandlers() { + return handlers; + } + + /** + * Gets the handlerList for this event + * + * @return HandlerList + */ + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * Gets the UUID of the player doing the blocking + * + * @return UUID + */ + + @NotNull + public UUID getInitiatorUuid() { + return initiatorUuid; + } + + /** + * Sets the UUID for which player will have their block list altered + * Changing this UUID will change which user has a new player added to their blocked list + * This method expects a Player UUID, using andy UUID that does not belong to a player will lead to + * unexpected and unsupported behavior + * + * @param initiatorUuid UUID + */ + public void setInitiatorUuid(@NotNull UUID initiatorUuid) { + this.initiatorUuid = initiatorUuid; + } + + /** + * Gets the UUID of the player being blocked in this event + * + * @return UUID player Being blocked + */ + @NotNull + public UUID getBlockedPlayerUuid() { + return blockedPlayerUuid; + } + + /** + * Sets the UUID of which player should be blocked + * Changing this UUID will alter which user is being placed into the player's block list + * This method expects a Player UUID, using any UUID that does not belong to a player will lead to + * unexpected and unsupported behavior + * + * @param blockedPlayerUuid UUID + */ + public void setBlockedPlayerUuid(@NotNull UUID blockedPlayerUuid) { + this.blockedPlayerUuid = blockedPlayerUuid; + } + + /** + * Gets the name of the player being blocked + * This name is not automatically updated when someone's username changes + * it is only used as a player-readable identifier for remembering who they blocked and being able to unblock them + * All verification is done through UUID + * + * @return String name + */ + @NotNull + public String getBlockedPlayerName() { + return blockedPlayerName; + } + + /** + * Sets the name of the player being blocked, as of the current time. + * This is solely for player-readable identification + * This is used in the block list and in the unblock command, but UUID is used for actual verification. + * Display names can be used here + * + * @param blockedPlayerName String name + */ + public void setBlockedPlayerName(@NotNull String blockedPlayerName) { + this.blockedPlayerName = blockedPlayerName; + } + + /** + * Gets the provided reason for blocking. May be null if no reason was provided. + * + * @return String block reason + */ + @Nullable + public String getBlockReason() { + return blockReason; + } + + /** + * Sets the reason for blocking the other player. + * This is displayed in the user's own blocklist, and when hovering over usernames when unblocking + * + * @param blockReason String + */ + public void setBlockReason(@Nullable String blockReason) { + this.blockReason = blockReason; + } +} diff --git a/src/main/java/simplexity/simplepms/events/PrivateMessageEvent.java b/src/main/java/simplexity/simplepms/events/PrivateMessageEvent.java index 6be2176..498a913 100644 --- a/src/main/java/simplexity/simplepms/events/PrivateMessageEvent.java +++ b/src/main/java/simplexity/simplepms/events/PrivateMessageEvent.java @@ -13,42 +13,42 @@ /** * Called when a private message is sent */ +@SuppressWarnings("unused") public class PrivateMessageEvent extends Event implements Cancellable { - private final CommandSender initiator; - private final CommandSender recipient; - private final String messageContent; + private CommandSender initiator; + private CommandSender recipient; + private String messageContent; private final Set spyingPlayers; private boolean cancelled; private static final HandlerList handlers = new HandlerList(); - public PrivateMessageEvent(CommandSender initiator, CommandSender recipient, String messageContent, Set spyingPlayers) { + public PrivateMessageEvent(@NotNull CommandSender initiator, @NotNull CommandSender recipient, @NotNull String messageContent, @NotNull Set spyingPlayers) { this.initiator = initiator; this.recipient = recipient; this.messageContent = messageContent; this.spyingPlayers = spyingPlayers; } - public @NotNull HandlerList getHandlers() { - return handlers; - } - /** - * Gets the handlerList for this event + * Gets the CommandSender who sent the message. * - * @return HandlerList + * @return CommandSender */ - public static HandlerList getHandlerList() { - return handlers; + public CommandSender getInitiator() { + return initiator; } /** - * Gets the CommandSender who sent the message + * Sets which CommandSender will start this message. + * Expected types are either a Player or a ConsoleCommandSender + * Using other types of CommandSender may lead to unexpected and unsupported behavior * - * @return CommandSender + * @param initiator CommandSender */ - public CommandSender getInitiator() { - return initiator; + + public void setInitiator(CommandSender initiator) { + this.initiator = initiator; } /** @@ -61,14 +61,37 @@ public CommandSender getRecipient() { } /** - * Gets the content of the message being sent + * Sets which CommandSender will receive this message. + * Expected types are either a Player or a ConsoleCommandSender + * Using other types of CommandSender may lead to unexpected and unsupported behavior + * + * @param recipient CommandSender + */ + + public void setRecipient(CommandSender recipient) { + this.recipient = recipient; + } + + /** + * Gets the message that is going to be sent from this event * - * @return String + * @return String message */ public String getMessageContent() { return messageContent; } + /** + * Sets the message that will be sent from this event. + * Note that this only affects the actual message content and not the way the message is formatted + * + * @param messageContent String + */ + + public void setMessageContent(String messageContent) { + this.messageContent = messageContent; + } + /** * Gets the list of players who currently have SocialSpy toggled on * @@ -96,5 +119,23 @@ public void setCancelled(boolean cancel) { cancelled = cancel; } -} + /** + * Gets the handlerList for this event + * + * @return HandlerList + */ + + public @NotNull HandlerList getHandlers() { + return handlers; + } + + /** + * Gets the handlerList for this event + * + * @return HandlerList + */ + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/simplexity/simplepms/events/UnblockUserEvent.java b/src/main/java/simplexity/simplepms/events/UnblockUserEvent.java new file mode 100644 index 0000000..fc91969 --- /dev/null +++ b/src/main/java/simplexity/simplepms/events/UnblockUserEvent.java @@ -0,0 +1,100 @@ +package simplexity.simplepms.events; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +@SuppressWarnings("unused") +public class UnblockUserEvent extends Event implements Cancellable { + private boolean cancelled; + private UUID initiatorUuid; + private UUID blockedPlayerUuid; + private static final HandlerList handlers = new HandlerList(); + + public UnblockUserEvent(UUID initiatorUuid, UUID blockedPlayerUuid) { + this.initiatorUuid = initiatorUuid; + this.blockedPlayerUuid = blockedPlayerUuid; + } + + /** + * Gets whether this event has been cancelled + * + * @return boolean Cancelled + */ + + @Override + public boolean isCancelled() { + return cancelled; + } + + /** + * Sets whether this event should be cancelled + * + * @param cancel boolean + */ + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + /** + * Gets the handler list, idk bukkit requires 2 of these or I'm just doing it wrong + * + * @return HandlerList + */ + + public @NotNull HandlerList getHandlers() { + return handlers; + } + + /** + * Gets the handlerList for this event + * + * @return HandlerList + */ + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * Gets the UUID of the player who requested to unblock someone + * + * @return UUID + */ + public UUID getInitiatorUuid() { + return initiatorUuid; + } + + /** + * Sets the UUID of the person who will request to unblock someone + * + * @param initiatorUuid UUID + */ + + public void setInitiatorUuid(UUID initiatorUuid) { + this.initiatorUuid = initiatorUuid; + } + + /** + * Gets the UUID of the player who will be unblocked + * + * @return UUID + */ + public UUID getBlockedPlayerUuid() { + return blockedPlayerUuid; + } + + /** + * Sets the UUID of the player who will be unblocked + * + * @param blockedPlayerUuid UUID + */ + public void setBlockedPlayerUuid(UUID blockedPlayerUuid) { + this.blockedPlayerUuid = blockedPlayerUuid; + } + +} diff --git a/src/main/java/simplexity/simplepms/listeners/JoinListener.java b/src/main/java/simplexity/simplepms/listeners/JoinListener.java new file mode 100644 index 0000000..f168329 --- /dev/null +++ b/src/main/java/simplexity/simplepms/listeners/JoinListener.java @@ -0,0 +1,20 @@ +package simplexity.simplepms.listeners; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import simplexity.simplepms.logic.Constants; +import simplexity.simplepms.saving.Cache; + +import java.util.UUID; + +public class JoinListener implements Listener { + + @EventHandler + public void onLogin(PlayerJoinEvent joinEvent) { + Player player = joinEvent.getPlayer(); + UUID playerUuid = player.getUniqueId(); + Cache.populateCache(playerUuid, player, player.hasPermission(Constants.ADMIN_SOCIAL_SPY)); + } +} diff --git a/src/main/java/simplexity/simplepms/listeners/LoginListener.java b/src/main/java/simplexity/simplepms/listeners/LoginListener.java deleted file mode 100644 index 598085e..0000000 --- a/src/main/java/simplexity/simplepms/listeners/LoginListener.java +++ /dev/null @@ -1,23 +0,0 @@ -package simplexity.simplepms.listeners; - -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerLoginEvent; -import simplexity.simplepms.SimplePMs; -import simplexity.simplepms.objects.PlayerSettings; -import simplexity.simplepms.saving.SqlHandler; - -public class LoginListener implements Listener { - - @EventHandler - public void onLogin(PlayerLoginEvent event) { - Player player = event.getPlayer(); - PlayerSettings playerSettings = SqlHandler.getInstance().getSettings(player.getUniqueId()); - if (playerSettings.socialSpyEnabled()) { - SimplePMs.getSpyingPlayers().add(player); - } - SimplePMs.getPlayers().add(player); - } - -} diff --git a/src/main/java/simplexity/simplepms/listeners/PreCommandListener.java b/src/main/java/simplexity/simplepms/listeners/PreCommandListener.java index 5633a20..3fb8efa 100644 --- a/src/main/java/simplexity/simplepms/listeners/PreCommandListener.java +++ b/src/main/java/simplexity/simplepms/listeners/PreCommandListener.java @@ -5,10 +5,10 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import simplexity.simplepms.config.ConfigHandler; -import simplexity.simplepms.logic.Messaging; +import simplexity.simplepms.logic.SpyHandler; public class PreCommandListener implements Listener { - @EventHandler(priority= EventPriority.MONITOR, ignoreCancelled = true) + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onCommand(PlayerCommandPreprocessEvent event) { if (!ConfigHandler.getInstance().isCommandSpyEnabled()) return; @@ -16,6 +16,6 @@ public void onCommand(PlayerCommandPreprocessEvent event) { if (!ConfigHandler.getInstance().getCommandsToSpy().contains(args[0])) return; String command = args[0].toLowerCase(); String message = event.getMessage(); - Messaging.sendCommandSpy(event.getPlayer(), command, message); + SpyHandler.sendCommandSpy(event.getPlayer(), command, message); } } diff --git a/src/main/java/simplexity/simplepms/listeners/QuitListener.java b/src/main/java/simplexity/simplepms/listeners/QuitListener.java index 229a684..a7b552c 100644 --- a/src/main/java/simplexity/simplepms/listeners/QuitListener.java +++ b/src/main/java/simplexity/simplepms/listeners/QuitListener.java @@ -3,13 +3,14 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; -import simplexity.simplepms.SimplePMs; +import simplexity.simplepms.saving.Cache; public class QuitListener implements Listener { @EventHandler public void onQuit(PlayerQuitEvent e) { - SimplePMs.getSpyingPlayers().remove(e.getPlayer()); - SimplePMs.getPlayers().remove(e.getPlayer()); + Cache.getSpyingPlayers().remove(e.getPlayer()); + Cache.removeBlockListFromCache(e.getPlayer().getUniqueId()); + Cache.removePlayerSettingsFromCache(e.getPlayer().getUniqueId()); } } diff --git a/src/main/java/simplexity/simplepms/logic/BlockHandler.java b/src/main/java/simplexity/simplepms/logic/BlockHandler.java new file mode 100644 index 0000000..d8349c5 --- /dev/null +++ b/src/main/java/simplexity/simplepms/logic/BlockHandler.java @@ -0,0 +1,35 @@ +package simplexity.simplepms.logic; + +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import simplexity.simplepms.SimplePMs; +import simplexity.simplepms.events.BlockUserEvent; +import simplexity.simplepms.saving.Cache; +import simplexity.simplepms.saving.objects.PlayerBlock; + +import javax.annotation.Nullable; + +public class BlockHandler { + + public static void addBlockedPlayer(@NotNull Player blockingPlayer, @NotNull OfflinePlayer playerToBlock, @Nullable String reason) { + BlockUserEvent blockUserEvent = callBlockEvent(blockingPlayer, playerToBlock, reason); + if (blockUserEvent.isCancelled()) return; + PlayerBlock playerBlock = new PlayerBlock( + blockUserEvent.getInitiatorUuid(), + blockUserEvent.getBlockedPlayerName(), + blockUserEvent.getBlockedPlayerUuid(), + blockUserEvent.getBlockReason()); + Cache.addBlockedUser(blockingPlayer.getUniqueId(), playerBlock); + } + + private static BlockUserEvent callBlockEvent(@NotNull Player blockingPlayer, @NotNull OfflinePlayer playerToBlock, @Nullable String reason) { + String blockedPlayerName = playerToBlock.getName(); + if (blockedPlayerName == null) blockedPlayerName = "[NO NAME FOUND]"; + BlockUserEvent blockUserEvent = new BlockUserEvent(blockingPlayer.getUniqueId(), playerToBlock.getUniqueId(), blockedPlayerName, reason); + SimplePMs.getInstance().getServer().getPluginManager().callEvent(blockUserEvent); + return blockUserEvent; + } + + +} diff --git a/src/main/java/simplexity/simplepms/logic/Constants.java b/src/main/java/simplexity/simplepms/logic/Constants.java new file mode 100644 index 0000000..c89439e --- /dev/null +++ b/src/main/java/simplexity/simplepms/logic/Constants.java @@ -0,0 +1,47 @@ +package simplexity.simplepms.logic; + +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; + +import java.util.Map; + +public class Constants { + public static Permission MESSAGE_BASIC = new Permission("message.basic", "Base permission for basic functionality", + PermissionDefault.TRUE, Map.of( + "message.basic.send", true, + "message.basic.receive", true, + "message.basic.toggle", true, + "message.basic.block", true + )); + public static Permission MESSAGE_ADMIN = new Permission("message.admin", "Base permission for the admin commands", + PermissionDefault.OP, Map.of( + "message.admin.override", true, + "message.admin.social-spy", true, + "message.admin.console-spy", true + )); + + public static Permission MESSAGE_SEND = new Permission("message.basic.send", + "Allows sending messages", PermissionDefault.TRUE); + public static Permission MESSAGE_RECEIVE = new Permission("message.basic.receive", + "Allows receiving messages", PermissionDefault.TRUE); + public static Permission MESSAGE_TOGGLE = new Permission("message.basic.toggle", + "Allows enabling/disabling direct messages", PermissionDefault.TRUE); + public static Permission MESSAGE_BLOCK = new Permission("message.basic.block", + "Allows blocking direct messages from and to specific users", PermissionDefault.TRUE); + public static Permission PLUGIN_RELOAD = new Permission("message.reload", + "Reloads the Simple PMs plugin", PermissionDefault.OP); + public static Permission ADMIN_OVERRIDE = new Permission("message.admin.override", + "Allows messaging someone who has their messages currently disabled, " + + "has you blocked or does not have permissions to usually see messages", PermissionDefault.OP); + public static Permission ADMIN_SOCIAL_SPY = new Permission("message.admin.social-spy", + "Shows the direct messages of other players for moderation purposes", PermissionDefault.OP); + public static Permission ADMIN_CONSOLE_SPY = new Permission("message.admin.console-spy", + "Shows the direct messages sent to and from the console sender (from this plugin) " + + "to other players", PermissionDefault.OP); + public static Permission BYPASS_SOCIAL_SPY = new Permission("message.bypass.social-spy", + "Prevents messages to and from this player from showing in social spy, " + + "does not prevent the message from being formatted on console", PermissionDefault.OP); + public static Permission BYPASS_COMMAND_SPY = new Permission("message.bypass.command-spy", + "Stops your commands from being shown to others with command spy (if they are configured to be tracked). " + + "Does not prevent the message from being formatted on console", PermissionDefault.OP); +} diff --git a/src/main/java/simplexity/simplepms/logic/Util.java b/src/main/java/simplexity/simplepms/logic/MessageUtils.java similarity index 74% rename from src/main/java/simplexity/simplepms/logic/Util.java rename to src/main/java/simplexity/simplepms/logic/MessageUtils.java index 8ce2ac0..bebb868 100644 --- a/src/main/java/simplexity/simplepms/logic/Util.java +++ b/src/main/java/simplexity/simplepms/logic/MessageUtils.java @@ -7,23 +7,22 @@ import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import simplexity.simplepms.SimplePMs; import simplexity.simplepms.config.ConfigHandler; -import simplexity.simplepms.config.Message; +import simplexity.simplepms.config.LocaleMessage; -public class Util { - private static Util instance; +public class MessageUtils { + private static MessageUtils instance; private final MiniMessage miniMessage = SimplePMs.getMiniMessage(); - private Util() { + private MessageUtils() { } - public static Util getInstance() { - if (instance == null) instance = new Util(); + public static MessageUtils getInstance() { + if (instance == null) instance = new MessageUtils(); return instance; } @@ -49,8 +48,8 @@ public Component parseMessage(String localeMessage, @NotNull CommandSender initi private Component getCommmandSenderComponent(CommandSender sender, boolean socialSpy) { if (!(sender instanceof Player player)) { - if (socialSpy) return miniMessage.deserialize(Message.CONSOLE_NAME_SOCIAL_SPY.getMessage()); - return miniMessage.deserialize(Message.CONSOLE_SENDER_NAME.getMessage()); + if (socialSpy) return miniMessage.deserialize(LocaleMessage.CONSOLE_NAME_SOCIAL_SPY.getMessage()); + return miniMessage.deserialize(LocaleMessage.CONSOLE_SENDER_NAME.getMessage()); } if (!SimplePMs.isPapiEnabled()) { if (socialSpy) return parseName(player, ConfigHandler.getInstance().getSocialSpyFormat()); @@ -77,16 +76,9 @@ private Component parsePapiName(Player player, String message) { ); } - public Player getPlayerFromCommandSender(CommandSender sender) { - if (!(sender instanceof Player player)) { - return null; - } - return player; - } - public TagResolver papiTag(final Player player) { if (player == null) return TagResolver.empty(); - return TagResolver.resolver("papi", (argumentQueue, context) -> { + return TagResolver.resolver("papi", (argumentQueue, _) -> { final String papiPlaceholder = argumentQueue.popOr("PLACEHOLDER API NEEDS ARGUMENT").value(); final String parsedPlaceholder = PlaceholderAPI.setPlaceholders(player, '%' + papiPlaceholder + '%'); final Component componentPlaceholder = LegacyComponentSerializer.legacySection().deserialize(parsedPlaceholder); @@ -94,18 +86,4 @@ public TagResolver papiTag(final Player player) { }); } - public Player getPlayer(String name) { - Player player; - player = SimplePMs.getInstance().getServer().getPlayer(name); - if (player != null) { - return player; - } - for (Player listedPlayer : SimplePMs.getPlayers()) { - String listedPlayerPlainName = PlainTextComponentSerializer.plainText().serialize(listedPlayer.displayName()); - if (listedPlayerPlainName.equalsIgnoreCase(name)) { - return listedPlayer; - } - } - return null; - } } diff --git a/src/main/java/simplexity/simplepms/logic/Messaging.java b/src/main/java/simplexity/simplepms/logic/Messaging.java deleted file mode 100644 index 4dc9dd6..0000000 --- a/src/main/java/simplexity/simplepms/logic/Messaging.java +++ /dev/null @@ -1,121 +0,0 @@ -package simplexity.simplepms.logic; - -import net.kyori.adventure.text.Component; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import simplexity.simplepms.SimplePMs; -import simplexity.simplepms.config.ConfigHandler; -import simplexity.simplepms.config.Message; - -public class Messaging { - - private static final String CONSOLE_SPY = "message.admin.console-spy"; - private static final String SOCIAL_SPY_BYPASS = "message.bypass.social-spy"; - private static final String COMMAND_SPY_BYPASS = "message.bypass.command-spy"; - - public static void sendMessage(CommandSender initiator, CommandSender target, String messageContent) { - handleMessageSend(initiator, target, messageContent); - handleMessageReceive(initiator, target, messageContent); - handleSocialSpy(initiator, target, messageContent); - PreProcessing.lastMessaged.put(initiator, target); - PreProcessing.lastMessaged.put(target, initiator); - } - - private static void handleMessageSend(CommandSender initiator, CommandSender target, String messageContent) { - initiator.sendMessage(Util.getInstance().parseMessage( - Message.FORMAT_SENT.getMessage(), - initiator, target, messageContent, false)); - if (!ConfigHandler.getInstance().sendingMessagePlaysSound()) return; - if (!(initiator instanceof Player player)) return; - player.playSound(player, - ConfigHandler.getInstance().getSendSound(), - ConfigHandler.getInstance().getSendVolume(), - ConfigHandler.getInstance().getSendPitch()); - } - - private static void handleMessageReceive(CommandSender initiator, CommandSender target, String messageContent) { - target.sendMessage(Util.getInstance().parseMessage( - Message.FORMAT_RECEIVED.getMessage(), - initiator, target, messageContent, false)); - if (!ConfigHandler.getInstance().receivingMessagePlaysSound()) return; - if (!(target instanceof Player player)) return; - player.playSound(player, - ConfigHandler.getInstance().getReceiveSound(), - ConfigHandler.getInstance().getReceiveVolume(), - ConfigHandler.getInstance().getReceivePitch()); - } - - - public static void sendCommandSpy(CommandSender initiator, String command, String messageContent) { - if (initiator.hasPermission(COMMAND_SPY_BYPASS)) return; - Component parsedMessage = Util.getInstance().parseMessage( - Message.FORMAT_COMMAND_SPY.getMessage(), initiator, - command, messageContent, true); - for (Player spyingPlayer : SimplePMs.getSpyingPlayers()) { - if (initiator.equals(spyingPlayer)) continue; - spyingPlayer.sendMessage(parsedMessage); - playSpySound(spyingPlayer); - } - if (ConfigHandler.getInstance().doesConsoleHaveCommandSpy()) { - sendConsoleMessage(parsedMessage); - } - } - - public static void handleSocialSpy(CommandSender initiator, CommandSender target, String messageContent) { - boolean consoleSpy = false; - Player initiatorPlayer = Util.getInstance().getPlayerFromCommandSender(initiator); - Player targetPlayer = Util.getInstance().getPlayerFromCommandSender(target); - if (initiatorPlayer == null || targetPlayer == null) consoleSpy = true; - if (!consoleSpy) { - if (initiatorPlayer.hasPermission(SOCIAL_SPY_BYPASS) || targetPlayer.hasPermission(SOCIAL_SPY_BYPASS)) return; - sendSocialSpy(initiator, target, messageContent); - } else { - sendConsoleSpy(initiator, target, messageContent); - } - } - - private static void sendConsoleSpy(CommandSender initiator, CommandSender target, String messageContent) { - Component parsedMessage = Util.getInstance().parseMessage( - Message.FORMAT_SOCIAL_SPY.getMessage(), - initiator, target, messageContent, - true); - for (Player spyingPlayer : SimplePMs.getSpyingPlayers()) { - if (initiator.equals(spyingPlayer) || target.equals(spyingPlayer)) continue; - if (!spyingPlayer.hasPermission(CONSOLE_SPY)) continue; - spyingPlayer.sendMessage(parsedMessage); - playSpySound(spyingPlayer); - } - if (ConfigHandler.getInstance().doesConsoleHaveSocialSpy()) { - sendConsoleMessage(parsedMessage); - } - } - - private static void sendSocialSpy(CommandSender initiator, CommandSender target, String messageContent) { - Component parsedMessage = Util.getInstance().parseMessage( - Message.FORMAT_SOCIAL_SPY.getMessage(), - initiator, target, messageContent, - true); - for (Player spyingPlayer : SimplePMs.getSpyingPlayers()) { - if (initiator.equals(spyingPlayer) || target.equals(spyingPlayer)) continue; - spyingPlayer.sendMessage(parsedMessage); - playSpySound(spyingPlayer); - } - if (ConfigHandler.getInstance().doesConsoleHaveSocialSpy()) { - sendConsoleMessage(parsedMessage); - } - } - - private static void sendConsoleMessage(Component message) { - SimplePMs.getPMConsoleSender().sendMessage(message); - } - - private static void playSpySound(Player spyingPlayer) { - if (!ConfigHandler.getInstance().messagePlaysSoundForSpy()) return; - spyingPlayer.playSound(spyingPlayer, - ConfigHandler.getInstance().getSpySound(), - ConfigHandler.getInstance().getSpyVolume(), - ConfigHandler.getInstance().getSpyPitch()); - } - - -} diff --git a/src/main/java/simplexity/simplepms/logic/PMHandler.java b/src/main/java/simplexity/simplepms/logic/PMHandler.java new file mode 100644 index 0000000..ca17c7b --- /dev/null +++ b/src/main/java/simplexity/simplepms/logic/PMHandler.java @@ -0,0 +1,68 @@ +package simplexity.simplepms.logic; + +import org.bukkit.Registry; +import org.bukkit.Sound; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import simplexity.simplepms.SimplePMs; +import simplexity.simplepms.config.ConfigHandler; +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.events.PrivateMessageEvent; +import simplexity.simplepms.saving.Cache; + +import java.util.HashMap; + +public class PMHandler { + public static final HashMap lastMessaged = new HashMap<>(); + + public static void handlePrivateMessage(CommandSender initiator, CommandSender target, String messageContent) { + PrivateMessageEvent messageEvent = callPMEvent(initiator, target, messageContent); + if (messageEvent.isCancelled()) return; + initiator = messageEvent.getInitiator(); + target = messageEvent.getRecipient(); + messageContent = messageEvent.getMessageContent(); + handleMessageSend(initiator, target, messageContent); + handleMessageReceive(initiator, target, messageContent); + lastMessaged.put(initiator, target); + lastMessaged.put(target, initiator); + if (!(initiator instanceof Player) || !(target instanceof Player)) { + SpyHandler.handleConsoleSpy(messageEvent); + } else { + SpyHandler.handleSocialSpy(messageEvent); + } + } + + private static void handleMessageSend(CommandSender initiator, CommandSender target, String messageContent) { + initiator.sendMessage(MessageUtils.getInstance().parseMessage( + LocaleMessage.FORMAT_SENT.getMessage(), + initiator, target, messageContent, false)); + if (!ConfigHandler.getInstance().sendingMessagePlaysSound()) return; + if (!(initiator instanceof Player player)) return; + Sound sound = Registry.SOUNDS.get(ConfigHandler.getInstance().getSendSound()); + if (sound == null) return; + player.playSound(player, sound, + ConfigHandler.getInstance().getSendVolume(), + ConfigHandler.getInstance().getSendPitch()); + } + + private static void handleMessageReceive(CommandSender initiator, CommandSender target, String messageContent) { + target.sendMessage(MessageUtils.getInstance().parseMessage( + LocaleMessage.FORMAT_RECEIVED.getMessage(), + initiator, target, messageContent, false)); + if (!ConfigHandler.getInstance().receivingMessagePlaysSound()) return; + if (!(target instanceof Player player)) return; + Sound sound = Registry.SOUNDS.get(ConfigHandler.getInstance().getReceiveSound()); + if (sound == null) return; + player.playSound(player, sound, + ConfigHandler.getInstance().getReceiveVolume(), + ConfigHandler.getInstance().getReceivePitch()); + } + + + private static PrivateMessageEvent callPMEvent(CommandSender initiator, CommandSender target, String messageContent) { + PrivateMessageEvent messageEvent = new PrivateMessageEvent(initiator, target, messageContent, Cache.getSpyingPlayers()); + SimplePMs.getInstance().getServer().getPluginManager().callEvent(messageEvent); + return messageEvent; + } + +} diff --git a/src/main/java/simplexity/simplepms/logic/PreProcessing.java b/src/main/java/simplexity/simplepms/logic/PreProcessing.java deleted file mode 100644 index 95701f8..0000000 --- a/src/main/java/simplexity/simplepms/logic/PreProcessing.java +++ /dev/null @@ -1,119 +0,0 @@ -package simplexity.simplepms.logic; - -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import simplexity.simplepms.SimplePMs; -import simplexity.simplepms.config.ConfigHandler; -import simplexity.simplepms.config.Message; -import simplexity.simplepms.events.PrivateMessageEvent; -import simplexity.simplepms.objects.PlayerBlock; -import simplexity.simplepms.objects.PlayerSettings; -import simplexity.simplepms.saving.Cache; - -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -public class PreProcessing { - private static PreProcessing instance; - private static final String RECEIVE_PERMISSION = "message.basic.receive"; - private static final String ADMIN_OVERRIDE = "message.admin.override"; - private static final Logger logger = SimplePMs.getInstance().getLogger(); - public static final HashMap lastMessaged = new HashMap<>(); - - - private PreProcessing() { - } - - public static PreProcessing getInstance() { - if (instance == null) instance = new PreProcessing(); - return instance; - } - - public CommandSender getTarget(String[] args) { - String targetString = args[0]; - if (ConfigHandler.getInstance().getValidNamesForConsole().contains(targetString)) { - return SimplePMs.getPMConsoleSender(); - } - return Util.getInstance().getPlayer(targetString); - } - - public boolean messagingBlocked(CommandSender sender, CommandSender recipient, String providedName) { - if (sender.hasPermission(ADMIN_OVERRIDE)) { - return false; - } - if (!(recipient instanceof Player target)) { - return !canSendToNonPlayer(sender, recipient); - } - if (!(sender instanceof Player initiator)) { - logger.info("[ERROR] There was an attempt to send a message from a non-player that is not the console. Info: "); - logger.info("Sender: " + sender.getName() + " [" + sender + "]"); - logger.info("Recipient: " + recipient.getName() + " [" + recipient + "]"); - sender.sendRichMessage(Message.SOMETHING_WENT_WRONG.getMessage()); - return true; - } - if (!initiator.canSee(target) && !ConfigHandler.getInstance().canPlayersSendToHiddenPlayers()) { - initiator.sendRichMessage(Message.RECIPIENT_NOT_EXIST.getMessage(), - Placeholder.unparsed("name", providedName)); - return true; - } - if (messagesDisabled(initiator)) { - initiator.sendRichMessage(Message.YOUR_MESSAGES_CURRENTLY_DISABLED.getMessage()); - return true; - } - if (messagesDisabled(target) || !target.hasPermission(RECEIVE_PERMISSION) || userBlocked(target, initiator)) { - initiator.sendRichMessage(Message.TARGET_CANNOT_RECIEVE_MESSAGE.getMessage()); - return true; - } - if (userBlocked(initiator, target)) { - initiator.sendRichMessage(Message.CANNOT_MESSAGE_SOMEONE_YOU_BLOCKED.getMessage()); - return true; - } - return false; - } - - private boolean canSendToNonPlayer(CommandSender sender, CommandSender recipient) { - if (!recipient.equals(SimplePMs.getPMConsoleSender())) { - logger.info("[ERROR] There was an attempt to send a message to a non-player that is not the console. Info: "); - logger.info("Sender: " + sender.getName() + " [" + sender + "]"); - logger.info("Recipient: " + recipient.getName() + " [" + recipient + "]"); - sender.sendRichMessage(Message.SOMETHING_WENT_WRONG.getMessage()); - return true; - } - if (ConfigHandler.getInstance().canPlayersSendToConsole()) return true; - sender.sendRichMessage(Message.CANNOT_MESSAGE_CONSOLE.getMessage()); - return false; - } - - public boolean messagesDisabled(Player player) { - PlayerSettings playerSettings = Cache.playerSettings.get(player.getUniqueId()); - if (playerSettings == null) { - return false; - } - return playerSettings.messagesDisabled(); - } - - public boolean userBlocked(Player player1, Player player2) { - List playerBlocks = Cache.blockList.get(player1.getUniqueId()); - if (playerBlocks == null) { - return false; - } - for (PlayerBlock playerBlock : playerBlocks) { - if (playerBlock.blockedPlayerUUID().equals(player2.getUniqueId())) { - return true; - } - } - return false; - } - - public void callPMEvent(CommandSender initiator, CommandSender target, String messageContent) { - PrivateMessageEvent messageEvent = new PrivateMessageEvent(initiator, target, messageContent, SimplePMs.getSpyingPlayers()); - SimplePMs.getInstance().getServer().getPluginManager().callEvent(messageEvent); - if (!messageEvent.isCancelled()) { - Messaging.sendMessage(initiator, target, messageContent); - } - - } - -} diff --git a/src/main/java/simplexity/simplepms/logic/SpyHandler.java b/src/main/java/simplexity/simplepms/logic/SpyHandler.java new file mode 100644 index 0000000..5847f8f --- /dev/null +++ b/src/main/java/simplexity/simplepms/logic/SpyHandler.java @@ -0,0 +1,75 @@ +package simplexity.simplepms.logic; + +import net.kyori.adventure.text.Component; +import org.bukkit.Registry; +import org.bukkit.Sound; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import simplexity.simplepms.SimplePMs; +import simplexity.simplepms.config.ConfigHandler; +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.events.PrivateMessageEvent; +import simplexity.simplepms.saving.Cache; + +public class SpyHandler { + + private static final CommandSender console = SimplePMs.getPMConsoleSender(); + + public static void sendCommandSpy(CommandSender initiator, String command, String messageContent) { + Component parsedMessage = MessageUtils.getInstance().parseMessage( + LocaleMessage.FORMAT_COMMAND_SPY.getMessage(), initiator, + command, messageContent, true); + if (ConfigHandler.getInstance().doesConsoleHaveCommandSpy()) { + console.sendMessage(parsedMessage); + } + if (initiator.hasPermission(Constants.BYPASS_COMMAND_SPY)) return; + for (Player spyingPlayer : Cache.getSpyingPlayers()) { + if (initiator.equals(spyingPlayer)) continue; + if (!spyingPlayer.hasPermission(Constants.ADMIN_SOCIAL_SPY)) continue; + spyingPlayer.sendMessage(parsedMessage); + playSpySound(spyingPlayer); + } + } + + public static void handleSocialSpy(PrivateMessageEvent messageEvent) { + Player initiatorPlayer = (Player) messageEvent.getInitiator(); + Player targetPlayer = (Player) messageEvent.getRecipient(); + Component parsedMessage = MessageUtils.getInstance().parseMessage( + LocaleMessage.FORMAT_SOCIAL_SPY.getMessage(), + initiatorPlayer, targetPlayer, messageEvent.getMessageContent(), + true); + if (ConfigHandler.getInstance().doesConsoleHaveSocialSpy()) console.sendMessage(parsedMessage); + if (initiatorPlayer.hasPermission(Constants.BYPASS_SOCIAL_SPY) || + targetPlayer.hasPermission(Constants.BYPASS_SOCIAL_SPY)) return; + for (Player spyingPlayer : messageEvent.getSpyingPlayers()) { + if (!spyingPlayer.hasPermission(Constants.ADMIN_SOCIAL_SPY)) continue; + if (spyingPlayer.equals(initiatorPlayer) || + spyingPlayer.equals(targetPlayer)) continue; + spyingPlayer.sendMessage(parsedMessage); + playSpySound(spyingPlayer); + } + } + + public static void handleConsoleSpy(PrivateMessageEvent messageEvent) { + Component parsedMessage = MessageUtils.getInstance().parseMessage( + LocaleMessage.FORMAT_SOCIAL_SPY.getMessage(), + messageEvent.getInitiator(), messageEvent.getRecipient(), messageEvent.getMessageContent(), + true); + for (Player spyingPlayer : messageEvent.getSpyingPlayers()) { + if (!spyingPlayer.hasPermission(Constants.ADMIN_CONSOLE_SPY)) continue; + if (spyingPlayer.equals(messageEvent.getInitiator()) || + spyingPlayer.equals(messageEvent.getRecipient())) continue; + spyingPlayer.sendMessage(parsedMessage); + playSpySound(spyingPlayer); + } + } + + private static void playSpySound(Player spyingPlayer) { + if (!ConfigHandler.getInstance().messagePlaysSoundForSpy()) return; + Sound sound = Registry.SOUNDS.get(ConfigHandler.getInstance().getSpySound()); + if (sound == null) return; + spyingPlayer.playSound(spyingPlayer, sound, + ConfigHandler.getInstance().getSpyVolume(), + ConfigHandler.getInstance().getSpyPitch()); + } +} diff --git a/src/main/java/simplexity/simplepms/logic/UnblockHandler.java b/src/main/java/simplexity/simplepms/logic/UnblockHandler.java new file mode 100644 index 0000000..4b71693 --- /dev/null +++ b/src/main/java/simplexity/simplepms/logic/UnblockHandler.java @@ -0,0 +1,38 @@ +package simplexity.simplepms.logic; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import simplexity.simplepms.commands.util.Exceptions; +import simplexity.simplepms.events.UnblockUserEvent; +import simplexity.simplepms.saving.Cache; +import simplexity.simplepms.saving.objects.PlayerBlock; + +import java.util.List; +import java.util.UUID; + +public class UnblockHandler { + + public static void removeBlockedPlayer(@NotNull Player blockingPlayer, @NotNull String userToRemove) throws CommandSyntaxException { + List playerBlocks = Cache.getBlockList(blockingPlayer.getUniqueId()); + UUID playerToUnblockUuid = null; + for (PlayerBlock block : playerBlocks) { + if (block.getBlockedPlayerName().equalsIgnoreCase(userToRemove)) { + playerToUnblockUuid = block.getBlockedPlayerUUID(); + break; + } + } + if (playerToUnblockUuid == null) throw Exceptions.ERROR_NOT_BLOCKING_ANYONE_BY_THIS_NAME.create(); + UnblockUserEvent unblockEvent = callUnblockEvent(blockingPlayer.getUniqueId(), playerToUnblockUuid); + if (unblockEvent.isCancelled()) return; + Cache.removeBlockedUser(unblockEvent.getInitiatorUuid(), unblockEvent.getBlockedPlayerUuid()); + + } + + private static UnblockUserEvent callUnblockEvent(@NotNull UUID initiatorUuid, @NotNull UUID playerToUnblockUuid) { + UnblockUserEvent unblockEvent = new UnblockUserEvent(initiatorUuid, playerToUnblockUuid); + Bukkit.getServer().getPluginManager().callEvent(unblockEvent); + return unblockEvent; + } +} diff --git a/src/main/java/simplexity/simplepms/objects/PlayerBlock.java b/src/main/java/simplexity/simplepms/objects/PlayerBlock.java deleted file mode 100644 index 4d69567..0000000 --- a/src/main/java/simplexity/simplepms/objects/PlayerBlock.java +++ /dev/null @@ -1,13 +0,0 @@ -package simplexity.simplepms.objects; - -import java.util.UUID; - -public record PlayerBlock(UUID blockingPlayerUUID, String blockedPlayerName, UUID blockedPlayerUUID, String blockReason) { - - public String toString() { - return "PlayerBlock [" + "blockingPlayerUUID=" + blockingPlayerUUID - + ", blockedPlayerName=" + blockedPlayerName - + "blockedPlayerUUID=" + blockedPlayerUUID - + ", blockReason=" + blockReason + "]"; - } -} diff --git a/src/main/java/simplexity/simplepms/saving/Cache.java b/src/main/java/simplexity/simplepms/saving/Cache.java index a83329e..f686fd8 100644 --- a/src/main/java/simplexity/simplepms/saving/Cache.java +++ b/src/main/java/simplexity/simplepms/saving/Cache.java @@ -1,71 +1,146 @@ package simplexity.simplepms.saving; -import simplexity.simplepms.objects.PlayerBlock; -import simplexity.simplepms.objects.PlayerSettings; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import simplexity.simplepms.SimplePMs; +import simplexity.simplepms.config.LocaleMessage; +import simplexity.simplepms.saving.objects.PlayerBlock; +import simplexity.simplepms.saving.objects.PlayerSettings; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; public class Cache { public static final HashMap> blockList = new HashMap<>(); public static final HashMap playerSettings = new HashMap<>(); + public static final HashSet spyingPlayers = new HashSet<>(); public static List getBlockList(UUID uuid) { - if (blockList.containsKey(uuid)) { - return blockList.get(uuid); - } - List blockedPlayers = SqlHandler.getInstance().getBlockedPlayers(uuid); - blockList.put(uuid, blockedPlayers); - return blockedPlayers; + return blockList.get(uuid); } public static PlayerSettings getPlayerSettings(UUID uuid) { - if (playerSettings.containsKey(uuid)) { - return playerSettings.get(uuid); - } - PlayerSettings settings = SqlHandler.getInstance().getSettings(uuid); - playerSettings.put(uuid, settings); - return settings; + return playerSettings.get(uuid); } + + public static void populateCache(UUID uuid, Player player, boolean hasSpyPerms) { + Bukkit.getScheduler().runTaskAsynchronously(SimplePMs.getInstance(), () -> { + SqlHandler.getInstance().getBlockedPlayers(uuid).thenAccept(blocklist -> { + blockList.put(uuid, blocklist); + populateNullNames(uuid); + }); + SqlHandler.getInstance().getSettings(uuid).thenAccept(settings -> { + playerSettings.put(uuid, settings); + if (hasSpyPerms && settings.isSocialSpyEnabled()) { + spyingPlayers.add(player); + } + }); + }); + } + + /** + * Clears the user from the settings cache + * + * @param uuid Player's UUID + */ + public static void removePlayerSettingsFromCache(UUID uuid) { + playerSettings.remove(uuid); + } + + /** + * Clears the user from the blocklist cache + * + * @param uuid Player's UUID + */ + public static void removeBlockListFromCache(UUID uuid) { + playerSettings.remove(uuid); + } + + /** + * Updates the provided player's current social spy settings. Updates cache and then updates SQL + * + * @param uuid UUID Player Uuid + * @param socialSpy boolean New Setting + */ public static void updateSocialSpySettings(UUID uuid, boolean socialSpy) { - PlayerSettings settings = getPlayerSettings(uuid); + PlayerSettings settings = playerSettings.get(uuid); settings.setSocialSpyEnabled(socialSpy); playerSettings.put(uuid, settings); - SqlHandler.getInstance().updateSettings(uuid, settings); + SqlHandler.getInstance().updateSettings(uuid, settings.isSocialSpyEnabled(), settings.areMessagesDisabled()); } + /** + * Updates the provided player's current message toggle state. Updates cache and then updates SQL + * + * @param uuid UUID Player Uuid + * @param messageDisabled boolean New Setting + */ public static void updateMessageSettings(UUID uuid, boolean messageDisabled) { - PlayerSettings settings = getPlayerSettings(uuid); + PlayerSettings settings = playerSettings.get(uuid); settings.setMessagesDisabled(messageDisabled); playerSettings.put(uuid, settings); - SqlHandler.getInstance().updateSettings(uuid, settings); + SqlHandler.getInstance().updateSettings(uuid, settings.isSocialSpyEnabled(), settings.areMessagesDisabled()); } + /** + * Updates a player's blocklist by adding or updating a blocked player. + * + * @param uuid UUID blocking player + * @param playerBlock PlayerBlock block + */ + public static void addBlockedUser(UUID uuid, PlayerBlock playerBlock) { - List blockedPlayers = getBlockList(uuid); - if (blockedPlayers == null) blockedPlayers = new ArrayList<>(); - blockedPlayers.removeIf(block -> { - UUID blockedUUID = playerBlock.blockedPlayerUUID(); - UUID currentUUID = block.blockedPlayerUUID(); - return currentUUID.equals(blockedUUID); - }); + removeCachedDuplicates(uuid, playerBlock.getBlockedPlayerUUID()); + List blockedPlayers = blockList.get(uuid); blockedPlayers.add(playerBlock); blockList.put(uuid, blockedPlayers); - SqlHandler.getInstance().addBlockedPlayer(uuid, playerBlock.blockedPlayerUUID(), playerBlock.blockReason()); + SqlHandler.getInstance().addBlockedPlayer(uuid, playerBlock.getBlockedPlayerUUID(), playerBlock.getBlockedPlayerName(), playerBlock.getBlockReason()); } - public static void removeBlockedUser(UUID uuid, PlayerBlock playerBlock) { - List blockedPlayers = getBlockList(uuid); - blockedPlayers.removeIf(block -> { - UUID blockedUUID = playerBlock.blockedPlayerUUID(); - UUID currentUUID = block.blockedPlayerUUID(); - return currentUUID.equals(blockedUUID); - }); - blockList.put(uuid, blockedPlayers); - SqlHandler.getInstance().removeBlockedPlayer(uuid, playerBlock.blockedPlayerUUID()); + /** + * Removes a blocked player from a player's blocklist + * + * @param uuid UUID unblocking player + * @param blockedPlayerUuid UUID + */ + public static void removeBlockedUser(UUID uuid, UUID blockedPlayerUuid) { + List userBlockList = blockList.get(uuid); + for (PlayerBlock block : userBlockList) { + if (block.getBlockedPlayerUUID().equals(blockedPlayerUuid)) { + userBlockList.remove(block); + break; + } + } + blockList.put(uuid, userBlockList); + SqlHandler.getInstance().removeBlockedPlayer(uuid, blockedPlayerUuid); + } + + private static void removeCachedDuplicates(UUID blockingUuid, UUID blockedUuid) { + List blockedPlayers = blockList.get(blockingUuid); + if (blockedPlayers == null) blockedPlayers = new ArrayList<>(); + blockedPlayers.removeIf(block -> block.getBlockedPlayerUUID().equals(blockedUuid)); + blockList.put(blockingUuid, blockedPlayers); + } + + private static void populateNullNames(UUID uuidToCheck) { + List playerBlocks = blockList.get(uuidToCheck); + if (playerBlocks == null || playerBlocks.isEmpty()) return; + for (PlayerBlock block : playerBlocks) { + if (block.getBlockedPlayerName() == null || block.getBlockedPlayerName().isEmpty()) { + String newName = Bukkit.getOfflinePlayer(block.getBlockedPlayerUUID()).getName(); + if (newName == null) newName = LocaleMessage.ERROR_NAME_NOT_FOUND.getMessage(); + block.setBlockedPlayerName(newName); + } + } + blockList.put(uuidToCheck, playerBlocks); } + public static Set getSpyingPlayers() { + return spyingPlayers; + } } diff --git a/src/main/java/simplexity/simplepms/saving/SqlHandler.java b/src/main/java/simplexity/simplepms/saving/SqlHandler.java index baa7631..86d0851 100644 --- a/src/main/java/simplexity/simplepms/saving/SqlHandler.java +++ b/src/main/java/simplexity/simplepms/saving/SqlHandler.java @@ -1,62 +1,27 @@ package simplexity.simplepms.saving; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.slf4j.Logger; import simplexity.simplepms.SimplePMs; import simplexity.simplepms.config.ConfigHandler; -import simplexity.simplepms.objects.PlayerBlock; -import simplexity.simplepms.objects.PlayerSettings; +import simplexity.simplepms.saving.objects.PlayerBlock; +import simplexity.simplepms.saving.objects.PlayerSettings; import java.sql.Connection; -import java.sql.DriverManager; +import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.logging.Logger; +import java.util.concurrent.CompletableFuture; -@SuppressWarnings("CallToPrintStackTrace") +@SuppressWarnings({"CallToPrintStackTrace", "SqlResolve", "StringTemplateMigration", "SameParameterValue"}) public class SqlHandler { - private Connection connection; - private final Logger logger = SimplePMs.getInstance().getLogger(); - private static final String blocklistInitStatement = """ - CREATE TABLE IF NOT EXISTS blocklist ( - player_uuid VARCHAR (36) NOT NULL, - blocked_player_uuid VARCHAR(36) NOT NULL, - block_reason VARCHAR(256), - PRIMARY KEY (player_uuid, blocked_player_uuid) - );"""; - - private static final String settingsInitStatement = """ - CREATE TABLE IF NOT EXISTS settings ( - player_uuid VARCHAR (36) NOT NULL PRIMARY KEY, - socialspy_enabled BOOLEAN NOT NULL, - messages_disabled BOOLEAN NOT NULL - );"""; - - private static final String settingsUpdateStatement = """ - REPLACE INTO settings (player_uuid, socialspy_enabled, messages_disabled) - VALUES (?, ?, ?);"""; - - private static final String settingsSelection = """ - SELECT socialspy_enabled, messages_disabled - FROM settings - WHERE player_uuid = ?;"""; - - private static final String blocklistUpdateStatement = """ - REPLACE INTO blocklist (player_uuid, blocked_player_uuid, block_reason) - VALUES (?, ?, ?);"""; - - private static final String deleteBlockStatement = """ - DELETE FROM blocklist - WHERE player_uuid = ? and blocked_player_uuid = ?;"""; - - private static final String blockSelection = """ - SELECT blocked_player_uuid, block_reason - from blocklist - WHERE player_uuid = ?;"""; private SqlHandler() { } @@ -71,103 +36,221 @@ public static SqlHandler getInstance() { } + private static final HikariConfig hikariConfig = new HikariConfig(); + private static HikariDataSource dataSource; + private static final Plugin plugin = SimplePMs.getInstance(); + private final Logger logger = SimplePMs.getInstance().getSLF4JLogger(); + + public void init() { - try { - connection = sqlOrSqlLite(); - try (Statement statement = connection.createStatement()) { - statement.execute(blocklistInitStatement); - statement.execute(settingsInitStatement); - } + setupConfig(); + try (Connection connection = getConnection()) { + PreparedStatement blocklistInitStatement = connection.prepareStatement(""" + CREATE TABLE IF NOT EXISTS blocklist ( + player_uuid VARCHAR (36) NOT NULL, + blocked_player_uuid VARCHAR(36) NOT NULL, + blocked_player_name VARCHAR(256), + block_reason VARCHAR(256), + PRIMARY KEY (player_uuid, blocked_player_uuid) + );"""); + blocklistInitStatement.execute(); + PreparedStatement playerSettingsInitStatement = connection.prepareStatement(""" + CREATE TABLE IF NOT EXISTS settings ( + player_uuid VARCHAR (36) NOT NULL PRIMARY KEY, + socialspy_enabled BOOLEAN NOT NULL, + messages_disabled BOOLEAN NOT NULL + );"""); + playerSettingsInitStatement.execute(); + updateDatabaseColumns(); } catch (SQLException e) { - logger.severe("Failed to connect to database: " + e.getMessage()); - e.printStackTrace(); + logger.warn("Failed to connect to database: {}", e.getMessage(), e); } } - public PlayerSettings getSettings(UUID playerUUID) { - try (PreparedStatement statement = connection.prepareStatement(settingsSelection)) { - statement.setString(1, String.valueOf(playerUUID)); - try (ResultSet resultSet = statement.executeQuery()) { - if (!resultSet.next()) { - PlayerSettings settings = new PlayerSettings(playerUUID); - updateSettings(playerUUID, settings); - return settings; - } else { - boolean socialSpy = resultSet.getBoolean("socialspy_enabled"); - boolean messagesDisabled = resultSet.getBoolean("messages_disabled"); - return new PlayerSettings(playerUUID, socialSpy, messagesDisabled); + public void reloadDatabase() { + logger.info("Reconnecting to SimplePMs database..."); + shutdownConnection(); + setupConfig(); + logger.info("Database reloaded successfully"); + } + + + public CompletableFuture getSettings(UUID playerUUID) { + return CompletableFuture.supplyAsync(() -> { + String queryString = "SELECT socialspy_enabled, messages_disabled FROM settings WHERE player_uuid = ?;"; + PlayerSettings settings = null; + try (Connection connection = getConnection()) { + PreparedStatement statement = connection.prepareStatement(queryString); + statement.setString(1, String.valueOf(playerUUID)); + try (ResultSet resultSet = statement.executeQuery()) { + if (!resultSet.next()) { + settings = new PlayerSettings(playerUUID); + updateSettings(playerUUID, settings.isSocialSpyEnabled(), settings.areMessagesDisabled()); + } else { + boolean socialSpy = resultSet.getBoolean("socialspy_enabled"); + boolean messagesDisabled = resultSet.getBoolean("messages_disabled"); + settings = new PlayerSettings(playerUUID, socialSpy, messagesDisabled); + } } + } catch (SQLException e) { + logger.warn("Failed to retrieve settings from database: {}", e.getMessage(), e); } - } catch (SQLException e) { - logger.severe("Failed to retrieve settings from database: " + e.getMessage()); - e.printStackTrace(); - } - return null; + return settings; + }); } - public void addBlockedPlayer(UUID playerUUID, UUID blockedPlayerUUID, String reason) { - try (PreparedStatement statement = connection.prepareStatement(blocklistUpdateStatement)) { - statement.setString(1, String.valueOf(playerUUID)); - statement.setString(2, String.valueOf(blockedPlayerUUID)); - statement.setString(3, reason); - statement.executeUpdate(); - } catch (SQLException e) { - logger.severe("Failed to add blocked player: " + e.getMessage()); - e.printStackTrace(); - } + public CompletableFuture> getBlockedPlayers(UUID playerUUID) { + return CompletableFuture.supplyAsync(() -> { + String queryString = "SELECT blocked_player_uuid, block_reason, blocked_player_name from blocklist WHERE player_uuid = ?;"; + List blockedPlayers = new ArrayList<>(); + try (Connection connection = getConnection()) { + PreparedStatement statement = connection.prepareStatement(queryString); + statement.setString(1, String.valueOf(playerUUID)); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + UUID blockedPlayerUUID = UUID.fromString(resultSet.getString("blocked_player_uuid")); + String blockedPlayerName = resultSet.getString("blocked_player_name"); + String reason = resultSet.getString("block_reason"); + PlayerBlock block = new PlayerBlock(playerUUID, blockedPlayerName, blockedPlayerUUID, reason); + blockedPlayers.add(block); + } + } + } catch (SQLException e) { + logger.warn("Failed to get blocked players: {}", e.getMessage(), e); + } + return blockedPlayers; + }); + } + + public void addBlockedPlayer(UUID playerUUID, UUID blockedPlayerUUID, String blockedPlayerName, String reason) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + String queryString = "REPLACE INTO blocklist (player_uuid, blocked_player_uuid, blocked_player_name, block_reason) VALUES (?, ?, ?, ?);"; + try (Connection connection = getConnection()) { + PreparedStatement statement = connection.prepareStatement(queryString); + statement.setString(1, String.valueOf(playerUUID)); + statement.setString(2, String.valueOf(blockedPlayerUUID)); + statement.setString(3, blockedPlayerName); + statement.setString(4, reason); + statement.executeUpdate(); + } catch (SQLException e) { + logger.warn("Failed to add blocked player: {}", e.getMessage(), e); + e.printStackTrace(); + } + }); } public void removeBlockedPlayer(UUID playerUUID, UUID blockedPlayerUUID) { - try (PreparedStatement statement = connection.prepareStatement(deleteBlockStatement)) { - statement.setString(1, String.valueOf(playerUUID)); - statement.setString(2, String.valueOf(blockedPlayerUUID)); - statement.executeUpdate(); - } catch (SQLException e) { - logger.severe("Failed to remove blocked player: " + e.getMessage()); - e.printStackTrace(); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + String queryString = "DELETE FROM blocklist WHERE player_uuid = ? and blocked_player_uuid = ?;"; + try (Connection connection = getConnection()) { + PreparedStatement statement = connection.prepareStatement(queryString); + statement.setString(1, String.valueOf(playerUUID)); + statement.setString(2, String.valueOf(blockedPlayerUUID)); + statement.executeUpdate(); + } catch (SQLException e) { + logger.warn("Failed to remove blocked player: {}", e.getMessage(), e); + } + }); + } + + public void updateSettings(UUID playerUUID, boolean socialSpyEnabled, boolean messagesDisabled) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + String queryString = "REPLACE INTO settings (player_uuid, socialspy_enabled, messages_disabled) VALUES (?, ?, ?);"; + try (Connection connection = getConnection()) { + PreparedStatement statement = connection.prepareStatement(queryString); + statement.setString(1, String.valueOf(playerUUID)); + statement.setBoolean(2, socialSpyEnabled); + statement.setBoolean(3, messagesDisabled); + statement.executeUpdate(); + } catch (SQLException e) { + logger.warn("Failed to update settings to database: {}", e.getMessage(), e); + } + }); + + } + + private void updateDatabaseColumns() { + if (ConfigHandler.getInstance().isMysqlEnabled()) { + doesMysqlColumnExist("blocklist", "blocked_player_name").thenAccept(exists -> { + if (!exists) { + addColumn("blocklist", "blocked_player_name", "VARCHAR(256)", ""); + } + }); + } else { + doesSqliteColumnExist("blocklist", "blocked_player_name").thenAccept(exists -> { + if (!exists) { + addColumn("blocklist", "blocked_player_name", "VARCHAR(256)", ""); + } + }); } } - public List getBlockedPlayers(UUID playerUUID) { - List blockedPlayers = new ArrayList<>(); - try (PreparedStatement statement = connection.prepareStatement(blockSelection)) { - statement.setString(1, String.valueOf(playerUUID)); - try (ResultSet resultSet = statement.executeQuery()) { - if (!resultSet.next()) return null; + private CompletableFuture doesSqliteColumnExist(String tableName, String columnName) { + return CompletableFuture.supplyAsync(() -> { + String query = "PRAGMA table_info(" + tableName + ")"; + try (Connection connection = getConnection()) { + PreparedStatement statement = connection.prepareStatement(query); + ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { - UUID blockedPlayerUUID = UUID.fromString(resultSet.getString("blocked_player_uuid")); - String blockedPlayerName = Bukkit.getOfflinePlayer(blockedPlayerUUID).getName(); - String reason = resultSet.getString("block_reason"); - PlayerBlock block = new PlayerBlock(playerUUID, blockedPlayerName, blockedPlayerUUID, reason); - blockedPlayers.add(block); + if (columnName.equalsIgnoreCase(resultSet.getString("name"))) { + return true; + } } + } catch (SQLException e) { + logger.warn("Failed to to check for column {} in table {}: {}", columnName, tableName, e.getMessage(), e); } - return blockedPlayers; - } catch (SQLException e) { - logger.severe("Failed to get blocked players: " + e.getMessage()); - e.printStackTrace(); - } - return null; + return false; + }); + } + + private CompletableFuture doesMysqlColumnExist(String tableName, String columnName) { + return CompletableFuture.supplyAsync(() -> { + try (Connection connection = getConnection()) { + DatabaseMetaData metaData = connection.getMetaData(); + ResultSet resultSet = metaData.getColumns(null, null, tableName, columnName); + return resultSet.next(); + } catch (SQLException e) { + logger.warn("Failed to check for column {} in table {}: {}", columnName, tableName, e.getMessage(), e); + } + return false; + }); } - public void updateSettings(UUID playerUUID, PlayerSettings settings) { - try (PreparedStatement statement = connection.prepareStatement(settingsUpdateStatement)) { - statement.setString(1, String.valueOf(playerUUID)); - statement.setBoolean(2, settings.socialSpyEnabled()); - statement.setBoolean(3, settings.messagesDisabled()); + // Possibly extremely cursed way to do this :cackle: + + private void addColumn(String tableName, String columnName, String dataType, String constraints) { + String query = "ALTER TABLE " + tableName + " ADD COLUMN " + columnName + dataType + constraints + ";"; + try (Connection connection = getConnection()) { + PreparedStatement statement = connection.prepareStatement(query); statement.executeUpdate(); + logger.info("Added new column '{}' to table '{}'", columnName, tableName); } catch (SQLException e) { - logger.severe("Failed to update settings to database: " + e.getMessage()); - e.printStackTrace(); + logger.warn("Failed to add new column {} to table {}: {}", columnName, tableName, e.getMessage(), e); } - } - private Connection sqlOrSqlLite() throws SQLException { - if (ConfigHandler.getInstance().isMysqlEnabled()) { - return DriverManager.getConnection("jdbc:mysql://" + ConfigHandler.getInstance().getMysqlIp() + "/" + ConfigHandler.getInstance().getMysqlName(), ConfigHandler.getInstance().getMysqlUsername(), ConfigHandler.getInstance().getMysqlPassword()); - } else { - return DriverManager.getConnection("jdbc:sqlite:" + SimplePMs.getInstance().getDataFolder() + "/simple-pms.db"); + + private void setupConfig() { + if (!ConfigHandler.getInstance().isMysqlEnabled()) { + hikariConfig.setJdbcUrl("jdbc:sqlite:" + SimplePMs.getInstance().getDataFolder() + "/simple-pms.db"); + hikariConfig.setConnectionTestQuery("PRAGMA journal_mode = WAL;"); + dataSource = new HikariDataSource(hikariConfig); + return; } + hikariConfig.setJdbcUrl("jdbc:mysql://" + ConfigHandler.getInstance().getMysqlIp() + "/" + ConfigHandler.getInstance().getMysqlName()); + hikariConfig.setUsername(ConfigHandler.getInstance().getMysqlUsername()); + hikariConfig.setPassword(ConfigHandler.getInstance().getMysqlPassword()); + dataSource = new HikariDataSource(hikariConfig); + } + + private static Connection getConnection() throws SQLException { + return dataSource.getConnection(); + } + + public void shutdownConnection() { + if (dataSource == null || dataSource.isClosed()) return; + dataSource.close(); + dataSource = null; + logger.info("Closed existing database connection"); } } diff --git a/src/main/java/simplexity/simplepms/saving/objects/PlayerBlock.java b/src/main/java/simplexity/simplepms/saving/objects/PlayerBlock.java new file mode 100644 index 0000000..c68cc50 --- /dev/null +++ b/src/main/java/simplexity/simplepms/saving/objects/PlayerBlock.java @@ -0,0 +1,51 @@ +package simplexity.simplepms.saving.objects; + +import java.util.UUID; + +@SuppressWarnings({"StringTemplateMigration", "unused"}) +public class PlayerBlock { + + private final UUID blockingPlayerUUID; + private final UUID blockedPlayerUUID; + private String blockedPlayerName; + private String blockReason; + + public PlayerBlock(UUID blockingPlayerUUID, String blockedPlayerName, UUID blockedPlayerUUID, String blockReason) { + this.blockingPlayerUUID = blockingPlayerUUID; + this.blockedPlayerUUID = blockedPlayerUUID; + this.blockedPlayerName = blockedPlayerName; + this.blockReason = blockReason; + } + + public UUID getBlockingPlayerUUID() { + return blockingPlayerUUID; + } + + public UUID getBlockedPlayerUUID() { + return blockedPlayerUUID; + } + + public String getBlockedPlayerName() { + return blockedPlayerName; + } + + public void setBlockedPlayerName(String name) { + blockedPlayerName = name; + } + + public String getBlockReason() { + return blockReason; + } + + public void setBlockReason(String reason) { + blockReason = reason; + } + + + public String toString() { + return "PlayerBlock [" + "blockingPlayerUUID=" + blockingPlayerUUID + + ", blockedPlayerName=" + blockedPlayerName + + "blockedPlayerUUID=" + blockedPlayerUUID + + ", blockReason=" + blockReason + "]"; + } +} diff --git a/src/main/java/simplexity/simplepms/objects/PlayerSettings.java b/src/main/java/simplexity/simplepms/saving/objects/PlayerSettings.java similarity index 75% rename from src/main/java/simplexity/simplepms/objects/PlayerSettings.java rename to src/main/java/simplexity/simplepms/saving/objects/PlayerSettings.java index 3b08e35..7edb289 100644 --- a/src/main/java/simplexity/simplepms/objects/PlayerSettings.java +++ b/src/main/java/simplexity/simplepms/saving/objects/PlayerSettings.java @@ -1,7 +1,8 @@ -package simplexity.simplepms.objects; +package simplexity.simplepms.saving.objects; import java.util.UUID; +@SuppressWarnings({"StringTemplateMigration", "unused"}) public final class PlayerSettings { private final UUID playerUUID; private boolean socialSpyEnabled; @@ -21,19 +22,19 @@ public PlayerSettings(UUID playerUUID) { public String toString() { return "Player UUID: " + playerUUID.toString() - + "\nSocial Spy Enabled: " + socialSpyEnabled - + "\nMessages Enabled: " + messagesDisabled; + + "\nSocial Spy Enabled: " + socialSpyEnabled + + "\nMessages Enabled: " + messagesDisabled; } - public UUID playerUUID() { + public UUID getPlayerUUID() { return playerUUID; } - public boolean socialSpyEnabled() { + public boolean isSocialSpyEnabled() { return socialSpyEnabled; } - public boolean messagesDisabled() { + public boolean areMessagesDisabled() { return messagesDisabled; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7e2349d..1729f97 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -37,16 +37,16 @@ command-spy: sounds: received: enabled: false - sound: BLOCK_NOTE_BLOCK_XYLOPHONE + sound: minecraft:block.note_block.xylophone pitch: 1.8 volume: 0.5 sent: enabled: false - sound: ENTITY_ALLAY_ITEM_THROWN + sound: minecraft:entity.allay.item_thrown pitch: 1.8 volume: 0.5 spy: enabled: false - sound: ENTITY_ITEM_FRAME_ROTATE_ITEM + sound: minecraft:entity.item_frame.rotate_item pitch: 1.8 - volume: 0.5 \ No newline at end of file + volume: 0.5 diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml new file mode 100644 index 0000000..b7235b7 --- /dev/null +++ b/src/main/resources/paper-plugin.yml @@ -0,0 +1,10 @@ +name: SimplePMs +version: '${project.version}' +main: simplexity.simplepms.SimplePMs +api-version: 1.20.6 +description: Plugin focused on simple private messaging. +dependencies: + server: + PlaceholderAPI: + load: BEFORE + required: false diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml deleted file mode 100644 index 6fe8a27..0000000 --- a/src/main/resources/plugin.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: SimplePMs -version: '${project.version}' -main: simplexity.simplepms.SimplePMs -api-version: 1.20.6 -authors: [ Rhythmic, Peashooter101 ] -description: Plugin focused on simple private messaging. -softdepend: - - PlaceholderAPI -commands: - msg: - description: "Allows the user to send a private message to someone." - aliases: [tell, w] - permission: message.basic.send - msgtoggle: - description: "Toggles direct messages for the user" - permission: message.basic.toggle - reply: - description: "allows the user to reply to a private message" - aliases: [r] - permission: message.basic.send - block: - description: "Blocks a user from direct-messaging you" - permission: message.basic.block - unblock: - description: "Unblocks a user you have blocked" - permission: message.basic.block - blocklist: - description: "Lists the players you have blocked and the reasons" - permission: message.basic.block - socialspy: - description: "toggles socialspy" - aliases: [ss] - permission: message.admin.social-spy - spmreload: - description: "reloads SimplePMs" - permission: message.reload -permissions: - message.basic: - default: true - description: Base permission for basic functionality - children: - message.basic.send: true - message.basic.receive: true - message.basic.toggle: true - message.basic.block: true - message.basic.send: - default: true - description: Allows sending messages - message.basic.receive: - default: true - description: Allows receiving messages - message.basic.toggle: - default: true - description: Allows enabling/disabling direct messages - message.basic.block: - default: true - description: Allows blocking direct messages from and to specific users - message.reload: - default: op - description: reloads the config and locale - message.admin: - default: op - description: Base permission for the admin commands - children: - message.admin.override: true - message.admin.social-spy: true - message.admin.console-spy: true - message.admin.override: - default: op - description: Allows messaging someone who has their messages currently disabled, has you blocked or does not have permissions to usually see messages - message.admin.social-spy: - default: op - description: Shows the direct messages of other players for moderation purposes - message.admin.console-spy: - default: op - description: Shows the direct messages sent to and from the console sender (from this plugin) to other players - message.bypass.social-spy: - default: op - description: Prevents messages to and from you from showing in social spy, does not prevent the formatted console spy message - message.bypass.command-spy: - default: op - description: Stops your commands from being shown to others with command spy (if they are configured to be tracked). Does not prevent the formatted console spy message