Skip to content

Commit 2b75dbb

Browse files
committed
feat: advanced inventory management
1 parent 7f66313 commit 2b75dbb

5 files changed

Lines changed: 195 additions & 33 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package cc.modlabs.kpaper.coroutines
2+
3+
import cc.modlabs.kpaper.main.PluginInstance
4+
import org.bukkit.Bukkit
5+
6+
/**
7+
* Executes the given [runnable] with the given [delay].
8+
* Either sync or async (specified by the [sync] parameter).
9+
*/
10+
fun taskRunLater(delay: Long, sync: Boolean = true, runnable: () -> Unit) {
11+
if (sync)
12+
Bukkit.getScheduler().runTaskLater(PluginInstance, runnable, delay)
13+
else
14+
Bukkit.getScheduler().runTaskLaterAsynchronously(PluginInstance, runnable, delay)
15+
}
16+
17+
/**
18+
* Executes the given [runnable] either
19+
* sync or async (specified by the [sync] parameter).
20+
*/
21+
fun taskRun(sync: Boolean = true, runnable: () -> Unit) {
22+
if (sync) {
23+
sync(runnable)
24+
} else {
25+
async(runnable)
26+
}
27+
}

src/main/kotlin/cc/modlabs/kpaper/extensions/InventoryExtensions.kt

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import cc.modlabs.kpaper.consts.NAMESPACE_GUI_IDENTIFIER
44
import cc.modlabs.kpaper.consts.NAMESPACE_ITEM_IDENTIFIER
55
import cc.modlabs.kpaper.inventory.ItemBuilder
66
import cc.modlabs.kpaper.inventory.toItemBuilder
7+
import dev.fruxz.ascend.extension.isNull
78
import dev.fruxz.stacked.text
89
import org.bukkit.Material
910
import org.bukkit.NamespacedKey
@@ -163,26 +164,120 @@ fun Inventory.setItem(range: IntProgression, item: ItemStack) {
163164
}
164165

165166
fun fillEmptyAndOpenInventory(player: Player, inv: Inventory, identifier: String? = null, vararg identifiers: Map<NamespacedKey, String>? = arrayOf()) {
166-
fillEmpty(inv)
167+
fillEmpty(inv, PLACEHOLDER_GRAY)
167168
if (identifier != null) inv.identify(identifier, *identifiers)
168169
player.openInventory(inv)
169170
}
170171

