Skip to content

Commit

Permalink
wip: ui system
Browse files Browse the repository at this point in the history
* added UIsModule entrypoint
* removed UiClickEvent.kt in favor of kotlin functions
* added BukkitExtensions.kt
  • Loading branch information
Im-Fran committed Jan 16, 2024
1 parent b69529d commit 8817ac1
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 35 deletions.
@@ -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)
@@ -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() {}
}
@@ -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()
}
Expand Up @@ -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
Expand All @@ -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<Int, ItemStack> = emptyMap(),
val actions: Map<Int, (UiClickEvent) -> Boolean> = emptyMap(),
) {
val entries: List<UiEntry>,
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()
}
}
}

This file was deleted.

0 comments on commit 8817ac1

Please sign in to comment.