From 8817ac18cb37db0ac1ca3611523e470b04c1afa8 Mon Sep 17 00:00:00 2001 From: Francisco Solis <30329003+Im-Fran@users.noreply.github.com> Date: Mon, 15 Jan 2024 23:50:01 -0300 Subject: [PATCH] wip: ui system * added UIsModule entrypoint * removed UiClickEvent.kt in favor of kotlin functions * added BukkitExtensions.kt --- .../spigot/extensions/BukkitExtensions.kt | 24 ++++++ .../spigot/modules/uismodule/UIsModule.kt | 17 ++++ .../modules/uismodule/models/UiEntry.kt | 26 ++++++ .../spigot/modules/uismodule/ui/Ui.kt | 81 +++++++++++++++++-- .../uismodule/ui/events/UiClickEvent.kt | 28 ------- 5 files changed, 141 insertions(+), 35 deletions(-) create mode 100644 simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/extensions/BukkitExtensions.kt create mode 100644 simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/UIsModule.kt create mode 100644 simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/models/UiEntry.kt delete mode 100644 simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/ui/events/UiClickEvent.kt diff --git a/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/extensions/BukkitExtensions.kt b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/extensions/BukkitExtensions.kt new file mode 100644 index 0000000..4f714f2 --- /dev/null +++ b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/extensions/BukkitExtensions.kt @@ -0,0 +1,24 @@ +package xyz.theprogramsrc.simplecoreapi.spigot.extensions + +import org.bukkit.Bukkit +import org.bukkit.event.Event +import org.bukkit.event.Listener +import org.bukkit.plugin.Plugin +import org.bukkit.plugin.PluginManager + +/** + * Registers an event listener + * @param listener the listener to register + * @param plugin the plugin to register the listener for + * @see PluginManager.registerEvents + */ +fun registerEvent(listener: Listener, plugin: Plugin) = + Bukkit.getPluginManager().registerEvents(listener, plugin) + +/** + * Calls an event + * @param event the event to call + * @see PluginManager.callEvent + */ +fun callEvent(event: Event) = + Bukkit.getPluginManager().callEvent(event) \ No newline at end of file diff --git a/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/UIsModule.kt b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/UIsModule.kt new file mode 100644 index 0000000..2ee52b7 --- /dev/null +++ b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/UIsModule.kt @@ -0,0 +1,17 @@ +package xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule + +import xyz.theprogramsrc.simplecoreapi.global.module.Module +import xyz.theprogramsrc.simplecoreapi.global.module.ModuleDescription + +class UIsModule : Module { + + override val description: ModuleDescription = ModuleDescription( + name = "UIsModule", + version = "1.0.0", + authors = listOf("Im-Fran") + ) + + override fun onEnable() {} + + override fun onDisable() {} +} \ No newline at end of file diff --git a/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/models/UiEntry.kt b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/models/UiEntry.kt new file mode 100644 index 0000000..41d3926 --- /dev/null +++ b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/models/UiEntry.kt @@ -0,0 +1,26 @@ +package xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule.models + +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack +import xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule.ui.Ui + +/** + * Representation of an Ui Entry, which is an item in an Ui. + * @param slot the slot of where the item should be placed + * @param item the item that should be displayed in the slot (as a function, so it can be dynamic) + * @param action the action that should be executed when a player clicks on the item. The action should return true if the UI should be closed after the action is executed, false otherwise. + * @param dynamic if true, this item will be updated at least every tick (20 times per second) + */ +data class UiEntry( + val slot: Int, + val item: () -> ItemStack, + val action: (Ui, Player) -> Unit = { _, _ -> }, + val dynamic: Boolean = false +) { + + /** + * The cached item, which is the item that will be displayed in the UI. + * This is used to avoid calling the [item] function every time the UI is updated (unless it's dynamic). + */ + val cachedItem = item.invoke() +} \ No newline at end of file diff --git a/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/ui/Ui.kt b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/ui/Ui.kt index 2098fb5..b54676f 100644 --- a/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/ui/Ui.kt +++ b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/ui/Ui.kt @@ -2,9 +2,15 @@ package xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule.ui import org.bukkit.Bukkit 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.InventoryClickEvent import org.bukkit.inventory.Inventory -import org.bukkit.inventory.ItemStack -import xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule.ui.events.UiClickEvent +import xyz.theprogramsrc.simplecoreapi.spigot.SpigotLoader +import xyz.theprogramsrc.simplecoreapi.spigot.extensions.bukkitColor +import xyz.theprogramsrc.simplecoreapi.spigot.extensions.registerEvent +import xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule.models.UiEntry /** * Representation of a "raw" UI, meaning there are no @@ -13,14 +19,75 @@ import xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule.ui.events.UiClic * @param player the player that should see the UI * @param title the title of the UI * @param rows the amount of rows the UI should have - * @param items the items that should be displayed in the UI - * @param actions the actions that should be executed when a player clicks on an item + * @param entries a list of [UiEntry] that will contain the items of the UI + * @param shouldCloseInventory whether the UI should be able to be closed by the player or not (usually when pressing the ESC or inventory key) */ class Ui( val player: Player, val title: String, val rows: Int = 1, - val items: Map = emptyMap(), - val actions: Map Boolean> = emptyMap(), -) { + val entries: List, + val shouldCloseInventory: Boolean = true +): Listener { + + private val mappedEntries = entries.associateBy { it.slot } + val inventory: Inventory + + init { + check(rows in 1..6) { "Invalid amount of rows: $rows. Must be between 1 and 6" } + check(title.bukkitColor().isNotBlank()) { "Invalid title: $title" } + check(entries.isNotEmpty()) { "Entries cannot be empty" } + inventory = Bukkit.createInventory(null, rows * 9, title.bukkitColor()) + } + + /** + * Opens the UI to the player + */ + fun open() { + if(!inventory.isEmpty) { + HandlerList.unregisterAll(this) + } + inventory.clear() + mappedEntries.forEach { (slot, entry) -> + check(slot in 0 until inventory.size) { "Invalid slot: $slot. Must be between 0 and ${inventory.size}" } + inventory.setItem(slot, entry.cachedItem) + } + registerEvent(this, SpigotLoader.instance) + player.openInventory(inventory) + } + + /** + * Closes the UI to the player + */ + fun close() { + HandlerList.unregisterAll(this) + player.closeInventory() + } + + @EventHandler + fun onClick(e: InventoryClickEvent) { + if(e.whoClicked.uniqueId != player.uniqueId && e.clickedInventory != inventory) { + return + } + + val slot = e.slot + + if(mappedEntries[slot]?.cachedItem?.isSimilar(e.currentItem) != true) { + return + } + + e.isCancelled = true + mappedEntries[slot]?.action?.invoke(this, player) + } + + @EventHandler + fun onClose(e: InventoryClickEvent) { + if (e.whoClicked.uniqueId != player.uniqueId && e.clickedInventory != inventory) { + return + } + + if (!shouldCloseInventory) { + open() + } + } } \ No newline at end of file diff --git a/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/ui/events/UiClickEvent.kt b/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/ui/events/UiClickEvent.kt deleted file mode 100644 index 72ad78d..0000000 --- a/simplecoreapi/src/main/kotlin/xyz/theprogramsrc/simplecoreapi/spigot/modules/uismodule/ui/events/UiClickEvent.kt +++ /dev/null @@ -1,28 +0,0 @@ -package xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule.ui.events - -import org.bukkit.entity.Player -import xyz.theprogramsrc.simplecoreapi.spigot.modules.uismodule.ui.Ui - -/** - * Represents an event fired when a player clicks on a UI - */ -interface UiClickEvent { - - /** - * Gets the slot that was clicked - * @return the slot - */ - fun getSlot(): Int - - /** - * Gets the player that clicked - * @return the player - */ - fun getPlayer(): Player - - /** - * Gets the UI that was clicked - * @return the UI - */ - fun getUi(): Ui -} \ No newline at end of file