Skip to content

Commit e8697f6

Browse files
committed
fix: Reduce times player interfaces are drawn on re-opening
Previously a background open player interface would be seen as open causing draws that got overwritten
1 parent 12dadbc commit e8697f6

File tree

4 files changed

+90
-52
lines changed

4 files changed

+90
-52
lines changed

examples/src/main/kotlin/com/noxcrew/interfaces/example/ExamplePlugin.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class ExamplePlugin : JavaPlugin(), Listener {
4545

4646
suspendingHandler {
4747
val player = it.sender() as Player
48-
InterfacesListeners.INSTANCE.getOpenInterface(player.uniqueId)?.close()
48+
InterfacesListeners.INSTANCE.getOpenPlayerInterface(player.uniqueId)?.close()
4949
player.inventory.clear()
5050
}
5151
}

interfaces/src/main/kotlin/com/noxcrew/interfaces/InterfacesListeners.kt

+56-20
Original file line numberDiff line numberDiff line change
@@ -150,44 +150,73 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
150150
private val queries: Cache<UUID, ChatQuery> = Caffeine.newBuilder()
151151
.build()
152152

153-
/** A cache of open player interface views, with weak values. */
153+
/** A cache of player interfaces that should be opened again in the future. */
154+
private val backgroundPlayerInterfaceViews: Cache<UUID, PlayerInterfaceView> = Caffeine.newBuilder()
155+
.weakValues()
156+
.build()
157+
158+
/** A cache of actively open player interfaces. */
154159
private val openPlayerInterfaceViews: Cache<UUID, PlayerInterfaceView> = Caffeine.newBuilder()
155160
.weakValues()
156161
.build()
157162

