From 72274b23fc1a54a4a8e3a5a800c84fe3b6e82254 Mon Sep 17 00:00:00 2001 From: Stephen Date: Thu, 9 Nov 2023 02:46:59 +0000 Subject: [PATCH] ChatClickEvent addition --- README.md | 39 ++++++++++++++++++- build.gradle.kts | 2 +- src/main/kotlin/gg/flyte/twilight/Twilight.kt | 6 ++- .../event/custom/chat/ChatClickEvent.kt | 19 +++++++++ .../twilight/event/custom/chat/Extension.kt | 37 ++++++++++++++++++ .../custom/chat/command/ChatClickCommand.kt | 27 +++++++++++++ .../interact/PlayerMainHandInteractEvent.kt | 1 - 7 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 src/main/kotlin/gg/flyte/twilight/event/custom/chat/ChatClickEvent.kt create mode 100644 src/main/kotlin/gg/flyte/twilight/event/custom/chat/Extension.kt create mode 100644 src/main/kotlin/gg/flyte/twilight/event/custom/chat/command/ChatClickCommand.kt diff --git a/README.md b/README.md index d1ec0a5..30aae54 100644 --- a/README.md +++ b/README.md @@ -107,19 +107,54 @@ Twilight provides additional events which are not found in Spigot or Paper. Thes - PlayerOpChangeEvent - PlayerOpEvent - PlayerDeopEvent +- ChatClickEvent [(see below)](#custom-chatclickevent) You can opt out of Twilight calling these events. For example: ```kotlin disableCustomEventListeners(OpEventListener, InteractEventListener) ``` +### Custom ChatClickEvent +Due to limitations imposed by the Minecraft server software, when interacting with a clickable message in chat or in a book the only response options are `RUN_COMMAND`, `SUGGEST_COMMAND`, `CHANGE_PAGE`, `COPY_TO_CLIPBOARD`, `OPEN_FILE` and `OPEN_URL`. None of these match the most common use case: running custom code. Twilight utilizes the `RUN_COMMAND` response to call a custom `ChatClickEvent` which can be listened to like a regular event. -### Scheduler +To use this feature, where you would normally build your clickable message, use the Twilight extension functions to add a custom click event. Twilight will then redirect any data which you put in the parameters to be accessable as a variable from within the `ChatClickEvent`. + +For Paper/Adventure (recommended): +```kotlin +import net.kyori.adventure.text.Component + +Component.text("Click here") + .customClickEvent("openGUI", "warps") +``` + +Or for Spigot/BungeeCord: +```kotlin +import net.md_5.bungee.api.chat.TextComponent + +TextComponent("Click here") + .customClickEvent("openGUI", "warps") +``` + +From there, simply listen to the event as normal, and access the data attached to the message the player has clicked. In this basic example, information to open a "warps" GUI has been passed through as the custom data, and so the correct action can be taken: + +```kotlin +event { + if (data.size != 2) return@event + if (data[0] != "openGUI") return@event + when (data[1]) { + "warps" -> GUIManager.openWarps(player) + ... + } +} + +``` + +`### Scheduler Bukkit's build in scheduler is tedious at best, so Twilight takes advantage of beautiful Kotlin syntax to make it easier to write, as well as adding a custom TimeUnit to save you calculating ticks. How to schedule a single task to run on Bukkit's main thread either sync or async: - +` ```kotlin sync { println("I am a sync BukkitRunnable") diff --git a/build.gradle.kts b/build.gradle.kts index c972241..07a7a11 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "gg.flyte" -version = "1.0.29" +version = "1.0.30" repositories { mavenCentral() diff --git a/src/main/kotlin/gg/flyte/twilight/Twilight.kt b/src/main/kotlin/gg/flyte/twilight/Twilight.kt index 605d290..515016e 100644 --- a/src/main/kotlin/gg/flyte/twilight/Twilight.kt +++ b/src/main/kotlin/gg/flyte/twilight/Twilight.kt @@ -3,6 +3,7 @@ package gg.flyte.twilight import gg.flyte.twilight.data.MongoDB import gg.flyte.twilight.data.service.NameCacheService import gg.flyte.twilight.environment.Environment +import gg.flyte.twilight.event.custom.chat.command.ChatClickCommand import gg.flyte.twilight.event.customEventListeners import gg.flyte.twilight.extension.applyForEach import org.bukkit.plugin.java.JavaPlugin @@ -11,7 +12,10 @@ class Twilight(javaPlugin: JavaPlugin) { init { plugin = javaPlugin - run { customEventListeners } + run { + customEventListeners + ChatClickCommand.register() + } } companion object { diff --git a/src/main/kotlin/gg/flyte/twilight/event/custom/chat/ChatClickEvent.kt b/src/main/kotlin/gg/flyte/twilight/event/custom/chat/ChatClickEvent.kt new file mode 100644 index 0000000..f8fd3cd --- /dev/null +++ b/src/main/kotlin/gg/flyte/twilight/event/custom/chat/ChatClickEvent.kt @@ -0,0 +1,19 @@ +package gg.flyte.twilight.event.custom.chat + +import gg.flyte.twilight.event.TwilightEvent +import org.bukkit.entity.Player + +/** + * Represents an event that is triggered when a chat component with a custom click event is interacted with. + * + * This event carries information about the player who clicked the chat component and the data that was + * sent along with the click event, typically used to determine what action should be taken as a result + * of the click. + * + * @param player The player who clicked the chat component. + * @param data The array of strings sent with the click event. + */ +class ChatClickEvent( + val player: Player, + val data: Array +) : TwilightEvent() \ No newline at end of file diff --git a/src/main/kotlin/gg/flyte/twilight/event/custom/chat/Extension.kt b/src/main/kotlin/gg/flyte/twilight/event/custom/chat/Extension.kt new file mode 100644 index 0000000..ff17c54 --- /dev/null +++ b/src/main/kotlin/gg/flyte/twilight/event/custom/chat/Extension.kt @@ -0,0 +1,37 @@ +package gg.flyte.twilight.event.custom.chat + +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.event.ClickEvent +import net.md_5.bungee.api.chat.TextComponent + +/** + * Attaches a custom click event to a Component. + * + * This function adds a click event to the Component that triggers a command + * when the component is clicked in the chat. The command is constructed by + * prefixing '/chatclick' with the joined string representations of the provided + * vararg data parameters, separated by spaces. This will then trigger the + * ChatClickEvent which will contain the data. + * + * @param data Vararg parameter strings that are concatenated and used as data for the command. + * @return The Component with the attached click event. + */ +fun Component.customClickEvent(vararg data: String): Component { + return this.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/chatclick ${data.joinToString(" ")}")) +} + +/** + * Attaches a custom click event to a TextComponent. + * + * This function assigns a new click event to the TextComponent that will execute a command + * when the component is interacted with in the chat. The command consists of '/chatclick' + * followed by the space-separated concatenation of the input data. This will then trigger + * the ChatClickEvent which will contain the data. + * + * @param data Vararg parameter strings that are combined into a single command string. + * @return The TextComponent with the new click event. + */ +fun TextComponent.customClickEvent(vararg data: String): TextComponent { + clickEvent = net.md_5.bungee.api.chat.ClickEvent(net.md_5.bungee.api.chat.ClickEvent.Action.RUN_COMMAND, "/chatclick ${data.joinToString(" ")}") + return this +} \ No newline at end of file diff --git a/src/main/kotlin/gg/flyte/twilight/event/custom/chat/command/ChatClickCommand.kt b/src/main/kotlin/gg/flyte/twilight/event/custom/chat/command/ChatClickCommand.kt new file mode 100644 index 0000000..7f2947c --- /dev/null +++ b/src/main/kotlin/gg/flyte/twilight/event/custom/chat/command/ChatClickCommand.kt @@ -0,0 +1,27 @@ +package gg.flyte.twilight.event.custom.chat.command + +import gg.flyte.twilight.Twilight +import gg.flyte.twilight.event.custom.chat.ChatClickEvent +import org.bukkit.command.CommandMap +import org.bukkit.command.CommandSender +import org.bukkit.command.defaults.BukkitCommand +import org.bukkit.entity.Player + +object ChatClickCommand : BukkitCommand("chatclick") { + + fun register() { + runCatching { + val commandMapField = Twilight.plugin.server.javaClass.getDeclaredField("commandMap") + commandMapField.isAccessible = true + val commandMap = commandMapField.get(Twilight.plugin.server) as CommandMap + commandMap.register("chatclick", this@ChatClickCommand) + } + } + + override fun execute(sender: CommandSender, commandLabel: String, args: Array): Boolean { + if (sender !is Player) return false + Twilight.plugin.server.pluginManager.callEvent(ChatClickEvent(sender, args)) + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/gg/flyte/twilight/event/custom/interact/PlayerMainHandInteractEvent.kt b/src/main/kotlin/gg/flyte/twilight/event/custom/interact/PlayerMainHandInteractEvent.kt index 5949967..f78e11b 100644 --- a/src/main/kotlin/gg/flyte/twilight/event/custom/interact/PlayerMainHandInteractEvent.kt +++ b/src/main/kotlin/gg/flyte/twilight/event/custom/interact/PlayerMainHandInteractEvent.kt @@ -5,7 +5,6 @@ import org.bukkit.block.Block import org.bukkit.block.BlockFace import org.bukkit.entity.Player import org.bukkit.event.block.Action -import org.bukkit.event.player.PlayerInteractEvent import org.bukkit.inventory.ItemStack import org.bukkit.util.Vector