Skip to content

Commit 014e880

Browse files
committed
Rewire menu close handling; update to J21; fixes #2
1 parent 40cc5f6 commit 014e880

15 files changed

+78
-96
lines changed

build.gradle.kts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
import com.diffplug.gradle.spotless.SpotlessExtension
22
import com.diffplug.gradle.spotless.SpotlessPlugin
3-
import java.io.ByteArrayOutputStream
43
import xyz.jpenilla.runpaper.task.RunServer
54
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
65

76
plugins {
87
alias(libs.plugins.run.paper) apply false
98

109
// Kotlin plugin prefers to be applied to parent when it's used in multiple sub-modules.
11-
kotlin("jvm") version "1.8.21" apply false
10+
kotlin("jvm") version "1.9.22" apply false
1211
alias(libs.plugins.spotless)
1312
}
1413

15-
val javaVersion: Int = 17
14+
val javaVersion: Int = 21
1615

1716
allprojects {
1817
group = "com.noxcrew.interfaces"
19-
version = "1.0.2-SNAPSHOT"
18+
version = "1.0.3-SNAPSHOT"
2019

2120
tasks.withType<JavaCompile> {
2221
sourceCompatibility = javaVersion.toString()
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

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

+23-34
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,10 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
5454
require(!::INSTANCE.isInitialized) { "Already installed!" }
5555
INSTANCE = InterfacesListeners(plugin)
5656
Bukkit.getPluginManager().registerEvents(INSTANCE, plugin)
57-
println("Installed interfaces listeners")
5857
}
5958

60-
/** All valid closing reasons that should re-open the opened player inventory. */
61-
private val VALID_REASON = EnumSet.of(
59+
/** All valid closing reasons that should re-open the previously opened player inventory. */
60+
private val REOPEN_REASONS = EnumSet.of(
6261
Reason.PLAYER,
6362
Reason.UNKNOWN,
6463
Reason.PLUGIN
@@ -126,32 +125,27 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
126125
@EventHandler
127126
public fun onOpen(event: InventoryOpenEvent) {
128127
val holder = event.inventory.holder
128+
val view = convertHolderToInterfaceView(holder) ?: return
129129

130-
if (holder !is InterfaceView) {
131-
return
132-
}
133-
130+
// Abort any previous query the player had
134131
abortQuery(event.player.uniqueId, null)
135-
holder.onOpen()
132+
view.onOpen()
136133
}
137134

138135
@EventHandler
139136
public fun onClose(event: InventoryCloseEvent) {
140137
val holder = event.inventory.holder
138+
val view = convertHolderToInterfaceView(holder) ?: return
141139
val reason = event.reason
142140

143-
if (holder !is InterfaceView) {
144-
return
145-
}
146-
147141
SCOPE.launch {
148-
val view = convertHolderToInterfaceView(holder)
149-
if (view != null) {
150-
view.backing.closeHandlers[reason]?.invoke(reason, view)
151-
}
142+
// Mark the current view as closed properly
143+
view.markClosed(reason)
152144

153-
if (reason !in VALID_REASON) return@launch
154-
getOpenInterface(event.player.uniqueId)?.open()
145+
// Try to open back up a previous interface
146+
if (reason in REOPEN_REASONS) {
147+
getOpenInterface(event.player.uniqueId)?.open()
148+
}
155149
}
156150
}
157151

@@ -171,19 +165,13 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
171165

172166
@EventHandler
173167
public fun onInteract(event: PlayerInteractEvent) {
174-
if (event.action !in VALID_INTERACT) {
175-
return
176-
}
177-
if (event.hand != EquipmentSlot.HAND) {
178-
return
179-
}
168+
if (event.action !in VALID_INTERACT) return
169+
if (event.hand != EquipmentSlot.HAND) return
180170

181171
val player = event.player
182-
val view = getOpenInterface(player.uniqueId) as? AbstractInterfaceView<*, *> ?: return
183-
172+
val view = getOpenInterface(player.uniqueId) ?: return
184173
val slot = player.inventory.heldItemSlot
185174
val clickedPoint = GridPoint.at(3, slot)
186-
187175
val click = convertAction(event.action, player.isSneaking)
188176

189177
handleClick(view, clickedPoint, click, event, -1)
@@ -272,7 +260,7 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
272260

273261
val clickContext = ClickContext(view.player, view, click, slot)
274262

275-
view.backing.clickPreprocessors
263+
view.backing.properties.clickPreprocessors
276264
.forEach { handler -> ClickHandler.process(handler, clickContext) }
277265

278266
val clickHandler = view.pane.getRaw(clickedPoint)
@@ -391,12 +379,13 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
391379
// Run the cancellation handler
392380
query.onCancel()
393381

394-
// Try to run the close handler on the view as it got closed now
395-
val reason = Reason.PLAYER
396-
(query.view as AbstractInterfaceView<*, *>).backing.closeHandlers[reason]?.also { handler ->
397-
SCOPE.launch {
398-
handler.invoke(reason, query.view)
399-
}
382+
// If a view is given we are already in a markClosed call
383+
// and we can leave it here!
384+
if (view != null) return
385+
386+
// Mark the view as properly closed
387+
SCOPE.launch {
388+
(query.view as AbstractInterfaceView<*, *>).markClosed(Reason.PLAYER)
400389
}
401390
}
402391
}

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

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ public abstract class AbstractInterfaceBuilder<P : Pane, I : Interface<P>> inter
2727
/** Sets an item post processor to apply to every item in the interface. */
2828
public var itemPostProcessor: ((ItemStack) -> Unit)? = null
2929

30+
/** The properties object to use for the created interface. */
31+
public val properties: InterfaceProperties<P>
32+
get() = InterfaceProperties(
33+
closeHandlers,
34+
transforms,
35+
clickPreprocessors,
36+
itemPostProcessor
37+
)
38+
3039
/** Adds a new transform to the interface that updates whenever [triggers] change. */
3140
public fun withTransform(vararg triggers: Trigger, transform: Transform<P>) {
3241
transforms += AppliedTransform(transformCounter, triggers.toSet(), transform)

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

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,16 @@
11
package com.noxcrew.interfaces.interfaces
22

3-
import com.noxcrew.interfaces.click.ClickHandler
43
import com.noxcrew.interfaces.pane.Pane
5-
import com.noxcrew.interfaces.transform.AppliedTransform
64
import com.noxcrew.interfaces.view.ChestInterfaceView
75
import com.noxcrew.interfaces.view.InterfaceView
86
import net.kyori.adventure.text.Component
97
import org.bukkit.entity.Player
10-
import org.bukkit.event.inventory.InventoryCloseEvent
11-
import org.bukkit.inventory.ItemStack
128

139
/** An interface that uses a chest GUI. */
1410
public class ChestInterface internal constructor(
1511
override val rows: Int,
1612
override val initialTitle: Component?,
17-
override val closeHandlers: MutableMap<InventoryCloseEvent.Reason, CloseHandler>,
18-
override val transforms: Collection<AppliedTransform<Pane>>,
19-
override val clickPreprocessors: Collection<ClickHandler>,
20-
override val itemPostProcessor: ((ItemStack) -> Unit)?
13+
override val properties: InterfaceProperties<Pane>,
2114
) : Interface<Pane>, TitledInterface {
2215

2316
public companion object {

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ public class ChestInterfaceBuilder :
1616
override fun build(): ChestInterface = ChestInterface(
1717
rows,
1818
initialTitle,
19-
closeHandlers,
20-
transforms,
21-
clickPreprocessors,
22-
itemPostProcessor
19+
properties,
2320
)
2421
}

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

+2-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.noxcrew.interfaces.interfaces
22

33
import com.noxcrew.interfaces.click.ClickHandler
44
import com.noxcrew.interfaces.pane.CombinedPane
5+
import com.noxcrew.interfaces.pane.Pane
56
import com.noxcrew.interfaces.transform.AppliedTransform
67
import com.noxcrew.interfaces.view.CombinedInterfaceView
78
import com.noxcrew.interfaces.view.InterfaceView
@@ -14,10 +15,7 @@ import org.bukkit.inventory.ItemStack
1415
public class CombinedInterface internal constructor(
1516
override val rows: Int,
1617
override val initialTitle: Component?,
17-
override val closeHandlers: MutableMap<InventoryCloseEvent.Reason, CloseHandler>,
18-
override val transforms: Collection<AppliedTransform<CombinedPane>>,
19-
override val clickPreprocessors: Collection<ClickHandler>,
20-
override val itemPostProcessor: ((ItemStack) -> Unit)?
18+
override val properties: InterfaceProperties<CombinedPane>,
2119
) : Interface<CombinedPane>, TitledInterface {
2220

2321
public companion object {

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ public class CombinedInterfaceBuilder :
1616
override fun build(): CombinedInterface = CombinedInterface(
1717
rows,
1818
initialTitle,
19-
closeHandlers,
20-
transforms,
21-
clickPreprocessors,
22-
itemPostProcessor
19+
properties
2320
)
2421
}

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

+2-14
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,18 @@
11
package com.noxcrew.interfaces.interfaces
22

33
import com.noxcrew.interfaces.InterfacesListeners
4-
import com.noxcrew.interfaces.click.ClickHandler
54
import com.noxcrew.interfaces.pane.Pane
6-
import com.noxcrew.interfaces.transform.AppliedTransform
75
import com.noxcrew.interfaces.view.InterfaceView
86
import org.bukkit.entity.Player
9-
import org.bukkit.event.inventory.InventoryCloseEvent
10-
import org.bukkit.inventory.ItemStack
117

128
/** A created interface that can be opened for a player to create a unique view. */
139
public interface Interface<P : Pane> {
1410

1511
/** The amount of rows this interface contains. */
1612
public val rows: Int
1713

18-
/** All close handlers on this interface mapped by closing reason. */
19-
public val closeHandlers: Map<InventoryCloseEvent.Reason, CloseHandler>
20-
21-
/** All transforms that make up this interface. */
22-
public val transforms: Collection<AppliedTransform<P>>
23-
24-
/** A collection of click handlers that will be run before each click without blocking. */
25-
public val clickPreprocessors: Collection<ClickHandler>
26-
27-
public val itemPostProcessor: ((ItemStack) -> Unit)?
14+
/** The properties of this interface. */
15+
public val properties: InterfaceProperties<P>
2816

2917
/** Returns the total amount of rows. */
3018
public fun totalRows(): Int = rows
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.noxcrew.interfaces.interfaces
2+
3+
import com.noxcrew.interfaces.click.ClickHandler
4+
import com.noxcrew.interfaces.pane.Pane
5+
import com.noxcrew.interfaces.transform.AppliedTransform
6+
import org.bukkit.event.inventory.InventoryCloseEvent
7+
import org.bukkit.inventory.ItemStack
8+
9+
/** Stores all shared properties of an interface. */
10+
public data class InterfaceProperties<P : Pane>(
11+
/** All close handlers on this interface mapped by closing reason. */
12+
public val closeHandlers: Map<InventoryCloseEvent.Reason, CloseHandler> = emptyMap(),
13+
/** All transforms that make up this interface. */
14+
public val transforms: Collection<AppliedTransform<P>> = emptySet(),
15+
/** A collection of click handlers that will be run before each click without blocking. */
16+
public val clickPreprocessors: Collection<ClickHandler> = emptySet(),
17+
/** A post-processor applied to all items placed in the inventory. */
18+
public val itemPostProcessor: ((ItemStack) -> Unit)? = {}
19+
)

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

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
package com.noxcrew.interfaces.interfaces
22

3-
import com.noxcrew.interfaces.click.ClickHandler
43
import com.noxcrew.interfaces.pane.PlayerPane
5-
import com.noxcrew.interfaces.transform.AppliedTransform
64
import com.noxcrew.interfaces.view.InterfaceView
75
import com.noxcrew.interfaces.view.PlayerInterfaceView
86
import org.bukkit.entity.Player
9-
import org.bukkit.event.inventory.InventoryCloseEvent
10-
import org.bukkit.inventory.ItemStack
117

128
/** An interface that uses the entire player inventory. */
139
public class PlayerInterface internal constructor(
14-
override val closeHandlers: MutableMap<InventoryCloseEvent.Reason, CloseHandler>,
15-
override val transforms: Collection<AppliedTransform<PlayerPane>>,
16-
override val clickPreprocessors: Collection<ClickHandler>,
17-
override val itemPostProcessor: ((ItemStack) -> Unit)?
10+
override val properties: InterfaceProperties<PlayerPane>,
1811
) : Interface<PlayerPane> {
1912

2013
public companion object {

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

+1-6
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,5 @@ import com.noxcrew.interfaces.pane.PlayerPane
55
/** Assists in building a [PlayerInterface]. */
66
public class PlayerInterfaceBuilder : AbstractInterfaceBuilder<PlayerPane, PlayerInterface>() {
77

8-
override fun build(): PlayerInterface = PlayerInterface(
9-
closeHandlers,
10-
transforms,
11-
clickPreprocessors,
12-
itemPostProcessor
13-
)
8+
override fun build(): PlayerInterface = PlayerInterface(properties)
149
}

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

+12-7
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ import kotlinx.coroutines.withTimeout
1919
import net.kyori.adventure.text.Component
2020
import org.bukkit.Bukkit
2121
import org.bukkit.entity.Player
22+
import org.bukkit.event.inventory.InventoryCloseEvent
2223
import org.slf4j.LoggerFactory
2324
import java.util.WeakHashMap
2425
import java.util.concurrent.ConcurrentHashMap
2526
import java.util.concurrent.atomic.AtomicBoolean
2627
import java.util.concurrent.atomic.AtomicInteger
27-
import kotlin.Exception
2828
import kotlin.time.Duration
2929
import kotlin.time.Duration.Companion.seconds
3030

@@ -74,13 +74,17 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, P : Pane>(
7474
public abstract fun openInventory()
7575

7676
/** Marks this menu as closed and processes it. */
77-
protected fun markClosed() {
77+
internal suspend fun markClosed(reason: InventoryCloseEvent.Reason = InventoryCloseEvent.Reason.UNKNOWN) {
7878
// End a possible chat query with the listener
7979
InterfacesListeners.INSTANCE.abortQuery(player.uniqueId, this)
8080

8181
// Ensure that the menu does not open
8282
openIfClosed.set(false)
83-
shouldBeOpened.set(false)
83+
84+
// Run a generic close handler if it's still opened
85+
if (shouldBeOpened.compareAndSet(true, false)) {
86+
backing.properties.closeHandlers[reason]?.invoke(reason, this)
87+
}
8488

8589
// Close any children, this is a bit of a lossy system,
8690
// we don't particularly care if this happens nicely we
@@ -97,7 +101,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, P : Pane>(
97101
private fun setup() {
98102
// Determine for each trigger what transforms it updates
99103
val triggers = HashMultimap.create<Trigger, AppliedTransform<P>>()
100-
for (transform in backing.transforms) {
104+
for (transform in backing.properties.transforms) {
101105
for (trigger in transform.triggers) {
102106
triggers.put(trigger, transform)
103107
}
@@ -117,7 +121,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, P : Pane>(
117121
}
118122

119123
override fun redrawComplete() {
120-
applyTransforms(backing.transforms)
124+
applyTransforms(backing.properties.transforms)
121125
}
122126

123127
override suspend fun open() {
@@ -141,7 +145,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, P : Pane>(
141145
}
142146
}
143147

144-
override fun close() {
148+
override suspend fun close() {
145149
markClosed()
146150

147151
if (isOpen()) {
@@ -262,7 +266,8 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, P : Pane>(
262266
val isPlayerInventory = currentInventory.isPlayerInventory(row, column)
263267
if ((!drawNormalInventory && !isPlayerInventory) || (!drawPlayerInventory && isPlayerInventory)) return@forEach
264268

265-
currentInventory.set(row, column, element.itemStack.apply { this?.let { backing.itemPostProcessor?.invoke(it) } })
269+
currentInventory.set(row, column, element.itemStack.apply { this?.let { backing.properties.itemPostProcessor?.invoke
270+
(it) } })
266271
madeChanges = true
267272
}
268273
if (madeChanges) {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public interface InterfaceView {
2727
public suspend fun open()
2828

2929
/** Closes this view. */
30-
public fun close()
30+
public suspend fun close()
3131

3232
/** Returns whether this view is opened based on the player's current shown inventory. */
3333
public fun isOpen(): Boolean

0 commit comments

Comments
 (0)