Merge pull request #9 from bluefireoly/guispace

Added GUI Space functionality
This commit is contained in:
Jakob K
2020-10-21 21:05:57 +02:00
committed by GitHub
20 changed files with 342 additions and 168 deletions

View File

@@ -58,7 +58,7 @@ dependencies {
testCompileOnly("org.spigotmc", "spigot", "1.16.3-R0.1-SNAPSHOT") testCompileOnly("org.spigotmc", "spigot", "1.16.3-R0.1-SNAPSHOT")
// KHTTP // KHTTP
implementation("khttp", "khttp", "1.0.0") api("khttp", "khttp", "1.0.0")
} }

View File

@@ -2,7 +2,7 @@
package net.axay.kspigot.config package net.axay.kspigot.config
import net.axay.kspigot.languageextensions.createIfNotExists import net.axay.kspigot.languageextensions.kotlinextensions.createIfNotExists
import net.axay.kspigot.main.ValueHolder.getGson import net.axay.kspigot.main.ValueHolder.getGson
import java.io.File import java.io.File
import java.io.FileReader import java.io.FileReader

View File

@@ -2,76 +2,9 @@
package net.axay.kspigot.inventory package net.axay.kspigot.inventory
import net.axay.kspigot.event.listen
import org.bukkit.entity.HumanEntity
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.Inventory import org.bukkit.inventory.Inventory
import org.bukkit.inventory.InventoryView
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
// EXTENSIONS
fun HumanEntity.openGUI(gui: InventoryGUI<*>, page: Int? = null): InventoryView? {
closeInventory()
if (page != null)
gui.loadPageUnsafe(page)
return openInventory(gui.bukkitInventory)
}
// GUI HOLDER
object InventoryGUIHolder : AutoCloseable {
private val registered = HashSet<InventoryGUI<ForInventory>>()
fun register(inventoryGUI: InventoryGUI<ForInventory>) {
registered.add(inventoryGUI)
}
fun unregister(inventoryGUI: InventoryGUI<ForInventory>) {
registered.remove(inventoryGUI)
}
init {
listen<InventoryClickEvent> {
val clickedInv = it.clickedInventory ?: return@listen
val inv = registered.find { search -> search.isThisInv(clickedInv) } ?: return@listen
val invPage = inv.currentPageInt
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<T : ForInventory>(
val bukkitEvent: InventoryClickEvent,
val gui: InventoryGUI<T>
)
/*
* INVENTORY GUI
*/
private const val DEFAULT_PAGE = 1 private const val DEFAULT_PAGE = 1
class InventoryGUIData<T : ForInventory>( class InventoryGUIData<T : ForInventory>(
@@ -94,13 +27,25 @@ abstract class InventoryGUI<T : ForInventory>(
internal abstract val bukkitInventory: Inventory internal abstract val bukkitInventory: Inventory
internal var isInMove: Boolean = false
internal abstract fun loadPageUnsafe(
page: Int,
offsetHorizontally: Int = 0,
offsetVertically: Int = 0
)
internal abstract fun loadPageUnsafe( internal abstract fun loadPageUnsafe(
page: InventoryGUIPage<*>, page: InventoryGUIPage<*>,
offsetHorizontally: Int = 0, offsetHorizontally: Int = 0,
offsetVertically: Int = 0 offsetVertically: Int = 0
) )
internal abstract fun loadPageUnsafe(page: Int, offsetHorizontally: Int = 0, offsetVertically: Int = 0) internal abstract fun loadContent(
content: Map<Int, InventoryGUISlot<*>>,
offsetHorizontally: Int = 0,
offsetVertically: Int = 0
)
/** /**
* @return True, if the [inventory] belongs to this GUI. * @return True, if the [inventory] belongs to this GUI.
@@ -136,6 +81,14 @@ abstract class InventoryGUI<T : ForInventory>(
*/ */
fun getPage(page: Int?) = data.pages[page] fun getPage(page: Int?) = data.pages[page]
/**
* Reloads the current page.
*/
fun reloadCurrentPage() {
if (!isInMove)
loadPage(currentPage)
}
} }
// Inventory GUI implementations // Inventory GUI implementations
@@ -152,43 +105,59 @@ class InventoryGUIShared<T : ForInventory>(
override fun isThisInv(inventory: Inventory) = inventory == bukkitInventory override fun isThisInv(inventory: Inventory) = inventory == bukkitInventory
override fun loadPageUnsafe(page: Int, offsetHorizontally: Int, offsetVertically: Int) {
data.pages[page]?.let { loadPageUnsafe(it, offsetHorizontally, offsetVertically) }
}
override fun loadPageUnsafe(page: InventoryGUIPage<*>, offsetHorizontally: Int, offsetVertically: Int) { override fun loadPageUnsafe(page: InventoryGUIPage<*>, offsetHorizontally: Int, offsetVertically: Int) {
val ifOffset = offsetHorizontally != 0 || offsetVertically != 0 val ifOffset = offsetHorizontally != 0 || offsetVertically != 0
if (!ifOffset) if (!ifOffset) {
// unregister this inv from all elements on the previous page
HashSet(currentPage.slots.values).forEach { if (it is InventoryGUIElement) it.stopUsing(this) }
currentPageInt = page.number currentPageInt = page.number
page.slots.let { slots -> }
val dimensions = data.inventoryType.dimensions loadContent(page.slots, offsetHorizontally, offsetVertically)
if (ifOffset) { }
dimensions.invSlots.forEach {
dimensions.invSlotsWithRealSlots[it.add(offsetHorizontally, offsetVertically)]?.let { slotToClear -> override fun loadContent(
if (dimensions.realSlots.contains(slotToClear)) content: Map<Int, InventoryGUISlot<*>>,
bukkitInventory.clear(slotToClear) offsetHorizontally: Int,
} offsetVertically: Int
} ) {
} else {
bukkitInventory.clear() val ifOffset = offsetHorizontally != 0 || offsetVertically != 0
val dimensions = data.inventoryType.dimensions
// clear the space which will be redefined
if (ifOffset) {
dimensions.invSlots.forEach {
val slotToClear = dimensions.invSlotsWithRealSlots[it.add(offsetHorizontally, offsetVertically)]
if (slotToClear != null) bukkitInventory.clear(slotToClear)
} }
} else bukkitInventory.clear()
slots.forEach { content.forEach {
val slot = it.value
if (slot is InventoryGUIElement) {
if (ifOffset) { val slot = it.value
val invSlot = InventorySlot.fromRealSlot(it.key, dimensions) if (slot is InventoryGUIElement) {
if (invSlot != null) {
val offsetSlot = invSlot.add(offsetHorizontally, offsetVertically).realSlotIn(dimensions) if (ifOffset) {
if (offsetSlot != null) val invSlot = InventorySlot.fromRealSlot(it.key, dimensions)
bukkitInventory.setItem(offsetSlot, slot.inventoryGUIElementData.itemStack) if (invSlot != null) {
} val offsetSlot = invSlot.add(offsetHorizontally, offsetVertically).realSlotIn(dimensions)
} else { if (offsetSlot != null) bukkitInventory.setItem(offsetSlot, slot.getItemStack(offsetSlot))
bukkitInventory.setItem(it.key, slot.inventoryGUIElementData.itemStack)
} }
} else {
bukkitInventory.setItem(it.key, slot.getItemStack(it.key))
slot.startUsing(this)
} }
} }
@@ -197,21 +166,10 @@ class InventoryGUIShared<T : ForInventory>(
} }
override fun loadPageUnsafe(page: Int, offsetHorizontally: Int, offsetVertically: Int) {
data.pages[page]?.let { loadPageUnsafe(it, offsetHorizontally, offsetVertically) }
}
override operator fun set(slot: InventorySlotCompound<T>, value: ItemStack) { override operator fun set(slot: InventorySlotCompound<T>, value: ItemStack) {
slot.realSlotsWithInvType(data.inventoryType).forEach { slot.realSlotsWithInvType(data.inventoryType).forEach {
bukkitInventory.setItem(it, value) bukkitInventory.setItem(it, value)
} }
} }
} }
class InventoryGUIPage<T : ForInventory>(
val number: Int,
internal val slots: Map<Int, InventoryGUISlot<T>>,
val transitionTo: PageChangeEffect?,
val transitionFrom: PageChangeEffect?
)

View File

@@ -5,13 +5,15 @@ package net.axay.kspigot.inventory
import net.axay.kspigot.inventory.elements.* import net.axay.kspigot.inventory.elements.*
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
fun <T : ForInventory> inventoryGUI( fun <T : ForInventory> kSpigotGUI(
type: InventoryType<T>, type: InventoryType<T>,
shared: Boolean = true,
builder: InventoryGUIBuilder<T>.() -> Unit, builder: InventoryGUIBuilder<T>.() -> Unit,
) = InventoryGUIBuilder(type).apply(builder).build() ) = InventoryGUIBuilder(type, shared).apply(builder).build()
class InventoryGUIBuilder<T : ForInventory>( class InventoryGUIBuilder<T : ForInventory>(
val type: InventoryType<T> val type: InventoryType<T>,
val shared: Boolean
) { ) {
var title: String = "" var title: String = ""
@@ -36,14 +38,17 @@ class InventoryGUIBuilder<T : ForInventory>(
onClickElement = onClick onClickElement = onClick
} }
internal fun build() = InventoryGUIShared( internal fun build(): InventoryGUI<T> {
InventoryGUIData(type, title, guiSlots, transitionTo, transitionFrom, onClickElement) val guiData = InventoryGUIData(type, title, guiSlots, transitionTo, transitionFrom, onClickElement)
).apply { register() } val gui =
if (shared) InventoryGUIShared(guiData) else TODO("Currently, there is no non-shared GUI implementation available.")
return gui.apply { register() }
}
} }
class InventoryGUIPageBuilder<T : ForInventory>( class InventoryGUIPageBuilder<T : ForInventory>(
val type: InventoryType<T>, private val type: InventoryType<T>,
val page: Int val page: Int
) { ) {
@@ -60,14 +65,14 @@ class InventoryGUIPageBuilder<T : ForInventory>(
* function is invoked. * function is invoked.
*/ */
fun button(slots: InventorySlotCompound<T>, itemStack: ItemStack, onClick: (InventoryGUIClickEvent<T>) -> Unit) = fun button(slots: InventorySlotCompound<T>, itemStack: ItemStack, onClick: (InventoryGUIClickEvent<T>) -> Unit) =
defineSlots(slots, InventoryGUIButton(InventoryGUIElementData(itemStack), onClick)) defineSlots(slots, InventoryGUIButton(itemStack, onClick))
/** /**
* An item protected from any player actions. * An item protected from any player actions.
* This is not a button. * This is not a button.
*/ */
fun placeholder(slots: InventorySlotCompound<T>, itemStack: ItemStack) = fun placeholder(slots: InventorySlotCompound<T>, itemStack: ItemStack) =
defineSlots(slots, InventoryGUIPlaceholder(InventoryGUIElementData(itemStack))) defineSlots(slots, InventoryGUIPlaceholder(itemStack))
/** /**
* A free slot does not block any player actions. * A free slot does not block any player actions.
@@ -87,7 +92,7 @@ class InventoryGUIPageBuilder<T : ForInventory>(
onChange: ((InventoryGUIClickEvent<T>) -> Unit)? = null onChange: ((InventoryGUIClickEvent<T>) -> Unit)? = null
) = defineSlots( ) = defineSlots(
slots, InventoryGUIButtonPageChange( slots, InventoryGUIButtonPageChange(
InventoryGUIElementData(itemStack), itemStack,
InventoryGUIPageChangeCalculator.InventoryGUIConsistentPageCalculator(toPage), InventoryGUIPageChangeCalculator.InventoryGUIConsistentPageCalculator(toPage),
onChange onChange
) )
@@ -104,7 +109,7 @@ class InventoryGUIPageBuilder<T : ForInventory>(
onChange: ((InventoryGUIClickEvent<T>) -> Unit)? = null onChange: ((InventoryGUIClickEvent<T>) -> Unit)? = null
) = defineSlots( ) = defineSlots(
slots, InventoryGUIButtonPageChange( slots, InventoryGUIButtonPageChange(
InventoryGUIElementData(itemStack), itemStack,
InventoryGUIPageChangeCalculator.InventoryGUIPreviousPageCalculator, InventoryGUIPageChangeCalculator.InventoryGUIPreviousPageCalculator,
onChange onChange
) )
@@ -121,7 +126,7 @@ class InventoryGUIPageBuilder<T : ForInventory>(
onChange: ((InventoryGUIClickEvent<T>) -> Unit)? = null onChange: ((InventoryGUIClickEvent<T>) -> Unit)? = null
) = defineSlots( ) = defineSlots(
slots, InventoryGUIButtonPageChange( slots, InventoryGUIButtonPageChange(
InventoryGUIElementData(itemStack), itemStack,
InventoryGUIPageChangeCalculator.InventoryGUINextPageCalculator, InventoryGUIPageChangeCalculator.InventoryGUINextPageCalculator,
onChange onChange
) )
@@ -139,13 +144,37 @@ class InventoryGUIPageBuilder<T : ForInventory>(
onChange: ((InventoryGUIClickEvent<T>) -> Unit)? = null onChange: ((InventoryGUIClickEvent<T>) -> Unit)? = null
) = defineSlots( ) = defineSlots(
slots, InventoryGUIButtonInventoryChange( slots, InventoryGUIButtonInventoryChange(
InventoryGUIElementData(itemStack), itemStack,
newGUI, newGUI,
newPage, newPage,
onChange onChange
) )
) )
/**
* Defines an area where the content of the given compound
* is displayed.
*/
fun <E> compoundSpace(
slots: InventorySlotCompound<T>,
compound: InventoryGUISpaceCompound<T, E>
) {
compound.addSlots(slots)
defineSlots(
slots,
InventoryGUISpaceCompoundElement(compound)
)
}
/**
* Creates a new compound, holding data which can be displayed
* in any compound space.
*/
fun <E> createCompound(
iconGenerator: (E) -> ItemStack,
onClick: (clickEvent: InventoryGUIClickEvent<T>, element: E) -> Unit
) = InventoryGUISpaceCompound(type, iconGenerator, onClick)
private fun defineSlots(slots: InventorySlotCompound<T>, element: InventoryGUISlot<T>) = private fun defineSlots(slots: InventorySlotCompound<T>, element: InventoryGUISlot<T>) =
slots.withInvType(type).forEach { curSlot -> slots.withInvType(type).forEach { curSlot ->
curSlot.realSlotIn(type.dimensions)?.let { guiSlots[it] = element } curSlot.realSlotIn(type.dimensions)?.let { guiSlots[it] = element }

View File

@@ -0,0 +1,8 @@
package net.axay.kspigot.inventory
import org.bukkit.event.inventory.InventoryClickEvent
class InventoryGUIClickEvent<T : ForInventory>(
val bukkitEvent: InventoryClickEvent,
val gui: InventoryGUI<T>
)

View File

@@ -8,13 +8,9 @@ abstract class InventoryGUISlot<T : ForInventory> {
// ELEMENT // ELEMENT
class InventoryGUIElementData( abstract class InventoryGUIElement<T : ForInventory> : InventoryGUISlot<T>() {
val itemStack: ItemStack
)
abstract class InventoryGUIElement<T : ForInventory>( abstract fun getItemStack(slot: Int): ItemStack
val inventoryGUIElementData: InventoryGUIElementData
) : InventoryGUISlot<T>() {
final override fun onClick(clickEvent: InventoryGUIClickEvent<T>) { final override fun onClick(clickEvent: InventoryGUIClickEvent<T>) {
clickEvent.gui.data.generalOnClick?.invoke(clickEvent) clickEvent.gui.data.generalOnClick?.invoke(clickEvent)
@@ -23,4 +19,7 @@ abstract class InventoryGUIElement<T : ForInventory>(
protected abstract fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) protected abstract fun onClickElement(clickEvent: InventoryGUIClickEvent<T>)
internal open fun startUsing(gui: InventoryGUI<*>) { }
internal open fun stopUsing(gui: InventoryGUI<*>) { }
} }

View File

@@ -0,0 +1,15 @@
package net.axay.kspigot.inventory
import org.bukkit.entity.HumanEntity
import org.bukkit.inventory.InventoryView
fun HumanEntity.openGUI(gui: InventoryGUI<*>, page: Int? = null): InventoryView? {
closeInventory()
if (page != null)
gui.loadPageUnsafe(page)
return openInventory(gui.bukkitInventory)
}

View File

@@ -0,0 +1,47 @@
package net.axay.kspigot.inventory
import net.axay.kspigot.event.listen
import org.bukkit.event.inventory.InventoryClickEvent
object InventoryGUIHolder : AutoCloseable {
private val registered = HashSet<InventoryGUI<ForInventory>>()
fun register(inventoryGUI: InventoryGUI<ForInventory>) {
registered.add(inventoryGUI)
}
fun unregister(inventoryGUI: InventoryGUI<ForInventory>) {
registered.remove(inventoryGUI)
}
init {
listen<InventoryClickEvent> {
val clickedInv = it.clickedInventory ?: return@listen
val inv = registered.find { search -> search.isThisInv(clickedInv) } ?: return@listen
if (inv.isInMove) {
it.isCancelled = true
return@listen
}
val invPage = inv.currentPageInt
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()
}
}

View File

@@ -0,0 +1,8 @@
package net.axay.kspigot.inventory
class InventoryGUIPage<T : ForInventory>(
val number: Int,
internal val slots: Map<Int, InventoryGUISlot<T>>,
val transitionTo: PageChangeEffect?,
val transitionFrom: PageChangeEffect?
)

View File

@@ -67,7 +67,7 @@ internal fun InventoryGUI<*>.changePage(
PageChangeEffect.SLIDE_VERTICALLY -> { PageChangeEffect.SLIDE_VERTICALLY -> {
val height = data.inventoryType.dimensions.heigth val height = data.inventoryType.dimensions.height
changePageEffect(fromPageInt, toPageInt, height) { currentOffset, ifInverted -> changePageEffect(fromPageInt, toPageInt, height) { currentOffset, ifInverted ->
if (ifInverted) { if (ifInverted) {
@@ -97,7 +97,7 @@ internal fun InventoryGUI<*>.changePage(
PageChangeEffect.SWIPE_VERTICALLY -> { PageChangeEffect.SWIPE_VERTICALLY -> {
val height = data.inventoryType.dimensions.heigth val height = data.inventoryType.dimensions.height
changePageEffect(fromPageInt, toPageInt, height) { currentOffset, ifInverted -> changePageEffect(fromPageInt, toPageInt, height) { currentOffset, ifInverted ->
if (ifInverted) { if (ifInverted) {

View File

@@ -2,15 +2,17 @@
package net.axay.kspigot.inventory package net.axay.kspigot.inventory
import net.axay.kspigot.languageextensions.MinMaxPair import net.axay.kspigot.languageextensions.kotlinextensions.MinMaxPair
// INVENTORY // INVENTORY
data class InventoryDimensions(val width: Int, val heigth: Int) { data class InventoryDimensions(val width: Int, val height: Int) {
val slotAmount = width * height
val invSlots by lazy { val invSlots by lazy {
ArrayList<InventorySlot>().apply { ArrayList<InventorySlot>().apply {
(1..heigth).forEach { row -> (1..height).forEach { row ->
(1..width).forEach { slotInRow -> (1..width).forEach { slotInRow ->
this += InventorySlot(row, slotInRow) this += InventorySlot(row, slotInRow)
} }
@@ -18,14 +20,6 @@ data class InventoryDimensions(val width: Int, val heigth: Int) {
} }
} }
val realSlots by lazy {
ArrayList<Int>().apply {
invSlots.forEach { curSlot ->
curSlot.realSlotIn(this@InventoryDimensions)?.let { this += it }
}
}
}
val invSlotsWithRealSlots by lazy { val invSlotsWithRealSlots by lazy {
HashMap<InventorySlot, Int>().apply { HashMap<InventorySlot, Int>().apply {
invSlots.forEach { curSlot -> invSlots.forEach { curSlot ->
@@ -34,6 +28,8 @@ data class InventoryDimensions(val width: Int, val heigth: Int) {
} }
} }
val realSlots by lazy { invSlotsWithRealSlots.values }
} }
// SLOTS // SLOTS
@@ -57,13 +53,13 @@ data class InventorySlot(val row: Int, val slotInRow: Int) : Comparable<Inventor
fun realSlotIn(inventoryDimensions: InventoryDimensions): Int? { fun realSlotIn(inventoryDimensions: InventoryDimensions): Int? {
if (!isInDimension(inventoryDimensions)) return null if (!isInDimension(inventoryDimensions)) return null
val realRow = inventoryDimensions.heigth - (row - 1) val realRow = inventoryDimensions.height - (row - 1)
val rowsUnder = if (realRow - 1 >= 0) realRow - 1 else 0 val rowsUnder = if (realRow - 1 >= 0) realRow - 1 else 0
return ((rowsUnder * inventoryDimensions.width) + slotInRow) - 1 return ((rowsUnder * inventoryDimensions.width) + slotInRow) - 1
} }
fun isInDimension(inventoryDimensions: InventoryDimensions) = fun isInDimension(inventoryDimensions: InventoryDimensions) =
(1..inventoryDimensions.width).contains(slotInRow) && (1..inventoryDimensions.heigth).contains(row) (1..inventoryDimensions.width).contains(slotInRow) && (1..inventoryDimensions.height).contains(row)
fun add(offsetHorizontally: Int, offsetVertically: Int) = InventorySlot( fun add(offsetHorizontally: Int, offsetVertically: Int) = InventorySlot(
row + offsetVertically, row + offsetVertically,
@@ -182,7 +178,7 @@ class InventoryColumnSlots<T : ForInventory> internal constructor(
) : InventorySlotCompound<T> { ) : InventorySlotCompound<T> {
override fun withInvType(invType: InventoryType<T>) = HashSet<InventorySlot>().apply { override fun withInvType(invType: InventoryType<T>) = HashSet<InventorySlot>().apply {
for (row in 1..invType.dimensions.heigth) for (row in 1..invType.dimensions.height)
this += InventorySlot(row, column) this += InventorySlot(row, column)
} }
@@ -199,9 +195,9 @@ class InventoryBorderSlots<T : ForInventory> internal constructor(
for (currentPadding in 0 until padding) { for (currentPadding in 0 until padding) {
for (slotInRow in 1 + currentPadding..dimensions.width - currentPadding) { for (slotInRow in 1 + currentPadding..dimensions.width - currentPadding) {
this += InventorySlot(1, slotInRow) this += InventorySlot(1, slotInRow)
this += InventorySlot(dimensions.heigth, slotInRow) this += InventorySlot(dimensions.height, slotInRow)
} }
for (row in 2 + currentPadding until dimensions.heigth - currentPadding) { for (row in 2 + currentPadding until dimensions.height - currentPadding) {
this += InventorySlot(row, 1) this += InventorySlot(row, 1)
this += InventorySlot(row, dimensions.width) this += InventorySlot(row, dimensions.width)
} }
@@ -224,8 +220,8 @@ class InventoryCornerSlots<T : ForInventory> internal constructor(
if (ifBottomLeft) this += InventorySlot(1, 1) if (ifBottomLeft) this += InventorySlot(1, 1)
if (ifBottomRight) this += InventorySlot(1, dimensions.width) if (ifBottomRight) this += InventorySlot(1, dimensions.width)
if (ifTopLeft) this += InventorySlot(dimensions.heigth, 1) if (ifTopLeft) this += InventorySlot(dimensions.height, 1)
if (ifTopRight) this += InventorySlot(dimensions.heigth, dimensions.width) if (ifTopRight) this += InventorySlot(dimensions.height, dimensions.width)
} }

View File

@@ -12,8 +12,6 @@ class InventoryType<in T : ForInventory>(
val bukkitType: InventoryType? = null val bukkitType: InventoryType? = null
) { ) {
private val size = dimensions.width * dimensions.heigth
companion object { companion object {
val ONE_BY_NINE = InventoryType<ForInventoryOneByNine>(InventoryDimensions(9, 1)) val ONE_BY_NINE = InventoryType<ForInventoryOneByNine>(InventoryDimensions(9, 1))
@@ -33,7 +31,7 @@ class InventoryType<in T : ForInventory>(
val realTitle = title ?: "" val realTitle = title ?: ""
return when { return when {
bukkitType != null -> Bukkit.createInventory(holder, bukkitType, realTitle) bukkitType != null -> Bukkit.createInventory(holder, bukkitType, realTitle)
else -> Bukkit.createInventory(holder, size, realTitle) else -> Bukkit.createInventory(holder, dimensions.slotAmount, realTitle)
} }
} }

View File

@@ -1,14 +1,14 @@
package net.axay.kspigot.inventory.elements package net.axay.kspigot.inventory.elements
import net.axay.kspigot.inventory.ForInventory import net.axay.kspigot.inventory.*
import net.axay.kspigot.inventory.InventoryGUIClickEvent import org.bukkit.inventory.ItemStack
import net.axay.kspigot.inventory.InventoryGUIElement
import net.axay.kspigot.inventory.InventoryGUIElementData
open class InventoryGUIButton<T : ForInventory>( open class InventoryGUIButton<T : ForInventory>(
inventoryGUIElementData: InventoryGUIElementData, private val icon: ItemStack,
val action: (InventoryGUIClickEvent<T>) -> Unit, val action: (InventoryGUIClickEvent<T>) -> Unit,
) : InventoryGUIElement<T>(inventoryGUIElementData) { ) : InventoryGUIElement<T>() {
override fun getItemStack(slot: Int) = icon
override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) { override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
clickEvent.bukkitEvent.isCancelled = true clickEvent.bukkitEvent.isCancelled = true

View File

@@ -1,13 +1,14 @@
package net.axay.kspigot.inventory.elements package net.axay.kspigot.inventory.elements
import net.axay.kspigot.inventory.* import net.axay.kspigot.inventory.*
import org.bukkit.inventory.ItemStack
class InventoryGUIButtonInventoryChange<T : ForInventory>( class InventoryGUIButtonInventoryChange<T : ForInventory>(
inventoryGUIElementData: InventoryGUIElementData, icon: ItemStack,
changeToGUICallback: () -> InventoryGUI<*>, changeToGUICallback: () -> InventoryGUI<*>,
changeToPageInt: Int?, changeToPageInt: Int?,
onChange: ((InventoryGUIClickEvent<T>) -> Unit)? onChange: ((InventoryGUIClickEvent<T>) -> Unit)?
) : InventoryGUIButton<T>(inventoryGUIElementData, { ) : InventoryGUIButton<T>(icon, {
val changeToGUI = changeToGUICallback.invoke() val changeToGUI = changeToGUICallback.invoke()

View File

@@ -1,12 +1,13 @@
package net.axay.kspigot.inventory.elements package net.axay.kspigot.inventory.elements
import net.axay.kspigot.inventory.* import net.axay.kspigot.inventory.*
import org.bukkit.inventory.ItemStack
class InventoryGUIButtonPageChange<T : ForInventory>( class InventoryGUIButtonPageChange<T : ForInventory>(
inventoryGUIElementData: InventoryGUIElementData, icon: ItemStack,
calculator: InventoryGUIPageChangeCalculator, calculator: InventoryGUIPageChangeCalculator,
onChange: ((InventoryGUIClickEvent<T>) -> Unit)? onChange: ((InventoryGUIClickEvent<T>) -> Unit)?
) : InventoryGUIButton<T>(inventoryGUIElementData, { ) : InventoryGUIButton<T>(icon, {
val currentPage = it.gui.currentPage val currentPage = it.gui.currentPage
val newPage = it.gui.getPage(calculator.calculateNewPage(it.gui.currentPageInt, it.gui.data.pages.keys)) val newPage = it.gui.getPage(calculator.calculateNewPage(it.gui.currentPageInt, it.gui.data.pages.keys))

View File

@@ -1,13 +1,13 @@
package net.axay.kspigot.inventory.elements package net.axay.kspigot.inventory.elements
import net.axay.kspigot.inventory.ForInventory import net.axay.kspigot.inventory.*
import net.axay.kspigot.inventory.InventoryGUIClickEvent import org.bukkit.inventory.ItemStack
import net.axay.kspigot.inventory.InventoryGUIElement
import net.axay.kspigot.inventory.InventoryGUIElementData
class InventoryGUIPlaceholder<T : ForInventory>( class InventoryGUIPlaceholder<T : ForInventory>(
inventoryGUIElementData: InventoryGUIElementData private val icon: ItemStack
) : InventoryGUIElement<T>(inventoryGUIElementData) { ) : InventoryGUIElement<T>() {
override fun getItemStack(slot: Int) = icon
override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) { override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
clickEvent.bukkitEvent.isCancelled = true clickEvent.bukkitEvent.isCancelled = true

View File

@@ -0,0 +1,114 @@
@file:Suppress("MemberVisibilityCanBePrivate", "unused")
package net.axay.kspigot.inventory.elements
import net.axay.kspigot.inventory.*
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
class InventoryGUISpaceCompoundElement<T : ForInventory, E>(
private val compound: InventoryGUISpaceCompound<T, E>
) : InventoryGUIElement<T>() {
override fun getItemStack(slot: Int) = compound.getItemStack(slot)
override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
compound.onClickElement(clickEvent)
}
override fun startUsing(gui: InventoryGUI<*>) = compound.registerGUI(gui)
override fun stopUsing(gui: InventoryGUI<*>) = compound.unregisterGUI(gui)
}
class InventoryGUISpaceCompound<T : ForInventory, E>(
private val invType: InventoryType<T>,
private val iconGenerator: (E) -> ItemStack,
private val onClick: (InventoryGUIClickEvent<T>, E) -> Unit
) {
private val content = ArrayList<E>()
private val realInternalSlots = ArrayList<Int>()
private val currentInternalSlots: List<Int> get() {
val result = ArrayList(realInternalSlots)
var more = 1
while (content.size > result.size) {
result += realInternalSlots.mapTo(ArrayList()) { it + (more * invType.dimensions.slotAmount) }
more++
}
return result
}
private var scrolledLines: Int = 0
private var contentSort: () -> Unit = { }
private val registeredGUIs = HashSet<InventoryGUI<*>>()
private fun translateSlot(slot: Int) = (scrolledLines * invType.dimensions.width) + slot
private fun contentAtSlot(slot: Int) = content.getOrNull(
realInternalSlots.indexOf(translateSlot(slot))
)
internal fun getItemStack(slot: Int): ItemStack {
return contentAtSlot(slot)?.let { return@let iconGenerator.invoke(it) }
?: ItemStack(Material.AIR)
}
internal fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
val element = contentAtSlot(clickEvent.bukkitEvent.slot) ?: return
onClick.invoke(clickEvent, element)
}
internal fun addSlots(slots: InventorySlotCompound<T>) {
slots.realSlotsWithInvType(invType).forEach {
if (!realInternalSlots.contains(it))
realInternalSlots.add(it)
}
realInternalSlots.sort()
}
internal fun registerGUI(gui: InventoryGUI<*>) {
registeredGUIs += gui
}
internal fun unregisterGUI(gui: InventoryGUI<*>) {
registeredGUIs -= gui
}
/**
* Defines the sort behaviour which gets applied to the content
* automatically.
*/
fun <R : Comparable<R>> sortContentBy(reverse: Boolean = false, selector: (E) -> R?) {
contentSort = {
if (!reverse) content.sortBy(selector) else content.sortByDescending(selector)
}
contentSort.invoke()
}
/**
* Adds a new element to the compound.
*/
fun addContent(element: E) {
addContent(listOf(element))
}
/**
* Adds new elements to the compound.
*/
fun addContent(elements: Collection<E>) {
content += elements
contentSort.invoke()
registeredGUIs.forEach { it.reloadCurrentPage() }
}
}

View File

@@ -1,7 +1,7 @@
package net.axay.kspigot.main package net.axay.kspigot.main
import net.axay.kspigot.inventory.InventoryGUIHolder import net.axay.kspigot.inventory.InventoryGUIHolder
import net.axay.kspigot.languageextensions.closeIfInitialized import net.axay.kspigot.languageextensions.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

View File

@@ -1,7 +1,7 @@
package net.axay.kspigot.particles package net.axay.kspigot.particles
import net.axay.kspigot.extensions.bukkit.worldOrException import net.axay.kspigot.extensions.bukkit.worldOrException
import net.axay.kspigot.languageextensions.applyIfNotNull import net.axay.kspigot.languageextensions.kotlinextensions.applyIfNotNull
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.Particle import org.bukkit.Particle
import org.bukkit.entity.Player import org.bukkit.entity.Player

View File

@@ -1,7 +1,7 @@
package net.axay.kspigot.sound package net.axay.kspigot.sound
import net.axay.kspigot.extensions.bukkit.worldOrException import net.axay.kspigot.extensions.bukkit.worldOrException
import net.axay.kspigot.languageextensions.applyIfNotNull import net.axay.kspigot.languageextensions.kotlinextensions.applyIfNotNull
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.Sound import org.bukkit.Sound
import org.bukkit.SoundCategory import org.bukkit.SoundCategory