DLib/src/main/kotlin/nl/kallestruik/dlib/gui/TextInputDialog.kt

138 lines
3.4 KiB
Kotlin

package nl.kallestruik.dlib.gui
import kotlinx.coroutines.runBlocking
import net.kyori.adventure.text.Component
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.inventory.*
import org.bukkit.inventory.InventoryView
import org.bukkit.inventory.ItemStack
import org.bukkit.plugin.Plugin
fun textInputDialog(player: Player, plugin: Plugin, configure: suspend TextInputDialog.() -> Unit) {
val textInputDialog = TextInputDialog()
runBlocking {
textInputDialog.configure()
}
textInputDialog.display(player, plugin)
}
class TextInputDialog: Listener {
private data class Configuration(
var item: suspend TextInputDialogItem.() -> Unit = {},
var onFinish: suspend (value: String) -> Unit = {},
var onCancel: suspend () -> Unit = {}
)
private val configuration = Configuration()
var prompt: Component = Component.empty()
private lateinit var view: InventoryView
private lateinit var plugin: Plugin
fun item(entry: suspend TextInputDialogItem.() -> Unit) {
configuration.item = entry
}
fun onFinish(onFinish: suspend (value: String) -> Unit) {
configuration.onFinish = onFinish
}
fun onCancel(onCancel: suspend () -> Unit) {
configuration.onCancel = onCancel
}
fun display(player: Player, plugin: Plugin) {
player.closeInventory()
this.plugin = plugin
view = player.openAnvil(null, true) ?: return
val entry = TextInputDialogItem()
runBlocking {
configuration.item.invoke(entry)
}
val itemStack = ItemStack(entry.material, entry.amount)
val itemMeta = itemStack.itemMeta
itemMeta.displayName(prompt)
itemStack.itemMeta = itemMeta
view.setItem(0, itemStack)
plugin.server.pluginManager.registerEvents(this, plugin)
}
private fun cleanup() {
view.close()
HandlerList.unregisterAll(this)
}
/*
Bukkit event handlers
*/
@EventHandler
fun onInventoryClose(event: InventoryCloseEvent) {
if (event.view != this.view)
return
if (event.reason == InventoryCloseEvent.Reason.PLUGIN) {
return
}
runBlocking {
configuration.onCancel.invoke()
cleanup()
}
}
@EventHandler
fun onAnvilPrepare(event: PrepareAnvilEvent) {
if (event.view != view)
return
// Always keep the cost at 1. 0 Causes the client to not be able to click it.
event.inventory.repairCost = 1
}
@EventHandler
fun onOperationFinish(event: InventoryClickEvent) {
if (event.view != view) {
return
}
if (event.action != InventoryAction.PICKUP_ALL) {
event.isCancelled = true
return
}
if (view.convertSlot(event.rawSlot) != 2) {
event.isCancelled = true
return
}
val item = event.currentItem
val name = item?.itemMeta?.displayName ?: ""
if (name == "") {
event.isCancelled = true
return
}
event.isCancelled = true
runBlocking {
configuration.onFinish.invoke(name)
cleanup()
}
}
}
data class TextInputDialogItem(
var material: Material = Material.AIR,
var amount: Int = 1,
)