Skip to content

Commit

Permalink
Merge pull request #70 from flytegg/gui-builder
Browse files Browse the repository at this point in the history
GUI Builder
  • Loading branch information
stephendotgg authored Sep 9, 2024
2 parents 65ced5e + f911607 commit 1d62add
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,58 @@ repeat(5, 10, TimeUnit.SECONDS, true) {

> Twilight `repeat` conflicting with Kotlin's `repeat`? As an alternative, you can use `repeatingTask`.
### GUI Builder
Creating GUI's can be an incredibly long and tedious process, however, in Twilight we offer a clean and efficient way to build GUIs.

Here's an example of a simple, bog-standard GUI:
```kotlin
val basicGui = gui(Component.text("Click the apple!"), 9) {
set(4, ItemStack(Material.APPLE)) {
isCancelled = true
viewer.sendMessage(Component.text("This is an apple!"))
}
}
player.openInventory(basicGui)
```
As you can see, setting the click event logic has never been easier. You can reference the player at any time using `viewer`.

Here's an example of a gui implementing the pattern feature, making it much easier to visualise:
```kotlin
val complexGui = gui {
pattern(
"#########",
"# S #",
"#########"
)

set('S', ItemStack(Material.PLAYER_HEAD).apply {
val meta = itemMeta as SkullMeta
meta.displayName(Component.text("${viewer.name}'s Head!"))
meta.owningPlayer = viewer
itemMeta = meta
}) {
isCancelled = true
viewer.sendMessage(Component.text("Ouch!", NamedTextColor.RED))
}

set('#', ItemStack(Material.LIGHT_GRAY_STAINED_GLASS_PANE).apply {
val meta = itemMeta
meta.displayName(Component.empty())
itemMeta = meta
}) { isCancelled = true }
}
player.openInventory(complexGui)
```
You can, of course, also implement GUIs for other inventory types:
```kotlin
val dropperGui = gui(Component.text("Title"), 9, InventoryType.DROPPER) {
// You can also set multiple indexes at once
set(listOf(1, 3, 4, 5, 7), ItemStack(Material.GRAY_STAINED_GLASS_PANE))
}
player.openInventory(dropperGui)
```
To open the gui, simply do `Player#openInventory(GUI)` like shown in the examples.

## Databases
### MongoDB
Currently we have support for MongoDB. To configure it, you can take one of two routes:
Expand Down
79 changes: 79 additions & 0 deletions src/main/kotlin/gg/flyte/twilight/gui/GUI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package gg.flyte.twilight.gui

import gg.flyte.twilight.event.event
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryType
import org.bukkit.inventory.ItemStack

inline fun gui(
title: Component = Component.text("Custom GUI"),
size: Int = 27,
type: InventoryType = InventoryType.CHEST,
noinline context: GUI.() -> Unit
): GUI {
return GUI(title, size, type, context)
}

class GUI(val title: Component, val size: Int, val type: InventoryType, val context: GUI.() -> Unit) {

private val inventory = when (type) {
InventoryType.CHEST -> Bukkit.createInventory(null, size, title)
else -> Bukkit.createInventory(null, type, title)
}

private val keySlot = mutableMapOf<Char, MutableList<Int>>()
private val slotAction = mutableMapOf<Int, InventoryClickEvent.() -> Unit>()

lateinit var viewer: Player

private val clickEvent = event<InventoryClickEvent> {
if (inventory != this@GUI.inventory) return@event
slotAction[slot]?.invoke(this)
}

fun pattern(vararg pattern: String) {
for ((index, value) in pattern.joinToString("").withIndex()) {
keySlot.getOrPut(value) { mutableListOf() }.add(index)
}
}

@JvmName("setSlot")
fun set(slot: Int, item: ItemStack, action: InventoryClickEvent.() -> Unit = {}) {
inventory.setItem(slot, item)
slotAction[slot] = action
}

@JvmName("setSlots")
fun set(indexes: Collection<Int>, item: ItemStack, action: InventoryClickEvent.() -> Unit = {}) {
indexes.forEach { set(it, item, action) }
}

@JvmName("setKey")
fun set(key: Char, item: ItemStack, action: InventoryClickEvent.() -> Unit = {}) {
keySlot[key]?.forEach { set(it, item, action) }
}

@JvmName("setKeys")
fun set(keys: Collection<Char>, item: ItemStack, action: InventoryClickEvent.() -> Unit = {}) {
keys.forEach { set(it, item, action) }
}

private fun remove() {
keySlot.clear()
slotAction.clear()
inventory.clear()
clickEvent.unregister()
}

companion object {
fun Player.openInventory(gui: GUI) {
gui.viewer = this
gui.context.invoke(gui)
openInventory(gui.inventory)
}
}

}

0 comments on commit 1d62add

Please sign in to comment.