@@ -5,6 +5,7 @@ import li.angu.challengeplugin.models.Challenge
5
5
import li.angu.challengeplugin.models.ChallengeStatus
6
6
import org.bukkit.Bukkit
7
7
import org.bukkit.Material
8
+ import org.bukkit.NamespacedKey
8
9
import org.bukkit.entity.Player
9
10
import org.bukkit.event.EventHandler
10
11
import org.bukkit.event.HandlerList
@@ -14,13 +15,15 @@ import org.bukkit.event.inventory.InventoryCloseEvent
14
15
import org.bukkit.inventory.Inventory
15
16
import org.bukkit.inventory.ItemStack
16
17
import org.bukkit.inventory.meta.ItemMeta
18
+ import org.bukkit.persistence.PersistentDataType
17
19
import java.util.UUID
18
20
import java.util.concurrent.ConcurrentHashMap
19
21
20
22
class ChallengeMenuManager (private val plugin : ChallengePluginPlugin ) : Listener {
21
23
22
24
private val playerMenus = ConcurrentHashMap <UUID , Inventory >()
23
- private val challengesPerInventory = ConcurrentHashMap <Inventory , List <Challenge >>()
25
+ private val challengesPerInventory = ConcurrentHashMap <Inventory , List <ChallengeMenuData >>()
26
+ private val filterToggleKey = NamespacedKey (plugin, " filter_show_all" )
24
27
25
28
init {
26
29
plugin.server.pluginManager.registerEvents(this , plugin)
@@ -32,7 +35,7 @@ class ChallengeMenuManager(private val plugin: ChallengePluginPlugin) : Listener
32
35
challengesPerInventory.clear()
33
36
}
34
37
35
- fun openMainMenu (player : Player ) {
38
+ fun openMainMenu (player : Player , showAll : Boolean = false ) {
36
39
val inventory = Bukkit .createInventory(
37
40
player,
38
41
54 , // 6 rows
@@ -56,7 +59,11 @@ class ChallengeMenuManager(private val plugin: ChallengePluginPlugin) : Listener
56
59
createMeta.setDisplayName(plugin.languageManager.getMessage(" challenge.menu.create" , player))
57
60
createMeta.lore = listOf (plugin.languageManager.getMessage(" challenge.menu.create_lore" , player))
58
61
createItem.itemMeta = createMeta
59
- inventory.setItem(4 , createItem)
62
+ inventory.setItem(0 , createItem)
63
+
64
+ // Filter toggle button (slot 4)
65
+ val filterItem = createFilterToggleItem(player, showAll)
66
+ inventory.setItem(4 , filterItem)
60
67
61
68
// Create Leave Challenge button
62
69
val leaveItem = ItemStack (Material .BARRIER )
@@ -66,24 +73,24 @@ class ChallengeMenuManager(private val plugin: ChallengePluginPlugin) : Listener
66
73
leaveItem.itemMeta = leaveMeta
67
74
inventory.setItem(8 , leaveItem)
68
75
69
- // Get all active challenges
70
- val challenges = plugin.challengeManager.getActiveChallenges( )
76
+ // Get challenges using efficient database query
77
+ val challenges = plugin.challengeManager.getChallengesForMenu(player.uniqueId, showAll )
71
78
val playerCurrentChallenge = plugin.challengeManager.getPlayerChallenge(player)
72
79
73
80
// Store the challenges for this inventory so we can retrieve them in the click handler
74
81
challengesPerInventory[inventory] = challenges
75
82
76
83
// Add challenges to inventory
77
84
if (challenges.isNotEmpty()) {
78
- challenges.forEachIndexed { index, challenge ->
85
+ challenges.forEachIndexed { index, challengeData ->
79
86
// Start at slot 18 (third row) and fill rows from there
80
87
val slot = 18 + index
81
88
82
89
// Skip if we've reached the end of the inventory
83
90
if (slot >= inventory.size) return @forEachIndexed
84
91
85
- val isCurrentChallenge = playerCurrentChallenge?.id == challenge .id
86
- val challengeItem = createChallengeItem(challenge , player, isCurrentChallenge)
92
+ val isCurrentChallenge = playerCurrentChallenge?.id == challengeData .id
93
+ val challengeItem = createChallengeItemFromData(challengeData , player, isCurrentChallenge)
87
94
inventory.setItem(slot, challengeItem)
88
95
}
89
96
} else {
@@ -102,43 +109,63 @@ class ChallengeMenuManager(private val plugin: ChallengePluginPlugin) : Listener
102
109
player.openInventory(inventory)
103
110
}
104
111
105
- private fun createChallengeItem (challenge : Challenge , player : Player , isCurrentChallenge : Boolean ): ItemStack {
106
- // Choose material based on whether this is the player's current challenge
107
- val material = when {
108
- isCurrentChallenge -> Material .ENCHANTED_BOOK
109
- else -> Material .BOOK
112
+ private fun createFilterToggleItem (player : Player , showAll : Boolean ): ItemStack {
113
+ val item = ItemStack (Material .PLAYER_HEAD )
114
+ val meta = item.itemMeta ? : Bukkit .getItemFactory().getItemMeta(Material .PLAYER_HEAD )
115
+
116
+ // Store filter state in persistent data
117
+ meta.persistentDataContainer.set(filterToggleKey, PersistentDataType .BYTE , if (showAll) 1 else 0 )
118
+
119
+ if (showAll) {
120
+ meta.setDisplayName(plugin.languageManager.getMessage(" challenge.menu.filter_all" , player))
121
+ meta.lore = listOf (plugin.languageManager.getMessage(" challenge.menu.filter_all_lore" , player))
122
+ } else {
123
+ meta.setDisplayName(plugin.languageManager.getMessage(" challenge.menu.filter_your" , player))
124
+ meta.lore = listOf (plugin.languageManager.getMessage(" challenge.menu.filter_your_lore" , player))
125
+
126
+ // Set to player's head
127
+ if (meta is org.bukkit.inventory.meta.SkullMeta ) {
128
+ meta.owningPlayer = player
129
+ }
110
130
}
111
131
132
+ item.itemMeta = meta
133
+ return item
134
+ }
135
+
136
+ private fun createChallengeItemFromData (challengeData : ChallengeMenuData , player : Player , isCurrentChallenge : Boolean ): ItemStack {
137
+ val material = if (isCurrentChallenge) Material .ENCHANTED_BOOK else Material .BOOK
138
+
112
139
val item = ItemStack (material)
113
140
val meta = item.itemMeta ? : Bukkit .getItemFactory().getItemMeta(material)
114
141
115
142
meta.setDisplayName(
116
143
if (isCurrentChallenge)
117
- plugin.languageManager.getMessage(" challenge.menu.current_challenge" , player, " name" to challenge .name)
144
+ plugin.languageManager.getMessage(" challenge.menu.current_challenge" , player, " name" to challengeData .name)
118
145
else
119
- plugin.languageManager.getMessage(" challenge.menu.challenge" , player, " name" to challenge .name)
146
+ plugin.languageManager.getMessage(" challenge.menu.challenge" , player, " name" to challengeData .name)
120
147
)
121
148
122
149
val loreList = mutableListOf<String >()
123
150
124
151
// Challenge ID
125
- loreList.add(plugin.languageManager.getMessage(" challenge.menu.id" , player, " id" to challenge.id.toString()))
126
-
127
- // Challenge status
128
- val statusKey = when (challenge.status) {
129
- ChallengeStatus .ACTIVE -> " status.active"
130
- ChallengeStatus .COMPLETED -> " status.completed"
131
- ChallengeStatus .FAILED -> " status.failed"
132
- }
133
- loreList.add(plugin.languageManager.getMessage(" challenge.menu.status" , player,
134
- " status" to plugin.languageManager.getMessage(statusKey, player)))
152
+ loreList.add(plugin.languageManager.getMessage(" challenge.menu.id" , player, " id" to challengeData.id.toString()))
135
153
136
154
// Players
137
- loreList.add(plugin.languageManager.getMessage(" challenge.menu.players" , player, " count" to challenge.players.size.toString()))
155
+ loreList.add(plugin.languageManager.getMessage(" challenge.menu.players" , player, " count" to challengeData.playerCount.toString()))
156
+
157
+ // Player status for this challenge
158
+ val playerStatusMessage = when (challengeData.playerStatus) {
159
+ " active" -> plugin.languageManager.getMessage(" player_status.active" , player)
160
+ " failed" -> plugin.languageManager.getMessage(" player_status.failed" , player)
161
+ " completed" -> plugin.languageManager.getMessage(" player_status.completed" , player)
162
+ else -> plugin.languageManager.getMessage(" player_status.not_joined" , player)
163
+ }
164
+ loreList.add(plugin.languageManager.getMessage(" challenge.menu.your_status" , player, " status" to playerStatusMessage))
138
165
139
166
// Duration (if started)
140
- if (challenge .startedAt != null ) {
141
- loreList.add(plugin.languageManager.getMessage(" challenge.menu.duration" , player, " time" to challenge .getFormattedDuration()))
167
+ if (challengeData .startedAt != null ) {
168
+ loreList.add(plugin.languageManager.getMessage(" challenge.menu.duration" , player, " time" to challengeData .getFormattedDuration()))
142
169
}
143
170
144
171
// Action text
@@ -155,6 +182,7 @@ class ChallengeMenuManager(private val plugin: ChallengePluginPlugin) : Listener
155
182
return item
156
183
}
157
184
185
+
158
186
@EventHandler
159
187
fun onInventoryClick (event : InventoryClickEvent ) {
160
188
val player = event.whoClicked as ? Player ? : return
@@ -171,11 +199,21 @@ class ChallengeMenuManager(private val plugin: ChallengePluginPlugin) : Listener
171
199
172
200
when (event.slot) {
173
201
// Create Challenge button
174
- 4 -> {
202
+ 0 -> {
175
203
player.closeInventory()
176
204
player.performCommand(" create " ) // Open create name prompt
177
205
}
178
206
207
+ // Filter Toggle button
208
+ 4 -> {
209
+ val filterItem = event.currentItem ? : return
210
+ val currentShowAll = filterItem.itemMeta?.persistentDataContainer?.get(filterToggleKey, PersistentDataType .BYTE ) == 1 .toByte()
211
+
212
+ // Toggle filter and refresh menu
213
+ player.closeInventory()
214
+ openMainMenu(player, ! currentShowAll)
215
+ }
216
+
179
217
// Leave Challenge button
180
218
8 -> {
181
219
val currentChallenge = plugin.challengeManager.getPlayerChallenge(player)
@@ -202,15 +240,15 @@ class ChallengeMenuManager(private val plugin: ChallengePluginPlugin) : Listener
202
240
// Calculate index in the challenges list
203
241
val index = event.slot - 18
204
242
if (index >= 0 && index < challenges.size) {
205
- val challenge = challenges[index]
243
+ val challengeData = challenges[index]
206
244
val currentChallenge = plugin.challengeManager.getPlayerChallenge(player)
207
245
208
- if (currentChallenge?.id == challenge .id) {
246
+ if (currentChallenge?.id == challengeData .id) {
209
247
// Player clicked their current challenge, leave it
210
- plugin.playerDataManager.savePlayerData(player, challenge .id)
248
+ plugin.playerDataManager.savePlayerData(player, challengeData .id)
211
249
212
250
if (plugin.challengeManager.leaveChallenge(player)) {
213
- player.sendMessage(plugin.languageManager.getMessage(" challenge.left" , player, " name" to challenge .name))
251
+ player.sendMessage(plugin.languageManager.getMessage(" challenge.left" , player, " name" to challengeData .name))
214
252
215
253
// Refresh the menu
216
254
player.closeInventory()
@@ -220,13 +258,15 @@ class ChallengeMenuManager(private val plugin: ChallengePluginPlugin) : Listener
220
258
}
221
259
} else {
222
260
// Player clicked a different challenge, join it
223
- if (challenge .status != ChallengeStatus .ACTIVE ) {
261
+ if (challengeData .status != ChallengeStatus .ACTIVE ) {
224
262
player.sendMessage(plugin.languageManager.getMessage(" challenge.already_completed" , player))
225
263
return
226
264
}
227
265
228
- if (plugin.challengeManager.joinChallenge(player, challenge)) {
229
- player.sendMessage(plugin.languageManager.getMessage(" challenge.joined" , player, " name" to challenge.name))
266
+ // Get full challenge object from memory to join
267
+ val fullChallenge = plugin.challengeManager.getChallenge(challengeData.id)
268
+ if (fullChallenge != null && plugin.challengeManager.joinChallenge(player, fullChallenge)) {
269
+ player.sendMessage(plugin.languageManager.getMessage(" challenge.joined" , player, " name" to challengeData.name))
230
270
231
271
// Close the menu
232
272
player.closeInventory()
0 commit comments