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