Skip to content

Commit 307936c

Browse files
committed
chore: Better mutex usage to ensure rendering happens once
1 parent 5850195 commit 307936c

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

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

+10-1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,15 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
198198
openPlayerInterfaceViews.put(playerId, view)
199199
}
200200

201+
/** Sets the background view for [playerId] to [view]. */
202+
public fun setBackgroundView(playerId: UUID, view: PlayerInterfaceView?) {
203+
if (view == null) {
204+
backgroundPlayerInterfaceViews.invalidate(playerId)
205+
} else {
206+
backgroundPlayerInterfaceViews.put(playerId, view)
207+
}
208+
}
209+
201210
/** Closes the given [view] of a player interface. */
202211
public fun closePlayerInterface(playerId: UUID, view: PlayerInterfaceView?) {
203212
// Save the contents of their currently shown inventory
@@ -244,7 +253,7 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
244253
// Move the current open inventory to the background to indicate
245254
// it is no longer the actually opened inventory!
246255
openPlayerInterfaceViews.getIfPresent(event.player.uniqueId)?.also {
247-
backgroundPlayerInterfaceViews.put(event.player.uniqueId, it)
256+
setBackgroundView(event.player.uniqueId, it)
248257
openPlayerInterfaceViews.invalidate(event.player.uniqueId)
249258
}
250259

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

+21-14
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import kotlinx.coroutines.Job
1919
import kotlinx.coroutines.async
2020
import kotlinx.coroutines.launch
2121
import kotlinx.coroutines.sync.Mutex
22-
import kotlinx.coroutines.sync.Semaphore
2322
import kotlinx.coroutines.withTimeout
2423
import net.kyori.adventure.text.Component
2524
import org.bukkit.Bukkit
@@ -32,7 +31,6 @@ import org.slf4j.LoggerFactory
3231
import java.util.WeakHashMap
3332
import java.util.concurrent.ConcurrentLinkedQueue
3433
import java.util.concurrent.atomic.AtomicBoolean
35-
import java.util.concurrent.atomic.AtomicInteger
3634
import kotlin.time.Duration
3735
import kotlin.time.Duration.Companion.seconds
3836

@@ -50,8 +48,8 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
5048
}
5149

5250
private val logger = LoggerFactory.getLogger(AbstractInterfaceView::class.java)
53-
private val semaphore = Semaphore(1)
54-
private val queue = AtomicInteger(0)
51+
private val paneMutex = Mutex()
52+
private val debouncedRender = AtomicBoolean(false)
5553

5654
private val children = WeakHashMap<AbstractInterfaceView<*, *, *>, Unit>()
5755

@@ -202,12 +200,14 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
202200
// Don't update if closed
203201
if (!openIfClosed.get() && !isOpen()) return
204202

205-
// If there is already queue of 2 renders we don't bother!
206-
if (queue.get() >= 2) return
203+
// If we're already rendering we queue up another render!
204+
if (paneMutex.isLocked) {
205+
debouncedRender.set(true)
206+
return
207+
}
207208

208-
// Await to acquire a semaphore before starting the render
209-
queue.incrementAndGet()
210-
semaphore.acquire()
209+
// Await to acquire the mutex before we start rendering
210+
paneMutex.lock()
211211
try {
212212
withTimeout(6.seconds) {
213213
pane = panes.collapse(backing.totalRows(), builder.fillMenuWithAir)
@@ -219,8 +219,12 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
219219
}
220220
}
221221
} finally {
222-
semaphore.release()
223-
queue.decrementAndGet()
222+
paneMutex.unlock()
223+
}
224+
225+
// If we queued up a debounced render we trigger another one!
226+
if (debouncedRender.compareAndSet(true, false)) {
227+
renderAndOpen()
224228
}
225229
}
226230

@@ -279,9 +283,12 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
279283
val completedPane = pane.complete(player)
280284

281285
// Access to the pane has to be shared through a semaphore
282-
semaphore.acquire()
283-
panes[transform.priority] = completedPane
284-
semaphore.release()
286+
paneMutex.lock()
287+
try {
288+
panes[transform.priority] = completedPane
289+
} finally {
290+
paneMutex.unlock()
291+
}
285292
}
286293

287294
protected open fun drawPaneToInventory(drawNormalInventory: Boolean, drawPlayerInventory: Boolean) {

0 commit comments

Comments
 (0)