Beginning of InventoryGUI
This commit is contained in:
166
src/main/kotlin/net/axay/kspigot/inventory/InventoryGUI.kt
Normal file
166
src/main/kotlin/net/axay/kspigot/inventory/InventoryGUI.kt
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
|
||||||
|
package net.axay.kspigot.inventory
|
||||||
|
|
||||||
|
import net.axay.kspigot.event.listen
|
||||||
|
import net.axay.kspigot.event.register
|
||||||
|
import net.axay.kspigot.main.KSpigot
|
||||||
|
import org.bukkit.entity.HumanEntity
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
|
import org.bukkit.event.inventory.InventoryInteractEvent
|
||||||
|
import org.bukkit.inventory.Inventory
|
||||||
|
import org.bukkit.inventory.InventoryView
|
||||||
|
|
||||||
|
// EXTENSIONS
|
||||||
|
|
||||||
|
fun HumanEntity.openGUI(gui: InventoryGUI, page: Int = 1): InventoryView? {
|
||||||
|
closeInventory()
|
||||||
|
gui.loadPage(page)
|
||||||
|
return openInventory(gui.bukkitInventory)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GUI HOLDER
|
||||||
|
|
||||||
|
class InventoryGUIHolder(kSpigot: KSpigot) : AutoCloseable {
|
||||||
|
|
||||||
|
private val registered = HashSet<InventoryGUI>()
|
||||||
|
|
||||||
|
fun register(inventoryGUI: InventoryGUI) {
|
||||||
|
registered += inventoryGUI
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unregister(inventoryGUI: InventoryGUI) {
|
||||||
|
registered -= inventoryGUI
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
object : Listener {
|
||||||
|
@EventHandler
|
||||||
|
private fun onInteract(event: InventoryInteractEvent) {
|
||||||
|
println("interact geht hier")
|
||||||
|
}
|
||||||
|
}.register(kSpigot)
|
||||||
|
|
||||||
|
kSpigot.listen<InventoryClickEvent> {
|
||||||
|
|
||||||
|
val inv = registered.find { search -> search.isThisInv(it.inventory) } ?: return@listen
|
||||||
|
val invPage = inv.currentPage ?: return@listen
|
||||||
|
|
||||||
|
val slot = inv.data.pages[invPage]?.slots?.get(it.slot)
|
||||||
|
if (slot != null)
|
||||||
|
slot.onClick(InventoryGUIClickEvent(it, inv))
|
||||||
|
else
|
||||||
|
it.isCancelled = true
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
registered.forEach { inv -> inv.bukkitInventory.viewers.forEach { it.closeInventory() } }
|
||||||
|
registered.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// EVENT
|
||||||
|
|
||||||
|
class InventoryGUIClickEvent(
|
||||||
|
val bukkitEvent: InventoryClickEvent,
|
||||||
|
val gui: InventoryGUI,
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INVENTORY GUI
|
||||||
|
*/
|
||||||
|
|
||||||
|
class InventoryGUIData(
|
||||||
|
val plugin: KSpigot,
|
||||||
|
val inventoryGUIType: InventoryGUIType<*>,
|
||||||
|
val title: String?,
|
||||||
|
val pages: Map<Int, InventoryGUIPage>
|
||||||
|
)
|
||||||
|
|
||||||
|
abstract class InventoryGUI(
|
||||||
|
val data: InventoryGUIData
|
||||||
|
) {
|
||||||
|
|
||||||
|
var currentPage: Int? = null; protected set
|
||||||
|
|
||||||
|
abstract val bukkitInventory: Inventory
|
||||||
|
|
||||||
|
abstract fun loadPage(page: Int, offsetHorizontally: Int = 0, offsetVertically: Int = 0)
|
||||||
|
|
||||||
|
abstract fun isThisInv(inventory: Inventory): Boolean
|
||||||
|
|
||||||
|
fun register() = data.plugin.inventoryGUIHolder.register(this)
|
||||||
|
fun unregister() = data.plugin.inventoryGUIHolder.unregister(this)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inventory GUI implementations
|
||||||
|
|
||||||
|
class InventoryGUIShared(
|
||||||
|
inventoryGUIData: InventoryGUIData
|
||||||
|
) : InventoryGUI(inventoryGUIData) {
|
||||||
|
|
||||||
|
override val bukkitInventory by lazy { data.inventoryGUIType.createBukkitInv(null, data.title) }
|
||||||
|
|
||||||
|
override fun isThisInv(inventory: Inventory) = inventory == bukkitInventory
|
||||||
|
|
||||||
|
override fun loadPage(page: Int, offsetHorizontally: Int, offsetVertically: Int) {
|
||||||
|
|
||||||
|
fun ifOffset(): Boolean = offsetHorizontally != 0 || offsetVertically != 0
|
||||||
|
|
||||||
|
currentPage = page
|
||||||
|
|
||||||
|
data.pages[page]?.slots?.let { slots ->
|
||||||
|
|
||||||
|
val dimensions = data.inventoryGUIType.dimensions
|
||||||
|
|
||||||
|
if (ifOffset()) {
|
||||||
|
dimensions.invSlots.forEach {
|
||||||
|
dimensions.invSlotsWithRealSlots[it.add(offsetHorizontally, offsetVertically)]?.let { slotToClear ->
|
||||||
|
if (dimensions.realSlots.contains(slotToClear))
|
||||||
|
bukkitInventory.clear(slotToClear)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bukkitInventory.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
slots.forEach {
|
||||||
|
val slot = it.value
|
||||||
|
if (slot is InventoryGUIElement) {
|
||||||
|
|
||||||
|
if (ifOffset()) {
|
||||||
|
val invSlot = InventorySlot.fromRealSlot(it.key, dimensions)
|
||||||
|
if (invSlot != null) {
|
||||||
|
val offsetSlot = invSlot.add(offsetHorizontally, offsetVertically).realSlotIn(dimensions)
|
||||||
|
if (offsetSlot != null)
|
||||||
|
bukkitInventory.setItem(offsetSlot, slot.inventoryGUIElementData.itemStack)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bukkitInventory.setItem(it.key, slot.inventoryGUIElementData.itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class InventoryGUIPage(
|
||||||
|
val slots: Map<Int, InventoryGUISlot>,
|
||||||
|
transitionTo: InventoryGUIPageChangeEffect?,
|
||||||
|
transitionFrom: InventoryGUIPageChangeEffect?
|
||||||
|
) {
|
||||||
|
val pageChangerTo = transitionTo?.let { InventoryGUIPageChanger(it) }
|
||||||
|
val pageChangerFrom = transitionFrom?.let { InventoryGUIPageChanger(it) }
|
||||||
|
}
|
@@ -0,0 +1,108 @@
|
|||||||
|
@file:Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||||
|
|
||||||
|
package net.axay.kspigot.inventory
|
||||||
|
|
||||||
|
import net.axay.kspigot.main.KSpigot
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
|
inline fun <T : ForInventory> KSpigot.inventoryGUI(
|
||||||
|
type: InventoryGUIType<T>,
|
||||||
|
builder: InventoryGUIBuilder<T>.() -> Unit,
|
||||||
|
) = InventoryGUIBuilder(this, type).apply(builder).build()
|
||||||
|
|
||||||
|
class InventoryGUIBuilder<in T : ForInventory>(
|
||||||
|
private val kSpigot: KSpigot,
|
||||||
|
val type: InventoryGUIType<in T>
|
||||||
|
) {
|
||||||
|
|
||||||
|
var title: String = ""
|
||||||
|
|
||||||
|
private val guiSlots = HashMap<Int, InventoryGUIPage>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun page(page: Int, builder: InventoryGUIPageBuilder<T>.() -> Unit) {
|
||||||
|
guiSlots[page] = InventoryGUIPageBuilder(type, page).apply(builder).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build() = InventoryGUIShared(InventoryGUIData(kSpigot, type, title, guiSlots)).apply { register() }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class InventoryGUIPageBuilder<in T : ForInventory>(
|
||||||
|
val type: InventoryGUIType<in T>,
|
||||||
|
val page: Int
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val guiSlots = HashMap<Int, InventoryGUISlot>()
|
||||||
|
|
||||||
|
var transitionTo: InventoryGUIPageChangeEffect? = null
|
||||||
|
var transitionFrom: InventoryGUIPageChangeEffect? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A button is an item protected from any player
|
||||||
|
* actions. If clicked, the specified [onClick]
|
||||||
|
* function is invoked.
|
||||||
|
*/
|
||||||
|
fun button(slots: InventorySlotCompound<T>, itemStack: ItemStack, onClick: (InventoryGUIClickEvent) -> Unit)
|
||||||
|
= slots(slots, InventoryGUIButton(InventoryGUIElementData(itemStack), onClick))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item protected from any player actions.
|
||||||
|
* This is not a button.
|
||||||
|
*/
|
||||||
|
fun placeholder(slots: InventorySlotCompound<T>, itemStack: ItemStack)
|
||||||
|
= slots(slots, InventoryGUIPlaceholder(InventoryGUIElementData(itemStack)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A free slot does not block any player actions.
|
||||||
|
* The player can put items in this slot or take
|
||||||
|
* items out of it.
|
||||||
|
*/
|
||||||
|
fun freeSlot(slots: InventorySlotCompound<T>)
|
||||||
|
= slots(slots, InventoryGUIFreeSlot())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a button which loads the specified
|
||||||
|
* [toPage] if clicked.
|
||||||
|
*/
|
||||||
|
fun pageChanger(slots: InventorySlotCompound<T>, itemStack: ItemStack, toPage: Int, onChange: ((InventoryGUIClickEvent) -> Unit)? = null)
|
||||||
|
= slots(slots, InventoryGUIButtonPageChange(
|
||||||
|
InventoryGUIElementData(itemStack),
|
||||||
|
InventoryGUIPageChangeCalculator.InventoryGUIConsistentPageCalculator(toPage),
|
||||||
|
onChange
|
||||||
|
))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This button always tries to find the previous
|
||||||
|
* page if clicked, and if a previous page
|
||||||
|
* exists it is loaded.
|
||||||
|
*/
|
||||||
|
fun previousPage(slots: InventorySlotCompound<T>, itemStack: ItemStack, onChange: ((InventoryGUIClickEvent) -> Unit)? = null)
|
||||||
|
= slots(slots, InventoryGUIButtonPageChange(
|
||||||
|
InventoryGUIElementData(itemStack),
|
||||||
|
InventoryGUIPageChangeCalculator.InventoryGUIPreviousPageCalculator,
|
||||||
|
onChange
|
||||||
|
))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This button always tries to find the next
|
||||||
|
* page if clicked, and if a next page
|
||||||
|
* exists it is loaded.
|
||||||
|
*/
|
||||||
|
fun nextPage(slots: InventorySlotCompound<T>, itemStack: ItemStack, onChange: ((InventoryGUIClickEvent) -> Unit)? = null)
|
||||||
|
= slots(slots, InventoryGUIButtonPageChange(
|
||||||
|
InventoryGUIElementData(itemStack),
|
||||||
|
InventoryGUIPageChangeCalculator.InventoryGUINextPageCalculator,
|
||||||
|
onChange
|
||||||
|
))
|
||||||
|
|
||||||
|
private fun slots(slots: InventorySlotCompound<T>, element: InventoryGUISlot)
|
||||||
|
= slots.withGUIType(type).forEach { curSlot ->
|
||||||
|
curSlot.realSlotIn(type.dimensions)?.let { guiSlots[it] = element }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build() = InventoryGUIPage(guiSlots, transitionTo, transitionFrom)
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,71 @@
|
|||||||
|
package net.axay.kspigot.inventory
|
||||||
|
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
|
interface InventoryGUISlot {
|
||||||
|
fun onClick(clickEvent: InventoryGUIClickEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELEMENT
|
||||||
|
|
||||||
|
class InventoryGUIElementData(
|
||||||
|
val itemStack: ItemStack
|
||||||
|
)
|
||||||
|
|
||||||
|
abstract class InventoryGUIElement(
|
||||||
|
val inventoryGUIElementData: InventoryGUIElementData
|
||||||
|
) : InventoryGUISlot
|
||||||
|
|
||||||
|
// Element implementations
|
||||||
|
|
||||||
|
open class InventoryGUIButton(
|
||||||
|
inventoryGUIElementData: InventoryGUIElementData,
|
||||||
|
val action: (InventoryGUIClickEvent) -> Unit,
|
||||||
|
) : InventoryGUIElement(inventoryGUIElementData) {
|
||||||
|
|
||||||
|
override fun onClick(clickEvent: InventoryGUIClickEvent) {
|
||||||
|
clickEvent.bukkitEvent.isCancelled = true
|
||||||
|
action(clickEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class InventoryGUIPlaceholder(
|
||||||
|
inventoryGUIElementData: InventoryGUIElementData
|
||||||
|
) : InventoryGUIElement(inventoryGUIElementData) {
|
||||||
|
|
||||||
|
override fun onClick(clickEvent: InventoryGUIClickEvent) {
|
||||||
|
clickEvent.bukkitEvent.isCancelled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class InventoryGUIButtonPageChange(
|
||||||
|
inventoryGUIElementData: InventoryGUIElementData,
|
||||||
|
calculator: InventoryGUIPageChangeCalculator,
|
||||||
|
onChange: ((InventoryGUIClickEvent) -> Unit)?
|
||||||
|
)
|
||||||
|
: InventoryGUIButton(inventoryGUIElementData, {
|
||||||
|
it.gui.currentPage?.let { currentPageInt ->
|
||||||
|
|
||||||
|
val newPageInt = calculator.calculateNewPage(currentPageInt, it.gui.data.pages.keys)
|
||||||
|
if (newPageInt != null) {
|
||||||
|
|
||||||
|
onChange?.invoke(it)
|
||||||
|
|
||||||
|
val pageChanger
|
||||||
|
= (it.gui.data.pages[newPageInt]?.pageChangerTo ?: it.gui.data.pages[currentPageInt]?.pageChangerFrom)
|
||||||
|
?: InventoryGUIPageChanger(InventoryGUIPageChangeEffect.INSTANT)
|
||||||
|
|
||||||
|
pageChanger.changePage(it.gui, currentPageInt, newPageInt)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// FREE SLOT
|
||||||
|
|
||||||
|
class InventoryGUIFreeSlot : InventoryGUISlot {
|
||||||
|
override fun onClick(clickEvent: InventoryGUIClickEvent) { /* do nothing */ }
|
||||||
|
}
|
@@ -0,0 +1,68 @@
|
|||||||
|
package net.axay.kspigot.inventory
|
||||||
|
|
||||||
|
import net.axay.kspigot.runnables.task
|
||||||
|
|
||||||
|
abstract class InventoryGUIPageChangeCalculator {
|
||||||
|
|
||||||
|
abstract fun calculateNewPage(currentPage: Int, pages: Collection<Int>): Int?
|
||||||
|
|
||||||
|
object InventoryGUIPreviousPageCalculator : InventoryGUIPageChangeCalculator() {
|
||||||
|
override fun calculateNewPage(currentPage: Int, pages: Collection<Int>) = pages.sortedDescending().find { it < currentPage }
|
||||||
|
}
|
||||||
|
|
||||||
|
object InventoryGUINextPageCalculator : InventoryGUIPageChangeCalculator() {
|
||||||
|
override fun calculateNewPage(currentPage: Int, pages: Collection<Int>) = pages.sorted().find { it > currentPage }
|
||||||
|
}
|
||||||
|
|
||||||
|
class InventoryGUIConsistentPageCalculator(private val toPage: Int) : InventoryGUIPageChangeCalculator() {
|
||||||
|
override fun calculateNewPage(currentPage: Int, pages: Collection<Int>) = toPage
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class InventoryGUIPageChangeEffect {
|
||||||
|
INSTANT, SLIDE_HORIZONTALLY
|
||||||
|
}
|
||||||
|
|
||||||
|
class InventoryGUIPageChanger(private val effect: InventoryGUIPageChangeEffect) {
|
||||||
|
|
||||||
|
fun changePage(gui: InventoryGUI, fromPage: Int, toPage: Int) {
|
||||||
|
when (effect) {
|
||||||
|
|
||||||
|
InventoryGUIPageChangeEffect.SLIDE_HORIZONTALLY -> {
|
||||||
|
|
||||||
|
val width = gui.data.inventoryGUIType.dimensions.width
|
||||||
|
|
||||||
|
val ifInverted = fromPage >= toPage
|
||||||
|
|
||||||
|
var currentOffset = 1
|
||||||
|
gui.data.plugin.task(
|
||||||
|
sync = true,
|
||||||
|
period = 1,
|
||||||
|
howOften = width.toLong()
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (ifInverted) {
|
||||||
|
gui.loadPage(fromPage, currentOffset)
|
||||||
|
gui.loadPage(toPage, - (width - currentOffset))
|
||||||
|
} else {
|
||||||
|
gui.loadPage(fromPage, -currentOffset)
|
||||||
|
gui.loadPage(toPage, width - currentOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentOffset++
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryGUIPageChangeEffect.INSTANT -> {
|
||||||
|
|
||||||
|
gui.loadPage(toPage)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
236
src/main/kotlin/net/axay/kspigot/inventory/InventoryGUISlots.kt
Normal file
236
src/main/kotlin/net/axay/kspigot/inventory/InventoryGUISlots.kt
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||||
|
|
||||||
|
package net.axay.kspigot.inventory
|
||||||
|
|
||||||
|
// INVENTORY
|
||||||
|
|
||||||
|
data class InventoryDimensions(val width: Int, val heigth: Int) {
|
||||||
|
|
||||||
|
val invSlots by lazy {
|
||||||
|
ArrayList<InventorySlot>().apply {
|
||||||
|
(1 .. heigth).forEach { row ->
|
||||||
|
(1 .. width).forEach { slotInRow ->
|
||||||
|
this += InventorySlot(row, slotInRow)
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val realSlots by lazy {
|
||||||
|
ArrayList<Int>().apply {
|
||||||
|
invSlots.forEach { curSlot ->
|
||||||
|
curSlot.realSlotIn(this@InventoryDimensions)?.let { this += it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val invSlotsWithRealSlots by lazy {
|
||||||
|
HashMap<InventorySlot, Int>().apply {
|
||||||
|
invSlots.forEach { curSlot ->
|
||||||
|
curSlot.realSlotIn(this@InventoryDimensions)?.let { this[curSlot] = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// SLOTS
|
||||||
|
|
||||||
|
data class InventorySlot(val row: Int, val slotInRow: Int) : Comparable<InventorySlot> {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromRealSlot(realSlot: Int, dimensions: InventoryDimensions)
|
||||||
|
= dimensions.invSlotsWithRealSlots.toList().find { it.second == realSlot }?.first
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun compareTo(other: InventorySlot) = when {
|
||||||
|
row > other.row -> 1
|
||||||
|
row < other.row -> -1
|
||||||
|
else -> when {
|
||||||
|
slotInRow > other.slotInRow -> 1
|
||||||
|
slotInRow < other.slotInRow -> -1
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun realSlotIn(inventoryDimensions: InventoryDimensions): Int? {
|
||||||
|
if (!isInDimension(inventoryDimensions)) return null
|
||||||
|
val realRow = inventoryDimensions.heigth - (row - 1)
|
||||||
|
val rowsUnder = if (realRow - 1 >= 0) realRow - 1 else 0
|
||||||
|
return ((rowsUnder * inventoryDimensions.width) + slotInRow) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isInDimension(inventoryDimensions: InventoryDimensions)
|
||||||
|
= (1 .. inventoryDimensions.width).contains(slotInRow) && (1 .. inventoryDimensions.heigth).contains(row)
|
||||||
|
|
||||||
|
fun add(offsetHorizontally: Int, offsetVertically: Int) = InventorySlot(
|
||||||
|
row + offsetVertically,
|
||||||
|
slotInRow + offsetHorizontally
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InventorySlotCompound<out T : ForInventory> {
|
||||||
|
fun withGUIType(invType: InventoryGUIType<in T>): Collection<InventorySlot>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class SingleInventorySlot<out T : ForInventory>(val inventorySlot: InventorySlot)
|
||||||
|
: InventorySlotCompound<T> {
|
||||||
|
|
||||||
|
constructor(row: Int, slotInRow: Int) : this(InventorySlot(row, slotInRow))
|
||||||
|
|
||||||
|
private val slotAsList = listOf(inventorySlot)
|
||||||
|
|
||||||
|
override fun withGUIType(invType: InventoryGUIType<in T>) = slotAsList
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class InventorySlotRangeType { LINEAR, RECTANGLE }
|
||||||
|
|
||||||
|
class InventorySlotRange<out T : ForInventory> (
|
||||||
|
|
||||||
|
startSlot: SingleInventorySlot<T>,
|
||||||
|
endSlot: SingleInventorySlot<T>,
|
||||||
|
|
||||||
|
private val type: InventorySlotRangeType
|
||||||
|
|
||||||
|
) : InventorySlotCompound<T>, ClosedRange<InventorySlot> {
|
||||||
|
|
||||||
|
override val start: InventorySlot
|
||||||
|
override val endInclusive: InventorySlot
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (startSlot.inventorySlot <= endSlot.inventorySlot) {
|
||||||
|
start = startSlot.inventorySlot
|
||||||
|
endInclusive = endSlot.inventorySlot
|
||||||
|
} else {
|
||||||
|
start = endSlot.inventorySlot
|
||||||
|
endInclusive = startSlot.inventorySlot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun withGUIType(invType: InventoryGUIType<in T>)
|
||||||
|
= LinkedHashSet<InventorySlot>().apply {
|
||||||
|
when (type) {
|
||||||
|
|
||||||
|
InventorySlotRangeType.RECTANGLE -> {
|
||||||
|
// all possible combinations between the two slots
|
||||||
|
// -> form a rectangle
|
||||||
|
for (row in start.row .. endInclusive.row)
|
||||||
|
for (slotInRow in start.slotInRow .. endInclusive.slotInRow)
|
||||||
|
this += InventorySlot(row, slotInRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
InventorySlotRangeType.LINEAR -> {
|
||||||
|
if (endInclusive.row > start.row) {
|
||||||
|
// from start --->| to end of row
|
||||||
|
for (slotInRow in start.slotInRow .. invType.dimensions.width)
|
||||||
|
this += InventorySlot(start.row, slotInRow)
|
||||||
|
// all rows in between
|
||||||
|
if (endInclusive.row > start.row + 1)
|
||||||
|
for (row in start.row + 1 until endInclusive.row)
|
||||||
|
for (slotInRow in 1 .. invType.dimensions.width)
|
||||||
|
this += InventorySlot(row, slotInRow)
|
||||||
|
// from start of row |----> to endInclusive
|
||||||
|
for (slotInRow in 1 .. endInclusive.slotInRow)
|
||||||
|
this += InventorySlot(endInclusive.row, slotInRow)
|
||||||
|
} else if (endInclusive.row == start.row) {
|
||||||
|
// from start ---> to endInclusive in the same row
|
||||||
|
for (slotInRow in start.slotInRow .. endInclusive.slotInRow)
|
||||||
|
this += InventorySlot(start.row, slotInRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// SLOT RANGE OPERATOR FUNCTIONS
|
||||||
|
|
||||||
|
infix fun <T : ForInventory> SingleInventorySlot<T>.linTo(slot: SingleInventorySlot<T>)
|
||||||
|
= InventorySlotRange(this, slot, InventorySlotRangeType.LINEAR)
|
||||||
|
|
||||||
|
infix fun <T : ForInventory> SingleInventorySlot<T>.rectTo(slot: SingleInventorySlot<T>)
|
||||||
|
= InventorySlotRange(this, slot, InventorySlotRangeType.RECTANGLE)
|
||||||
|
|
||||||
|
// SLOT TYPE SAFETY
|
||||||
|
|
||||||
|
// ROWS
|
||||||
|
interface ForRowOne : ForInventoryOneByNine, ForInventoryTwoByNine, ForInventoryThreeByNine, ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine
|
||||||
|
interface ForRowTwo : ForInventoryTwoByNine, ForInventoryThreeByNine, ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine
|
||||||
|
interface ForRowThree : ForInventoryThreeByNine, ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine
|
||||||
|
interface ForRowFour : ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine
|
||||||
|
interface ForRowFive : ForInventoryFiveByNine, ForInventorySixByNine
|
||||||
|
interface ForRowSix : ForInventorySixByNine
|
||||||
|
|
||||||
|
// EDGE CASES:
|
||||||
|
// ROW ONE
|
||||||
|
interface ForRowOneSlotOneToThree : ForRowOne, ForInventoryOneByFive, ForInventoryThreeByThree
|
||||||
|
interface ForRowOneSlotFourToFive : ForRowOne, ForInventoryOneByFive
|
||||||
|
// ROW TWO
|
||||||
|
interface ForRowTwoSlotOneToThree : ForRowTwo, ForInventoryThreeByThree
|
||||||
|
// ROW THREE
|
||||||
|
interface ForRowThreeSlotOneToThree : ForRowThree, ForInventoryThreeByThree
|
||||||
|
|
||||||
|
object Slots {
|
||||||
|
// ROW ONE
|
||||||
|
val RowOneSlotOne = SingleInventorySlot<ForRowOneSlotOneToThree>(1, 1)
|
||||||
|
val RowOneSlotTwo = SingleInventorySlot<ForRowOneSlotOneToThree>(1, 2)
|
||||||
|
val RowOneSlotThree = SingleInventorySlot<ForRowOneSlotOneToThree>(1, 3)
|
||||||
|
val RowOneSlotFour = SingleInventorySlot<ForRowOneSlotFourToFive>(1, 4)
|
||||||
|
val RowOneSlotFive = SingleInventorySlot<ForRowOneSlotFourToFive>(1, 5)
|
||||||
|
val RowOneSlotSix = SingleInventorySlot<ForRowOne>(1, 6)
|
||||||
|
val RowOneSlotSeven = SingleInventorySlot<ForRowOne>(1, 7)
|
||||||
|
val RowOneSlotEight = SingleInventorySlot<ForRowOne>(1, 8)
|
||||||
|
val RowOneSlotNine = SingleInventorySlot<ForRowOne>(1, 9)
|
||||||
|
// ROW TWO
|
||||||
|
val RowTwoSlotOne = SingleInventorySlot<ForRowTwoSlotOneToThree>(2, 1)
|
||||||
|
val RowTwoSlotTwo = SingleInventorySlot<ForRowTwoSlotOneToThree>(2, 2)
|
||||||
|
val RowTwoSlotThree = SingleInventorySlot<ForRowTwoSlotOneToThree>(2, 3)
|
||||||
|
val RowTwoSlotFour = SingleInventorySlot<ForRowTwo>(2, 4)
|
||||||
|
val RowTwoSlotFive = SingleInventorySlot<ForRowTwo>(2, 5)
|
||||||
|
val RowTwoSlotSix = SingleInventorySlot<ForRowTwo>(2, 6)
|
||||||
|
val RowTwoSlotSeven = SingleInventorySlot<ForRowTwo>(2, 7)
|
||||||
|
val RowTwoSlotEight = SingleInventorySlot<ForRowTwo>(2, 8)
|
||||||
|
val RowTwoSlotNine = SingleInventorySlot<ForRowTwo>(2, 9)
|
||||||
|
// ROW THREE
|
||||||
|
val RowThreeSlotOne = SingleInventorySlot<ForRowThreeSlotOneToThree>(3, 1)
|
||||||
|
val RowThreeSlotTwo = SingleInventorySlot<ForRowThreeSlotOneToThree>(3, 2)
|
||||||
|
val RowThreeSlotThree = SingleInventorySlot<ForRowThreeSlotOneToThree>(3, 3)
|
||||||
|
val RowThreeSlotFour = SingleInventorySlot<ForRowThree>(3, 4)
|
||||||
|
val RowThreeSlotFive = SingleInventorySlot<ForRowThree>(3, 5)
|
||||||
|
val RowThreeSlotSix = SingleInventorySlot<ForRowThree>(3, 6)
|
||||||
|
val RowThreeSlotSeven = SingleInventorySlot<ForRowThree>(3, 7)
|
||||||
|
val RowThreeSlotEight = SingleInventorySlot<ForRowThree>(3, 8)
|
||||||
|
val RowThreeSlotNine = SingleInventorySlot<ForRowThree>(3, 9)
|
||||||
|
// ROW FOUR
|
||||||
|
val RowFourSlotOne = SingleInventorySlot<ForRowFour>(4, 1)
|
||||||
|
val RowFourSlotTwo = SingleInventorySlot<ForRowFour>(4, 2)
|
||||||
|
val RowFourSlotThree = SingleInventorySlot<ForRowFour>(4, 3)
|
||||||
|
val RowFourSlotFour = SingleInventorySlot<ForRowFour>(4, 4)
|
||||||
|
val RowFourSlotFive = SingleInventorySlot<ForRowFour>(4, 5)
|
||||||
|
val RowFourSlotSix = SingleInventorySlot<ForRowFour>(4, 6)
|
||||||
|
val RowFourSlotSeven = SingleInventorySlot<ForRowFour>(4, 7)
|
||||||
|
val RowFourSlotEight = SingleInventorySlot<ForRowFour>(4, 8)
|
||||||
|
val RowFourSlotNine = SingleInventorySlot<ForRowFour>(4, 9)
|
||||||
|
// ROW FIVE
|
||||||
|
val RowFiveSlotOne = SingleInventorySlot<ForRowFive>(5, 1)
|
||||||
|
val RowFiveSlotTwo = SingleInventorySlot<ForRowFive>(5, 2)
|
||||||
|
val RowFiveSlotThree = SingleInventorySlot<ForRowFive>(5, 3)
|
||||||
|
val RowFiveSlotFour = SingleInventorySlot<ForRowFive>(5, 4)
|
||||||
|
val RowFiveSlotFive = SingleInventorySlot<ForRowFive>(5, 5)
|
||||||
|
val RowFiveSlotSix = SingleInventorySlot<ForRowFive>(5, 6)
|
||||||
|
val RowFiveSlotSeven = SingleInventorySlot<ForRowFive>(5, 7)
|
||||||
|
val RowFiveSlotEight = SingleInventorySlot<ForRowFive>(5, 8)
|
||||||
|
val RowFiveSlotNine = SingleInventorySlot<ForRowFive>(5, 9)
|
||||||
|
// ROW SIX
|
||||||
|
val RowSixSlotOne = SingleInventorySlot<ForRowSix>(6, 1)
|
||||||
|
val RowSixSlotTwo = SingleInventorySlot<ForRowSix>(6, 2)
|
||||||
|
val RowSixSlotThree = SingleInventorySlot<ForRowSix>(6, 3)
|
||||||
|
val RowSixSlotFour = SingleInventorySlot<ForRowSix>(6, 4)
|
||||||
|
val RowSixSlotFive = SingleInventorySlot<ForRowSix>(6, 5)
|
||||||
|
val RowSixSlotSix = SingleInventorySlot<ForRowSix>(6, 6)
|
||||||
|
val RowSixSlotSeven = SingleInventorySlot<ForRowSix>(6, 7)
|
||||||
|
val RowSixSlotEight = SingleInventorySlot<ForRowSix>(6, 8)
|
||||||
|
val RowSixSlotNine = SingleInventorySlot<ForRowSix>(6, 9)
|
||||||
|
}
|
@@ -0,0 +1,56 @@
|
|||||||
|
@file:Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
|
||||||
|
|
||||||
|
package net.axay.kspigot.inventory
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.event.inventory.InventoryType
|
||||||
|
import org.bukkit.inventory.Inventory
|
||||||
|
import org.bukkit.inventory.InventoryHolder
|
||||||
|
|
||||||
|
class InventoryGUIType<T : ForInventory>(
|
||||||
|
val dimensions: InventoryDimensions,
|
||||||
|
val bukkitType: InventoryType? = null
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val size = dimensions.width * dimensions.heigth
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val ONE_BY_NINE = InventoryGUIType<ForInventoryOneByNine>(InventoryDimensions(9, 1))
|
||||||
|
val TWO_BY_NINE = InventoryGUIType<ForInventoryTwoByNine>(InventoryDimensions(9, 2))
|
||||||
|
val THREE_BY_NINE = InventoryGUIType<ForInventoryThreeByNine>(InventoryDimensions(9, 3))
|
||||||
|
val FOUR_BY_NINE = InventoryGUIType<ForInventoryFourByNine>(InventoryDimensions(9, 4))
|
||||||
|
val FIVE_BY_NINE = InventoryGUIType<ForInventoryFiveByNine>(InventoryDimensions(9, 5))
|
||||||
|
val SIX_BY_NINE = InventoryGUIType<ForInventorySixByNine>(InventoryDimensions(9, 6))
|
||||||
|
val ONE_BY_FIVE = InventoryGUIType<ForInventoryOneByFive>(InventoryDimensions(5, 1), bukkitType = InventoryType.HOPPER)
|
||||||
|
val THREE_BY_THREE = InventoryGUIType<ForInventoryThreeByThree>(InventoryDimensions(3, 3), bukkitType = InventoryType.DROPPER)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createBukkitInv(holder: InventoryHolder? = null, title: String? = null): Inventory {
|
||||||
|
val realTitle = title ?: ""
|
||||||
|
return when {
|
||||||
|
bukkitType != null -> Bukkit.createInventory(holder, bukkitType, realTitle)
|
||||||
|
else -> Bukkit.createInventory(holder, size, realTitle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// INVENTORY TYPE SAFETY
|
||||||
|
|
||||||
|
interface ForInventory
|
||||||
|
|
||||||
|
interface ForInventoryOneByNine : ForInventory
|
||||||
|
interface ForInventoryTwoByNine : ForInventory
|
||||||
|
interface ForInventoryThreeByNine : ForInventory
|
||||||
|
interface ForInventoryFourByNine : ForInventory
|
||||||
|
interface ForInventoryFiveByNine : ForInventory
|
||||||
|
interface ForInventorySixByNine : ForInventory
|
||||||
|
interface ForInventoryThreeByThree : ForInventory
|
||||||
|
interface ForInventoryOneByFive : ForInventory
|
||||||
|
|
||||||
|
interface ForEveryInventory
|
||||||
|
: ForInventoryOneByNine, ForInventoryTwoByNine, ForInventoryThreeByNine,
|
||||||
|
ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine,
|
||||||
|
ForInventoryThreeByThree, ForInventoryOneByFive
|
@@ -1,5 +1,6 @@
|
|||||||
package net.axay.kspigot.main
|
package net.axay.kspigot.main
|
||||||
|
|
||||||
|
import net.axay.kspigot.inventory.InventoryGUIHolder
|
||||||
import net.axay.kspigot.kotlinextensions.closeIfInitialized
|
import net.axay.kspigot.kotlinextensions.closeIfInitialized
|
||||||
import net.axay.kspigot.runnables.KRunnableHolder
|
import net.axay.kspigot.runnables.KRunnableHolder
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
@@ -21,8 +22,10 @@ abstract class KSpigot : JavaPlugin() {
|
|||||||
|
|
||||||
// lazy properties
|
// lazy properties
|
||||||
private val kRunnableHolderProperty = lazy { KRunnableHolder() }
|
private val kRunnableHolderProperty = lazy { KRunnableHolder() }
|
||||||
|
private val inventoryGUIHolderProperty = lazy { InventoryGUIHolder(this) }
|
||||||
|
|
||||||
val kRunnableHolder by kRunnableHolderProperty
|
val kRunnableHolder by kRunnableHolderProperty
|
||||||
|
val inventoryGUIHolder by inventoryGUIHolderProperty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the plugin was loaded
|
* Called when the plugin was loaded
|
||||||
@@ -53,6 +56,7 @@ abstract class KSpigot : JavaPlugin() {
|
|||||||
|
|
||||||
// avoid unnecessary load of lazy properties
|
// avoid unnecessary load of lazy properties
|
||||||
kRunnableHolderProperty.closeIfInitialized()
|
kRunnableHolderProperty.closeIfInitialized()
|
||||||
|
inventoryGUIHolderProperty.closeIfInitialized()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user