diff --git a/.idea/libraries/Gradle__org_antlr_antlr4_4_13_2.xml b/.idea/libraries/Gradle__org_antlr_antlr4_4_13_2.xml
deleted file mode 100644
index ad25f7151..000000000
--- a/.idea/libraries/Gradle__org_antlr_antlr4_4_13_2.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_antlr_antlr4_runtime_4_13_2.xml b/.idea/libraries/Gradle__org_antlr_antlr4_runtime_4_13_2.xml
deleted file mode 100644
index a25aa6458..000000000
--- a/.idea/libraries/Gradle__org_antlr_antlr4_runtime_4_13_2.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt b/src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt
index 6cf7827b1..028c3b63f 100644
--- a/src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt
+++ b/src/main/kotlin/org/xodium/vanillaplus/modules/PlayerModule.kt
@@ -8,6 +8,9 @@ import io.papermc.paper.datacomponent.item.ResolvableProfile
import io.papermc.paper.event.entity.EntityEquipmentChangedEvent
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder
import org.bukkit.Material
+import org.bukkit.NamespacedKey
+import org.bukkit.Tag
+import org.bukkit.block.ShulkerBox
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
@@ -16,12 +19,16 @@ import org.bukkit.event.block.BlockDropItemEvent
import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
+import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.inventory.InventoryType
import org.bukkit.event.player.PlayerAdvancementDoneEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
import org.bukkit.inventory.ItemStack
+import org.bukkit.inventory.Recipe
+import org.bukkit.inventory.ShapelessRecipe
+import org.bukkit.inventory.meta.BlockStateMeta
import org.bukkit.permissions.Permission
import org.bukkit.permissions.PermissionDefault
import org.xodium.vanillaplus.VanillaPlus.Companion.instance
@@ -29,6 +36,7 @@ import org.xodium.vanillaplus.data.CommandData
import org.xodium.vanillaplus.enchantments.*
import org.xodium.vanillaplus.interfaces.ModuleInterface
import org.xodium.vanillaplus.pdcs.PlayerPDC.nickname
+import org.xodium.vanillaplus.pdcs.ShulkerPDC.lock
import org.xodium.vanillaplus.utils.ExtUtils.mm
import org.xodium.vanillaplus.utils.ExtUtils.tryCatch
import org.xodium.vanillaplus.utils.FmtUtils.fireFmt
@@ -138,14 +146,75 @@ internal class PlayerModule(
@EventHandler
fun on(event: InventoryClickEvent) {
- if (!enabled() ||
- event.click != config.enderChestClickType ||
- event.currentItem?.type != Material.ENDER_CHEST ||
- event.clickedInventory?.type != InventoryType.PLAYER
+ if (!enabled()) return
+
+ val player = event.whoClicked as? Player ?: return
+
+ if (event.clickedInventory?.type != InventoryType.PLAYER) return
+
+ if (event.click == config.enderChestClickType &&
+ event.currentItem?.type == Material.ENDER_CHEST
) {
- return
+ event.isCancelled = true
+ instance.server.scheduler.runTask(
+ instance,
+ Runnable { player.openInventory(player.enderChest) },
+ )
+ }
+
+ val item = event.currentItem ?: return
+
+ if (event.click == config.shulkerClickType &&
+ Tag.SHULKER_BOXES.isTagged(item.type)
+ ) {
+ event.isCancelled = true
+
+ val meta = item.itemMeta as? BlockStateMeta ?: return
+ val shulker = meta.blockState as? ShulkerBox ?: return
+
+ if (!shulker.lock()) {
+ shulker.lock(true)
+
+ meta.blockState = shulker
+ item.itemMeta = meta
+
+ instance.server.scheduler.runTask(
+ instance,
+ Runnable { player.openInventory(shulker.inventory) },
+ )
+ }
}
+ // TODO: make it so when click on enderchest/shulker it first closes current inventory before opening the new one.
+ }
+
+ @EventHandler
+ fun on(event: InventoryCloseEvent) {
+ if (!enabled()) return
+
+ val player = event.player as? Player ?: return
+ for (item in player.inventory.contents) {
+ if (item != null && Tag.SHULKER_BOXES.isTagged(item.type)) {
+ val meta = item.itemMeta as? BlockStateMeta ?: continue
+ val shulker = meta.blockState as? ShulkerBox ?: continue
+
+ if (shulker.lock()) {
+ shulker.inventory.contents = event.inventory.contents
+ shulker.lock(false)
+
+ meta.blockState = shulker
+ item.itemMeta = meta
+
+ instance.server.scheduler.runTask(
+ instance,
+ Runnable { player.updateInventory() },
+ )
+
+ break
+ }
+ }
+ }
+ // FIX
event.isCancelled = true
instance.server.scheduler.runTask(
@@ -256,6 +325,7 @@ internal class PlayerModule(
data class Config(
var enderChestClickType: ClickType = ClickType.SHIFT_RIGHT,
+ var shulkerClickType: ClickType = ClickType.SHIFT_RIGHT,
var skullDropChance: Double = 0.1,
var xpCostToBottle: Int = 11,
var silkTouchConfig: SilkTouchEnchantment.Config = SilkTouchEnchantment.Config(),
diff --git a/src/main/kotlin/org/xodium/vanillaplus/pdcs/PlayerPDC.kt b/src/main/kotlin/org/xodium/vanillaplus/pdcs/PlayerPDC.kt
index c4146c5bb..ac2549fee 100644
--- a/src/main/kotlin/org/xodium/vanillaplus/pdcs/PlayerPDC.kt
+++ b/src/main/kotlin/org/xodium/vanillaplus/pdcs/PlayerPDC.kt
@@ -4,14 +4,8 @@ import org.bukkit.NamespacedKey
import org.bukkit.entity.Player
import org.bukkit.persistence.PersistentDataType
import org.xodium.vanillaplus.VanillaPlus.Companion.instance
-import org.xodium.vanillaplus.pdcs.PlayerPDC.NICKNAME_KEY
-import org.xodium.vanillaplus.pdcs.PlayerPDC.SCOREBOARD_VISIBILITY_KEY
-/**
- * Provides access to player-specific persistent data including nicknames and scoreboard preferences.
- * @property NICKNAME_KEY The namespaced key used for storing nickname data.
- * @property SCOREBOARD_VISIBILITY_KEY The namespaced key used for storing scoreboard visibility preferences.
- */
+/** Provides access to player-specific persistent data including nicknames and scoreboard preferences. */
internal object PlayerPDC {
private val NICKNAME_KEY = NamespacedKey(instance, "nickname")
private val SCOREBOARD_VISIBILITY_KEY = NamespacedKey(instance, "scoreboard_visibility")
diff --git a/src/main/kotlin/org/xodium/vanillaplus/pdcs/ShulkerPDC.kt b/src/main/kotlin/org/xodium/vanillaplus/pdcs/ShulkerPDC.kt
new file mode 100644
index 000000000..426d835ef
--- /dev/null
+++ b/src/main/kotlin/org/xodium/vanillaplus/pdcs/ShulkerPDC.kt
@@ -0,0 +1,25 @@
+package org.xodium.vanillaplus.pdcs
+
+import org.bukkit.NamespacedKey
+import org.bukkit.block.ShulkerBox
+import org.bukkit.persistence.PersistentDataType
+import org.xodium.vanillaplus.VanillaPlus.Companion.instance
+
+/** Provides access to shulker-specific persistent data including sold status. */
+internal object ShulkerPDC {
+ private val LOCK_KEY = NamespacedKey(instance, "lock")
+
+ /**
+ * Retrieves the usage status of this shulker box from its persistent data container.
+ * @receiver The shulker box whose usage status to retrieve.
+ * @return `true` if the shulker box is marked as in use, `false` otherwise.
+ */
+ fun ShulkerBox.lock(): Boolean = persistentDataContainer.get(LOCK_KEY, PersistentDataType.BOOLEAN) ?: false
+
+ /**
+ * Sets the usage status of this shulker box in its persistent data container.
+ * @receiver The shulker box whose usage status to modify.
+ * @param boolean The usage state to set (`true` for in use, `false` for not in use).
+ */
+ fun ShulkerBox.lock(boolean: Boolean) = persistentDataContainer.set(LOCK_KEY, PersistentDataType.BOOLEAN, boolean)
+}