@@ -150,6 +150,8 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
150
150
.expireAfterWrite(200 .toLong(), TimeUnit .MILLISECONDS )
151
151
.build()
152
152
153
+ private var dontReopen: Boolean = false
154
+
153
155
/* * The inventory currently opened by players, we track this internally because the [InventoryCloseEvent] has the wrong parameters. */
154
156
private val openInventory = ConcurrentHashMap <HumanEntity , AbstractInterfaceView <* , * , * >>()
155
157
@@ -165,8 +167,18 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
165
167
/* * A map of interfaces being rendered for each player. */
166
168
private val renderingPlayerInterfaceViews = ConcurrentHashMap <UUID , InterfaceView >()
167
169
170
+ /* * Runs [function] without reopening a new menu. */
171
+ public fun withoutReopen (function : () -> Unit ) {
172
+ val oldValue = dontReopen
173
+ dontReopen = true
174
+ function()
175
+ dontReopen = oldValue
176
+ }
177
+
168
178
/* * Re-opens the current background interface of [player]. */
169
179
public fun reopenInventory (player : Player ) {
180
+ // Don't re-open the background inventory when we're coming from the open event.
181
+ if (dontReopen) return
170
182
(getOpenPlayerInterface(player.uniqueId) ? : getBackgroundPlayerInterface(player.uniqueId))?.also {
171
183
SCOPE .launch(InterfacesCoroutineDetails (player.uniqueId, " reopening background interface" )) {
172
184
it.reopenIfIntended()
@@ -269,10 +281,12 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
269
281
// Close the previous view first with open new as the reason, unless we
270
282
// are currently opening this view!
271
283
if (openInventory[event.player] != view) {
284
+ dontReopen = true
272
285
openInventory.put(event.player, view)?.markClosed(SCOPE , Reason .OPEN_NEW )
286
+ dontReopen = false
273
287
}
274
288
275
- // Move the current open inventory to the background to indicate
289
+ // Move any currently open player inventory to the background to indicate
276
290
// it is no longer the actually opened inventory!
277
291
demoteOpenView(event.player.uniqueId)
278
292
@@ -283,20 +297,26 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
283
297
284
298
@EventHandler
285
299
public fun onClose (event : InventoryCloseEvent ) {
286
- // Don't listen to close events unless we have an inventory open
287
- if (! openInventory.containsKey(event.player)) return
288
300
val reason = event.reason
289
301
290
- // Save previous inventory contents before we open the new one
291
- saveInventoryContentsIfOpened(event.player)
302
+ // Save previous inventory contents before we open the new one (only if we have one open!)
303
+ if (openInventory.containsKey(event.player)) {
304
+ saveInventoryContentsIfOpened(event.player)
305
+ }
292
306
293
307
// When opening a new inventory we ignore the close event as it wrongly
294
308
// reports the actual menu being closed! We rely entirely on the open event
295
309
// and what we have previously stored as the open inventory.
296
310
if (reason == Reason .OPEN_NEW ) return
297
311
298
312
// Mark whatever inventory was open as closed!
299
- openInventory.remove(event.player)?.markClosed(SCOPE , reason)
313
+ val opened = openInventory.remove(event.player)
314
+ if (opened != null ) {
315
+ opened.markClosed(SCOPE , reason)
316
+ } else if (reason in REOPEN_REASONS && ! event.player.isDead) {
317
+ // If the opened menu didn't trigger a re-open, do it manually!
318
+ reopenInventory(event.player as Player )
319
+ }
300
320
}
301
321
302
322
@EventHandler(priority = EventPriority .LOW , ignoreCancelled = true )
@@ -659,8 +679,8 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
659
679
val completedClickHandler = view.executeSync(
660
680
InterfacesExceptionContext (
661
681
view.player,
662
- InterfacesOperation .RUNNING_CLICK_HANDLER
663
- )
682
+ InterfacesOperation .RUNNING_CLICK_HANDLER ,
683
+ ),
664
684
) {
665
685
// Run any pre-processors
666
686
view.builder.clickPreprocessors
@@ -734,7 +754,9 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
734
754
runSync {
735
755
// Close the current inventory to open another to avoid close reasons
736
756
val reopen = view.shouldStillBeOpened
737
- view.player.closeInventory(Reason .OPEN_NEW )
757
+ INSTANCE .withoutReopen {
758
+ view.player.closeInventory(Reason .OPEN_NEW )
759
+ }
738
760
739
761
// Ensure the view is allowed to be opened again after we're done
740
762
if (reopen) {
0 commit comments