From 0caa328b1ec2bcf08c14d085dc2c761f6a71f04c Mon Sep 17 00:00:00 2001 From: Auxilor Date: Thu, 29 Sep 2022 15:08:34 +0100 Subject: [PATCH] Overhauled GUI component-based backend to support reactive and static slots --- .../eco/core/gui/component/GUIComponent.java | 32 +++++++++++- .../com/willfp/eco/core/gui/menu/Menu.java | 23 ++++++++- .../willfp/eco/internal/gui/menu/Anchor.kt | 6 --- .../willfp/eco/internal/gui/menu/EcoMenu.kt | 49 +++++++++++++++++-- .../eco/internal/gui/menu/EcoMenuBuilder.kt | 12 +++-- .../gui/menu/MenuRenderedInventory.kt | 6 ++- .../eco/internal/gui/slot/EcoFillerSlot.kt | 18 +++---- .../eco/internal/spigot/gui/GUIListener.kt | 6 ++- 8 files changed, 121 insertions(+), 31 deletions(-) delete mode 100644 eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/Anchor.kt diff --git a/eco-api/src/main/java/com/willfp/eco/core/gui/component/GUIComponent.java b/eco-api/src/main/java/com/willfp/eco/core/gui/component/GUIComponent.java index 5b78cc28..cb67321e 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/gui/component/GUIComponent.java +++ b/eco-api/src/main/java/com/willfp/eco/core/gui/component/GUIComponent.java @@ -1,6 +1,12 @@ package com.willfp.eco.core.gui.component; +import com.willfp.eco.core.gui.menu.Menu; +import com.willfp.eco.core.gui.slot.FillerSlot; import com.willfp.eco.core.gui.slot.Slot; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -30,6 +36,28 @@ public interface GUIComponent { * @return The slot, or null if no slot at the location. */ @Nullable - Slot getSlotAt(final int row, - final int column); + default Slot getSlotAt(int row, + int column) { + return new FillerSlot(new ItemStack(Material.AIR)); + } + + /** + * Get the slot at a certain position in the component. + *

+ * If your component doesn't use context data (player, menu), + * then it will default to the raw slot. + * + * @param row The row (1-indexed). + * @param column The column (1-indexed). + * @param player The player. + * @param menu The menu. + * @return The slot, or null if no slot at the location. + */ + @Nullable + default Slot getSlotAt(int row, + int column, + @NotNull Player player, + @NotNull Menu menu) { + return getSlotAt(row, column); + } } diff --git a/eco-api/src/main/java/com/willfp/eco/core/gui/menu/Menu.java b/eco-api/src/main/java/com/willfp/eco/core/gui/menu/Menu.java index 3ec4eeaf..c6a34b5f 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/gui/menu/Menu.java +++ b/eco-api/src/main/java/com/willfp/eco/core/gui/menu/Menu.java @@ -28,7 +28,10 @@ public interface Menu { int getRows(); /** - * Get slot at given row and column. + * Get a static slot at a given row and column. + *

+ * If the slot at the location is reactive, this will return + * an empty slot. * * @param row The row. * @param column The column. @@ -37,6 +40,24 @@ public interface Menu { Slot getSlot(int row, int column); + /** + * Get a slot at a given row and column. + *

+ * Defaults to static slot if no reactive slot exists. + * + * @param row The row. + * @param column The column. + * @param player The player + * @param menu The menu. + * @return The slot. + */ + default Slot getSlot(int row, + int column, + @NotNull Player player, + @NotNull Menu menu) { + return this.getSlot(row, column); + } + /** * Get the menu title. * diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/Anchor.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/Anchor.kt deleted file mode 100644 index 701cfa76..00000000 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/Anchor.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.willfp.eco.internal.gui.menu - -data class Anchor( - val row: Int, - val column: Int -) diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenu.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenu.kt index bcec98c9..15669323 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenu.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenu.kt @@ -1,12 +1,14 @@ package com.willfp.eco.internal.gui.menu +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.Slot -import com.willfp.eco.internal.gui.slot.EmptyFillerSlot +import com.willfp.eco.internal.gui.slot.EcoFillerSlot import com.willfp.eco.util.NamespacedKeyUtils import org.bukkit.Bukkit +import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.entity.Player import org.bukkit.event.inventory.InventoryCloseEvent @@ -17,18 +19,38 @@ import org.bukkit.persistence.PersistentDataType @Suppress("UNCHECKED_CAST") class EcoMenu( private val rows: Int, - private val slots: Map, + private val componentsAtPoints: Map, private val title: String, private val onClose: CloseHandler, private val onRender: (Player, Menu) -> Unit, private val onOpen: OpenHandler ) : Menu { - override fun getSlot(row: Int, column: Int): Slot { + private fun getComponent(row: Int, column: Int): OffsetComponent? { if (row < 1 || row > this.rows || column < 1 || column > 9) { - return EmptyFillerSlot + return emptyOffsetComponent } - return slots[Anchor(row, column)] ?: EmptyFillerSlot + return componentsAtPoints[Anchor(row, column)] + } + + override fun getSlot(row: Int, column: Int): Slot { + val found = getComponent(row, column) ?: return emptyFillerSlot + + 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 open(player: Player): Inventory { @@ -63,6 +85,7 @@ class EcoMenu( return inventory.captiveItems } + @Deprecated("Deprecated in Java", ReplaceWith("addState(player, key.toString(), value)")) override fun writeData( player: Player, key: NamespacedKey, @@ -70,9 +93,11 @@ class EcoMenu( value: Z ) = addState(player, key.toString(), value) + @Deprecated("Deprecated in Java", ReplaceWith("getState(player, key.toString())")) override fun readData(player: Player, key: NamespacedKey, type: PersistentDataType): T? = getState(player, key.toString()) + @Deprecated("Deprecated in Java") override fun getKeys(player: Player): Set { val inventory = player.openInventory.topInventory.asRenderedInventory() ?: return emptySet() return inventory.state.keys.mapNotNull { NamespacedKeyUtils.fromStringOrNull(it) }.toSet() @@ -109,3 +134,17 @@ class EcoMenu( fun runOnRender(player: Player) = onRender(player, this) } + +data class OffsetComponent( + val component: GUIComponent, + val rowOffset: Int, + val columnOffset: Int +) + +data class Anchor( + val row: Int, + val column: Int +) + +val emptyFillerSlot = EcoFillerSlot(ItemStack(Material.AIR)) +val emptyOffsetComponent = OffsetComponent(emptyFillerSlot, 0, 0) diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenuBuilder.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenuBuilder.kt index dc26f63a..79549194 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenuBuilder.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/EcoMenuBuilder.kt @@ -64,7 +64,7 @@ class EcoMenuBuilder(private val rows: Int) : MenuBuilder { } override fun build(): Menu { - val slots = mutableMapOf() + val componentsAtPoints = mutableMapOf() for (row in (1..rows)) { for (column in (1..9)) { @@ -84,16 +84,20 @@ class EcoMenuBuilder(private val rows: Int) : MenuBuilder { val slot = component.getSlotAt(rowOffset, columnOffset) if (slot != null) { - slots[Anchor(row, column)] = slot + componentsAtPoints[Anchor(row, column)] = OffsetComponent( + component, + rowOffset, + columnOffset + ) } } } } - return EcoMenu(rows, slots, title, onClose, onRender, onOpen) + return EcoMenu(rows, componentsAtPoints, title, onClose, onRender, onOpen) } init { maskSlots = ListUtils.create2DList(rows, 9) } -} \ No newline at end of file +} diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/MenuRenderedInventory.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/MenuRenderedInventory.kt index 740fd6b6..db27e1e1 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/MenuRenderedInventory.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/menu/MenuRenderedInventory.kt @@ -21,7 +21,7 @@ class MenuRenderedInventory( for (row in (1..menu.rows)) { for (column in (1..9)) { val bukkit = MenuUtils.rowColumnToSlot(row, column) - val item = menu.getSlot(row, column).getItemStack(player) + val item = menu.getSlot(row, column, player, menu).getItemStack(player) inventory.setItem(bukkit, item) } @@ -36,7 +36,9 @@ class MenuRenderedInventory( captiveItems.clear() for (i in 0 until inventory.size) { val (row, column) = MenuUtils.convertSlotToRowColumn(i) - val slot = menu.getSlot(row, column) + + val slot = menu.getSlot(row, column, player, menu) + if (slot.isCaptive) { val renderedItem = slot.getItemStack(player) val itemStack = inventory.getItem(i) ?: continue diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/slot/EcoFillerSlot.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/slot/EcoFillerSlot.kt index 782cf6b0..6c24c56c 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/slot/EcoFillerSlot.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/gui/slot/EcoFillerSlot.kt @@ -1,16 +1,16 @@ package com.willfp.eco.internal.gui.slot -import org.bukkit.Material +import com.willfp.eco.core.gui.slot.functional.SlotHandler import org.bukkit.inventory.ItemStack -open class EcoFillerSlot(itemStack: ItemStack) : EcoSlot( +private val noop = SlotHandler { _, _, _ -> } + +class EcoFillerSlot(itemStack: ItemStack) : EcoSlot( { _, _ -> itemStack }, - { _, _, _ -> }, - { _, _, _ -> }, - { _, _, _ -> }, - { _, _, _ -> }, - { _, _, _ -> }, + noop, + noop, + noop, + noop, + noop, { _, _, prev -> prev } ) - -object EmptyFillerSlot : EcoFillerSlot(ItemStack(Material.AIR)) diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/gui/GUIListener.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/gui/GUIListener.kt index 1f74f7be..c1488e46 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/gui/GUIListener.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/gui/GUIListener.kt @@ -29,11 +29,13 @@ class GUIListener(private val plugin: EcoPlugin) : Listener { fun handleSlotClick(event: InventoryClickEvent) { val rendered = event.clickedInventory?.asRenderedInventory() ?: return + val player = event.whoClicked as? Player ?: return + val menu = rendered.menu val (row, column) = MenuUtils.convertSlotToRowColumn(event.slot) - menu.getSlot(row, column).handle(event, menu) + menu.getSlot(row, column, player, menu).handle(event, menu) plugin.scheduler.run { rendered.render() } } @@ -56,7 +58,7 @@ class GUIListener(private val plugin: EcoPlugin) : Listener { val (row, column) = MenuUtils.convertSlotToRowColumn(inv.firstEmpty()) - val slot = menu.getSlot(row, column) + val slot = menu.getSlot(row, column, player, menu) if (!slot.isCaptive) { event.isCancelled = true