Skip to content

Commit

Permalink
ChatClickEvent addition
Browse files Browse the repository at this point in the history
  • Loading branch information
stephendotgg committed Nov 9, 2023
1 parent 1e18156 commit 72274b2
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 5 deletions.
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<ChatClickEvent> {
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")
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

group = "gg.flyte"
version = "1.0.29"
version = "1.0.30"

repositories {
mavenCentral()
Expand Down
6 changes: 5 additions & 1 deletion src/main/kotlin/gg/flyte/twilight/Twilight.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -11,7 +12,10 @@ class Twilight(javaPlugin: JavaPlugin) {

init {
plugin = javaPlugin
run { customEventListeners }
run {
customEventListeners
ChatClickCommand.register()
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String>
) : TwilightEvent()
37 changes: 37 additions & 0 deletions src/main/kotlin/gg/flyte/twilight/event/custom/chat/Extension.kt
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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<String>): Boolean {
if (sender !is Player) return false
Twilight.plugin.server.pluginManager.callEvent(ChatClickEvent(sender, args))
return false
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 72274b2

Please sign in to comment.