Skip to content

Commit

Permalink
Rewire menu close handling; update to J21; fixes #2
Browse files Browse the repository at this point in the history
  • Loading branch information
Aeltumn committed Apr 23, 2024
1 parent 40cc5f6 commit 014e880
Show file tree
Hide file tree
Showing 15 changed files with 78 additions and 96 deletions.
7 changes: 3 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import com.diffplug.gradle.spotless.SpotlessExtension
import com.diffplug.gradle.spotless.SpotlessPlugin
import java.io.ByteArrayOutputStream
import xyz.jpenilla.runpaper.task.RunServer
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
alias(libs.plugins.run.paper) apply false

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

val javaVersion: Int = 17
val javaVersion: Int = 21

allprojects {
group = "com.noxcrew.interfaces"
version = "1.0.2-SNAPSHOT"
version = "1.0.3-SNAPSHOT"

tasks.withType<JavaCompile> {
sourceCompatibility = javaVersion.toString()
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,10 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
require(!::INSTANCE.isInitialized) { "Already installed!" }
INSTANCE = InterfacesListeners(plugin)
Bukkit.getPluginManager().registerEvents(INSTANCE, plugin)
println("Installed interfaces listeners")
}

/** All valid closing reasons that should re-open the opened player inventory. */
private val VALID_REASON = EnumSet.of(
/** All valid closing reasons that should re-open the previously opened player inventory. */
private val REOPEN_REASONS = EnumSet.of(
Reason.PLAYER,
Reason.UNKNOWN,
Reason.PLUGIN
Expand Down Expand Up @@ -126,32 +125,27 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
@EventHandler
public fun onOpen(event: InventoryOpenEvent) {
val holder = event.inventory.holder
val view = convertHolderToInterfaceView(holder) ?: return

if (holder !is InterfaceView) {
return
}

// Abort any previous query the player had
abortQuery(event.player.uniqueId, null)
holder.onOpen()
view.onOpen()
}

@EventHandler
public fun onClose(event: InventoryCloseEvent) {
val holder = event.inventory.holder
val view = convertHolderToInterfaceView(holder) ?: return
val reason = event.reason

if (holder !is InterfaceView) {
return
}

SCOPE.launch {
val view = convertHolderToInterfaceView(holder)
if (view != null) {
view.backing.closeHandlers[reason]?.invoke(reason, view)
}
// Mark the current view as closed properly
view.markClosed(reason)

if (reason !in VALID_REASON) return@launch
getOpenInterface(event.player.uniqueId)?.open()
// Try to open back up a previous interface
if (reason in REOPEN_REASONS) {
getOpenInterface(event.player.uniqueId)?.open()
}
}
}

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

@EventHandler
public fun onInteract(event: PlayerInteractEvent) {
if (event.action !in VALID_INTERACT) {
return
}
if (event.hand != EquipmentSlot.HAND) {
return
}
if (event.action !in VALID_INTERACT) return
if (event.hand != EquipmentSlot.HAND) return

val player = event.player
val view = getOpenInterface(player.uniqueId) as? AbstractInterfaceView<*, *> ?: return

val view = getOpenInterface(player.uniqueId) ?: return
val slot = player.inventory.heldItemSlot
val clickedPoint = GridPoint.at(3, slot)

val click = convertAction(event.action, player.isSneaking)

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

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

view.backing.clickPreprocessors
view.backing.properties.clickPreprocessors
.forEach { handler -> ClickHandler.process(handler, clickContext) }

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

// Try to run the close handler on the view as it got closed now
val reason = Reason.PLAYER
(query.view as AbstractInterfaceView<*, *>).backing.closeHandlers[reason]?.also { handler ->
SCOPE.launch {
handler.invoke(reason, query.view)
}
// If a view is given we are already in a markClosed call
// and we can leave it here!
if (view != null) return

// Mark the view as properly closed
SCOPE.launch {
(query.view as AbstractInterfaceView<*, *>).markClosed(Reason.PLAYER)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ public abstract class AbstractInterfaceBuilder<P : Pane, I : Interface<P>> inter
/** Sets an item post processor to apply to every item in the interface. */
public var itemPostProcessor: ((ItemStack) -> Unit)? = null

/** The properties object to use for the created interface. */
public val properties: InterfaceProperties<P>
get() = InterfaceProperties(
closeHandlers,
transforms,
clickPreprocessors,
itemPostProcessor
)

/** Adds a new transform to the interface that updates whenever [triggers] change. */
public fun withTransform(vararg triggers: Trigger, transform: Transform<P>) {
transforms += AppliedTransform(transformCounter, triggers.toSet(), transform)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
package com.noxcrew.interfaces.interfaces

import com.noxcrew.interfaces.click.ClickHandler
import com.noxcrew.interfaces.pane.Pane
import com.noxcrew.interfaces.transform.AppliedTransform
import com.noxcrew.interfaces.view.ChestInterfaceView
import com.noxcrew.interfaces.view.InterfaceView
import net.kyori.adventure.text.Component
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.ItemStack

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

public companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ public class ChestInterfaceBuilder :
override fun build(): ChestInterface = ChestInterface(
rows,
initialTitle,
closeHandlers,
transforms,
clickPreprocessors,
itemPostProcessor
properties,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.noxcrew.interfaces.interfaces

import com.noxcrew.interfaces.click.ClickHandler
import com.noxcrew.interfaces.pane.CombinedPane
import com.noxcrew.interfaces.pane.Pane
import com.noxcrew.interfaces.transform.AppliedTransform
import com.noxcrew.interfaces.view.CombinedInterfaceView
import com.noxcrew.interfaces.view.InterfaceView
Expand All @@ -14,10 +15,7 @@ import org.bukkit.inventory.ItemStack
public class CombinedInterface internal constructor(
override val rows: Int,
override val initialTitle: Component?,
override val closeHandlers: MutableMap<InventoryCloseEvent.Reason, CloseHandler>,
override val transforms: Collection<AppliedTransform<CombinedPane>>,
override val clickPreprocessors: Collection<ClickHandler>,
override val itemPostProcessor: ((ItemStack) -> Unit)?
override val properties: InterfaceProperties<CombinedPane>,
) : Interface<CombinedPane>, TitledInterface {

public companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ public class CombinedInterfaceBuilder :
override fun build(): CombinedInterface = CombinedInterface(
rows,
initialTitle,
closeHandlers,
transforms,
clickPreprocessors,
itemPostProcessor
properties
)
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,18 @@
package com.noxcrew.interfaces.interfaces

import com.noxcrew.interfaces.InterfacesListeners
import com.noxcrew.interfaces.click.ClickHandler
import com.noxcrew.interfaces.pane.Pane
import com.noxcrew.interfaces.transform.AppliedTransform
import com.noxcrew.interfaces.view.InterfaceView
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.ItemStack

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

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

/** All close handlers on this interface mapped by closing reason. */
public val closeHandlers: Map<InventoryCloseEvent.Reason, CloseHandler>

/** All transforms that make up this interface. */
public val transforms: Collection<AppliedTransform<P>>

/** A collection of click handlers that will be run before each click without blocking. */
public val clickPreprocessors: Collection<ClickHandler>

public val itemPostProcessor: ((ItemStack) -> Unit)?
/** The properties of this interface. */
public val properties: InterfaceProperties<P>

/** Returns the total amount of rows. */
public fun totalRows(): Int = rows
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.noxcrew.interfaces.interfaces

import com.noxcrew.interfaces.click.ClickHandler
import com.noxcrew.interfaces.pane.Pane
import com.noxcrew.interfaces.transform.AppliedTransform
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.ItemStack

/** Stores all shared properties of an interface. */
public data class InterfaceProperties<P : Pane>(
/** All close handlers on this interface mapped by closing reason. */
public val closeHandlers: Map<InventoryCloseEvent.Reason, CloseHandler> = emptyMap(),
/** All transforms that make up this interface. */
public val transforms: Collection<AppliedTransform<P>> = emptySet(),
/** A collection of click handlers that will be run before each click without blocking. */
public val clickPreprocessors: Collection<ClickHandler> = emptySet(),
/** A post-processor applied to all items placed in the inventory. */
public val itemPostProcessor: ((ItemStack) -> Unit)? = {}
)
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
package com.noxcrew.interfaces.interfaces

import com.noxcrew.interfaces.click.ClickHandler
import com.noxcrew.interfaces.pane.PlayerPane
import com.noxcrew.interfaces.transform.AppliedTransform
import com.noxcrew.interfaces.view.InterfaceView
import com.noxcrew.interfaces.view.PlayerInterfaceView
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.ItemStack

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

public companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,5 @@ import com.noxcrew.interfaces.pane.PlayerPane
/** Assists in building a [PlayerInterface]. */
public class PlayerInterfaceBuilder : AbstractInterfaceBuilder<PlayerPane, PlayerInterface>() {

override fun build(): PlayerInterface = PlayerInterface(
closeHandlers,
transforms,
clickPreprocessors,
itemPostProcessor
)
override fun build(): PlayerInterface = PlayerInterface(properties)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import kotlinx.coroutines.withTimeout
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryCloseEvent
import org.slf4j.LoggerFactory
import java.util.WeakHashMap
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import kotlin.Exception
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

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

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

// Ensure that the menu does not open
openIfClosed.set(false)
shouldBeOpened.set(false)

// Run a generic close handler if it's still opened
if (shouldBeOpened.compareAndSet(true, false)) {
backing.properties.closeHandlers[reason]?.invoke(reason, this)
}

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

override fun redrawComplete() {
applyTransforms(backing.transforms)
applyTransforms(backing.properties.transforms)
}

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

override fun close() {
override suspend fun close() {
markClosed()

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

currentInventory.set(row, column, element.itemStack.apply { this?.let { backing.itemPostProcessor?.invoke(it) } })
currentInventory.set(row, column, element.itemStack.apply { this?.let { backing.properties.itemPostProcessor?.invoke
(it) } })
madeChanges = true
}
if (madeChanges) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public interface InterfaceView {
public suspend fun open()

/** Closes this view. */
public fun close()
public suspend fun close()

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

0 comments on commit 014e880

Please sign in to comment.