Major improvements to menus

This commit is contained in:
Auxilor
2022-09-29 15:51:26 +01:00
parent 0caa328b1e
commit 3d35a91314
11 changed files with 142 additions and 172 deletions

View File

@@ -4,8 +4,8 @@ import com.willfp.eco.core.gui.component.GUIComponent
import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.OpenHandler
import com.willfp.eco.core.gui.slot.FillerSlot
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.internal.gui.slot.EcoFillerSlot
import com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.Bukkit
import org.bukkit.Material
@@ -19,39 +19,44 @@ import org.bukkit.persistence.PersistentDataType
@Suppress("UNCHECKED_CAST")
class EcoMenu(
private val rows: Int,
private val componentsAtPoints: Map<Anchor, OffsetComponent>,
private val componentsAtPoints: Map<Anchor, List<OffsetComponent>>,
private val title: String,
private val onClose: CloseHandler,
private val onRender: (Player, Menu) -> Unit,
private val onOpen: OpenHandler
) : Menu {
private fun getComponent(row: Int, column: Int): OffsetComponent? {
private fun getPossiblyReactiveSlot(row: Int, column: Int, player: Player?, menu: Menu?): Slot {
if (row < 1 || row > this.rows || column < 1 || column > 9) {
return emptyOffsetComponent
return emptyFillerSlot
}
return componentsAtPoints[Anchor(row, column)]
val anchor = Anchor(row, column)
val components = componentsAtPoints[anchor] ?: return emptyFillerSlot
for (component in components) {
val found = if (player != null && menu != null) component.component.getSlotAt(
component.rowOffset,
component.columnOffset,
player,
menu
) else component.component.getSlotAt(
component.rowOffset,
component.columnOffset
)
if (found != null) {
return found
}
}
return emptyFillerSlot
}
override fun getSlot(row: Int, column: Int): Slot {
val found = getComponent(row, column) ?: return emptyFillerSlot
override fun getSlot(row: Int, column: Int): Slot =
getPossiblyReactiveSlot(row, column, null, null)
return found.component.getSlotAt(
found.rowOffset,
found.columnOffset
) ?: emptyFillerSlot
}
override fun getSlot(row: Int, column: Int, player: Player, menu: Menu): Slot {
val found = getComponent(row, column) ?: return emptyFillerSlot
return found.component.getSlotAt(
found.rowOffset,
found.columnOffset,
player,
menu
) ?: emptyFillerSlot
}
override fun getSlot(row: Int, column: Int, player: Player, menu: Menu): Slot =
getPossiblyReactiveSlot(row, column, player, menu)
override fun open(player: Player): Inventory {
val inventory = Bukkit.createInventory(null, rows * 9, title)
@@ -146,5 +151,5 @@ data class Anchor(
val column: Int
)
val emptyFillerSlot = EcoFillerSlot(ItemStack(Material.AIR))
val emptyFillerSlot = FillerSlot(ItemStack(Material.AIR))
val emptyOffsetComponent = OffsetComponent(emptyFillerSlot, 0, 0)

View File

@@ -5,9 +5,6 @@ import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.menu.OpenHandler
import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.util.ListUtils
import com.willfp.eco.util.StringUtils
import org.bukkit.entity.Player
import java.util.function.BiConsumer
@@ -15,8 +12,7 @@ import java.util.function.Consumer
class EcoMenuBuilder(private val rows: Int) : MenuBuilder {
private var title = "Menu"
private var maskSlots: List<MutableList<Slot?>>
private val components = mutableMapOf<Anchor, GUIComponent>()
private val components = mutableMapOf<Anchor, MutableList<GUIComponent>>()
private var onClose = CloseHandler { _, _ -> }
private var onOpen = OpenHandler { _, _ -> }
private var onRender: (Player, Menu) -> Unit = { _, _ -> }
@@ -34,7 +30,9 @@ class EcoMenuBuilder(private val rows: Int) : MenuBuilder {
require(column + component.columns - 1 <= 9) { "Component is too large to be placed here!" }
require(row + component.rows - 1 <= getRows()) { "Component is too large to be placed here!" }
components[Anchor(row, column)] = component
val anchor = Anchor(row, column)
components.computeIfAbsent(anchor) { mutableListOf() } += component
return this
}
@@ -43,11 +41,6 @@ class EcoMenuBuilder(private val rows: Int) : MenuBuilder {
return this
}
override fun setMask(mask: FillerMask): MenuBuilder {
maskSlots = mask.mask
return this
}
override fun onClose(action: CloseHandler): MenuBuilder {
onClose = action
return this
@@ -64,27 +57,28 @@ class EcoMenuBuilder(private val rows: Int) : MenuBuilder {
}
override fun build(): Menu {
val componentsAtPoints = mutableMapOf<Anchor, OffsetComponent>()
val componentsAtPoints = mutableMapOf<Anchor, MutableList<OffsetComponent>>()
// 4 nested for loops? Shut up. Silence. Quiet.
for (row in (1..rows)) {
for (column in (1..9)) {
for ((anchor, component) in components) {
// Too far to the top / left to be in bounds
if (anchor.row > row || anchor.column > column) {
continue
}
for ((anchor, availableComponents) in components) {
for (component in availableComponents) {
// Too far to the top / left to be in bounds
if (anchor.row > row || anchor.column > column) {
continue
}
// Too far to the bottom / left to be in bounds
if (row > anchor.row + component.rows - 1 || column > anchor.column + component.columns - 1) {
continue
}
// Too far to the bottom / left to be in bounds
if (row > anchor.row + component.rows - 1 || column > anchor.column + component.columns - 1) {
continue
}
val rowOffset = anchor.row - row
val columnOffset = anchor.column - column
val rowOffset = anchor.row - row
val columnOffset = anchor.column - column
val slot = component.getSlotAt(rowOffset, columnOffset)
if (slot != null) {
componentsAtPoints[Anchor(row, column)] = OffsetComponent(
val point = Anchor(row, column)
componentsAtPoints.computeIfAbsent(point) { mutableListOf() } += OffsetComponent(
component,
rowOffset,
columnOffset
@@ -96,8 +90,4 @@ class EcoMenuBuilder(private val rows: Int) : MenuBuilder {
return EcoMenu(rows, componentsAtPoints, title, onClose, onRender, onOpen)
}
init {
maskSlots = ListUtils.create2DList(rows, 9)
}
}

View File

@@ -2,7 +2,9 @@ package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotProvider
import com.willfp.eco.util.toSingletonList
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType
class EcoCaptiveSlot(
provider: SlotProvider,
@@ -10,11 +12,9 @@ class EcoCaptiveSlot(
private val notCaptiveFor: (Player) -> Boolean
) : EcoSlot(
provider,
captiveWithTest(notCaptiveFor),
captiveWithTest(notCaptiveFor),
captiveWithTest(notCaptiveFor),
captiveWithTest(notCaptiveFor),
captiveWithTest(notCaptiveFor),
ClickType.values().associateWith {
captiveWithTest(notCaptiveFor).toSingletonList()
},
{ _, _, prev -> prev }
) {
override fun isCaptive(): Boolean {

View File

@@ -1,16 +0,0 @@
package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.slot.functional.SlotHandler
import org.bukkit.inventory.ItemStack
private val noop = SlotHandler { _, _, _ -> }
class EcoFillerSlot(itemStack: ItemStack) : EcoSlot(
{ _, _ -> itemStack },
noop,
noop,
noop,
noop,
noop,
{ _, _, prev -> prev }
)

View File

@@ -14,27 +14,19 @@ import org.bukkit.inventory.ItemStack
open class EcoSlot(
private val provider: SlotProvider,
private val onLeftClick: SlotHandler,
private val onRightClick: SlotHandler,
private val onShiftLeftClick: SlotHandler,
private val onShiftRightClick: SlotHandler,
private val onMiddleClick: SlotHandler,
private val handlers: Map<ClickType, List<SlotHandler>>,
private val updater: SlotUpdater
) : Slot {
private fun List<SlotHandler>.handle(event: InventoryClickEvent, slot: Slot, menu: Menu) =
this.forEach { it.handle(event, slot, menu) }
fun handleInventoryClick(
event: InventoryClickEvent,
menu: Menu
) {
event.isCancelled = true
when (event.click) {
ClickType.LEFT -> this.onLeftClick.handle(event, this, menu)
ClickType.RIGHT -> this.onRightClick.handle(event, this, menu)
ClickType.SHIFT_LEFT -> this.onShiftLeftClick.handle(event, this, menu)
ClickType.SHIFT_RIGHT -> this.onShiftRightClick.handle(event, this, menu)
ClickType.MIDDLE -> this.onMiddleClick.handle(event, this, menu)
else -> {}
}
handlers[event.click]?.handle(event, this, menu)
}
override fun getItemStack(player: Player): ItemStack {
@@ -55,4 +47,4 @@ open class EcoSlot(
override fun isCaptive(): Boolean {
return false
}
}
}

View File

@@ -1,62 +1,25 @@
package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder
import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotProvider
import com.willfp.eco.core.gui.slot.functional.SlotUpdater
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.ClickType
import java.util.function.Predicate
internal object NoOpSlot : SlotHandler {
override fun handle(event: InventoryClickEvent, slot: Slot, menu: Menu) {
}
override fun equals(other: Any?): Boolean {
return other is NoOpSlot
}
}
internal class NoOpForPlayer
class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
private var captive = false
private var captiveFromEmpty = false
private var updater: SlotUpdater = SlotUpdater { player, menu, _ -> provider.provide(player, menu) }
private var onLeftClick: SlotHandler = NoOpSlot
private var onRightClick: SlotHandler = NoOpSlot
private var onShiftLeftClick: SlotHandler = NoOpSlot
private var onShiftRightClick: SlotHandler = NoOpSlot
private var onMiddleClick: SlotHandler = NoOpSlot
private val handlers = mutableMapOf<ClickType, MutableList<SlotHandler>>()
private var notCaptiveFor: (Player) -> Boolean = { false }
override fun onLeftClick(action: SlotHandler): SlotBuilder {
onLeftClick = action
return this
}
override fun onRightClick(action: SlotHandler): SlotBuilder {
onRightClick = action
return this
}
override fun onShiftLeftClick(action: SlotHandler): SlotBuilder {
onShiftLeftClick = action
return this
}
override fun onShiftRightClick(action: SlotHandler): SlotBuilder {
onShiftRightClick = action
return this
}
override fun onMiddleClick(action: SlotHandler): SlotBuilder {
onMiddleClick = action
override fun onClick(type: ClickType, action: SlotHandler): SlotBuilder {
handlers.computeIfAbsent(type) { mutableListOf() } += action
return this
}
@@ -86,11 +49,7 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
} else {
EcoSlot(
provider,
onLeftClick,
onRightClick,
onShiftLeftClick,
onShiftRightClick,
onMiddleClick,
handlers,
updater
)
}