From 0757c6cb4937f6fc4de4b068b531b4ffbe86db53 Mon Sep 17 00:00:00 2001 From: Dominik Date: Mon, 14 Aug 2023 19:48:24 +0200 Subject: [PATCH] Continuation of writing the plugin. --- build.gradle | 3 +- .../github/imdmk/automessage/AutoMessage.java | 132 ++++++++++++++++++ .../imdmk/automessage/AutoMessagePlugin.java | 18 +++ .../command/AutoMessageCommand.java | 42 ++++++ .../command/AutoMessageCreateCommand.java | 86 ++++++++++++ .../command/AutoMessageListCommand.java | 47 +++++++ .../command/AutoMessageRemoveCommand.java | 28 ++++ .../argument/NotificationArgument.java | 45 ++++++ .../argument/NotificationTypeArgument.java | 20 +-- .../handler/MissingPermissionHandler.java | 30 ++++ .../command/handler/NotificationHandler.java | 8 +- .../command/handler/UsageHandler.java | 43 ++++++ .../configuration/PluginConfiguration.java | 16 +++ .../serializer/TitleTimesSerializer.java | 34 +++++ .../notification/Notification.java | 8 ++ .../notification/NotificationFormatter.java | 90 ++++++++++++ .../notification/NotificationSender.java | 83 +++++++++++ .../notification/NotificationType.java | 5 + .../NotificationConfiguration.java | 87 ++++++++++++ .../configuration/NotificationSerializer.java | 117 ++++++++++++++++ .../implementation/ActionBarNotification.java | 17 +++ .../implementation/ChatNotification.java | 17 +++ .../implementation/DisabledNotification.java | 17 +++ .../implementation/TitleNotification.java | 31 ++++ .../bossbar/BossBarManager.java | 25 ++++ .../bossbar/BossBarNotification.java | 32 +++++ .../implementation/bossbar/BossBarTask.java | 36 +++++ .../task/AutoNotificationTask.java | 57 ++++++++ .../automessage}/scheduler/TaskScheduler.java | 2 +- .../scheduler/TaskSchedulerImpl.java | 2 +- .../imdmk/automessage/util/ComponentUtil.java | 28 ++++ .../imdmk}/automessage/util/DurationUtil.java | 10 +- .../imdmk}/automessage/util/RandomUtil.java | 2 +- .../imdmk}/automessage/util/StringUtil.java | 2 +- .../java/me/dmk/automessage/AutoMessage.java | 94 ------------- .../command/AutoMessageCommand.java | 85 ----------- .../argument/NotificationArgument.java | 55 -------- .../editor/CommandPermissionEditor.java | 22 --- .../command/handler/PermissionHandler.java | 26 ---- .../command/handler/UsageHandler.java | 43 ------ .../configuration/PluginConfiguration.java | 71 ---------- .../notification/Notification.java | 30 ---- .../notification/NotificationBuilder.java | 89 ------------ .../notification/NotificationSender.java | 75 ---------- .../notification/NotificationType.java | 6 - .../dmk/automessage/task/AutoMessageTask.java | 57 -------- .../imdmk/automessage/DurationUtilTest.java | 30 ++++ .../imdmk/automessage/StringUtilTest.java | 26 ++++ 48 files changed, 1256 insertions(+), 673 deletions(-) create mode 100644 src/main/java/com/github/imdmk/automessage/AutoMessage.java create mode 100644 src/main/java/com/github/imdmk/automessage/AutoMessagePlugin.java create mode 100644 src/main/java/com/github/imdmk/automessage/command/AutoMessageCommand.java create mode 100644 src/main/java/com/github/imdmk/automessage/command/AutoMessageCreateCommand.java create mode 100644 src/main/java/com/github/imdmk/automessage/command/AutoMessageListCommand.java create mode 100644 src/main/java/com/github/imdmk/automessage/command/AutoMessageRemoveCommand.java create mode 100644 src/main/java/com/github/imdmk/automessage/command/argument/NotificationArgument.java rename src/main/java/{me/dmk => com/github/imdmk}/automessage/command/argument/NotificationTypeArgument.java (53%) create mode 100644 src/main/java/com/github/imdmk/automessage/command/handler/MissingPermissionHandler.java rename src/main/java/{me/dmk => com/github/imdmk}/automessage/command/handler/NotificationHandler.java (67%) create mode 100644 src/main/java/com/github/imdmk/automessage/command/handler/UsageHandler.java create mode 100644 src/main/java/com/github/imdmk/automessage/configuration/PluginConfiguration.java create mode 100644 src/main/java/com/github/imdmk/automessage/configuration/serializer/TitleTimesSerializer.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/Notification.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/NotificationFormatter.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/NotificationSender.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/NotificationType.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/configuration/NotificationConfiguration.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/configuration/NotificationSerializer.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/implementation/ActionBarNotification.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/implementation/ChatNotification.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/implementation/DisabledNotification.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/implementation/TitleNotification.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarManager.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarNotification.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarTask.java create mode 100644 src/main/java/com/github/imdmk/automessage/notification/task/AutoNotificationTask.java rename src/main/java/{me/dmk/automessage/task => com/github/imdmk/automessage}/scheduler/TaskScheduler.java (80%) rename src/main/java/{me/dmk/automessage/task => com/github/imdmk/automessage}/scheduler/TaskSchedulerImpl.java (94%) create mode 100644 src/main/java/com/github/imdmk/automessage/util/ComponentUtil.java rename src/main/java/{me/dmk => com/github/imdmk}/automessage/util/DurationUtil.java (50%) rename src/main/java/{me/dmk => com/github/imdmk}/automessage/util/RandomUtil.java (91%) rename src/main/java/{me/dmk => com/github/imdmk}/automessage/util/StringUtil.java (89%) delete mode 100644 src/main/java/me/dmk/automessage/AutoMessage.java delete mode 100644 src/main/java/me/dmk/automessage/command/AutoMessageCommand.java delete mode 100644 src/main/java/me/dmk/automessage/command/argument/NotificationArgument.java delete mode 100644 src/main/java/me/dmk/automessage/command/editor/CommandPermissionEditor.java delete mode 100644 src/main/java/me/dmk/automessage/command/handler/PermissionHandler.java delete mode 100644 src/main/java/me/dmk/automessage/command/handler/UsageHandler.java delete mode 100644 src/main/java/me/dmk/automessage/configuration/PluginConfiguration.java delete mode 100644 src/main/java/me/dmk/automessage/notification/Notification.java delete mode 100644 src/main/java/me/dmk/automessage/notification/NotificationBuilder.java delete mode 100644 src/main/java/me/dmk/automessage/notification/NotificationSender.java delete mode 100644 src/main/java/me/dmk/automessage/notification/NotificationType.java delete mode 100644 src/main/java/me/dmk/automessage/task/AutoMessageTask.java create mode 100644 src/test/java/com/github/imdmk/automessage/DurationUtilTest.java create mode 100644 src/test/java/com/github/imdmk/automessage/StringUtilTest.java diff --git a/build.gradle b/build.gradle index 71c0da5..4b44c3b 100644 --- a/build.gradle +++ b/build.gradle @@ -29,6 +29,7 @@ dependencies { implementation('eu.okaeri:okaeri-configs-yaml-bukkit:5.0.0-beta.5') implementation('eu.okaeri:okaeri-configs-serdes-commons:5.0.0-beta.5') + implementation('eu.okaeri:okaeri-configs-serdes-bukkit:5.0.0-beta.5') implementation('net.kyori:adventure-platform-bukkit:4.3.0') implementation('net.kyori:adventure-text-minimessage:4.14.0') @@ -54,7 +55,7 @@ bukkit { name = "AutoMessage" version = "${project.version}" apiVersion = "1.17" - main = "me.dmk.automessage.AutoMessage" + main = "com.github.imdmk.automessage.AutoMessagePlugin" author = "DMK" description = "Simple auto message plugin" website = "https://github.com/imDMK/AutoMessage" diff --git a/src/main/java/com/github/imdmk/automessage/AutoMessage.java b/src/main/java/com/github/imdmk/automessage/AutoMessage.java new file mode 100644 index 0000000..fe3ce5e --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/AutoMessage.java @@ -0,0 +1,132 @@ +package com.github.imdmk.automessage; + +import com.github.imdmk.automessage.command.AutoMessageCommand; +import com.github.imdmk.automessage.command.AutoMessageCreateCommand; +import com.github.imdmk.automessage.command.AutoMessageListCommand; +import com.github.imdmk.automessage.command.AutoMessageRemoveCommand; +import com.github.imdmk.automessage.command.argument.NotificationArgument; +import com.github.imdmk.automessage.command.argument.NotificationTypeArgument; +import com.github.imdmk.automessage.command.handler.MissingPermissionHandler; +import com.github.imdmk.automessage.command.handler.NotificationHandler; +import com.github.imdmk.automessage.command.handler.UsageHandler; +import com.github.imdmk.automessage.configuration.PluginConfiguration; +import com.github.imdmk.automessage.configuration.serializer.TitleTimesSerializer; +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationSender; +import com.github.imdmk.automessage.notification.NotificationType; +import com.github.imdmk.automessage.notification.configuration.NotificationSerializer; +import com.github.imdmk.automessage.notification.implementation.bossbar.BossBarManager; +import com.github.imdmk.automessage.notification.implementation.bossbar.BossBarTask; +import com.github.imdmk.automessage.notification.task.AutoNotificationTask; +import com.github.imdmk.automessage.scheduler.TaskScheduler; +import com.github.imdmk.automessage.scheduler.TaskSchedulerImpl; +import com.github.imdmk.automessage.util.DurationUtil; +import com.google.common.base.Stopwatch; +import dev.rollczi.litecommands.LiteCommands; +import dev.rollczi.litecommands.bukkit.adventure.platform.LiteBukkitAdventurePlatformFactory; +import dev.rollczi.litecommands.bukkit.tools.BukkitOnlyPlayerContextual; +import eu.okaeri.configs.ConfigManager; +import eu.okaeri.configs.serdes.commons.SerdesCommons; +import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +public class AutoMessage { + + private final Server server; + + private final PluginConfiguration pluginConfiguration; + + private final BukkitAudiences bukkitAudiences; + private final NotificationSender notificationSender; + + private final BossBarManager bossBarManager; + + private final TaskScheduler taskScheduler; + + private LiteCommands liteCommands; + + public AutoMessage(Plugin plugin) { + Stopwatch stopwatch = Stopwatch.createStarted(); + Logger logger = plugin.getLogger(); + + this.server = plugin.getServer(); + + /* Configuration */ + this.pluginConfiguration = this.createConfiguration(plugin.getDataFolder()); + + /* Adventure */ + this.bukkitAudiences = BukkitAudiences.create(plugin); + this.notificationSender = new NotificationSender(this.bukkitAudiences); + + /* Managers */ + this.bossBarManager = new BossBarManager(); + + /* Tasks */ + this.taskScheduler = new TaskSchedulerImpl(plugin, this.server); + + long delay = DurationUtil.toTicks(this.pluginConfiguration.notificationConfiguration.autoMessagesDelay); + this.taskScheduler.runTimerAsync(new AutoNotificationTask(this.pluginConfiguration.notificationConfiguration, this.notificationSender), delay, delay); + this.taskScheduler.runTimerAsync(new BossBarTask(this.bukkitAudiences, this.bossBarManager), 0L, DurationUtil.toTicks(Duration.ofSeconds(1))); + + /* Commands */ + if (this.pluginConfiguration.autoMessageCommandEnabled) { + this.liteCommands = this.registerLiteCommands(); + } + + /* Update service */ + + logger.info("Enabled plugin in " + stopwatch.stop().elapsed(TimeUnit.MILLISECONDS) + "ms."); + } + + public void onDisable() { + this.bukkitAudiences.close(); + + if (this.liteCommands != null) { + this.liteCommands.getPlatform().unregisterAll(); + } + } + + private PluginConfiguration createConfiguration(File dataFolder) { + return ConfigManager.create(PluginConfiguration.class, (it) -> { + it.withConfigurer(new YamlBukkitConfigurer(), new SerdesCommons()); + it.withSerdesPack(registry -> { + registry.register(new TitleTimesSerializer()); + registry.register(new NotificationSerializer()); + }); + it.withBindFile(new File(dataFolder, "configuration.yml")); + it.withRemoveOrphans(true); + it.saveDefaults(); + it.load(true); + }); + } + + private LiteCommands registerLiteCommands() { + return LiteBukkitAdventurePlatformFactory.builder(this.server, "AutoMessage", false, this.bukkitAudiences, true) + .contextualBind(Player.class, new BukkitOnlyPlayerContextual<>("Command only for player")) + + .argument(NotificationType.class, new NotificationTypeArgument(this.pluginConfiguration.notificationConfiguration)) + .argument(Notification.class, new NotificationArgument(this.pluginConfiguration.notificationConfiguration)) + + .invalidUsageHandler(new UsageHandler(this.pluginConfiguration.notificationConfiguration, this.notificationSender)) + .permissionHandler(new MissingPermissionHandler(this.pluginConfiguration.notificationConfiguration, this.notificationSender)) + .resultHandler(Notification.class, new NotificationHandler(this.notificationSender)) + + .commandInstance( + new AutoMessageCommand(this.pluginConfiguration.notificationConfiguration, this.notificationSender), + new AutoMessageCreateCommand(this.pluginConfiguration.notificationConfiguration, this.notificationSender), + new AutoMessageListCommand(this.pluginConfiguration.notificationConfiguration, this.notificationSender), + new AutoMessageRemoveCommand(this.pluginConfiguration.notificationConfiguration, this.notificationSender) + ) + + .register(); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/AutoMessagePlugin.java b/src/main/java/com/github/imdmk/automessage/AutoMessagePlugin.java new file mode 100644 index 0000000..96d727f --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/AutoMessagePlugin.java @@ -0,0 +1,18 @@ +package com.github.imdmk.automessage; + +import org.bukkit.plugin.java.JavaPlugin; + +public class AutoMessagePlugin extends JavaPlugin { + + private AutoMessage autoMessage; + + @Override + public void onEnable() { + this.autoMessage = new AutoMessage(this); + } + + @Override + public void onDisable() { + this.autoMessage.onDisable(); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/command/AutoMessageCommand.java b/src/main/java/com/github/imdmk/automessage/command/AutoMessageCommand.java new file mode 100644 index 0000000..177dae8 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/command/AutoMessageCommand.java @@ -0,0 +1,42 @@ +package com.github.imdmk.automessage.command; + +import com.github.imdmk.automessage.notification.NotificationSender; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import dev.rollczi.litecommands.command.execute.Execute; +import dev.rollczi.litecommands.command.route.Route; +import org.bukkit.command.CommandSender; + +import java.time.Duration; + +@Route(name = "automessage") +public class AutoMessageCommand { + + private final NotificationConfiguration notificationConfiguration; + private final NotificationSender notificationSender; + + public AutoMessageCommand(NotificationConfiguration notificationConfiguration, NotificationSender notificationSender) { + this.notificationConfiguration = notificationConfiguration; + this.notificationSender = notificationSender; + } + + @Execute(route = "enable") + public void enable(CommandSender sender) { + this.notificationConfiguration.autoMessagesEnabled = true; + + this.notificationSender.sendNotification(sender, this.notificationConfiguration.autoMessagesEnabledNotification); + } + + @Execute(route = "disable") + public void disable(CommandSender sender) { + this.notificationConfiguration.autoMessagesEnabled = false; + + this.notificationSender.sendNotification(sender, this.notificationConfiguration.autoMessagesDisabledNotification); + } + + @Execute(route = "delay") + public void delay(CommandSender sender, Duration delay) { + this.notificationConfiguration.autoMessagesDelay = delay; + + this.notificationSender.sendNotification(sender, this.notificationConfiguration.autoMessagesChangedDelayNotification); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/command/AutoMessageCreateCommand.java b/src/main/java/com/github/imdmk/automessage/command/AutoMessageCreateCommand.java new file mode 100644 index 0000000..165c373 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/command/AutoMessageCreateCommand.java @@ -0,0 +1,86 @@ +package com.github.imdmk.automessage.command; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationFormatter; +import com.github.imdmk.automessage.notification.NotificationSender; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import com.github.imdmk.automessage.notification.implementation.ActionBarNotification; +import com.github.imdmk.automessage.notification.implementation.ChatNotification; +import com.github.imdmk.automessage.notification.implementation.TitleNotification; +import com.github.imdmk.automessage.notification.implementation.bossbar.BossBarNotification; +import dev.rollczi.litecommands.argument.Arg; +import dev.rollczi.litecommands.argument.Name; +import dev.rollczi.litecommands.argument.joiner.Joiner; +import dev.rollczi.litecommands.command.execute.Execute; +import dev.rollczi.litecommands.command.route.Route; +import net.kyori.adventure.bossbar.BossBar; +import org.bukkit.command.CommandSender; + +import java.time.Duration; +import java.util.Arrays; + +@Route(name = "automessage create") +public class AutoMessageCreateCommand { + + private final NotificationConfiguration notificationConfiguration; + private final NotificationSender notificationSender; + + public AutoMessageCreateCommand(NotificationConfiguration notificationConfiguration, NotificationSender notificationSender) { + this.notificationConfiguration = notificationConfiguration; + this.notificationSender = notificationSender; + } + + @Execute(route = "CHAT") + void createChat(CommandSender sender, @Joiner @Name("message") String message) { + ChatNotification chatNotification = new ChatNotification(message); + + this.notificationConfiguration.autoMessages.add(chatNotification); + + this.notificationSender.sendNotification(sender, this.createAddedNotification(chatNotification)); + } + + @Execute(route = "ACTIONBAR") + void createActionbar(CommandSender sender, @Joiner @Name("message") String message) { + ActionBarNotification actionBarNotification = new ActionBarNotification(message); + + this.notificationConfiguration.autoMessages.add(actionBarNotification); + + this.notificationSender.sendNotification(sender, this.createAddedNotification(actionBarNotification)); + } + + @Execute(route = "TITLE") + void createTitle(CommandSender sender, @Joiner @Name("message") String message) { + System.out.println(message); + + String[] splitMessage = message.split("\\|"); + + System.out.println(Arrays.toString(splitMessage)); + + if (splitMessage[0] == null || splitMessage[1] == null) { + this.notificationSender.sendNotification(sender, this.notificationConfiguration.invalidTitleMessageNotification); + return; + } + + TitleNotification titleNotification = new TitleNotification(splitMessage[0], splitMessage[1]); + + this.notificationConfiguration.autoMessages.add(titleNotification); + + this.notificationSender.sendNotification(sender, this.createAddedNotification(titleNotification)); + } + + @Execute(route = "BOSSBAR") + void createBossBar(CommandSender sender, @Arg @Name("time") Duration time, @Arg @Name("progress") float progress, @Arg @Name("color") BossBar.Color color, @Arg @Name("overlay") BossBar.Overlay overlay, @Joiner @Name("name") String name) { + BossBarNotification bossBarNotification = new BossBarNotification(name, time, progress, color, overlay); + + this.notificationConfiguration.autoMessages.add(bossBarNotification); + + this.notificationSender.sendNotification(sender, this.createAddedNotification(bossBarNotification)); + } + + private Notification createAddedNotification(Notification notification) { + return new NotificationFormatter(this.notificationConfiguration.autoMessageAddedNotification) + .placeholder("{TYPE}", notification.type().name().toUpperCase()) + .placeholder("{POSITION}", this.notificationConfiguration.autoMessages.size() + 1) + .build(); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/command/AutoMessageListCommand.java b/src/main/java/com/github/imdmk/automessage/command/AutoMessageListCommand.java new file mode 100644 index 0000000..6f70aea --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/command/AutoMessageListCommand.java @@ -0,0 +1,47 @@ +package com.github.imdmk.automessage.command; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationFormatter; +import com.github.imdmk.automessage.notification.NotificationSender; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import dev.rollczi.litecommands.command.execute.Execute; +import dev.rollczi.litecommands.command.route.Route; +import org.bukkit.command.CommandSender; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +@Route(name = "automessage") +public class AutoMessageListCommand { + + private final NotificationConfiguration notificationConfiguration; + private final NotificationSender notificationSender; + + public AutoMessageListCommand(NotificationConfiguration notificationConfiguration, NotificationSender notificationSender) { + this.notificationConfiguration = notificationConfiguration; + this.notificationSender = notificationSender; + } + + @Execute(route = "list") + void listAutoMessages(CommandSender sender) { + List autoMessages = this.notificationConfiguration.autoMessages; + + if (autoMessages.isEmpty()) { + this.notificationSender.sendNotification(sender, this.notificationConfiguration.autoMessagesEmptyNotification); + return; + } + + AtomicInteger position = new AtomicInteger(1); + + for (Notification notification : autoMessages) { + position.incrementAndGet(); + + Notification autoMessagesList = new NotificationFormatter(this.notificationConfiguration.autoMessagesListNotification) + .placeholder("{POSITION}", position.get()) + .placeholder("{NOTIFICATION}", notification.format()) + .build(); + + this.notificationSender.sendNotification(sender, autoMessagesList); + } + } +} diff --git a/src/main/java/com/github/imdmk/automessage/command/AutoMessageRemoveCommand.java b/src/main/java/com/github/imdmk/automessage/command/AutoMessageRemoveCommand.java new file mode 100644 index 0000000..3bffef6 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/command/AutoMessageRemoveCommand.java @@ -0,0 +1,28 @@ +package com.github.imdmk.automessage.command; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationSender; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import dev.rollczi.litecommands.argument.Arg; +import dev.rollczi.litecommands.command.execute.Execute; +import dev.rollczi.litecommands.command.route.Route; +import org.bukkit.command.CommandSender; + +@Route(name = "automessage") +public class AutoMessageRemoveCommand { + + private final NotificationConfiguration notificationConfiguration; + private final NotificationSender notificationSender; + + public AutoMessageRemoveCommand(NotificationConfiguration notificationConfiguration, NotificationSender notificationSender) { + this.notificationConfiguration = notificationConfiguration; + this.notificationSender = notificationSender; + } + + @Execute(route = "remove") + void remove(CommandSender sender, @Arg Notification notification) { + this.notificationConfiguration.autoMessages.remove(notification); + + this.notificationSender.sendNotification(sender, this.notificationConfiguration.autoMessageRemovedNotification); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/command/argument/NotificationArgument.java b/src/main/java/com/github/imdmk/automessage/command/argument/NotificationArgument.java new file mode 100644 index 0000000..dd19be4 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/command/argument/NotificationArgument.java @@ -0,0 +1,45 @@ +package com.github.imdmk.automessage.command.argument; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import com.github.imdmk.automessage.util.StringUtil; +import dev.rollczi.litecommands.argument.simple.OneArgument; +import dev.rollczi.litecommands.command.LiteInvocation; +import dev.rollczi.litecommands.suggestion.Suggestion; +import panda.std.Result; + +import java.util.List; +import java.util.stream.IntStream; + +public class NotificationArgument implements OneArgument { + + private final NotificationConfiguration notificationConfiguration; + + public NotificationArgument(NotificationConfiguration notificationConfiguration) { + this.notificationConfiguration = notificationConfiguration; + } + + @Override + public Result parse(LiteInvocation invocation, String argument) { + if (!StringUtil.isInteger(argument)) { + return Result.error(this.notificationConfiguration.invalidNumberNotification); + } + + int position = Integer.parseInt(argument); + + if (position < 0 || position >= this.notificationConfiguration.autoMessages.size()) { + return Result.error(this.notificationConfiguration.autoMessageNotFoundNotification); + } + + Notification notification = this.notificationConfiguration.autoMessages.get(position); + return Result.ok(notification); + } + + @Override + public List suggest(LiteInvocation invocation) { + return IntStream.range(0, this.notificationConfiguration.autoMessages.size()) + .mapToObj(String::valueOf) + .map(Suggestion::of) + .toList(); + } +} diff --git a/src/main/java/me/dmk/automessage/command/argument/NotificationTypeArgument.java b/src/main/java/com/github/imdmk/automessage/command/argument/NotificationTypeArgument.java similarity index 53% rename from src/main/java/me/dmk/automessage/command/argument/NotificationTypeArgument.java rename to src/main/java/com/github/imdmk/automessage/command/argument/NotificationTypeArgument.java index 4a9a2bb..df2a79d 100644 --- a/src/main/java/me/dmk/automessage/command/argument/NotificationTypeArgument.java +++ b/src/main/java/com/github/imdmk/automessage/command/argument/NotificationTypeArgument.java @@ -1,36 +1,36 @@ -package me.dmk.automessage.command.argument; +package com.github.imdmk.automessage.command.argument; +import com.github.imdmk.automessage.notification.NotificationType; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; import dev.rollczi.litecommands.argument.ArgumentName; import dev.rollczi.litecommands.argument.simple.OneArgument; import dev.rollczi.litecommands.command.LiteInvocation; import dev.rollczi.litecommands.suggestion.Suggestion; -import me.dmk.automessage.configuration.PluginConfiguration; -import me.dmk.automessage.notification.Notification; -import me.dmk.automessage.notification.NotificationType; import panda.std.Result; import java.util.List; import java.util.stream.Stream; -@ArgumentName("type") +@ArgumentName("position") public class NotificationTypeArgument implements OneArgument { - private final PluginConfiguration pluginConfiguration; + private final NotificationConfiguration notificationConfiguration; - public NotificationTypeArgument(PluginConfiguration pluginConfiguration) { - this.pluginConfiguration = pluginConfiguration; + public NotificationTypeArgument(NotificationConfiguration notificationConfiguration) { + this.notificationConfiguration = notificationConfiguration; } @Override - public Result parse(LiteInvocation invocation, String argument) { + public Result parse(LiteInvocation invocation, String argument) { return Result.supplyThrowing(IllegalArgumentException.class, () -> NotificationType.valueOf(argument.toUpperCase())) - .mapErr(e -> this.pluginConfiguration.invalidNotificationTypeMessage); + .mapErr(e -> this.notificationConfiguration.invalidTypeNotification); } @Override public List suggest(LiteInvocation invocation) { return Stream.of(NotificationType.values()) .map(NotificationType::name) + .map(String::toUpperCase) .map(Suggestion::of) .toList(); } diff --git a/src/main/java/com/github/imdmk/automessage/command/handler/MissingPermissionHandler.java b/src/main/java/com/github/imdmk/automessage/command/handler/MissingPermissionHandler.java new file mode 100644 index 0000000..052222a --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/command/handler/MissingPermissionHandler.java @@ -0,0 +1,30 @@ +package com.github.imdmk.automessage.command.handler; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationFormatter; +import com.github.imdmk.automessage.notification.NotificationSender; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import dev.rollczi.litecommands.command.LiteInvocation; +import dev.rollczi.litecommands.command.permission.RequiredPermissions; +import dev.rollczi.litecommands.handle.PermissionHandler; +import org.bukkit.command.CommandSender; + +public class MissingPermissionHandler implements PermissionHandler { + + private final NotificationConfiguration notificationConfiguration; + private final NotificationSender notificationSender; + + public MissingPermissionHandler(NotificationConfiguration notificationConfiguration, NotificationSender notificationSender) { + this.notificationConfiguration = notificationConfiguration; + this.notificationSender = notificationSender; + } + + @Override + public void handle(CommandSender sender, LiteInvocation invocation, RequiredPermissions requiredPermissions) { + Notification notification = new NotificationFormatter(this.notificationConfiguration.missingPermissionNotification) + .placeholder("{PERMISSIONS}", requiredPermissions.getPermissions()) + .build(); + + this.notificationSender.sendNotification(sender, notification); + } +} diff --git a/src/main/java/me/dmk/automessage/command/handler/NotificationHandler.java b/src/main/java/com/github/imdmk/automessage/command/handler/NotificationHandler.java similarity index 67% rename from src/main/java/me/dmk/automessage/command/handler/NotificationHandler.java rename to src/main/java/com/github/imdmk/automessage/command/handler/NotificationHandler.java index b5f5d5f..d210f9b 100644 --- a/src/main/java/me/dmk/automessage/command/handler/NotificationHandler.java +++ b/src/main/java/com/github/imdmk/automessage/command/handler/NotificationHandler.java @@ -1,9 +1,9 @@ -package me.dmk.automessage.command.handler; +package com.github.imdmk.automessage.command.handler; +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationSender; import dev.rollczi.litecommands.command.LiteInvocation; import dev.rollczi.litecommands.handle.Handler; -import me.dmk.automessage.notification.Notification; -import me.dmk.automessage.notification.NotificationSender; import org.bukkit.command.CommandSender; public class NotificationHandler implements Handler { @@ -16,6 +16,6 @@ public NotificationHandler(NotificationSender notificationSender) { @Override public void handle(CommandSender sender, LiteInvocation invocation, Notification notification) { - this.notificationSender.sendMessage(sender, notification); + this.notificationSender.sendNotification(sender, notification); } } diff --git a/src/main/java/com/github/imdmk/automessage/command/handler/UsageHandler.java b/src/main/java/com/github/imdmk/automessage/command/handler/UsageHandler.java new file mode 100644 index 0000000..b995fba --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/command/handler/UsageHandler.java @@ -0,0 +1,43 @@ +package com.github.imdmk.automessage.command.handler; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationFormatter; +import com.github.imdmk.automessage.notification.NotificationSender; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import dev.rollczi.litecommands.command.LiteInvocation; +import dev.rollczi.litecommands.handle.InvalidUsageHandler; +import dev.rollczi.litecommands.schematic.Schematic; +import org.bukkit.command.CommandSender; + +public class UsageHandler implements InvalidUsageHandler { + + private final NotificationConfiguration notificationConfiguration; + private final NotificationSender notificationSender; + + public UsageHandler(NotificationConfiguration notificationConfiguration, NotificationSender notificationSender) { + this.notificationConfiguration = notificationConfiguration; + this.notificationSender = notificationSender; + } + + @Override + public void handle(CommandSender sender, LiteInvocation invocation, Schematic schematic) { + if (schematic.isOnlyFirst()) { + Notification notification = new NotificationFormatter(this.notificationConfiguration.invalidUsageNotification) + .placeholder("{USAGE}", schematic.first()) + .build(); + + this.notificationSender.sendNotification(sender, notification); + return; + } + + this.notificationSender.sendNotification(sender, this.notificationConfiguration.invalidUsageFirstNotification); + + for (String schema : schematic.getSchematics()) { + Notification notification = new NotificationFormatter(this.notificationConfiguration.invalidUsageListNotification) + .placeholder("{USAGE}", schema) + .build(); + + this.notificationSender.sendNotification(sender, notification); + } + } +} diff --git a/src/main/java/com/github/imdmk/automessage/configuration/PluginConfiguration.java b/src/main/java/com/github/imdmk/automessage/configuration/PluginConfiguration.java new file mode 100644 index 0000000..edb5040 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/configuration/PluginConfiguration.java @@ -0,0 +1,16 @@ +package com.github.imdmk.automessage.configuration; + +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import eu.okaeri.configs.OkaeriConfig; + +public class PluginConfiguration extends OkaeriConfig { + + public boolean checkForUpdates = true; + + public boolean autoMessageCommandEnabled = true; + + public String autoMessageCommandPermission = "command.automessage"; + + public NotificationConfiguration notificationConfiguration = new NotificationConfiguration(); + +} diff --git a/src/main/java/com/github/imdmk/automessage/configuration/serializer/TitleTimesSerializer.java b/src/main/java/com/github/imdmk/automessage/configuration/serializer/TitleTimesSerializer.java new file mode 100644 index 0000000..9d9c85e --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/configuration/serializer/TitleTimesSerializer.java @@ -0,0 +1,34 @@ +package com.github.imdmk.automessage.configuration.serializer; + +import eu.okaeri.configs.schema.GenericsDeclaration; +import eu.okaeri.configs.serdes.DeserializationData; +import eu.okaeri.configs.serdes.ObjectSerializer; +import eu.okaeri.configs.serdes.SerializationData; +import net.kyori.adventure.title.Title; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.time.Duration; + +public class TitleTimesSerializer implements ObjectSerializer { + + @Override + public boolean supports(@NonNull Class type) { + return Title.Times.class.isAssignableFrom(type); + } + + @Override + public void serialize(Title.Times times, @NonNull SerializationData data, @NonNull GenericsDeclaration generics) { + data.add("fadeIn", times.fadeIn(), Duration.class); + data.add("stay", times.stay(), Duration.class); + data.add("fadeOut", times.fadeOut(), Duration.class); + } + + @Override + public Title.Times deserialize(@NonNull DeserializationData data, @NonNull GenericsDeclaration generics) { + Duration fadeIn = data.get("fadeIn", Duration.class); + Duration stay = data.get("stay", Duration.class); + Duration fadeOut = data.get("fadeOut", Duration.class); + + return Title.Times.times(fadeIn, stay, fadeOut); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/Notification.java b/src/main/java/com/github/imdmk/automessage/notification/Notification.java new file mode 100644 index 0000000..72378ca --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/Notification.java @@ -0,0 +1,8 @@ +package com.github.imdmk.automessage.notification; + +public interface Notification { + + NotificationType type(); + + String format(); +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/NotificationFormatter.java b/src/main/java/com/github/imdmk/automessage/notification/NotificationFormatter.java new file mode 100644 index 0000000..2d79810 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/NotificationFormatter.java @@ -0,0 +1,90 @@ +package com.github.imdmk.automessage.notification; + +import com.github.imdmk.automessage.notification.implementation.ActionBarNotification; +import com.github.imdmk.automessage.notification.implementation.ChatNotification; +import com.github.imdmk.automessage.notification.implementation.DisabledNotification; +import com.github.imdmk.automessage.notification.implementation.TitleNotification; +import com.github.imdmk.automessage.notification.implementation.bossbar.BossBarNotification; + +import javax.annotation.CheckReturnValue; +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +public class NotificationFormatter { + + private final Notification notification; + private final HashMap placeholders = new HashMap<>(); + + public NotificationFormatter(Notification notification) { + this.notification = notification; + } + + @CheckReturnValue + public NotificationFormatter placeholder(@Nonnull String from, String to) { + this.placeholders.put(from, to); + return this; + } + + @CheckReturnValue + public NotificationFormatter placeholder(@Nonnull String from, Iterable sequences) { + this.placeholders.put(from, String.join(", ", sequences)); + return this; + } + + @CheckReturnValue + public NotificationFormatter placeholder(@Nonnull String from, T to) { + this.placeholders.put(from, to.toString()); + return this; + } + + public String replacePlaceholders(String message) { + AtomicReference replacedMessage = new AtomicReference<>(message); + + for (Map.Entry entry : this.placeholders.entrySet()) { + replacedMessage.updateAndGet(string -> string.replace(entry.getKey(), entry.getValue())); + } + + return replacedMessage.get(); + } + + public Notification build() { + return switch (this.notification.type()) { + case CHAT -> { + ChatNotification chatNotification = (ChatNotification) this.notification; + + String message = this.replacePlaceholders(chatNotification.message()); + + yield new ChatNotification(message); + } + + case ACTIONBAR -> { + ActionBarNotification actionBarNotification = (ActionBarNotification) this.notification; + + String message = this.replacePlaceholders(actionBarNotification.message()); + + yield new ActionBarNotification(message); + } + + case TITLE -> { + TitleNotification titleNotification = (TitleNotification) this.notification; + + String title = this.replacePlaceholders(titleNotification.title()); + String subtitle = this.replacePlaceholders(titleNotification.subtitle()); + + yield new TitleNotification(title, subtitle, titleNotification.times()); + } + + case BOSSBAR -> { + BossBarNotification bossBarNotification = (BossBarNotification) this.notification; + + String name = this.replacePlaceholders(bossBarNotification.name()); + + yield new BossBarNotification(name, bossBarNotification.time(), bossBarNotification.progress(), bossBarNotification.color(), bossBarNotification.overlay()); + } + + case DISABLED -> new DisabledNotification(); + }; + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/NotificationSender.java b/src/main/java/com/github/imdmk/automessage/notification/NotificationSender.java new file mode 100644 index 0000000..370c072 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/NotificationSender.java @@ -0,0 +1,83 @@ +package com.github.imdmk.automessage.notification; + +import com.github.imdmk.automessage.notification.implementation.ActionBarNotification; +import com.github.imdmk.automessage.notification.implementation.ChatNotification; +import com.github.imdmk.automessage.notification.implementation.TitleNotification; +import com.github.imdmk.automessage.notification.implementation.bossbar.BossBarNotification; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.platform.AudienceProvider; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.title.Title; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class NotificationSender { + + private final AudienceProvider audienceProvider; + private final MiniMessage miniMessage; + + public NotificationSender(AudienceProvider audienceProvider) { + this.audienceProvider = audienceProvider; + this.miniMessage = MiniMessage.miniMessage(); + } + + public void broadcast(Notification notification) { + Audience audience = this.audienceProvider.players(); + + this.sendNotification(audience, notification); + } + + public void sendNotification(CommandSender sender, Notification notification) { + Audience audience = this.createAudience(sender); + + this.sendNotification(audience, notification); + } + + public void sendNotification(Audience audience, Notification notification) { + switch (notification.type()) { + case CHAT -> { + ChatNotification chatNotification = (ChatNotification) notification; + + Component message = this.miniMessage.deserialize(chatNotification.message()); + + audience.sendMessage(message); + } + + case ACTIONBAR -> { + ActionBarNotification actionBarNotification = (ActionBarNotification) notification; + + Component message = this.miniMessage.deserialize(actionBarNotification.message()); + + audience.sendActionBar(message); + } + + case TITLE -> { + TitleNotification titleNotification = (TitleNotification) notification; + + Title titleMessage = titleNotification.create(); + + audience.showTitle(titleMessage); + } + + case BOSSBAR -> { + BossBarNotification bossBarNotification = (BossBarNotification) notification; + + BossBar bossBar = bossBarNotification.create(); + + audience.showBossBar(bossBar); + } + + default -> throw new IllegalStateException("Unexpected notification type: " + notification.type()); + } + } + + public Audience createAudience(CommandSender sender) { + if (sender instanceof Player player) { + return this.audienceProvider.player(player.getUniqueId()); + } + + return this.audienceProvider.console(); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/NotificationType.java b/src/main/java/com/github/imdmk/automessage/notification/NotificationType.java new file mode 100644 index 0000000..72f206b --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/NotificationType.java @@ -0,0 +1,5 @@ +package com.github.imdmk.automessage.notification; + +public enum NotificationType { + CHAT, ACTIONBAR, TITLE, BOSSBAR, DISABLED +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/configuration/NotificationConfiguration.java b/src/main/java/com/github/imdmk/automessage/notification/configuration/NotificationConfiguration.java new file mode 100644 index 0000000..3887589 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/configuration/NotificationConfiguration.java @@ -0,0 +1,87 @@ +package com.github.imdmk.automessage.notification.configuration; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.implementation.ActionBarNotification; +import com.github.imdmk.automessage.notification.implementation.ChatNotification; +import com.github.imdmk.automessage.notification.implementation.TitleNotification; +import com.github.imdmk.automessage.notification.implementation.bossbar.BossBarNotification; +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.annotation.Comment; +import net.kyori.adventure.bossbar.BossBar; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +public class NotificationConfiguration extends OkaeriConfig { + + @Comment({ + "# The value of whether automatic messages should be enabled", + "# This value is changed when auto messages are disabled using the automessage enable/disable command" + }) + public boolean autoMessagesEnabled = true; + + @Comment({ + "# How often should automatic messages be sent?", + "# Example: 10s" + }) + public Duration autoMessagesDelay = Duration.ofSeconds(10); + + @Comment({ + "# Automatic message sending mode", + "# Modes: ", + "# RANDOM: Automatic messages will be selected randomly", + "# SEQUENTIAL: Automatic messages will be selected in turn" + }) + public AutoMessageMode autoMessagesMode = AutoMessageMode.SEQUENTIAL; + + @Comment({ + "# Automatic message list", + "# If you have trouble configuring the messages, please refer to the project's github." + }) + public List autoMessages = new ArrayList<>(List.of( + new ChatNotification("This is first message"), + new ActionBarNotification("This is second message"), + new TitleNotification("Third message", "This is third message"), + new BossBarNotification("Fourth message announcement!", Duration.ofSeconds(5), BossBar.MAX_PROGRESS, BossBar.Color.RED, BossBar.Overlay.PROGRESS) + )); + + @Comment("# Command notifications") + public Notification autoMessagesEnabledNotification = new ChatNotification("Enabled automatic messages."); + public Notification autoMessagesDisabledNotification = new ChatNotification("Disabled automatic messages."); + + public Notification autoMessagesChangedDelayNotification = new ChatNotification("Changed automatic messages delay."); + + @Comment("# {POSITION} - Position of automatic message") + public Notification autoMessageAddedNotification = new ChatNotification("Added new automatic message with type {TYPE} at position {POSITION}."); + public Notification autoMessageRemovedNotification = new ChatNotification("Removed automatic message."); + + public Notification autoMessagesListFirstNotification = new ChatNotification("List of automatic messages:"); + + @Comment({ + "# {POSITION} - Position of automatic message", + "# {TYPE} - The notification type of automatic message", + "# {MESSAGE} - The content of automatic message" + }) + public Notification autoMessagesListNotification = new ChatNotification("{POSITION}. : {NOTIFICATION}"); + + public Notification autoMessagesEmptyNotification = new ChatNotification("Automatic messages is empty."); + + public Notification autoMessageNotFoundNotification = new ChatNotification("Automatic message not found."); + + public Notification invalidTitleMessageNotification = new ChatNotification("Use the | character to separate title and subtitle messages.\nExample: This is title message | This is subtitle message."); + + @Comment("# {USAGE} - The usage of command") + public Notification invalidUsageNotification = new ChatNotification("Invalid usage: {USAGE}"); + @Comment("# This notifications are used when there is more than one option to use a command") + public Notification invalidUsageFirstNotification = new ChatNotification("Invalid usage:"); + public ChatNotification invalidUsageListNotification = new ChatNotification("- {USAGE}"); + + public Notification invalidNumberNotification = new ChatNotification("Invalid number."); + public Notification invalidTypeNotification = new ChatNotification("Invalid notification type."); + public Notification missingPermissionNotification = new ChatNotification("Missing permissions: {PERMISSIONS}"); + + public enum AutoMessageMode { + RANDOM, SEQUENTIAL + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/configuration/NotificationSerializer.java b/src/main/java/com/github/imdmk/automessage/notification/configuration/NotificationSerializer.java new file mode 100644 index 0000000..69de76d --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/configuration/NotificationSerializer.java @@ -0,0 +1,117 @@ +package com.github.imdmk.automessage.notification.configuration; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationType; +import com.github.imdmk.automessage.notification.implementation.ActionBarNotification; +import com.github.imdmk.automessage.notification.implementation.ChatNotification; +import com.github.imdmk.automessage.notification.implementation.DisabledNotification; +import com.github.imdmk.automessage.notification.implementation.TitleNotification; +import com.github.imdmk.automessage.notification.implementation.bossbar.BossBarNotification; +import eu.okaeri.configs.schema.GenericsDeclaration; +import eu.okaeri.configs.serdes.DeserializationData; +import eu.okaeri.configs.serdes.ObjectSerializer; +import eu.okaeri.configs.serdes.SerializationData; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.title.Title; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.time.Duration; +import java.util.Optional; + +public class NotificationSerializer implements ObjectSerializer { + + @Override + public boolean supports(@NonNull Class type) { + return Notification.class.isAssignableFrom(type); + } + + @Override + public void serialize(@NonNull Notification notification, @NonNull SerializationData data, @NonNull GenericsDeclaration generics) { + NotificationType type = notification.type(); + + data.add("type", type, NotificationType.class); + + switch (type) { + case CHAT -> { + ChatNotification chatNotification = (ChatNotification) notification; + + data.add("message", chatNotification.message(), String.class); + } + + case ACTIONBAR -> { + ActionBarNotification actionBarNotification = (ActionBarNotification) notification; + + data.add("message", actionBarNotification.message(), String.class); + } + + case TITLE -> { + TitleNotification titleNotification = (TitleNotification) notification; + + data.add("title", titleNotification.title(), String.class); + data.add("subtitle", titleNotification.subtitle(), String.class); + + data.add("times", titleNotification.times(), Title.Times.class); + } + + case BOSSBAR -> { + BossBarNotification bossBarNotification = (BossBarNotification) notification; + + data.add("name", bossBarNotification.name(), String.class); + data.add("time", bossBarNotification.time(), Duration.class); + data.add("progress", bossBarNotification.progress(), float.class); + data.add("color", bossBarNotification.color(), BossBar.Color.class); + data.add("overlay", bossBarNotification.overlay(), BossBar.Overlay.class); + } + + case DISABLED -> { + } + + default -> throw new IllegalStateException("Unexpected notification type: " + type); + } + } + + @Override + public Notification deserialize(@NonNull DeserializationData data, @NonNull GenericsDeclaration generics) { + NotificationType type = data.get("type", NotificationType.class); + + switch (type) { + case CHAT -> { + String message = data.get("message", String.class); + + return new ChatNotification(message); + } + + case ACTIONBAR -> { + String message = data.get("message", String.class); + + return new ActionBarNotification(message); + } + + case TITLE -> { + String title = data.get("title", String.class); + String subtitle = data.get("subtitle", String.class); + + Title.Times times = Optional.ofNullable(data.get("times", Title.Times.class)) + .orElse(Title.DEFAULT_TIMES); + + return new TitleNotification(title, subtitle, times); + } + + case BOSSBAR -> { + String name = data.get("name", String.class); + Duration time = data.get("time", Duration.class); + float progress = data.get("progress", float.class); + BossBar.Color color = data.get("color", BossBar.Color.class); + BossBar.Overlay overlay = data.get("overlay", BossBar.Overlay.class); + + return new BossBarNotification(name, time, progress, color, overlay); + } + + case DISABLED -> { + return new DisabledNotification(); + } + + default -> throw new IllegalStateException("Unexpected notification type: " + type); + } + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/implementation/ActionBarNotification.java b/src/main/java/com/github/imdmk/automessage/notification/implementation/ActionBarNotification.java new file mode 100644 index 0000000..907fb7f --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/implementation/ActionBarNotification.java @@ -0,0 +1,17 @@ +package com.github.imdmk.automessage.notification.implementation; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationType; + +public record ActionBarNotification(String message) implements Notification { + + @Override + public NotificationType type() { + return NotificationType.ACTIONBAR; + } + + @Override + public String format() { + return this.type().name() + ", message: " + this.message; + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/implementation/ChatNotification.java b/src/main/java/com/github/imdmk/automessage/notification/implementation/ChatNotification.java new file mode 100644 index 0000000..2341959 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/implementation/ChatNotification.java @@ -0,0 +1,17 @@ +package com.github.imdmk.automessage.notification.implementation; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationType; + +public record ChatNotification(String message) implements Notification { + + @Override + public NotificationType type() { + return NotificationType.CHAT; + } + + @Override + public String format() { + return this.type().name() + ", message: " + this.message; + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/implementation/DisabledNotification.java b/src/main/java/com/github/imdmk/automessage/notification/implementation/DisabledNotification.java new file mode 100644 index 0000000..e931356 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/implementation/DisabledNotification.java @@ -0,0 +1,17 @@ +package com.github.imdmk.automessage.notification.implementation; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationType; + +public class DisabledNotification implements Notification { + + @Override + public NotificationType type() { + return NotificationType.DISABLED; + } + + @Override + public String format() { + return this.type().name(); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/implementation/TitleNotification.java b/src/main/java/com/github/imdmk/automessage/notification/implementation/TitleNotification.java new file mode 100644 index 0000000..1d504d5 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/implementation/TitleNotification.java @@ -0,0 +1,31 @@ +package com.github.imdmk.automessage.notification.implementation; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationType; +import com.github.imdmk.automessage.util.ComponentUtil; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; + +public record TitleNotification(String title, String subtitle, Title.Times times) implements Notification { + + public TitleNotification(String title, String subtitle) { + this(title, subtitle, Title.DEFAULT_TIMES); + } + + public Title create() { + Component title = ComponentUtil.deserialize(this.title); + Component subtitle = ComponentUtil.deserialize(this.subtitle); + + return Title.title(title, subtitle, this.times); + } + + @Override + public NotificationType type() { + return NotificationType.TITLE; + } + + @Override + public String format() { + return this.type().name() + ", title: " + this.title + ", subtitle: " + this.subtitle; + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarManager.java b/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarManager.java new file mode 100644 index 0000000..f9fe626 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarManager.java @@ -0,0 +1,25 @@ +package com.github.imdmk.automessage.notification.implementation.bossbar; + +import net.kyori.adventure.bossbar.BossBar; + +import java.time.Duration; +import java.time.Instant; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class BossBarManager { + + private final Map bossBars = new ConcurrentHashMap<>(); + + public void add(BossBar bossBar, Duration time) { + this.bossBars.put(bossBar, Instant.now().plus(time)); + } + + public void remove(BossBar bossBar) { + this.bossBars.remove(bossBar); + } + + public Map getBossBars() { + return this.bossBars; + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarNotification.java b/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarNotification.java new file mode 100644 index 0000000..83d5e4a --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarNotification.java @@ -0,0 +1,32 @@ +package com.github.imdmk.automessage.notification.implementation.bossbar; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationType; +import com.github.imdmk.automessage.util.ComponentUtil; +import com.github.imdmk.automessage.util.DurationUtil; +import net.kyori.adventure.bossbar.BossBar; + +import java.time.Duration; + +public record BossBarNotification(String name, Duration time, float progress, BossBar.Color color, + BossBar.Overlay overlay) implements Notification { + + public BossBar create() { + return BossBar.bossBar(ComponentUtil.deserialize(this.name), this.progress, this.color, this.overlay); + } + + @Override + public NotificationType type() { + return NotificationType.BOSSBAR; + } + + @Override + public String format() { + return this.type().name() + + ", message: " + this.name + + ", name: " + DurationUtil.toHumanReadable(this.time) + + ", progress: " + this.progress + + ", color: " + this.color.name().toUpperCase() + + ", overlay: " + this.overlay.name().toUpperCase(); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarTask.java b/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarTask.java new file mode 100644 index 0000000..8467818 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/implementation/bossbar/BossBarTask.java @@ -0,0 +1,36 @@ +package com.github.imdmk.automessage.notification.implementation.bossbar; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.platform.AudienceProvider; + +import java.time.Duration; +import java.time.Instant; + +public class BossBarTask implements Runnable { + + private final AudienceProvider audienceProvider; + private final BossBarManager bossBarManager; + + public BossBarTask(AudienceProvider audienceProvider, BossBarManager bossBarManager) { + this.audienceProvider = audienceProvider; + this.bossBarManager = bossBarManager; + } + + @Override + public void run() { + this.bossBarManager.getBossBars().forEach((bossBar, instant) -> { + Audience audience = this.audienceProvider.players(); + + if (instant.isAfter(Instant.now())) { + audience.hideBossBar(bossBar); + return; + } + + Duration between = Duration.between(Instant.now(), instant); + + float progress = (float) between.toMillis() / instant.getEpochSecond(); + + bossBar.progress(progress); + }); + } +} diff --git a/src/main/java/com/github/imdmk/automessage/notification/task/AutoNotificationTask.java b/src/main/java/com/github/imdmk/automessage/notification/task/AutoNotificationTask.java new file mode 100644 index 0000000..8154c0a --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/notification/task/AutoNotificationTask.java @@ -0,0 +1,57 @@ +package com.github.imdmk.automessage.notification.task; + +import com.github.imdmk.automessage.notification.Notification; +import com.github.imdmk.automessage.notification.NotificationSender; +import com.github.imdmk.automessage.notification.configuration.NotificationConfiguration; +import com.github.imdmk.automessage.util.RandomUtil; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; + +public class AutoNotificationTask implements Runnable { + + private final NotificationConfiguration notificationConfiguration; + private final NotificationSender notificationSender; + + private final AtomicInteger position = new AtomicInteger(0); + + public AutoNotificationTask(NotificationConfiguration notificationConfiguration, NotificationSender notificationSender) { + this.notificationConfiguration = notificationConfiguration; + this.notificationSender = notificationSender; + } + + @Override + public void run() { + if (!this.notificationConfiguration.autoMessagesEnabled) { + return; + } + + if (this.notificationConfiguration.autoMessages.isEmpty()) { + return; + } + + this.selectNotification().ifPresent(this.notificationSender::broadcast); + } + + private Optional selectNotification() { + return switch (this.notificationConfiguration.autoMessagesMode) { + case RANDOM -> this.selectRandomNotification(); + case SEQUENTIAL -> this.selectNextNotification(); + }; + } + + private Optional selectRandomNotification() { + return RandomUtil.getRandom(this.notificationConfiguration.autoMessages); + } + + private Optional selectNextNotification() { + List autoMessages = this.notificationConfiguration.autoMessages; + + int position = this.position.getAndIncrement() % autoMessages.size(); + + return autoMessages.stream() + .skip(position) + .findFirst(); + } +} diff --git a/src/main/java/me/dmk/automessage/task/scheduler/TaskScheduler.java b/src/main/java/com/github/imdmk/automessage/scheduler/TaskScheduler.java similarity index 80% rename from src/main/java/me/dmk/automessage/task/scheduler/TaskScheduler.java rename to src/main/java/com/github/imdmk/automessage/scheduler/TaskScheduler.java index 85ac444..ccb3c8a 100644 --- a/src/main/java/me/dmk/automessage/task/scheduler/TaskScheduler.java +++ b/src/main/java/com/github/imdmk/automessage/scheduler/TaskScheduler.java @@ -1,4 +1,4 @@ -package me.dmk.automessage.task.scheduler; +package com.github.imdmk.automessage.scheduler; public interface TaskScheduler { diff --git a/src/main/java/me/dmk/automessage/task/scheduler/TaskSchedulerImpl.java b/src/main/java/com/github/imdmk/automessage/scheduler/TaskSchedulerImpl.java similarity index 94% rename from src/main/java/me/dmk/automessage/task/scheduler/TaskSchedulerImpl.java rename to src/main/java/com/github/imdmk/automessage/scheduler/TaskSchedulerImpl.java index 4e1ebd0..fd57200 100644 --- a/src/main/java/me/dmk/automessage/task/scheduler/TaskSchedulerImpl.java +++ b/src/main/java/com/github/imdmk/automessage/scheduler/TaskSchedulerImpl.java @@ -1,4 +1,4 @@ -package me.dmk.automessage.task.scheduler; +package com.github.imdmk.automessage.scheduler; import org.bukkit.Server; import org.bukkit.plugin.Plugin; diff --git a/src/main/java/com/github/imdmk/automessage/util/ComponentUtil.java b/src/main/java/com/github/imdmk/automessage/util/ComponentUtil.java new file mode 100644 index 0000000..5198c41 --- /dev/null +++ b/src/main/java/com/github/imdmk/automessage/util/ComponentUtil.java @@ -0,0 +1,28 @@ +package com.github.imdmk.automessage.util; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; + +import java.util.List; + +public class ComponentUtil { + + public static final CharSequence LEGACY_CHAR = "ยง"; + + private ComponentUtil() { + throw new UnsupportedOperationException("This is utility class."); + } + + public static Component deserialize(String text) { + return text.contains(LEGACY_CHAR) + ? LegacyComponentSerializer.legacySection().deserialize(text) + : MiniMessage.miniMessage().deserialize(text); + } + + public static List deserialize(List strings) { + return strings.stream() + .map(ComponentUtil::deserialize) + .toList(); + } +} diff --git a/src/main/java/me/dmk/automessage/util/DurationUtil.java b/src/main/java/com/github/imdmk/automessage/util/DurationUtil.java similarity index 50% rename from src/main/java/me/dmk/automessage/util/DurationUtil.java rename to src/main/java/com/github/imdmk/automessage/util/DurationUtil.java index 3fd7890..26366c8 100644 --- a/src/main/java/me/dmk/automessage/util/DurationUtil.java +++ b/src/main/java/com/github/imdmk/automessage/util/DurationUtil.java @@ -1,4 +1,4 @@ -package me.dmk.automessage.util; +package com.github.imdmk.automessage.util; import java.time.Duration; @@ -8,6 +8,14 @@ private DurationUtil() { throw new UnsupportedOperationException("This is utility class."); } + public static String toHumanReadable(Duration duration) { + return Duration.ofSeconds(duration.toSeconds()) + .toString() + .substring(2) + .replaceAll("(\\d[HMS])(?!$)", "$1 ") + .toLowerCase(); + } + public static long toTicks(Duration duration) { return duration.dividedBy(50L).toMillis(); //50 Milliseconds = 1 tick } diff --git a/src/main/java/me/dmk/automessage/util/RandomUtil.java b/src/main/java/com/github/imdmk/automessage/util/RandomUtil.java similarity index 91% rename from src/main/java/me/dmk/automessage/util/RandomUtil.java rename to src/main/java/com/github/imdmk/automessage/util/RandomUtil.java index 594c65f..fcbe68d 100644 --- a/src/main/java/me/dmk/automessage/util/RandomUtil.java +++ b/src/main/java/com/github/imdmk/automessage/util/RandomUtil.java @@ -1,4 +1,4 @@ -package me.dmk.automessage.util; +package com.github.imdmk.automessage.util; import java.util.Collection; import java.util.Optional; diff --git a/src/main/java/me/dmk/automessage/util/StringUtil.java b/src/main/java/com/github/imdmk/automessage/util/StringUtil.java similarity index 89% rename from src/main/java/me/dmk/automessage/util/StringUtil.java rename to src/main/java/com/github/imdmk/automessage/util/StringUtil.java index 5e1caa1..bf25af9 100644 --- a/src/main/java/me/dmk/automessage/util/StringUtil.java +++ b/src/main/java/com/github/imdmk/automessage/util/StringUtil.java @@ -1,4 +1,4 @@ -package me.dmk.automessage.util; +package com.github.imdmk.automessage.util; public final class StringUtil { diff --git a/src/main/java/me/dmk/automessage/AutoMessage.java b/src/main/java/me/dmk/automessage/AutoMessage.java deleted file mode 100644 index e4d53c7..0000000 --- a/src/main/java/me/dmk/automessage/AutoMessage.java +++ /dev/null @@ -1,94 +0,0 @@ -package me.dmk.automessage; - -import dev.rollczi.litecommands.LiteCommands; -import dev.rollczi.litecommands.bukkit.adventure.platform.LiteBukkitAdventurePlatformFactory; -import dev.rollczi.litecommands.bukkit.tools.BukkitOnlyPlayerContextual; -import eu.okaeri.configs.ConfigManager; -import eu.okaeri.configs.serdes.commons.SerdesCommons; -import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer; -import me.dmk.automessage.command.AutoMessageCommand; -import me.dmk.automessage.command.argument.NotificationArgument; -import me.dmk.automessage.command.argument.NotificationTypeArgument; -import me.dmk.automessage.command.editor.CommandPermissionEditor; -import me.dmk.automessage.command.handler.NotificationHandler; -import me.dmk.automessage.command.handler.PermissionHandler; -import me.dmk.automessage.command.handler.UsageHandler; -import me.dmk.automessage.configuration.PluginConfiguration; -import me.dmk.automessage.notification.Notification; -import me.dmk.automessage.notification.NotificationSender; -import me.dmk.automessage.notification.NotificationType; -import me.dmk.automessage.task.AutoMessageTask; -import me.dmk.automessage.task.scheduler.TaskScheduler; -import me.dmk.automessage.task.scheduler.TaskSchedulerImpl; -import me.dmk.automessage.util.DurationUtil; -import net.kyori.adventure.platform.bukkit.BukkitAudiences; -import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.io.File; -import java.time.Duration; -import java.time.Instant; - -public class AutoMessage extends JavaPlugin { - - private PluginConfiguration pluginConfiguration; - - private BukkitAudiences bukkitAudiences; - private NotificationSender notificationSender; - - private LiteCommands liteCommands; - - @Override - public void onEnable() { - Instant start = Instant.now(); - - this.pluginConfiguration = ConfigManager.create(PluginConfiguration.class, (it) -> { - it.withConfigurer(new YamlBukkitConfigurer(), new SerdesCommons()); - it.withBindFile(new File(this.getDataFolder(), "configuration.yml")); - it.withRemoveOrphans(true); - it.saveDefaults(); - it.load(true); - }); - - this.bukkitAudiences = BukkitAudiences.create(this); - this.notificationSender = new NotificationSender(this.bukkitAudiences, MiniMessage.miniMessage()); - - TaskScheduler taskScheduler = new TaskSchedulerImpl(this, this.getServer()); - taskScheduler.runTimerAsync(new AutoMessageTask(this.pluginConfiguration, this.notificationSender), 0L, DurationUtil.toTicks(this.pluginConfiguration.autoMessagesDelay)); - - if (this.pluginConfiguration.autoMessageCommandEnabled) { - this.liteCommands = this.registerLiteCommands(); - } - - Duration startBetweenNow = Duration.between(start, Instant.now()); - this.getLogger().info("Enabled plugin in " + startBetweenNow.toMillis() + "ms."); - } - - @Override - public void onDisable() { - if (this.liteCommands != null) { - this.liteCommands.getPlatform().unregisterAll(); - } - - this.bukkitAudiences.close(); - } - - private LiteCommands registerLiteCommands() { - return LiteBukkitAdventurePlatformFactory.builder(this.getServer(), this.getName(), false, this.bukkitAudiences, true) - .contextualBind(Player.class, new BukkitOnlyPlayerContextual<>("Command only for player")) - - .argument(NotificationType.class, new NotificationTypeArgument(this.pluginConfiguration)) - .argument(Notification.class, new NotificationArgument(this.pluginConfiguration, this.notificationSender)) - - .invalidUsageHandler(new UsageHandler(this.pluginConfiguration, this.notificationSender)) - .permissionHandler(new PermissionHandler(this.pluginConfiguration, this.notificationSender)) - .resultHandler(Notification.class, new NotificationHandler(this.notificationSender)) - - .commandInstance(new AutoMessageCommand(this.pluginConfiguration, this.notificationSender)) - .commandEditor(AutoMessageCommand.class, new CommandPermissionEditor(this.pluginConfiguration)) - - .register(); - } -} diff --git a/src/main/java/me/dmk/automessage/command/AutoMessageCommand.java b/src/main/java/me/dmk/automessage/command/AutoMessageCommand.java deleted file mode 100644 index 44e0541..0000000 --- a/src/main/java/me/dmk/automessage/command/AutoMessageCommand.java +++ /dev/null @@ -1,85 +0,0 @@ -package me.dmk.automessage.command; - -import dev.rollczi.litecommands.argument.Arg; -import dev.rollczi.litecommands.argument.Name; -import dev.rollczi.litecommands.argument.joiner.Joiner; -import dev.rollczi.litecommands.command.async.Async; -import dev.rollczi.litecommands.command.execute.Execute; -import dev.rollczi.litecommands.command.route.Route; -import me.dmk.automessage.configuration.PluginConfiguration; -import me.dmk.automessage.notification.Notification; -import me.dmk.automessage.notification.NotificationSender; -import me.dmk.automessage.notification.NotificationType; -import org.bukkit.entity.Player; - -import java.util.List; - -@Route(name = "automessage") -public class AutoMessageCommand { - - private final PluginConfiguration pluginConfiguration; - private final NotificationSender notificationSender; - - public AutoMessageCommand(PluginConfiguration pluginConfiguration, NotificationSender notificationSender) { - this.pluginConfiguration = pluginConfiguration; - this.notificationSender = notificationSender; - } - - @Async - @Execute(route = "enable") - void enable(Player player) { - this.pluginConfiguration.autoMessagesEnabled = true; - - this.notificationSender.sendMessage(player, this.pluginConfiguration.autoMessagesEnabledMessage); - } - - @Async - @Execute(route = "disable") - void disable(Player player) { - this.pluginConfiguration.autoMessagesEnabled = false; - - this.notificationSender.sendMessage(player, this.pluginConfiguration.autoMessagesDisabledMessage); - } - - @Async - @Execute(route = "add-notification") - void addNotification(Player player, @Arg NotificationType notificationType, @Joiner @Name("message") String message) { - Notification notification = new Notification(notificationType, message); - - this.pluginConfiguration.autoMessages.add(notification); - - this.notificationSender.sendMessage(player, this.pluginConfiguration.addedNotificationMessage); - } - - @Async - @Execute(route = "list-notification") - void listNotification(Player player) { - List notifications = this.pluginConfiguration.autoMessages; - - if (notifications.isEmpty()) { - this.notificationSender.sendMessage(player, this.pluginConfiguration.notificationListEmptyMessage); - return; - } - - this.notificationSender.sendMessage(player, this.pluginConfiguration.listNotificationFirstMessage); - - for (int i = 0; i < notifications.size(); i++) { - Notification notification = notifications.get(i); - - this.notificationSender.builder() - .fromNotification(this.pluginConfiguration.listNotificationMessage) - .placeholder("{POSITION}", i) - .placeholder("{TYPE}", notification.getType()) - .placeholder("{MESSAGE}", notification.getMessage()) - .send(player); - } - } - - @Async - @Execute(route = "remove-notification") - void removeNotification(Player player, @Arg Notification notification) { - this.pluginConfiguration.autoMessages.remove(notification); - - this.notificationSender.sendMessage(player, this.pluginConfiguration.removedNotificationMessage); - } -} diff --git a/src/main/java/me/dmk/automessage/command/argument/NotificationArgument.java b/src/main/java/me/dmk/automessage/command/argument/NotificationArgument.java deleted file mode 100644 index 3100219..0000000 --- a/src/main/java/me/dmk/automessage/command/argument/NotificationArgument.java +++ /dev/null @@ -1,55 +0,0 @@ -package me.dmk.automessage.command.argument; - -import dev.rollczi.litecommands.argument.ArgumentName; -import dev.rollczi.litecommands.argument.simple.OneArgument; -import dev.rollczi.litecommands.command.LiteInvocation; -import dev.rollczi.litecommands.suggestion.Suggestion; -import me.dmk.automessage.configuration.PluginConfiguration; -import me.dmk.automessage.notification.Notification; -import me.dmk.automessage.notification.NotificationSender; -import me.dmk.automessage.util.StringUtil; -import panda.std.Result; - -import java.util.List; -import java.util.stream.IntStream; - -@ArgumentName("position") -public class NotificationArgument implements OneArgument { - - private final PluginConfiguration pluginConfiguration; - private final NotificationSender notificationSender; - - public NotificationArgument(PluginConfiguration pluginConfiguration, NotificationSender notificationSender) { - this.pluginConfiguration = pluginConfiguration; - this.notificationSender = notificationSender; - } - - @Override - public Result parse(LiteInvocation invocation, String argument) { - if (!StringUtil.isInteger(argument)) { - return Result.error(this.pluginConfiguration.invalidNumberMessage); - } - - int position = Integer.parseInt(argument); - - if (position < 0 || position >= this.pluginConfiguration.autoMessages.size()) { - Notification notification = this.notificationSender.builder() - .fromNotification(this.pluginConfiguration.notificationNotFoundMessage) - .placeholder("{POSITION}", position) - .build(); - - return Result.error(notification); - } - - Notification notification = this.pluginConfiguration.autoMessages.get(position); - return Result.ok(notification); - } - - @Override - public List suggest(LiteInvocation invocation) { - return IntStream.range(0, this.pluginConfiguration.autoMessages.size()) - .mapToObj(String::valueOf) - .map(Suggestion::of) - .toList(); - } -} diff --git a/src/main/java/me/dmk/automessage/command/editor/CommandPermissionEditor.java b/src/main/java/me/dmk/automessage/command/editor/CommandPermissionEditor.java deleted file mode 100644 index 3f629a3..0000000 --- a/src/main/java/me/dmk/automessage/command/editor/CommandPermissionEditor.java +++ /dev/null @@ -1,22 +0,0 @@ -package me.dmk.automessage.command.editor; - -import dev.rollczi.litecommands.factory.CommandEditor; -import me.dmk.automessage.configuration.PluginConfiguration; - -import java.util.List; - -public class CommandPermissionEditor implements CommandEditor { - - private final PluginConfiguration pluginConfiguration; - - public CommandPermissionEditor(PluginConfiguration pluginConfiguration) { - this.pluginConfiguration = pluginConfiguration; - } - - @Override - public State edit(State state) { - return state.permission(List.of( - this.pluginConfiguration.autoMessageCommandPermission - )); - } -} diff --git a/src/main/java/me/dmk/automessage/command/handler/PermissionHandler.java b/src/main/java/me/dmk/automessage/command/handler/PermissionHandler.java deleted file mode 100644 index 3bdafac..0000000 --- a/src/main/java/me/dmk/automessage/command/handler/PermissionHandler.java +++ /dev/null @@ -1,26 +0,0 @@ -package me.dmk.automessage.command.handler; - -import dev.rollczi.litecommands.command.LiteInvocation; -import dev.rollczi.litecommands.command.permission.RequiredPermissions; -import me.dmk.automessage.configuration.PluginConfiguration; -import me.dmk.automessage.notification.NotificationSender; -import org.bukkit.command.CommandSender; - -public class PermissionHandler implements dev.rollczi.litecommands.handle.PermissionHandler { - - private final PluginConfiguration pluginConfiguration; - private final NotificationSender notificationSender; - - public PermissionHandler(PluginConfiguration pluginConfiguration, NotificationSender notificationSender) { - this.pluginConfiguration = pluginConfiguration; - this.notificationSender = notificationSender; - } - - @Override - public void handle(CommandSender sender, LiteInvocation invocation, RequiredPermissions requiredPermissions) { - this.notificationSender.builder() - .fromNotification(this.pluginConfiguration.missingPermissionsMessage) - .placeholder("{PERMISSIONS}", requiredPermissions.getPermissions()) - .send(sender); - } -} diff --git a/src/main/java/me/dmk/automessage/command/handler/UsageHandler.java b/src/main/java/me/dmk/automessage/command/handler/UsageHandler.java deleted file mode 100644 index 0e272bb..0000000 --- a/src/main/java/me/dmk/automessage/command/handler/UsageHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -package me.dmk.automessage.command.handler; - -import dev.rollczi.litecommands.command.LiteInvocation; -import dev.rollczi.litecommands.handle.InvalidUsageHandler; -import dev.rollczi.litecommands.schematic.Schematic; -import me.dmk.automessage.configuration.PluginConfiguration; -import me.dmk.automessage.notification.NotificationSender; -import org.bukkit.command.CommandSender; - -import java.util.List; - -public class UsageHandler implements InvalidUsageHandler { - - private final PluginConfiguration pluginConfiguration; - private final NotificationSender notificationSender; - - public UsageHandler(PluginConfiguration pluginConfiguration, NotificationSender notificationSender) { - this.pluginConfiguration = pluginConfiguration; - this.notificationSender = notificationSender; - } - - @Override - public void handle(CommandSender sender, LiteInvocation invocation, Schematic schematic) { - List schematics = schematic.getSchematics(); - - if (schematics.size() == 1) { - this.notificationSender.builder() - .fromNotification(this.pluginConfiguration.invalidUsageMessage) - .placeholder("{USAGE}", schematics.get(0)) - .send(sender); - return; - } - - this.notificationSender.sendMessage(sender, this.pluginConfiguration.invalidUsageFirstMessage); - - for (String usage : schematics) { - this.notificationSender.builder() - .fromNotification(this.pluginConfiguration.invalidUsageListMessage) - .placeholder("{USAGE}", usage) - .send(sender); - } - } -} diff --git a/src/main/java/me/dmk/automessage/configuration/PluginConfiguration.java b/src/main/java/me/dmk/automessage/configuration/PluginConfiguration.java deleted file mode 100644 index 08506e5..0000000 --- a/src/main/java/me/dmk/automessage/configuration/PluginConfiguration.java +++ /dev/null @@ -1,71 +0,0 @@ -package me.dmk.automessage.configuration; - -import eu.okaeri.configs.OkaeriConfig; -import eu.okaeri.configs.annotation.Comment; -import eu.okaeri.configs.annotation.Header; -import me.dmk.automessage.notification.Notification; -import me.dmk.automessage.notification.NotificationType; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; - -@Header({ - "#", - "# Configuration file for auto message plugin", - "# If you have any question visit project's github", - "#" -}) -public class PluginConfiguration extends OkaeriConfig { - - @Comment("# Booleans") - public boolean checkForUpdates = true; - - public boolean autoMessagesEnabled = true; - - @Comment("# Auto message settings") - public Duration autoMessagesDelay = Duration.ofSeconds(5); - - @Comment({ - "# Auto message mode", - "# Modes: RANDOM, SEQUENTIAL" - }) - public AutoMessageMode autoMessageMode = AutoMessageMode.SEQUENTIAL; - - public List autoMessages = new ArrayList<>(List.of( - new Notification(NotificationType.CHAT, "This is first auto message!"), - new Notification(NotificationType.ACTIONBAR, "This is second auto message!") - )); - - @Comment("# Command section") - public boolean autoMessageCommandEnabled = true; - public String autoMessageCommandPermission = "command.automessage"; - - @Comment("# Messages") - @Comment("# Argument messages") - public Notification invalidNumberMessage = new Notification(NotificationType.CHAT, "Invalid number."); - public Notification invalidNotificationTypeMessage = new Notification(NotificationType.CHAT, "Invalid notification type."); - public Notification missingPermissionsMessage = new Notification(NotificationType.CHAT, "Missing permissions: {PERMISSIONS}"); - - public Notification notificationNotFoundMessage = new Notification(NotificationType.CHAT, "Notification at {POSITION} position not found."); - public Notification notificationListEmptyMessage = new Notification(NotificationType.CHAT, "No automatic messages."); - - public Notification invalidUsageMessage = new Notification(NotificationType.CHAT, "Invalid usage: {USAGE}"); - @Comment("# This messages is used when there is more than one option to use a command") - public Notification invalidUsageFirstMessage = new Notification(NotificationType.CHAT, "Invalid usage:"); - public Notification invalidUsageListMessage = new Notification(NotificationType.CHAT, "- {USAGE}"); - - @Comment("# Command messages") - public Notification autoMessagesEnabledMessage = new Notification(NotificationType.CHAT, "Enabled sending auto messages."); - public Notification autoMessagesDisabledMessage = new Notification(NotificationType.CHAT, "Disabled sending auto messages."); - - public Notification addedNotificationMessage = new Notification(NotificationType.CHAT, "Added notification."); - public Notification removedNotificationMessage = new Notification(NotificationType.CHAT, "Removed notification."); - - public Notification listNotificationFirstMessage = new Notification(NotificationType.CHAT, "List of auto messages:"); - public Notification listNotificationMessage = new Notification(NotificationType.CHAT, "{POSITION}. {TYPE}: {MESSAGE}"); - - public enum AutoMessageMode { - RANDOM, SEQUENTIAL - } -} diff --git a/src/main/java/me/dmk/automessage/notification/Notification.java b/src/main/java/me/dmk/automessage/notification/Notification.java deleted file mode 100644 index 3e8741c..0000000 --- a/src/main/java/me/dmk/automessage/notification/Notification.java +++ /dev/null @@ -1,30 +0,0 @@ -package me.dmk.automessage.notification; - -import eu.okaeri.configs.OkaeriConfig; - -public class Notification extends OkaeriConfig { - - private NotificationType type; - private String message; - - public Notification(NotificationType type, String message) { - this.type = type; - this.message = message; - } - - public NotificationType getType() { - return this.type; - } - - public void setType(NotificationType type) { - this.type = type; - } - - public String getMessage() { - return this.message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/src/main/java/me/dmk/automessage/notification/NotificationBuilder.java b/src/main/java/me/dmk/automessage/notification/NotificationBuilder.java deleted file mode 100644 index 00f81a9..0000000 --- a/src/main/java/me/dmk/automessage/notification/NotificationBuilder.java +++ /dev/null @@ -1,89 +0,0 @@ -package me.dmk.automessage.notification; - -import com.google.errorprone.annotations.CheckReturnValue; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.annotation.Nonnull; -import java.util.HashMap; -import java.util.Map; - -public class NotificationBuilder { - - private final NotificationSender notificationSender; - - private NotificationType type; - private String message; - - private final Map placeholders = new HashMap<>(); - - public NotificationBuilder(NotificationSender notificationSender) { - this.notificationSender = notificationSender; - } - - @CheckReturnValue - public NotificationBuilder fromNotification(@Nonnull Notification notification) { - this.type = notification.getType(); - this.message = notification.getMessage(); - return this; - } - - @CheckReturnValue - public NotificationBuilder type(@Nonnull NotificationType type) { - this.type = type; - return this; - } - - @CheckReturnValue - public NotificationBuilder message(@Nonnull String message) { - this.message = message; - return this; - } - - @CheckReturnValue - public NotificationBuilder placeholder(@Nonnull String from, String to) { - this.placeholders.put(from, to); - return this; - } - - @CheckReturnValue - public NotificationBuilder placeholder(@Nonnull String from, Iterable sequences) { - this.placeholders.put(from, String.join(", ", sequences)); - return this; - } - - @CheckReturnValue - public NotificationBuilder placeholder(@Nonnull String from, T to) { - this.placeholders.put(from, to.toString()); - return this; - } - - public Notification build() { - this.replacePlaceholders(); - - return new Notification(this.type, this.message); - } - - public void send(Player player) { - this.replacePlaceholders(); - - this.notificationSender.sendMessage(player, this.type, this.message); - } - - public void send(CommandSender sender) { - if (sender instanceof Player player) { - this.send(player); - return; - } - - this.replacePlaceholders(); - - sender.sendMessage(this.message); - } - - private void replacePlaceholders() { - for (Map.Entry entry : this.placeholders.entrySet()) { - this.message = this.message.replace(entry.getKey(), entry.getValue()); - } - } -} diff --git a/src/main/java/me/dmk/automessage/notification/NotificationSender.java b/src/main/java/me/dmk/automessage/notification/NotificationSender.java deleted file mode 100644 index a77c46a..0000000 --- a/src/main/java/me/dmk/automessage/notification/NotificationSender.java +++ /dev/null @@ -1,75 +0,0 @@ -package me.dmk.automessage.notification; - -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.platform.AudienceProvider; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.title.Title; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -public class NotificationSender { - - private final AudienceProvider audienceProvider; - private final MiniMessage miniMessage; - - public NotificationSender(AudienceProvider audienceProvider, MiniMessage miniMessage) { - this.audienceProvider = audienceProvider; - this.miniMessage = miniMessage; - } - - public NotificationBuilder builder() { - return new NotificationBuilder(this); - } - - public void broadcast(Notification notification) { - Audience audience = this.audienceProvider.players(); - - NotificationType type = notification.getType(); - Component message = this.miniMessage.deserialize(notification.getMessage()); - - this.sendMessage(audience, type, message); - } - - public void sendMessage(CommandSender sender, Notification notification) { - Audience audience = this.createAudience(sender); - - NotificationType type = notification.getType(); - Component message = this.miniMessage.deserialize(notification.getMessage()); - - this.sendMessage(audience, type, message); - } - - public void sendMessage(CommandSender sender, NotificationType type, String message) { - Audience audience = this.createAudience(sender); - Component deserializedMessage = this.miniMessage.deserialize(message); - - this.sendMessage(audience, type, deserializedMessage); - } - - public Audience createAudience(CommandSender sender) { - if (sender instanceof Player player) { - return this.audienceProvider.player(player.getUniqueId()); - } - - return this.audienceProvider.console(); - } - - public void sendMessage(Audience audience, NotificationType type, Component message) { - switch (type) { - case CHAT -> audience.sendMessage(message); - case ACTIONBAR -> audience.sendActionBar(message); - case TITLE -> { - Title title = Title.title(message, Component.empty(), Title.DEFAULT_TIMES); - - audience.showTitle(title); - } - case SUBTITLE -> { - Title subtitle = Title.title(Component.empty(), message, Title.DEFAULT_TIMES); - - audience.showTitle(subtitle); - } - default -> throw new IllegalStateException("Unexpected notification type value: " + type); - } - } -} diff --git a/src/main/java/me/dmk/automessage/notification/NotificationType.java b/src/main/java/me/dmk/automessage/notification/NotificationType.java deleted file mode 100644 index 063b382..0000000 --- a/src/main/java/me/dmk/automessage/notification/NotificationType.java +++ /dev/null @@ -1,6 +0,0 @@ -package me.dmk.automessage.notification; - -public enum NotificationType { - - CHAT, ACTIONBAR, TITLE, SUBTITLE -} diff --git a/src/main/java/me/dmk/automessage/task/AutoMessageTask.java b/src/main/java/me/dmk/automessage/task/AutoMessageTask.java deleted file mode 100644 index 1690c4e..0000000 --- a/src/main/java/me/dmk/automessage/task/AutoMessageTask.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.dmk.automessage.task; - -import me.dmk.automessage.configuration.PluginConfiguration; -import me.dmk.automessage.notification.Notification; -import me.dmk.automessage.notification.NotificationSender; -import me.dmk.automessage.util.RandomUtil; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; - -public class AutoMessageTask implements Runnable { - - private final PluginConfiguration pluginConfiguration; - private final NotificationSender notificationSender; - - private final AtomicInteger position = new AtomicInteger(0); - - public AutoMessageTask(PluginConfiguration pluginConfiguration, NotificationSender notificationSender) { - this.pluginConfiguration = pluginConfiguration; - this.notificationSender = notificationSender; - } - - @Override - public void run() { - if (!this.pluginConfiguration.autoMessagesEnabled) { - return; - } - - if (this.pluginConfiguration.autoMessages.isEmpty()) { - return; - } - - this.selectNotification().ifPresent(this.notificationSender::broadcast); - } - - private Optional selectNotification() { - return switch (this.pluginConfiguration.autoMessageMode) { - case RANDOM -> this.selectRandomNotification(); - case SEQUENTIAL -> this.selectNextNotification(); - }; - } - - private Optional selectRandomNotification() { - return RandomUtil.getRandom(this.pluginConfiguration.autoMessages); - } - - private Optional selectNextNotification() { - List autoMessages = this.pluginConfiguration.autoMessages; - - int position = this.position.getAndIncrement() % autoMessages.size(); - - return autoMessages.stream() - .skip(position) - .findFirst(); - } -} diff --git a/src/test/java/com/github/imdmk/automessage/DurationUtilTest.java b/src/test/java/com/github/imdmk/automessage/DurationUtilTest.java new file mode 100644 index 0000000..1b3f87a --- /dev/null +++ b/src/test/java/com/github/imdmk/automessage/DurationUtilTest.java @@ -0,0 +1,30 @@ +package com.github.imdmk.automessage; + +import com.github.imdmk.automessage.util.DurationUtil; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.time.Duration; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DurationUtilTest { + + static List durations() { + return List.of(new Object[][] { + { 0, Duration.ZERO }, + { 1, Duration.ofMillis(50) }, + { 20, Duration.ofSeconds(1) }, + { 1200, Duration.ofMinutes(1) }, + { 72000, Duration.ofHours(1) } + }); + } + + @ParameterizedTest + @MethodSource("durations") + void toTickTest(long expected, Duration duration) { + long result = DurationUtil.toTicks(duration); + assertEquals(expected, result); + } +} diff --git a/src/test/java/com/github/imdmk/automessage/StringUtilTest.java b/src/test/java/com/github/imdmk/automessage/StringUtilTest.java new file mode 100644 index 0000000..f2359f4 --- /dev/null +++ b/src/test/java/com/github/imdmk/automessage/StringUtilTest.java @@ -0,0 +1,26 @@ +package com.github.imdmk.automessage; + +import com.github.imdmk.automessage.util.StringUtil; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class StringUtilTest { + + static List integers() { + return List.of(new Object[][] { + { false, "AutoMessage" }, + { true, "50" } + }); + } + + @ParameterizedTest + @MethodSource("integers") + void integerTest(boolean excepted, String string) { + boolean result = StringUtil.isInteger(string); + assertEquals(excepted, result); + } +}