1+ package me.cepi.gameplay.util.menu
2+
3+ import me.cepi.gameplay.GameplayPlugin
4+ import me.cepi.gameplay.modules.MenuItemListener
5+ import me.cepi.gameplay.util.items.ItemBuilder
6+ import org.bukkit.Bukkit
7+ import org.bukkit.Material
8+ import org.bukkit.entity.Player
9+ import org.bukkit.event.inventory.InventoryCloseEvent
10+ import org.bukkit.inventory.Inventory
11+ import org.bukkit.inventory.ItemStack
12+ import org.bukkit.inventory.meta.ItemMeta
13+ import java.util.*
14+
15+ /* *
16+ * Basic Menu class for creating advanced Menus with multiple click events
17+ * easily
18+ *
19+ * @author LeoDog896, jeremy
20+ */
21+ class Menu (player : Player , inventoryRows : Int , inventoryTitle : String ) {
22+
23+ val inventory: Inventory
24+
25+ val player: Player
26+
27+ val title: String
28+
29+ private val menuItems: MutableList <MenuItem > = ArrayList ()
30+
31+ private val dataStorage: MutableMap <Int , Any > = HashMap ()
32+
33+ private var closeConsumer: (InventoryCloseEvent .Reason ) -> Unit = { }
34+
35+ fun setBorder (border : ItemStack ) {
36+ setRow(0 , border).onClick(true )
37+ setRow(rows - 1 , border).onClick(true )
38+ setColumn(0 , border).onClick(true )
39+ setColumn(8 , border).onClick(true )
40+ }
41+
42+ fun setBorder (mainBorder : Material ) = setBorder(ItemBuilder (mainBorder).setName(" " ).toItem())
43+
44+ /* *
45+ * Basic method for setting items
46+ *
47+ * @param slot Slot starting at 0s
48+ * @param item basic ItemStack
49+ * @return An editable MenuItem class for click events and editing
50+ */
51+ fun setItem (slot : Int , item : ItemStack ): MenuItem {
52+ inventory.setItem(slot, item)
53+ val menuItem = MenuItem (slot, this )
54+ menuItems.add(menuItem)
55+ return menuItem
56+ }
57+
58+ fun setItem (slot : Int , item : ItemBuilder ) = setItem(slot, item.toItem())
59+
60+ fun setItems (slotFrom : Int , slotTo : Int , item : ItemStack ): MenuItems {
61+ val items: MutableList <MenuItem > = ArrayList ()
62+ for (i in slotFrom.. slotTo) {
63+ items.add(setItem(i, item))
64+ }
65+ return MenuItems (items)
66+ }
67+
68+ fun setItems (slotFrom : Int , slotTo : Int , slotSpacing : Int , item : ItemStack ): MenuItems {
69+ val items: MutableList <MenuItem > = ArrayList ()
70+ var i = slotFrom
71+ while (i <= slotTo) {
72+ items.add(setItem(i, item))
73+ i + = slotSpacing
74+ }
75+ return MenuItems (items)
76+ }
77+
78+ private val rows: Int
79+ get() = inventory.size / 9
80+
81+ /* *
82+ * Clears the menu without removing any data
83+ */
84+ fun clearMenu () {
85+ killAllClickers()
86+ inventory.clear()
87+ menuItems.clear()
88+ }
89+
90+ /* *
91+ * Clears the menu with an optional data removal
92+ *
93+ * @param trueWipe If data will be removed or not
94+ */
95+ private fun clearMenu (trueWipe : Boolean = true) {
96+ killAllClickers()
97+ menuItems.clear()
98+ inventory.clear()
99+ if (trueWipe) dataStorage.clear()
100+ }
101+
102+ /* *
103+ * Updates an item for refreshing
104+ *
105+ * @param item The item to refresh (checks by slot)
106+ */
107+ fun reputItemBySlot (item : MenuItem ) {
108+ for (i in menuItems.indices) {
109+ if (menuItems[i].slot == item.slot) {
110+ menuItems[i] = item
111+ }
112+ }
113+ }
114+
115+ /* *
116+ * Finds and removes all clickers in the current menu
117+ */
118+ private fun killAllClickers () {
119+ menuItems.forEach { item -> MenuItemListener .remove(item) }
120+ }
121+
122+ /* *
123+ * Finds and removes all clickers at a specific slot
124+ *
125+ * @param slot The slot to remove clickers from
126+ */
127+ fun killClickerAtSlot (slot : Int ) {
128+ menuItems.stream()
129+ .filter { item: MenuItem -> item.slot == slot }
130+ .forEach { item: MenuItem -> MenuItemListener .remove(item) }
131+ }
132+
133+ /* *
134+ * Set the row of a menu with an ItemStack.
135+ *
136+ * @param row The row, starting from 0
137+ * @param stack The ItemStack to use
138+ * @return [MenuItems] (a group of [MenuItem] for quick handling)
139+ */
140+ fun setRow (row : Int , stack : ItemStack ): MenuItems {
141+ var startIndex = row * 9
142+ if (startIndex > inventory.size) throw ArrayIndexOutOfBoundsException ()
143+ val menuItems: MutableList <MenuItem > = ArrayList ()
144+ val endIndex = startIndex + 9
145+ startIndex = row * 9
146+ while (startIndex < endIndex) {
147+ val menuItem = setItem(startIndex, stack)
148+ this .menuItems.add(menuItem)
149+ menuItems.add(menuItem)
150+ startIndex++
151+ }
152+ return MenuItems (menuItems)
153+ }
154+
155+ fun setRow (row : Int , builder : ItemBuilder ) = setRow(row, builder.toItem())
156+
157+ private fun setColumn (column : Int , stack : ItemStack ): MenuItems {
158+ if (column > 8 ) throw ArrayIndexOutOfBoundsException (" Too many columns!" )
159+ val menuItems: MutableList <MenuItem > = ArrayList ()
160+ val endIndex = 9 * inventory.size / 9 + column
161+ var i = column
162+ while (i < endIndex) {
163+ val menuItem = setItem(i, stack)
164+ this .menuItems.add(menuItem)
165+ menuItems.add(menuItem)
166+ i + = 9
167+ }
168+ return MenuItems (menuItems)
169+ }
170+
171+ fun setRows (stack : ItemStack , vararg rows : Int ): MenuItems ? {
172+ var initialMenuItems = setRow(rows[0 ], stack)
173+ for (i in 1 until rows.size) {
174+ initialMenuItems = initialMenuItems.concat(setRow(rows[i], stack))
175+ }
176+ return initialMenuItems
177+ }
178+
179+ fun setColumns (stack : ItemStack , vararg columns : Int ): MenuItems ? {
180+ var initialMenuItems = setColumn(columns[0 ], stack)
181+ for (i in 1 until columns.size) {
182+ initialMenuItems = initialMenuItems.concat(setColumn(columns[i], stack))
183+ }
184+ return initialMenuItems
185+ }
186+
187+ /* *
188+ * Get an item from a slot
189+ *
190+ * @param slot The slot to get an item from
191+ * @return the [ItemStack] from there.
192+ */
193+ fun getItem (slot : Int ): ItemStack {
194+ return if (inventory.getItem(slot) == null ) ItemStack (Material .AIR ) else inventory.getItem(slot)!!
195+ }
196+
197+ /* *
198+ * Close the menu
199+ */
200+ fun close () {
201+ player.closeInventory(InventoryCloseEvent .Reason .PLUGIN )
202+ clearMenu()
203+ }
204+
205+ fun setData (slot : Int , `object `: Any ) {
206+ dataStorage[slot] = `object `
207+ }
208+
209+ fun getData (slot : Int ): Any? {
210+ return dataStorage[slot]
211+ }
212+
213+ fun setSlotMeta (slot : Int , meta : ItemMeta ) {
214+ val item = inventory.getItem(slot)
215+ (item ? : return ).itemMeta = meta
216+ inventory.setItem(slot, item)
217+ }
218+
219+ /* *
220+ * Clear a specific value of a specific slot
221+ *
222+ * @param slot The slot to clear data from
223+ * @param value The value to remove
224+ */
225+ fun clearData (slot : Int , value : String ) = dataStorage.remove(slot, value)
226+
227+ /* *
228+ * Clears a specific value
229+ *
230+ * @param slot The slot to remove
231+ */
232+ fun clearData (slot : Int ) = dataStorage.remove(slot)
233+
234+ /* *
235+ * Set function to run when the menu closes.
236+ *
237+ * @param consumer The consumer to run when the menu closes.
238+ */
239+ fun onClose (consumer : (InventoryCloseEvent .Reason ) -> Unit ) {
240+ closeConsumer = consumer
241+ }
242+
243+ fun triggerClose (reason : InventoryCloseEvent .Reason ) {
244+ closeConsumer.invoke(reason)
245+ }
246+
247+ fun open () {
248+ Bukkit .getScheduler().runTask(GameplayPlugin .plugin, Runnable { player.openInventory(inventory) })
249+ }
250+
251+ fun open (player : Player ) {
252+ Bukkit .getScheduler().runTask(GameplayPlugin .plugin, Runnable { player.openInventory(inventory) })
253+ }
254+
255+ init {
256+ val inventorySlots = inventoryRows * 9
257+ this .player = player
258+ title = inventoryTitle
259+ inventory = Bukkit .createInventory(null , inventorySlots, inventoryTitle)
260+ }
261+ }
0 commit comments