171-
fun Inventory.fillEmpty(filler: ItemStack, identifier: String? = null, vararg identifiers: Map<NamespacedKey, String>? = arrayOf()) {
172-
for (i in 0 until this.size) {
173-
if (this.getItem(i) == null || this.getItem(i)!!.type == Material.AIR) {
174-
this.setItem(i, filler)
175-
}
176-
}
177-
if (identifier != null) this.identify(identifier, *identifiers)
172+
173+
fun fillEmptyAndOpenInventoryWithCustomSpacer(player: Player, inv: Inventory, spacer: ItemStack, identifier: String? = null, vararg identifiers: Map<NamespacedKey, String>? = arrayOf()) {
174+
fillEmpty(inv, spacer)
175+
if (identifier != null) inv.identify(identifier, *identifiers)
176+
player.openInventory(inv)
178177
}
179178

180-
fun fillEmpty(inventory: Inventory, identifier: String? = null, vararg identifiers: Map<NamespacedKey, String>? = arrayOf()) {
181-
val item = PLACEHOLDER_GRAY
179+
fun fillEmpty(inventory: Inventory, customSpacer: ItemStack, identifier: String? = null, vararg identifiers: Map<NamespacedKey, String>? = arrayOf()) {
182180
for (i in 0 until inventory.size) {
183181
if (inventory.getItem(i) == null || inventory.getItem(i)!!.type == Material.AIR) {
184-
inventory.setItem(i, item)
182+
inventory.setItem(i, customSpacer)
185183
}
186184
}
187185
if (identifier != null) inventory.identify(identifier, *identifiers)
186+
}
187+
188+
fun Inventory.fillEmpty(filler: ItemStack, identifier: String? = null, vararg identifiers: Map<NamespacedKey, String>? = arrayOf()) {
189+
fillEmpty(this, filler, identifier, *identifiers)
190+
}
191+
192+
fun Inventory.arrangeItemsAround(newItem: ItemStack) {
193+
val centerSlot = this.getMiddleSlot()
194+
val slots = arrayOf(centerSlot - 9, centerSlot - 1, centerSlot + 1, centerSlot + 9)
195+
196+
for (slot in slots) {
197+
// Check if the slot is within the inventory bounds
198+
if (slot in this.contents.indices) {
199+
// Check if the slot is already occupied
200+
if (this.getItem(slot) == null || this.getItem(slot)!!.type == Material.AIR || this.getItem(slot)!!.hasKey("spacer")) {
201+
this.setItem(slot, newItem)
202+
break
203+
}
204+
}
205+
}
206+
}
207+
208+
fun Inventory.swapItems(firstSlot: Int, secondSlot: Int, newItem: ItemStack) {
209+
// Swap the two items
210+
val tempItem = this.getItem(firstSlot)
211+
this.setItem(firstSlot, this.getItem(secondSlot))
212+
this.setItem(secondSlot, tempItem)
213+
214+
// Place the new item in the empty slot
215+
if (this.getItem(firstSlot).isNull) {
216+
this.setItem(firstSlot, newItem)
217+
} else if (this.getItem(secondSlot).isNull) {
218+
this.setItem(secondSlot, newItem)
219+
}
220+
}
221+
222+
fun Inventory.getEmptySlot(): Int {
223+
for (i in 0 until this.size) {
224+
if (this.getItem(i) == null || this.getItem(i)!!.type == Material.AIR) {
225+
return i
226+
}
227+
}
228+
return -1
229+
}
230+
231+
fun Inventory.setItemInMiddle(item: ItemStack) {
232+
val roundedMiddle = this.size / 2
233+
val middle = if (roundedMiddle % 2 == 0) roundedMiddle else roundedMiddle
234+
this.setItem(middle, item)
235+
}
236+
237+
fun Inventory.getMiddleSlot(): Int {
238+
val roundedMiddle = this.size / 2
239+
return if (roundedMiddle % 2 == 0) roundedMiddle else roundedMiddle
240+
}
241+
242+
fun Inventory.setLeftUpperCorner(item: ItemStack) {
243+
this.setItem(0, item)
244+
}
245+
246+
fun Inventory.setRightUpperCorner(item: ItemStack) {
247+
this.setItem(8, item)
248+
}
249+
250+
fun Inventory.setMiddleLeft(item: ItemStack) {
251+
val rows = this.size / 9
252+
val middle = if (rows % 2 == 0) rows / 2 - 1 else rows / 2
253+
this.setItem(middle * 9, item)
254+
}
255+
256+
fun Inventory.setMiddleRight(item: ItemStack) {
257+
val rows = this.size / 9
258+
val middle = if (rows % 2 == 0) rows / 2 - 1 else rows / 2
259+
this.setItem(middle * 9 + 8, item)
260+
}
261+
262+
fun Inventory.setUpperMiddle(item: ItemStack) {
263+
this.setItem(4, item)
264+
}
265+
266+
fun Inventory.setLowerMiddle(item: ItemStack) {
267+
this.setItem(this.size - 5, item)
268+
}
269+
270+
fun Inventory.setLeftLowerCorner(item: ItemStack) {
271+
this.setItem(this.size - 9, item)
272+
}
273+
274+
fun Inventory.setRightLowerCorner(item: ItemStack) {
275+
this.setItem(this.size - 1, item)
276+
}
277+
278+
fun ItemStack.hasKey(namespacedKey: String): Boolean {
279+
return this.itemMeta?.persistentDataContainer?.has(
280+
pluginKey(namespacedKey),
281+
PersistentDataType.STRING
282+
) ?: false
188283
}

src/main/kotlin/cc/modlabs/kpaper/extensions/LocationExtension.kt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,36 @@ fun loc2Str(location: Location): String {
9191
loc += location.yaw.toString() + ","
9292
loc += location.pitch
9393
return loc
94+
}
95+
96+
97+
fun Location.asSafeLocation(): Location {
98+
// Now we test if the location (2 blocks high) is occupied and if so, we move up until we find a free spot
99+
var location = this.clone()
100+
while ((location.block.type.isSolid || location.clone().add(0.0, 1.0, 0.0).block.type.isSolid)) {
101+
location = location.add(0.0, 1.0, 0.0)
102+
}
103+
return location
104+
}
105+
106+
fun Location.asSafeLocationOrNull(): Location? {
107+
// Now we test if the location (2 blocks high) is occupied and if so, we move up until we find a free spot
108+
var location = this.clone()
109+
while ((location.block.type.isSolid || location.clone().add(0.0, 1.0, 0.0).block.type.isSolid)) {
110+
location = location.add(0.0, 1.0, 0.0)
111+
}
112+
if(location.y > 319) return null
113+
return location
114+
}
115+
116+
fun Location.isInRadius(middle: Location, radius: Int): Boolean {
117+
return this.x in middle.x - radius..middle.x + radius && this.z in middle.z - radius..middle.z + radius
118+
}
119+
120+
fun Location.inWorld(world: World) = this.clone().apply { this.world = world }
121+
122+
fun Location.inWorld(worlds: String) = this.clone().apply { this.world = Bukkit.getWorld(worlds.lowercase()) }
123+
124+
fun Location.toNorth(): Location {
125+
return this.apply { this.yaw = 180.0f; this.pitch = 0f }
94126
}

src/main/kotlin/cc/modlabs/kpaper/inventory/ItemBuilder.kt

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
package cc.modlabs.kpaper.inventory
1+
@file:Suppress("unused")
22

3+
package cc.modlabs.kpaper.inventory
4+
5+
import cc.modlabs.kpaper.coroutines.taskRunLater
36
import com.mojang.authlib.GameProfile
47
import com.mojang.authlib.properties.Property
58
import dev.fruxz.stacked.text
@@ -18,9 +21,9 @@ import org.bukkit.inventory.ItemStack
1821
import org.bukkit.inventory.meta.ItemMeta
1922
import org.bukkit.inventory.meta.SkullMeta
2023
import org.bukkit.persistence.PersistentDataType
21-
import org.jetbrains.annotations.ApiStatus
2224
import java.lang.reflect.Field
2325
import java.util.*
26+
import java.util.concurrent.TimeUnit
2427

2528

2629
/**
@@ -338,7 +341,7 @@ class ItemBuilder(material: Material, count: Int = 1, dsl: ItemBuilder.() -> Uni
338341
*/
339342
fun lore(vararg lores: String): ItemBuilder {
340343
val meta = itemStack.itemMeta
341-
var lore = listOf<Component>()
344+
val lore = mutableListOf<Component>()
342345

343346
lores.forEach {
344347
val lines = it.split("\n")
@@ -435,27 +438,15 @@ class ItemBuilder(material: Material, count: Int = 1, dsl: ItemBuilder.() -> Uni
435438

436439
/**
437440
* Sets the equippable state of the item in the specified slot.
438-
* This method is not yet supported in PaperMC 1.21.1.
439441
*/
440-
@ApiStatus.Internal
441-
fun setEquippable(slot: EquipmentSlot, equippable: Boolean): ItemBuilder {
442+
fun setEquippable(slot: EquipmentSlot): ItemBuilder {
442443
val meta = itemStack.itemMeta
443444

444-
TODO("Waiting for 1.21.2+ support")
445+
val equippable = meta.equippable
445446

446-
itemStack.itemMeta = meta
447-
return this
448-
}
447+
equippable.slot = slot
449448

450-
/**
451-
* Sets the consumable state of the item.
452-
* This method is not yet supported in PaperMC 1.21.1.
453-
*/
454-
@ApiStatus.Internal
455-
fun setConsumable(consumable: Boolean): ItemBuilder {
456-
val meta = itemStack.itemMeta
457-
458-
TODO("Waiting for 1.21.2+ support")
449+
meta.setEquippable(equippable)
459450

460451
itemStack.itemMeta = meta
461452
return this
@@ -594,7 +585,7 @@ class ItemBuilder(material: Material, count: Int = 1, dsl: ItemBuilder.() -> Uni
594585
)
595586

596587
fun fromItemStack(itemStack: ItemStack): ItemBuilder {
597-
var mat =
588+
val mat =
598589
if (invalidMaterials.contains(itemStack.type)) Material.GRASS_BLOCK else itemStack.type
599590
val builder = ItemBuilder(mat)
600591
builder.itemStack = itemStack
@@ -610,7 +601,7 @@ class ItemBuilder(material: Material, count: Int = 1, dsl: ItemBuilder.() -> Uni
610601
* @return The resulting ItemBuilder.
611602
*/
612603
fun Material.toItemBuilder(dsl: ItemBuilder.() -> Unit = {}): ItemBuilder {
613-
var mat = if (ItemBuilder.invalidMaterials.contains(this)) Material.GRASS_BLOCK else this
604+
val mat = if (ItemBuilder.invalidMaterials.contains(this)) Material.GRASS_BLOCK else this
614605
return ItemBuilder(mat).apply(dsl)
615606
}
616607

@@ -621,9 +612,21 @@ fun Material.toItemBuilder(dsl: ItemBuilder.() -> Unit = {}): ItemBuilder {
621612
* @return the converted ItemBuilder.
622613
*/
623614
fun ItemStack.toItemBuilder(dsl: ItemBuilder.() -> Unit = {}): ItemBuilder {
624-
var mat = if (ItemBuilder.invalidMaterials.contains(this.type)) Material.GRASS_BLOCK else this.type
615+
val mat = if (ItemBuilder.invalidMaterials.contains(this.type)) Material.GRASS_BLOCK else this.type
625616
val builder = ItemBuilder(mat)
626617
builder.itemStack = this
627618
builder.dsl()
628619
return builder
620+
}
621+
622+
fun ItemStack.changeNameForTime(name: String, time: Long, unit: TimeUnit = TimeUnit.SECONDS, afterTask: () -> Unit = {}) {
623+
val oldName = this.itemMeta.displayName()
624+
val meta = this.itemMeta
625+
meta.displayName(text(name))
626+
this.itemMeta = meta
627+
taskRunLater(unit.toSeconds(time) * 20L) {
628+
meta.displayName(oldName)
629+
this.itemMeta = meta
630+
afterTask()
631+
}
629632
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package cc.modlabs.kpaper.world
2+
3+
enum class Direction {
4+
MIDDLE, NORTH, NORTH_EAST, EAST, SOUTH_EAST, SOUTH(), SOUTH_WEST, WEST, NORTH_WEST
5+
}

0 commit comments

Comments
 (0)