158-
/** Re-opens the current open interface of [player]. */
163+
/** Re-opens the current background interface of [player]. */
159164
public fun reopenInventory(player: Player) {
160-
getOpenInterface(player.uniqueId)?.also {
165+
getBackgroundPlayerInterface(player.uniqueId)?.also {
161166
SCOPE.launch {
162167
it.open()
163168
}
164169
}
165170
}
166171

167-
/** Returns the currently open interface for [playerId]. */
168-
public fun getOpenInterface(playerId: UUID): PlayerInterfaceView? {
172+
/**
173+
* Returns the background interface for [playerId]. This is the last
174+
* player interface that was opened, which should be re-opened once
175+
* we no longer have anything else showing.
176+
*/
177+
public fun getBackgroundPlayerInterface(playerId: UUID): PlayerInterfaceView? {
169178
// Check if the menu is definitely still meant to be open
179+
val result = backgroundPlayerInterfaceViews.getIfPresent(playerId) ?: return null
180+
if (result.shouldStillBeOpened) return result
181+
backgroundPlayerInterfaceViews.invalidate(playerId)
182+
return null
183+
}
184+
185+
/**
186+
* Returns the currently open player interface for [playerId].
187+
*/
188+
public fun getOpenPlayerInterface(playerId: UUID): PlayerInterfaceView? {
170189
val result = openPlayerInterfaceViews.getIfPresent(playerId) ?: return null
171-
if (result.shouldStillBeOpened) {
172-
return result
173-
}
190+
if (result.shouldStillBeOpened) return result
174191
openPlayerInterfaceViews.invalidate(playerId)
175192
return null
176193
}
177194

178-
/** Updates the currently open interface for [playerId] to [view]. */
179-
public fun setOpenInterface(playerId: UUID, view: PlayerInterfaceView?) {
195+
/** Marks the given [view] as the opened player interface. */
196+
public fun openPlayerInterface(playerId: UUID, view: PlayerInterfaceView) {
197+
backgroundPlayerInterfaceViews.invalidate(playerId)
198+
openPlayerInterfaceViews.put(playerId, view)
199+
}
200+
201+
/** Closes the given [view] of a player interface. */
202+
public fun closePlayerInterface(playerId: UUID, view: PlayerInterfaceView?) {
180203
// Save the contents of their currently shown inventory
181204
val bukkitPlayer = Bukkit.getPlayer(playerId)
182205
if (bukkitPlayer != null) {
183206
saveInventoryContentsIfOpened(bukkitPlayer)
184207
}
185208

209+
abortQuery(playerId, view)
186210
if (view == null) {
211+
backgroundPlayerInterfaceViews.invalidate(playerId)
187212
openPlayerInterfaceViews.invalidate(playerId)
188213
} else {
189-
abortQuery(playerId, null)
190-
openPlayerInterfaceViews.put(playerId, view)
214+
if (backgroundPlayerInterfaceViews.getIfPresent(playerId) === view) {
215+
backgroundPlayerInterfaceViews.invalidate(playerId)
216+
}
217+
if (openPlayerInterfaceViews.getIfPresent(playerId) === view) {
218+
openPlayerInterfaceViews.invalidate(playerId)
219+
}
191220
}
192221
}
193222

@@ -212,6 +241,13 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
212241
val holder = event.inventory.holder
213242
val view = convertHolderToInterfaceView(holder) ?: return
214243

244+
// Move the current open inventory to the background to indicate
245+
// it is no longer the actually opened inventory!
246+
openPlayerInterfaceViews.getIfPresent(event.player.uniqueId)?.also {
247+
backgroundPlayerInterfaceViews.put(event.player.uniqueId, it)
248+
openPlayerInterfaceViews.invalidate(event.player.uniqueId)
249+
}
250+
215251
// Abort any previous query the player had
216252
abortQuery(event.player.uniqueId, null)
217253
view.onOpen()
@@ -231,15 +267,15 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
231267

232268
SCOPE.launch {
233269
// Determine if we can re-open a previous interface
234-
val openInterface = getOpenInterface(event.player.uniqueId)
235-
val shouldReopen = reason in REOPEN_REASONS && !event.player.isDead && openInterface != null
270+
val backgroundInterface = getBackgroundPlayerInterface(event.player.uniqueId)
271+
val shouldReopen = reason in REOPEN_REASONS && !event.player.isDead && backgroundInterface != null
236272

237273
// Mark the current view as closed properly
238274
view.markClosed(reason)
239275

240276
// If possible, open back up a previous interface
241277
if (shouldReopen) {
242-
requireNotNull(openInterface).open()
278+
requireNotNull(backgroundInterface).open()
243279
}
244280
}
245281
}
@@ -375,7 +411,7 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
375411
@EventHandler
376412
public fun onPlayerQuit(event: PlayerQuitEvent) {
377413
abortQuery(event.player.uniqueId, null)
378-
setOpenInterface(event.player.uniqueId, null)
414+
closePlayerInterface(event.player.uniqueId, null)
379415
}
380416

381417
/** Returns whether [block] will trigger some interaction if clicked with [item]. */
@@ -388,7 +424,7 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
388424
if (event.useItemInHand() == Event.Result.DENY) return
389425

390426
val player = event.player
391-
val view = getOpenInterface(player.uniqueId) ?: return
427+
val view = getOpenPlayerInterface(player.uniqueId) ?: return
392428

393429
// If we are prioritizing block interactions we assure they are not happening first
394430
if (view.builder.prioritiseBlockInteractions) {
@@ -428,7 +464,7 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
428464
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
429465
public fun onDropItem(event: PlayerDropItemEvent) {
430466
val player = event.player
431-
val view = getOpenInterface(player.uniqueId) ?: return
467+
val view = getOpenPlayerInterface(player.uniqueId) ?: return
432468
val slot = player.inventory.heldItemSlot
433469
val droppedSlot = GridPoint.at(3, slot)
434470

@@ -441,7 +477,7 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
441477
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
442478
public fun onSwapHands(event: PlayerSwapHandItemsEvent) {
443479
val player = event.player
444-
val view = getOpenInterface(player.uniqueId) ?: return
480+
val view = getOpenPlayerInterface(player.uniqueId) ?: return
445481
val slot = player.inventory.heldItemSlot
446482
val interactedSlot1 = GridPoint.at(3, slot)
447483
val interactedSlot2 = GridPoint.at(4, 4)
@@ -527,7 +563,7 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
527563
if (holder is AbstractInterfaceView<*, *, *>) return holder
528564

529565
// If it's the player's own inventory use the held one
530-
if (holder is HumanEntity) return getOpenInterface(holder.uniqueId)
566+
if (holder is HumanEntity) return getOpenPlayerInterface(holder.uniqueId)
531567

532568
return null
533569
}

interfaces/src/main/kotlin/com/noxcrew/interfaces/view/AbstractInterfaceView.kt

+13-7
Original file line numberDiff line numberDiff line change
@@ -412,15 +412,21 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
412412
drawPaneToInventory(drawNormalInventory = true, drawPlayerInventory = isOpen)
413413
callback(createdInventory)
414414

415-
if ((openIfClosed.get() && !isOpen) || createdInventory) {
416-
InterfacesListeners.INSTANCE.viewBeingOpened = this
417-
if (player.isConnected) openInventory()
418-
if (InterfacesListeners.INSTANCE.viewBeingOpened == this) {
419-
InterfacesListeners.INSTANCE.viewBeingOpened = null
415+
if (this is PlayerInterfaceView) {
416+
// If this is a player inventory we can't update the inventory without
417+
// opening it, so we trigger opening it properly.
418+
if (!isOpen && player.isConnected) openInventory()
419+
} else {
420+
if ((openIfClosed.get() && !isOpen) || createdInventory) {
421+
InterfacesListeners.INSTANCE.viewBeingOpened = this
422+
if (player.isConnected) openInventory()
423+
if (InterfacesListeners.INSTANCE.viewBeingOpened == this) {
424+
InterfacesListeners.INSTANCE.viewBeingOpened = null
425+
}
420426
}
421-
openIfClosed.set(false)
422-
firstPaint = false
423427
}
428+
openIfClosed.set(false)
429+
firstPaint = false
424430
}
425431
}
426432

interfaces/src/main/kotlin/com/noxcrew/interfaces/view/PlayerInterfaceView.kt

+20-24
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,29 @@ public class PlayerInterfaceView internal constructor(
3434
// Close whatever inventory the player has open so they can look at their normal inventory!
3535
// This will only continue if the menu hasn't been closed yet.
3636
if (!isOpen()) {
37-
// First we close then we set the interface so we don't double open!
38-
InterfacesListeners.INSTANCE.setOpenInterface(player.uniqueId, null)
37+
// Remove this inventory from the background interface before closing so it
38+
// doesn't automatically re-open!
39+
InterfacesListeners.INSTANCE.closePlayerInterface(player.uniqueId, this)
3940
player.closeInventory()
40-
InterfacesListeners.INSTANCE.setOpenInterface(player.uniqueId, this)
4141
}
4242

43-
// Double-check that this inventory is open now!
44-
if (isOpen()) {
45-
if (!builder.inheritExistingItems) {
46-
// Clear the player's inventory!
47-
player.inventory.clear()
48-
if (player.openInventory.topInventory.type == InventoryType.CRAFTING ||
49-
player.openInventory.topInventory.type == InventoryType.CREATIVE
50-
) {
51-
player.openInventory.topInventory.clear()
52-
}
53-
player.openInventory.setCursor(null)
54-
}
43+
// Open this player interface for the player
44+
InterfacesListeners.INSTANCE.openPlayerInterface(player.uniqueId, this)
5545

56-
// Trigger onOpen manually because there is no real inventory being opened,
57-
// this will also re-draw the player inventory parts!
58-
onOpen()
46+
if (!builder.inheritExistingItems) {
47+
// Clear the player's inventory!
48+
player.inventory.clear()
49+
if (player.openInventory.topInventory.type == InventoryType.CRAFTING ||
50+
player.openInventory.topInventory.type == InventoryType.CREATIVE
51+
) {
52+
player.openInventory.topInventory.clear()
53+
}
54+
player.openInventory.setCursor(null)
5955
}
56+
57+
// Trigger onOpen manually because there is no real inventory being opened,
58+
// this will also re-draw the player inventory parts!
59+
onOpen()
6060
}
6161

6262
override suspend fun close(reason: InventoryCloseEvent.Reason, changingView: Boolean) {
@@ -65,14 +65,10 @@ public class PlayerInterfaceView internal constructor(
6565
// Ensure we update the interface state in the main thread!
6666
// Even if the menu is not currently on the screen.
6767
InterfacesListeners.INSTANCE.runSync {
68-
InterfacesListeners.INSTANCE.setOpenInterface(player.uniqueId, null)
68+
InterfacesListeners.INSTANCE.closePlayerInterface(player.uniqueId, this)
6969
}
7070
}
7171

7272
override fun isOpen(): Boolean =
73-
(
74-
player.openInventory.type == InventoryType.CRAFTING ||
75-
player.openInventory.type == InventoryType.CREATIVE
76-
) &&
77-
InterfacesListeners.INSTANCE.getOpenInterface(player.uniqueId) == this
73+
InterfacesListeners.INSTANCE.getOpenPlayerInterface(player.uniqueId) == this
7874
}

0 commit comments

Comments
 (0)