From f43fa84f540295571245d73fe8f78f70c0fde9cb Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 3 May 2026 08:59:53 +0300 Subject: [PATCH 01/10] [FEAT] InventoryLayout.kt --- docker-compose.yml | 4 + .../astramarket/api/InventoryLayout.kt | 13 ++++ .../astramarket/api/SlotInventoryLayout.kt | 38 ++++++++++ .../api/SlotInventoryLayoutBuilder.kt | 18 +++++ .../gui/invmap/AuctionInventoryMap.kt | 34 --------- .../gui/invmap/DefaultAuctionInventoryMap.kt | 15 ---- .../astramarket/gui/invmap/InventoryMap.kt | 5 -- .../astramarket/gui/invmap/InventoryMapExt.kt | 35 --------- .../astramarket/gui/layout/AuctionSlotKey.kt | 30 ++++++++ .../DefaultAuctionInventoryLayoutFactory.kt | 75 +++++++++++++++++++ .../astramarket/gui/players/PlayersGui.kt | 34 ++++----- .../astramarket/gui/slots/SlotsGui.kt | 40 +++++----- 12 files changed, 215 insertions(+), 126 deletions(-) create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/InventoryLayout.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayout.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/AuctionInventoryMap.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/DefaultAuctionInventoryMap.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/InventoryMap.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/InventoryMapExt.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/AuctionSlotKey.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt diff --git a/docker-compose.yml b/docker-compose.yml index 175b847..2db713f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,10 @@ services: ports: - "25565:25565" environment: + LEVEL_TYPE: FLAT + EXISTING_OPS_FILE: MERGE + OPS: | + RomaRoman EULA: true ONLINE_MODE: false # Forge -------------------- diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/InventoryLayout.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/InventoryLayout.kt new file mode 100644 index 0000000..f89702f --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/InventoryLayout.kt @@ -0,0 +1,13 @@ +package ru.astrainteractive.astramarket.api + +interface InventoryLayout { + val size: Int + fun keyAt(index: Int): K + fun indicesOf(key: K): List + fun firstIndexOf(key: K): Int + fun count(key: K): Int + fun mapSlotsNotNull( + key: K, + transform: (index: Int) -> S? + ): List +} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayout.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayout.kt new file mode 100644 index 0000000..b9a1996 --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayout.kt @@ -0,0 +1,38 @@ +package ru.astrainteractive.astramarket.api + +import ru.astrainteractive.astralibs.menu.slot.InventorySlot + +class SlotInventoryLayout( + private val slots: List +) : InventoryLayout { + + override val size: Int get() = slots.size + + override fun keyAt(index: Int): K = slots[index] + + override fun indicesOf(key: K): List = slots.withIndex() + .filter { indexedValue -> indexedValue.value == key } + .map { indexedValue -> indexedValue.index } + + override fun firstIndexOf(key: K): Int = slots.indexOf(key) + .takeIf { index -> index != -1 } + ?: error("Key $key not found in layout") + + override fun count(key: K): Int = slots.count { slotKey -> slotKey == key } + + override fun mapSlotsNotNull( + key: K, + transform: (index: Int) -> InventorySlot? + ): List = indicesOf(key).mapNotNull(transform) +} + +fun SlotInventoryLayout(rows: List>): SlotInventoryLayout { + if (rows.isEmpty()) return SlotInventoryLayout(emptyList()) + + val width = rows.first().size + require(rows.all { row -> row.size == width }) { + "All rows must have the same width" + } + + return SlotInventoryLayout(rows.flatten()) +} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt new file mode 100644 index 0000000..78b66d3 --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt @@ -0,0 +1,18 @@ +package ru.astrainteractive.astramarket.api + +class SlotInventoryLayoutBuilder { + + private val rows = mutableListOf>() + + fun row(vararg keys: K) { + rows += keys.toList() + } + + fun build(): SlotInventoryLayout = SlotInventoryLayout(rows) +} + +fun slotInventoryLayout( + block: SlotInventoryLayoutBuilder.() -> Unit +): SlotInventoryLayout = SlotInventoryLayoutBuilder() + .apply(block) + .build() diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/AuctionInventoryMap.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/AuctionInventoryMap.kt deleted file mode 100644 index c6a4606..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/AuctionInventoryMap.kt +++ /dev/null @@ -1,34 +0,0 @@ -package ru.astrainteractive.astramarket.gui.invmap - -import ru.astrainteractive.astramarket.gui.invmap.AuctionInventoryMap.AuctionSlotKey - -internal interface AuctionInventoryMap : InventoryMap { - enum class AuctionSlotKey { - // Border - BO, - - // Prev - PR, - - // Next - NE, - - // Auction/Expired - AU, - - // Back - BA, - - // Filter - FI, - - // Auction item - AI, - - // Group by player or all slots - GR, - - // Empty - EM - } -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/DefaultAuctionInventoryMap.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/DefaultAuctionInventoryMap.kt deleted file mode 100644 index 4be658b..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/DefaultAuctionInventoryMap.kt +++ /dev/null @@ -1,15 +0,0 @@ -package ru.astrainteractive.astramarket.gui.invmap - -import ru.astrainteractive.astramarket.gui.invmap.AuctionInventoryMap.AuctionSlotKey - -internal object DefaultAuctionInventoryMap : AuctionInventoryMap { - @Suppress("MaxLineLength") - override val map: Array> = arrayOf( - arrayOf(AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI), - arrayOf(AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI), - arrayOf(AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI), - arrayOf(AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI), - arrayOf(AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI, AuctionSlotKey.AI), - arrayOf(AuctionSlotKey.PR, AuctionSlotKey.EM, AuctionSlotKey.GR, AuctionSlotKey.AU, AuctionSlotKey.BA, AuctionSlotKey.FI, AuctionSlotKey.EM, AuctionSlotKey.EM, AuctionSlotKey.NE), - ) -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/InventoryMap.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/InventoryMap.kt deleted file mode 100644 index c041dfb..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/InventoryMap.kt +++ /dev/null @@ -1,5 +0,0 @@ -package ru.astrainteractive.astramarket.gui.invmap - -internal interface InventoryMap { - val map: Array> -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/InventoryMapExt.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/InventoryMapExt.kt deleted file mode 100644 index 01381d5..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/invmap/InventoryMapExt.kt +++ /dev/null @@ -1,35 +0,0 @@ -package ru.astrainteractive.astramarket.gui.invmap - -import ru.astrainteractive.astralibs.menu.slot.InventorySlot - -internal object InventoryMapExt { - - private val InventoryMap<*>.flatMap get() = map.flatMap { it.map { guiKey -> guiKey } } - - fun InventoryMap.countKeys(key: T): Int { - return flatMap.count { it == key } - } - - fun InventoryMap.withKeySlot( - key: T, - transform: (index: Int) -> InventorySlot? - ): List { - return flatMap - .mapIndexed { i, k -> - if (key != k) { - null - } else { - transform.invoke(i) - } - } - .filterNotNull() - } - - fun InventoryMap.indexOf(key: T): Int { - val i = flatMap.indexOf(key) - if (i == -1) { - error("Could not find $key in inventory map") - } - return i - } -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/AuctionSlotKey.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/AuctionSlotKey.kt new file mode 100644 index 0000000..5de40fd --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/AuctionSlotKey.kt @@ -0,0 +1,30 @@ +package ru.astrainteractive.astramarket.gui.layout + +enum class AuctionSlotKey { + // Border + BO, + + // Prev + PR, + + // Next + NE, + + // Auction/Expired + AU, + + // Back + BA, + + // Filter + FI, + + // Auction item + AI, + + // Group by player or all slots + GR, + + // Empty + EM +} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt new file mode 100644 index 0000000..31e3e10 --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt @@ -0,0 +1,75 @@ +package ru.astrainteractive.astramarket.gui.layout + +import ru.astrainteractive.astramarket.api.slotInventoryLayout + +internal object DefaultAuctionInventoryLayoutFactory { + @Suppress("LongMethod") + fun create() = slotInventoryLayout { + row( + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI + ) + row( + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI + ) + row( + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI + ) + row( + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI + ) + row( + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI, + AuctionSlotKey.AI + ) + row( + AuctionSlotKey.PR, + AuctionSlotKey.EM, + AuctionSlotKey.GR, + AuctionSlotKey.AU, + AuctionSlotKey.BA, + AuctionSlotKey.FI, + AuctionSlotKey.EM, + AuctionSlotKey.EM, + AuctionSlotKey.NE + ) + } +} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt index 03c39a2..904ad11 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt @@ -20,6 +20,7 @@ import ru.astrainteractive.astralibs.menu.slot.InventorySlot import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astralibs.server.player.OnlineKPlayer import ru.astrainteractive.astralibs.server.util.asOnlineMinecraftPlayer +import ru.astrainteractive.astramarket.api.SlotInventoryLayout import ru.astrainteractive.astramarket.gui.button.back import ru.astrainteractive.astramarket.gui.button.di.ButtonContext import ru.astrainteractive.astramarket.gui.button.filterExpired @@ -29,12 +30,8 @@ import ru.astrainteractive.astramarket.gui.button.playersSort import ru.astrainteractive.astramarket.gui.button.prevPage import ru.astrainteractive.astramarket.gui.button.slotsType import ru.astrainteractive.astramarket.gui.di.AuctionGuiDependencies -import ru.astrainteractive.astramarket.gui.invmap.AuctionInventoryMap -import ru.astrainteractive.astramarket.gui.invmap.AuctionInventoryMap.AuctionSlotKey -import ru.astrainteractive.astramarket.gui.invmap.DefaultAuctionInventoryMap -import ru.astrainteractive.astramarket.gui.invmap.InventoryMapExt.countKeys -import ru.astrainteractive.astramarket.gui.invmap.InventoryMapExt.indexOf -import ru.astrainteractive.astramarket.gui.invmap.InventoryMapExt.withKeySlot +import ru.astrainteractive.astramarket.gui.layout.AuctionSlotKey +import ru.astrainteractive.astramarket.gui.layout.DefaultAuctionInventoryLayoutFactory import ru.astrainteractive.astramarket.gui.router.GuiRouter import ru.astrainteractive.astramarket.gui.util.ItemStackExt.playSound import ru.astrainteractive.astramarket.players.presentation.PlayersMarketComponent @@ -50,8 +47,9 @@ internal class PlayersGui( KyoriComponentSerializer by dependencies.kyoriComponentSerializer { override val inventorySize: InventorySize = InventorySize.XL - private val inventoryMap: AuctionInventoryMap - get() = DefaultAuctionInventoryMap + private val inventoryMap: SlotInventoryLayout by lazy { + DefaultAuctionInventoryLayoutFactory.create() + } override val title: Component = pluginTranslation.menu.market.component @@ -59,13 +57,13 @@ internal class PlayersGui( override var pageContext: PageContext = PageContext( page = 0, - maxItemsPerPage = inventoryMap.countKeys(AuctionSlotKey.AI), + maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AI), maxItems = 0 ) override val prevPageButton: InventorySlot get() = buttonContext.prevPage( - index = inventoryMap.indexOf(AuctionSlotKey.PR), + index = inventoryMap.firstIndexOf(AuctionSlotKey.PR), click = { playerHolder.player.playSound(config.sounds.open) showPrevPage() @@ -74,7 +72,7 @@ internal class PlayersGui( override val nextPageButton: InventorySlot get() = buttonContext.nextPage( - index = inventoryMap.indexOf(AuctionSlotKey.NE), + index = inventoryMap.firstIndexOf(AuctionSlotKey.NE), click = { playerHolder.player.playSound(config.sounds.open) showNextPage() @@ -83,7 +81,7 @@ internal class PlayersGui( private val sortButton: InventorySlot get() = buttonContext.playersSort( - index = inventoryMap.indexOf(AuctionSlotKey.FI), + index = inventoryMap.firstIndexOf(AuctionSlotKey.FI), sortType = playersMarketComponent.model.value.sort, click = { playerHolder.player.playSound(config.sounds.open) @@ -93,7 +91,7 @@ internal class PlayersGui( private val expiredButton: InventorySlot get() = buttonContext.filterExpired( - index = inventoryMap.indexOf(AuctionSlotKey.AU), + index = inventoryMap.firstIndexOf(AuctionSlotKey.AU), isExpired = playersMarketComponent.model.value.isExpired, click = { playerHolder.player.playSound(config.sounds.open) @@ -104,7 +102,7 @@ internal class PlayersGui( private val allSlots: InventorySlot get() = buttonContext.slotsType( - index = inventoryMap.indexOf(AuctionSlotKey.GR), + index = inventoryMap.firstIndexOf(AuctionSlotKey.GR), isGroupedByPlayers = true, click = { val route = GuiRouter.Route.Slots( @@ -118,7 +116,7 @@ internal class PlayersGui( private val closeButton: InventorySlot get() = buttonContext.back( - index = inventoryMap.indexOf(AuctionSlotKey.BA), + index = inventoryMap.firstIndexOf(AuctionSlotKey.BA), click = { playerHolder.player.closeInventory() } ) @@ -126,14 +124,14 @@ internal class PlayersGui( get() { var itemIndex = 0 val isExpired = playersMarketComponent.model.value.isExpired - return inventoryMap.withKeySlot(AuctionSlotKey.AI) { slotIndex -> + return inventoryMap.mapSlotsNotNull(AuctionSlotKey.AI) { slotIndex -> val index = pageContext.indexOfSlot(itemIndex) itemIndex++ val items = playersMarketComponent.model .value .playersAndSlots .filter { it.slots.any { slot -> slot.expired == isExpired } } - .getOrNull(index) ?: return@withKeySlot null + .getOrNull(index) ?: return@mapSlotsNotNull null buttonContext.playerItem( playerAndSlots = items, index = slotIndex, @@ -171,7 +169,7 @@ internal class PlayersGui( expiredButton.setInventorySlot() closeButton.setInventorySlot() allSlots.setInventorySlot() - slots.forEach { it.setInventorySlot() } + slots.forEach { slot -> slot.setInventorySlot() } } override fun onInventoryCreated() { diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt index b22f701..8ba20e3 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt @@ -25,6 +25,7 @@ import ru.astrainteractive.astralibs.server.permission.asKPermissible import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astralibs.server.player.OnlineKPlayer import ru.astrainteractive.astralibs.server.util.asOnlineMinecraftPlayer +import ru.astrainteractive.astramarket.api.SlotInventoryLayout import ru.astrainteractive.astramarket.core.PluginPermission import ru.astrainteractive.astramarket.gui.button.auctionSort import ru.astrainteractive.astramarket.gui.button.back @@ -36,12 +37,8 @@ import ru.astrainteractive.astramarket.gui.button.nextPage import ru.astrainteractive.astramarket.gui.button.prevPage import ru.astrainteractive.astramarket.gui.button.slotsType import ru.astrainteractive.astramarket.gui.di.AuctionGuiDependencies -import ru.astrainteractive.astramarket.gui.invmap.AuctionInventoryMap -import ru.astrainteractive.astramarket.gui.invmap.AuctionInventoryMap.AuctionSlotKey -import ru.astrainteractive.astramarket.gui.invmap.DefaultAuctionInventoryMap -import ru.astrainteractive.astramarket.gui.invmap.InventoryMapExt.countKeys -import ru.astrainteractive.astramarket.gui.invmap.InventoryMapExt.indexOf -import ru.astrainteractive.astramarket.gui.invmap.InventoryMapExt.withKeySlot +import ru.astrainteractive.astramarket.gui.layout.AuctionSlotKey +import ru.astrainteractive.astramarket.gui.layout.DefaultAuctionInventoryLayoutFactory import ru.astrainteractive.astramarket.gui.router.GuiRouter import ru.astrainteractive.astramarket.gui.util.ItemStackExt.playSound import ru.astrainteractive.astramarket.market.presentation.AuctionComponent @@ -67,36 +64,41 @@ internal class SlotsGui( } override val inventorySize: InventorySize = InventorySize.XL - private val inventoryMap: AuctionInventoryMap - get() = if (config.auction.useCompactDesign) DefaultAuctionInventoryMap else DefaultAuctionInventoryMap + private val inventoryMap: SlotInventoryLayout by lazy { + if (config.auction.useCompactDesign) { + DefaultAuctionInventoryLayoutFactory.create() + } else { + DefaultAuctionInventoryLayoutFactory.create() + } + } override var pageContext: PageContext = PageContext( page = 0, - maxItemsPerPage = inventoryMap.countKeys(AuctionSlotKey.AI), + maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AI), maxItems = 0 ) private val borderButtons: List - get() = inventoryMap.withKeySlot( + get() = inventoryMap.mapSlotsNotNull( key = AuctionSlotKey.BO, transform = buttonContext::border ) override val nextPageButton: InventorySlot get() = buttonContext.nextPage( - index = inventoryMap.indexOf(AuctionSlotKey.NE), + index = inventoryMap.firstIndexOf(AuctionSlotKey.NE), click = { onNextPageClicked() } ) override val prevPageButton: InventorySlot get() = buttonContext.prevPage( - index = inventoryMap.indexOf(AuctionSlotKey.PR), + index = inventoryMap.firstIndexOf(AuctionSlotKey.PR), click = { onPrevPageClicked() } ) private val sortButton: InventorySlot get() = buttonContext.auctionSort( - index = inventoryMap.indexOf(AuctionSlotKey.FI), + index = inventoryMap.firstIndexOf(AuctionSlotKey.FI), sortType = auctionComponent.model.value.sortType, click = { showPage(0) @@ -106,7 +108,7 @@ internal class SlotsGui( private val expiredSlotsButton: InventorySlot get() = buttonContext.filterExpired( - index = inventoryMap.indexOf(AuctionSlotKey.AU), + index = inventoryMap.firstIndexOf(AuctionSlotKey.AU), isExpired = auctionComponent.model.value.isExpired, click = { playerHolder.player.playSound(config.sounds.open) @@ -117,7 +119,7 @@ internal class SlotsGui( private val openPlayersButton: InventorySlot get() = buttonContext.back( - index = inventoryMap.indexOf(AuctionSlotKey.BA), + index = inventoryMap.firstIndexOf(AuctionSlotKey.BA), click = { val route = GuiRouter.Route.Players( player = playerHolder.player.asOnlineMinecraftPlayer(), @@ -129,7 +131,7 @@ internal class SlotsGui( private val playerSlots: InventorySlot get() = buttonContext.slotsType( - index = inventoryMap.indexOf(AuctionSlotKey.GR), + index = inventoryMap.firstIndexOf(AuctionSlotKey.GR), isGroupedByPlayers = false, click = { val route = GuiRouter.Route.Players( @@ -142,7 +144,7 @@ internal class SlotsGui( private val closeButton: InventorySlot get() = buttonContext.back( - index = inventoryMap.indexOf(AuctionSlotKey.BA), + index = inventoryMap.firstIndexOf(AuctionSlotKey.BA), click = { playerHolder.player.closeInventory() } ) @@ -165,14 +167,14 @@ internal class SlotsGui( private val itemSlots: List get() { var itemIndex = 0 - return inventoryMap.withKeySlot(AuctionSlotKey.AI) { slotIndex -> + return inventoryMap.mapSlotsNotNull(AuctionSlotKey.AI) { slotIndex -> val index = pageContext.indexOfSlot(itemIndex) itemIndex++ val auctionItem = auctionComponent.model .value .items .getOrNull(index) - ?: return@withKeySlot null + ?: return@mapSlotsNotNull null val permissible = playerHolder.player.asKPermissible() buttonContext.expiredSlot( auctionItem = auctionItem, From 05c1cab7a9db31e940334cfeed9b11dcd2219c57 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 3 May 2026 09:16:01 +0300 Subject: [PATCH 02/10] [FEAT] Improve InventoryLayout --- .../api/SlotInventoryLayoutBuilder.kt | 4 + .../astramarket/gui/layout/AuctionSlotKey.kt | 35 ++---- .../DefaultAuctionInventoryLayoutFactory.kt | 110 ++++++++---------- .../astramarket/gui/players/PlayersGui.kt | 18 +-- .../astramarket/gui/slots/SlotsGui.kt | 26 ++--- 5 files changed, 79 insertions(+), 114 deletions(-) diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt index 78b66d3..b84fd7e 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt @@ -8,6 +8,10 @@ class SlotInventoryLayoutBuilder { rows += keys.toList() } + fun row(size: Int, key: K) { + rows += List(size) { key } + } + fun build(): SlotInventoryLayout = SlotInventoryLayout(rows) } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/AuctionSlotKey.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/AuctionSlotKey.kt index 5de40fd..d655b41 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/AuctionSlotKey.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/AuctionSlotKey.kt @@ -1,30 +1,13 @@ package ru.astrainteractive.astramarket.gui.layout enum class AuctionSlotKey { - // Border - BO, - - // Prev - PR, - - // Next - NE, - - // Auction/Expired - AU, - - // Back - BA, - - // Filter - FI, - - // Auction item - AI, - - // Group by player or all slots - GR, - - // Empty - EM + BORDER, + PREV_PAGE, + NEXT_PAGE, + FILTER_EXPIRED, + BACK, + SORT, + AUCTION_ITEM, + DISPLAY_TYPE, + EMPTY } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt index 31e3e10..ad25eac 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt @@ -1,75 +1,57 @@ package ru.astrainteractive.astramarket.gui.layout +import ru.astrainteractive.astramarket.api.SlotInventoryLayout import ru.astrainteractive.astramarket.api.slotInventoryLayout +@Suppress("MagicNumber") internal object DefaultAuctionInventoryLayoutFactory { - @Suppress("LongMethod") - fun create() = slotInventoryLayout { - row( - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI - ) - row( - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI - ) - row( - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI - ) - row( - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI - ) + + private fun createCompactLayout() = slotInventoryLayout { + repeat(5) { + row(9, AuctionSlotKey.AUCTION_ITEM) + } row( - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI, - AuctionSlotKey.AI + AuctionSlotKey.PREV_PAGE, + AuctionSlotKey.EMPTY, + AuctionSlotKey.DISPLAY_TYPE, + AuctionSlotKey.FILTER_EXPIRED, + AuctionSlotKey.BACK, + AuctionSlotKey.SORT, + AuctionSlotKey.EMPTY, + AuctionSlotKey.EMPTY, + AuctionSlotKey.NEXT_PAGE ) + } + + private fun createBorderedLayout() = slotInventoryLayout { + row(9, AuctionSlotKey.BORDER) + repeat(4) { + row( + AuctionSlotKey.BORDER, + AuctionSlotKey.AUCTION_ITEM, + AuctionSlotKey.AUCTION_ITEM, + AuctionSlotKey.AUCTION_ITEM, + AuctionSlotKey.AUCTION_ITEM, + AuctionSlotKey.AUCTION_ITEM, + AuctionSlotKey.AUCTION_ITEM, + AuctionSlotKey.AUCTION_ITEM, + AuctionSlotKey.BORDER + ) + } row( - AuctionSlotKey.PR, - AuctionSlotKey.EM, - AuctionSlotKey.GR, - AuctionSlotKey.AU, - AuctionSlotKey.BA, - AuctionSlotKey.FI, - AuctionSlotKey.EM, - AuctionSlotKey.EM, - AuctionSlotKey.NE + AuctionSlotKey.BORDER, + AuctionSlotKey.PREV_PAGE, + AuctionSlotKey.DISPLAY_TYPE, + AuctionSlotKey.FILTER_EXPIRED, + AuctionSlotKey.BACK, + AuctionSlotKey.SORT, + AuctionSlotKey.EMPTY, + AuctionSlotKey.NEXT_PAGE, + AuctionSlotKey.BORDER ) } + + fun create(isCompact: Boolean): SlotInventoryLayout { + return if (isCompact) createCompactLayout() else createBorderedLayout() + } } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt index 904ad11..226439f 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt @@ -48,7 +48,7 @@ internal class PlayersGui( override val inventorySize: InventorySize = InventorySize.XL private val inventoryMap: SlotInventoryLayout by lazy { - DefaultAuctionInventoryLayoutFactory.create() + DefaultAuctionInventoryLayoutFactory.create(config.auction.useCompactDesign) } override val title: Component = pluginTranslation.menu.market.component @@ -57,13 +57,13 @@ internal class PlayersGui( override var pageContext: PageContext = PageContext( page = 0, - maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AI), + maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AUCTION_ITEM), maxItems = 0 ) override val prevPageButton: InventorySlot get() = buttonContext.prevPage( - index = inventoryMap.firstIndexOf(AuctionSlotKey.PR), + index = inventoryMap.firstIndexOf(AuctionSlotKey.PREV_PAGE), click = { playerHolder.player.playSound(config.sounds.open) showPrevPage() @@ -72,7 +72,7 @@ internal class PlayersGui( override val nextPageButton: InventorySlot get() = buttonContext.nextPage( - index = inventoryMap.firstIndexOf(AuctionSlotKey.NE), + index = inventoryMap.firstIndexOf(AuctionSlotKey.NEXT_PAGE), click = { playerHolder.player.playSound(config.sounds.open) showNextPage() @@ -81,7 +81,7 @@ internal class PlayersGui( private val sortButton: InventorySlot get() = buttonContext.playersSort( - index = inventoryMap.firstIndexOf(AuctionSlotKey.FI), + index = inventoryMap.firstIndexOf(AuctionSlotKey.SORT), sortType = playersMarketComponent.model.value.sort, click = { playerHolder.player.playSound(config.sounds.open) @@ -91,7 +91,7 @@ internal class PlayersGui( private val expiredButton: InventorySlot get() = buttonContext.filterExpired( - index = inventoryMap.firstIndexOf(AuctionSlotKey.AU), + index = inventoryMap.firstIndexOf(AuctionSlotKey.FILTER_EXPIRED), isExpired = playersMarketComponent.model.value.isExpired, click = { playerHolder.player.playSound(config.sounds.open) @@ -102,7 +102,7 @@ internal class PlayersGui( private val allSlots: InventorySlot get() = buttonContext.slotsType( - index = inventoryMap.firstIndexOf(AuctionSlotKey.GR), + index = inventoryMap.firstIndexOf(AuctionSlotKey.DISPLAY_TYPE), isGroupedByPlayers = true, click = { val route = GuiRouter.Route.Slots( @@ -116,7 +116,7 @@ internal class PlayersGui( private val closeButton: InventorySlot get() = buttonContext.back( - index = inventoryMap.firstIndexOf(AuctionSlotKey.BA), + index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), click = { playerHolder.player.closeInventory() } ) @@ -124,7 +124,7 @@ internal class PlayersGui( get() { var itemIndex = 0 val isExpired = playersMarketComponent.model.value.isExpired - return inventoryMap.mapSlotsNotNull(AuctionSlotKey.AI) { slotIndex -> + return inventoryMap.mapSlotsNotNull(AuctionSlotKey.AUCTION_ITEM) { slotIndex -> val index = pageContext.indexOfSlot(itemIndex) itemIndex++ val items = playersMarketComponent.model diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt index 8ba20e3..0f2381c 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt @@ -65,40 +65,36 @@ internal class SlotsGui( override val inventorySize: InventorySize = InventorySize.XL private val inventoryMap: SlotInventoryLayout by lazy { - if (config.auction.useCompactDesign) { - DefaultAuctionInventoryLayoutFactory.create() - } else { - DefaultAuctionInventoryLayoutFactory.create() - } + DefaultAuctionInventoryLayoutFactory.create(config.auction.useCompactDesign) } override var pageContext: PageContext = PageContext( page = 0, - maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AI), + maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AUCTION_ITEM), maxItems = 0 ) private val borderButtons: List get() = inventoryMap.mapSlotsNotNull( - key = AuctionSlotKey.BO, + key = AuctionSlotKey.BORDER, transform = buttonContext::border ) override val nextPageButton: InventorySlot get() = buttonContext.nextPage( - index = inventoryMap.firstIndexOf(AuctionSlotKey.NE), + index = inventoryMap.firstIndexOf(AuctionSlotKey.NEXT_PAGE), click = { onNextPageClicked() } ) override val prevPageButton: InventorySlot get() = buttonContext.prevPage( - index = inventoryMap.firstIndexOf(AuctionSlotKey.PR), + index = inventoryMap.firstIndexOf(AuctionSlotKey.PREV_PAGE), click = { onPrevPageClicked() } ) private val sortButton: InventorySlot get() = buttonContext.auctionSort( - index = inventoryMap.firstIndexOf(AuctionSlotKey.FI), + index = inventoryMap.firstIndexOf(AuctionSlotKey.SORT), sortType = auctionComponent.model.value.sortType, click = { showPage(0) @@ -108,7 +104,7 @@ internal class SlotsGui( private val expiredSlotsButton: InventorySlot get() = buttonContext.filterExpired( - index = inventoryMap.firstIndexOf(AuctionSlotKey.AU), + index = inventoryMap.firstIndexOf(AuctionSlotKey.AUCTION_ITEM), isExpired = auctionComponent.model.value.isExpired, click = { playerHolder.player.playSound(config.sounds.open) @@ -119,7 +115,7 @@ internal class SlotsGui( private val openPlayersButton: InventorySlot get() = buttonContext.back( - index = inventoryMap.firstIndexOf(AuctionSlotKey.BA), + index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), click = { val route = GuiRouter.Route.Players( player = playerHolder.player.asOnlineMinecraftPlayer(), @@ -131,7 +127,7 @@ internal class SlotsGui( private val playerSlots: InventorySlot get() = buttonContext.slotsType( - index = inventoryMap.firstIndexOf(AuctionSlotKey.GR), + index = inventoryMap.firstIndexOf(AuctionSlotKey.DISPLAY_TYPE), isGroupedByPlayers = false, click = { val route = GuiRouter.Route.Players( @@ -144,7 +140,7 @@ internal class SlotsGui( private val closeButton: InventorySlot get() = buttonContext.back( - index = inventoryMap.firstIndexOf(AuctionSlotKey.BA), + index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), click = { playerHolder.player.closeInventory() } ) @@ -167,7 +163,7 @@ internal class SlotsGui( private val itemSlots: List get() { var itemIndex = 0 - return inventoryMap.mapSlotsNotNull(AuctionSlotKey.AI) { slotIndex -> + return inventoryMap.mapSlotsNotNull(AuctionSlotKey.AUCTION_ITEM) { slotIndex -> val index = pageContext.indexOfSlot(itemIndex) itemIndex++ val auctionItem = auctionComponent.model From d911481005ac09cabed6a3b7438a8de8a1e737f3 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 3 May 2026 20:06:22 +0300 Subject: [PATCH 03/10] [FEAT] Improve InventoryLayout --- .../astramarket/api/InventoryLayout.kt | 13 ------- .../astramarket/api/SlotInventoryLayout.kt | 38 ------------------- .../api/SlotInventoryLayoutBuilder.kt | 22 ----------- .../api/layout/DefaultInventoryLayout.kt | 37 ++++++++++++++++++ .../astramarket/api/layout/InventoryLayout.kt | 13 +++++++ .../api/layout/InventoryLayoutBuilder.kt | 28 ++++++++++++++ .../DefaultAuctionInventoryLayoutFactory.kt | 8 ++-- .../astramarket/gui/players/PlayersGui.kt | 3 +- .../astramarket/gui/slots/SlotsGui.kt | 3 +- 9 files changed, 84 insertions(+), 81 deletions(-) delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/InventoryLayout.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayout.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/DefaultInventoryLayout.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayout.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayoutBuilder.kt diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/InventoryLayout.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/InventoryLayout.kt deleted file mode 100644 index f89702f..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/InventoryLayout.kt +++ /dev/null @@ -1,13 +0,0 @@ -package ru.astrainteractive.astramarket.api - -interface InventoryLayout { - val size: Int - fun keyAt(index: Int): K - fun indicesOf(key: K): List - fun firstIndexOf(key: K): Int - fun count(key: K): Int - fun mapSlotsNotNull( - key: K, - transform: (index: Int) -> S? - ): List -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayout.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayout.kt deleted file mode 100644 index b9a1996..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayout.kt +++ /dev/null @@ -1,38 +0,0 @@ -package ru.astrainteractive.astramarket.api - -import ru.astrainteractive.astralibs.menu.slot.InventorySlot - -class SlotInventoryLayout( - private val slots: List -) : InventoryLayout { - - override val size: Int get() = slots.size - - override fun keyAt(index: Int): K = slots[index] - - override fun indicesOf(key: K): List = slots.withIndex() - .filter { indexedValue -> indexedValue.value == key } - .map { indexedValue -> indexedValue.index } - - override fun firstIndexOf(key: K): Int = slots.indexOf(key) - .takeIf { index -> index != -1 } - ?: error("Key $key not found in layout") - - override fun count(key: K): Int = slots.count { slotKey -> slotKey == key } - - override fun mapSlotsNotNull( - key: K, - transform: (index: Int) -> InventorySlot? - ): List = indicesOf(key).mapNotNull(transform) -} - -fun SlotInventoryLayout(rows: List>): SlotInventoryLayout { - if (rows.isEmpty()) return SlotInventoryLayout(emptyList()) - - val width = rows.first().size - require(rows.all { row -> row.size == width }) { - "All rows must have the same width" - } - - return SlotInventoryLayout(rows.flatten()) -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt deleted file mode 100644 index b84fd7e..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/SlotInventoryLayoutBuilder.kt +++ /dev/null @@ -1,22 +0,0 @@ -package ru.astrainteractive.astramarket.api - -class SlotInventoryLayoutBuilder { - - private val rows = mutableListOf>() - - fun row(vararg keys: K) { - rows += keys.toList() - } - - fun row(size: Int, key: K) { - rows += List(size) { key } - } - - fun build(): SlotInventoryLayout = SlotInventoryLayout(rows) -} - -fun slotInventoryLayout( - block: SlotInventoryLayoutBuilder.() -> Unit -): SlotInventoryLayout = SlotInventoryLayoutBuilder() - .apply(block) - .build() diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/DefaultInventoryLayout.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/DefaultInventoryLayout.kt new file mode 100644 index 0000000..3e0b871 --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/DefaultInventoryLayout.kt @@ -0,0 +1,37 @@ +package ru.astrainteractive.astramarket.api.layout + +class DefaultInventoryLayout( + private val slots: List +) : InventoryLayout { + + override val size: Int get() = slots.size + + override fun keyAt(index: Int): KEY = slots[index] + + override fun indicesOf(key: KEY): List = slots.withIndex() + .filter { indexedValue -> indexedValue.value == key } + .map { indexedValue -> indexedValue.index } + + override fun firstIndexOf(key: KEY): Int = slots.indexOf(key) + .takeIf { index -> index != -1 } + ?: error("Key $key not found in layout") + + override fun count(key: KEY): Int = slots.count { slotKey -> slotKey == key } + + override fun mapSlotsNotNull( + key: KEY, + transform: (index: Int) -> SLOT? + ): List = indicesOf(key).mapNotNull(transform) +} + +@Suppress("FunctionNaming") +fun DefaultInventoryLayout(rows: List>): InventoryLayout { + if (rows.isEmpty()) return DefaultInventoryLayout(slots = emptyList()) + + val width = rows.first().size + require(rows.all { row -> row.size == width }) { + "All rows must have the same width" + } + + return DefaultInventoryLayout(slots = rows.flatten()) +} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayout.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayout.kt new file mode 100644 index 0000000..77d239d --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayout.kt @@ -0,0 +1,13 @@ +package ru.astrainteractive.astramarket.api.layout + +interface InventoryLayout { + val size: Int + fun keyAt(index: Int): KEY + fun indicesOf(key: KEY): List + fun firstIndexOf(key: KEY): Int + fun count(key: KEY): Int + fun mapSlotsNotNull( + key: KEY, + transform: (index: Int) -> SLOT? + ): List +} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayoutBuilder.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayoutBuilder.kt new file mode 100644 index 0000000..19bd3da --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayoutBuilder.kt @@ -0,0 +1,28 @@ +package ru.astrainteractive.astramarket.api.layout + +import ru.astrainteractive.astralibs.menu.slot.InventorySlot + +class InventoryLayoutBuilder { + + private val rows = mutableListOf>() + + fun row(vararg keys: KEY) { + rows += keys.toList() + } + + fun row(size: Int, key: KEY) { + rows += List(size) { key } + } + + fun build(): InventoryLayout = DefaultInventoryLayout(rows) +} + +fun inventoryLayout( + block: InventoryLayoutBuilder.() -> Unit +): InventoryLayout = InventoryLayoutBuilder() + .apply(block) + .build() + +fun slotInventoryLayout( + block: InventoryLayoutBuilder.() -> Unit +) = inventoryLayout(block) diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt index ad25eac..a020a1b 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt @@ -1,7 +1,6 @@ package ru.astrainteractive.astramarket.gui.layout -import ru.astrainteractive.astramarket.api.SlotInventoryLayout -import ru.astrainteractive.astramarket.api.slotInventoryLayout +import ru.astrainteractive.astramarket.api.layout.slotInventoryLayout @Suppress("MagicNumber") internal object DefaultAuctionInventoryLayoutFactory { @@ -51,7 +50,8 @@ internal object DefaultAuctionInventoryLayoutFactory { ) } - fun create(isCompact: Boolean): SlotInventoryLayout { - return if (isCompact) createCompactLayout() else createBorderedLayout() + fun create(isCompact: Boolean) = when { + isCompact -> createCompactLayout() + else -> createBorderedLayout() } } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt index 226439f..0672802 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt @@ -20,7 +20,6 @@ import ru.astrainteractive.astralibs.menu.slot.InventorySlot import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astralibs.server.player.OnlineKPlayer import ru.astrainteractive.astralibs.server.util.asOnlineMinecraftPlayer -import ru.astrainteractive.astramarket.api.SlotInventoryLayout import ru.astrainteractive.astramarket.gui.button.back import ru.astrainteractive.astramarket.gui.button.di.ButtonContext import ru.astrainteractive.astramarket.gui.button.filterExpired @@ -47,7 +46,7 @@ internal class PlayersGui( KyoriComponentSerializer by dependencies.kyoriComponentSerializer { override val inventorySize: InventorySize = InventorySize.XL - private val inventoryMap: SlotInventoryLayout by lazy { + private val inventoryMap by lazy { DefaultAuctionInventoryLayoutFactory.create(config.auction.useCompactDesign) } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt index 0f2381c..ffc6524 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt @@ -25,7 +25,6 @@ import ru.astrainteractive.astralibs.server.permission.asKPermissible import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astralibs.server.player.OnlineKPlayer import ru.astrainteractive.astralibs.server.util.asOnlineMinecraftPlayer -import ru.astrainteractive.astramarket.api.SlotInventoryLayout import ru.astrainteractive.astramarket.core.PluginPermission import ru.astrainteractive.astramarket.gui.button.auctionSort import ru.astrainteractive.astramarket.gui.button.back @@ -64,7 +63,7 @@ internal class SlotsGui( } override val inventorySize: InventorySize = InventorySize.XL - private val inventoryMap: SlotInventoryLayout by lazy { + private val inventoryMap by lazy { DefaultAuctionInventoryLayoutFactory.create(config.auction.useCompactDesign) } From 288887eb2d9118f590c8adb82d92ce312f1975fd Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 3 May 2026 20:20:40 +0300 Subject: [PATCH 04/10] [FIX] Remove dependencies interface --- .../astramarket/market/di/MarketViewModule.kt | 14 ++++--- .../presentation/DefaultAuctionComponent.kt | 19 +++++++-- .../di/AuctionComponentDependencies.kt | 40 ------------------- .../gui/di/AuctionGuiDependencies.kt | 38 ------------------ .../astramarket/gui/players/PlayersGui.kt | 21 +++++++--- .../astramarket/gui/router/GuiRouterImpl.kt | 21 +++++----- .../astramarket/gui/slots/SlotsGui.kt | 21 +++++++--- 7 files changed, 67 insertions(+), 107 deletions(-) delete mode 100644 modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/presentation/di/AuctionComponentDependencies.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/di/AuctionGuiDependencies.kt diff --git a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/di/MarketViewModule.kt b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/di/MarketViewModule.kt index 67134f6..9f2222a 100644 --- a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/di/MarketViewModule.kt +++ b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/di/MarketViewModule.kt @@ -7,7 +7,7 @@ import ru.astrainteractive.astramarket.market.domain.di.MarketViewDomainModule import ru.astrainteractive.astramarket.market.domain.di.PlatformMarketDomainModule import ru.astrainteractive.astramarket.market.presentation.AuctionComponent import ru.astrainteractive.astramarket.market.presentation.DefaultAuctionComponent -import ru.astrainteractive.astramarket.market.presentation.di.AuctionComponentDependencies +import ru.astrainteractive.klibs.kstorage.api.getValue import java.util.UUID interface MarketViewModule { @@ -43,11 +43,13 @@ interface MarketViewModule { playerUUID = playerUUID, targetPlayerUUID = targetPlayerUUID, isExpired = isExpired, - dependencies = AuctionComponentDependencies.Default( - coreModule = coreModule, - apiMarketModule = apiMarketModule, - marketViewDomainModule = marketViewDomainModule, - ) + configKrate = coreModule.configKrate, + marketApi = apiMarketModule.marketApi, + sortAuctionsUseCase = marketViewDomainModule.platformMarketDomainModule.sortAuctionsUseCase, + removeAuctionUseCase = marketViewDomainModule.removeAuctionUseCase, + auctionBuyUseCase = marketViewDomainModule.auctionBuyUseCase, + expireAuctionUseCase = marketViewDomainModule.expireAuctionUseCase, + playerInteractionBridge = marketViewDomainModule.marketDataModule.playerInteractionBridge ) } } diff --git a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/presentation/DefaultAuctionComponent.kt b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/presentation/DefaultAuctionComponent.kt index 74c1454..e9ea744 100644 --- a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/presentation/DefaultAuctionComponent.kt +++ b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/presentation/DefaultAuctionComponent.kt @@ -4,13 +4,17 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.sync.Mutex import ru.astrainteractive.astralibs.coroutines.withTimings +import ru.astrainteractive.astramarket.api.market.MarketApi import ru.astrainteractive.astramarket.api.market.model.MarketSlot +import ru.astrainteractive.astramarket.core.PluginConfig +import ru.astrainteractive.astramarket.market.data.bridge.PlayerInteractionBridge import ru.astrainteractive.astramarket.market.domain.model.AuctionSort import ru.astrainteractive.astramarket.market.domain.usecase.AuctionBuyUseCase import ru.astrainteractive.astramarket.market.domain.usecase.ExpireAuctionUseCase import ru.astrainteractive.astramarket.market.domain.usecase.RemoveAuctionUseCase import ru.astrainteractive.astramarket.market.domain.usecase.SortAuctionsUseCase -import ru.astrainteractive.astramarket.market.presentation.di.AuctionComponentDependencies +import ru.astrainteractive.klibs.kstorage.api.CachedKrate +import ru.astrainteractive.klibs.kstorage.api.getValue import ru.astrainteractive.klibs.mikro.core.coroutines.CoroutineFeature import ru.astrainteractive.klibs.mikro.core.coroutines.launch import java.util.UUID @@ -20,10 +24,17 @@ internal class DefaultAuctionComponent( private val playerUUID: UUID, private val targetPlayerUUID: UUID?, isExpired: Boolean, - private val dependencies: AuctionComponentDependencies + private val configKrate: CachedKrate, + private val marketApi: MarketApi, + private val sortAuctionsUseCase: SortAuctionsUseCase, + private val removeAuctionUseCase: RemoveAuctionUseCase, + private val auctionBuyUseCase: AuctionBuyUseCase, + private val expireAuctionUseCase: ExpireAuctionUseCase, + private val playerInteractionBridge: PlayerInteractionBridge ) : AuctionComponent, - CoroutineFeature by CoroutineFeature.IO.withTimings(), - AuctionComponentDependencies by dependencies { + CoroutineFeature by CoroutineFeature.IO.withTimings() { + private val config by configKrate + private val mutex = Mutex() override val model = MutableStateFlow( diff --git a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/presentation/di/AuctionComponentDependencies.kt b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/presentation/di/AuctionComponentDependencies.kt deleted file mode 100644 index 07e869a..0000000 --- a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/market/presentation/di/AuctionComponentDependencies.kt +++ /dev/null @@ -1,40 +0,0 @@ -package ru.astrainteractive.astramarket.market.presentation.di - -import ru.astrainteractive.astramarket.api.market.MarketApi -import ru.astrainteractive.astramarket.core.PluginConfig -import ru.astrainteractive.astramarket.core.di.CoreModule -import ru.astrainteractive.astramarket.di.ApiMarketModule -import ru.astrainteractive.astramarket.market.data.bridge.PlayerInteractionBridge -import ru.astrainteractive.astramarket.market.domain.di.MarketViewDomainModule -import ru.astrainteractive.astramarket.market.domain.usecase.AuctionBuyUseCase -import ru.astrainteractive.astramarket.market.domain.usecase.ExpireAuctionUseCase -import ru.astrainteractive.astramarket.market.domain.usecase.RemoveAuctionUseCase -import ru.astrainteractive.astramarket.market.domain.usecase.SortAuctionsUseCase -import ru.astrainteractive.klibs.kstorage.api.getValue -import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers - -internal interface AuctionComponentDependencies { - val config: PluginConfig - val dispatchers: KotlinDispatchers - val marketApi: MarketApi - val auctionBuyUseCase: AuctionBuyUseCase - val expireAuctionUseCase: ExpireAuctionUseCase - val removeAuctionUseCase: RemoveAuctionUseCase - val playerInteractionBridge: PlayerInteractionBridge - val sortAuctionsUseCase: SortAuctionsUseCase - - class Default( - coreModule: CoreModule, - apiMarketModule: ApiMarketModule, - marketViewDomainModule: MarketViewDomainModule, - ) : AuctionComponentDependencies { - override val config: PluginConfig by coreModule.configKrate - override val dispatchers: KotlinDispatchers = coreModule.dispatchers - override val marketApi: MarketApi = apiMarketModule.marketApi - override val auctionBuyUseCase: AuctionBuyUseCase = marketViewDomainModule.auctionBuyUseCase - override val expireAuctionUseCase: ExpireAuctionUseCase = marketViewDomainModule.expireAuctionUseCase - override val removeAuctionUseCase: RemoveAuctionUseCase = marketViewDomainModule.removeAuctionUseCase - override val playerInteractionBridge = marketViewDomainModule.marketDataModule.playerInteractionBridge - override val sortAuctionsUseCase = marketViewDomainModule.platformMarketDomainModule.sortAuctionsUseCase - } -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/di/AuctionGuiDependencies.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/di/AuctionGuiDependencies.kt deleted file mode 100644 index f55ba39..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/di/AuctionGuiDependencies.kt +++ /dev/null @@ -1,38 +0,0 @@ -package ru.astrainteractive.astramarket.gui.di - -import ru.astrainteractive.astralibs.kyori.KyoriComponentSerializer -import ru.astrainteractive.astramarket.core.PluginConfig -import ru.astrainteractive.astramarket.core.PluginTranslation -import ru.astrainteractive.astramarket.core.di.BukkitCoreModule -import ru.astrainteractive.astramarket.core.di.CoreModule -import ru.astrainteractive.astramarket.core.itemstack.ItemStackEncoder -import ru.astrainteractive.astramarket.gui.router.GuiRouter -import ru.astrainteractive.astramarket.market.domain.di.MarketViewDomainModule -import ru.astrainteractive.astramarket.market.domain.mapping.AuctionSortTranslationMapping -import ru.astrainteractive.klibs.kstorage.api.getValue -import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers - -internal interface AuctionGuiDependencies { - val config: PluginConfig - val pluginTranslation: PluginTranslation - val dispatchers: KotlinDispatchers - val sortTranslationMapping: AuctionSortTranslationMapping - val itemStackEncoder: ItemStackEncoder - val kyoriComponentSerializer: KyoriComponentSerializer - val router: GuiRouter - - class Default( - coreModule: CoreModule, - marketViewDomainModule: MarketViewDomainModule, - bukkitCoreModule: BukkitCoreModule, - override val router: GuiRouter - ) : AuctionGuiDependencies { - override val config: PluginConfig by coreModule.configKrate - override val pluginTranslation: PluginTranslation by coreModule.pluginTranslationKrate - override val kyoriComponentSerializer by bukkitCoreModule.kyoriKrate - - override val dispatchers: KotlinDispatchers = coreModule.dispatchers - override val sortTranslationMapping = marketViewDomainModule.auctionSortTranslationMapping - override val itemStackEncoder = bukkitCoreModule.itemStackEncoder - } -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt index 0672802..da7b7b0 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt @@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.onEach import net.kyori.adventure.text.Component import org.bukkit.event.inventory.InventoryClickEvent import ru.astrainteractive.astralibs.kyori.KyoriComponentSerializer +import ru.astrainteractive.astralibs.kyori.unwrap import ru.astrainteractive.astralibs.menu.holder.DefaultPlayerHolder import ru.astrainteractive.astralibs.menu.inventory.PaginatedInventoryMenu import ru.astrainteractive.astralibs.menu.inventory.model.InventorySize @@ -20,6 +21,8 @@ import ru.astrainteractive.astralibs.menu.slot.InventorySlot import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astralibs.server.player.OnlineKPlayer import ru.astrainteractive.astralibs.server.util.asOnlineMinecraftPlayer +import ru.astrainteractive.astramarket.core.PluginConfig +import ru.astrainteractive.astramarket.core.PluginTranslation import ru.astrainteractive.astramarket.gui.button.back import ru.astrainteractive.astramarket.gui.button.di.ButtonContext import ru.astrainteractive.astramarket.gui.button.filterExpired @@ -28,29 +31,37 @@ import ru.astrainteractive.astramarket.gui.button.playerItem import ru.astrainteractive.astramarket.gui.button.playersSort import ru.astrainteractive.astramarket.gui.button.prevPage import ru.astrainteractive.astramarket.gui.button.slotsType -import ru.astrainteractive.astramarket.gui.di.AuctionGuiDependencies import ru.astrainteractive.astramarket.gui.layout.AuctionSlotKey import ru.astrainteractive.astramarket.gui.layout.DefaultAuctionInventoryLayoutFactory import ru.astrainteractive.astramarket.gui.router.GuiRouter import ru.astrainteractive.astramarket.gui.util.ItemStackExt.playSound import ru.astrainteractive.astramarket.players.presentation.PlayersMarketComponent +import ru.astrainteractive.klibs.kstorage.api.CachedKrate +import ru.astrainteractive.klibs.kstorage.api.getValue +import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers import ru.astrainteractive.klibs.mikro.core.util.cast internal class PlayersGui( private val playersMarketComponent: PlayersMarketComponent, player: OnlineKPlayer, - dependencies: AuctionGuiDependencies, + private val configKrate: CachedKrate, + private val translationKrate: CachedKrate, + private val dispatchers: KotlinDispatchers, + private val router: GuiRouter, + kyoriKrate: CachedKrate, private val buttonContext: ButtonContext ) : PaginatedInventoryMenu(), - AuctionGuiDependencies by dependencies, - KyoriComponentSerializer by dependencies.kyoriComponentSerializer { + KyoriComponentSerializer by kyoriKrate.unwrap() { + private val config by configKrate + private val translation by translationKrate + override val inventorySize: InventorySize = InventorySize.XL private val inventoryMap by lazy { DefaultAuctionInventoryLayoutFactory.create(config.auction.useCompactDesign) } - override val title: Component = pluginTranslation.menu.market.component + override val title: Component = translation.menu.market.component override val playerHolder = DefaultPlayerHolder(player.cast().instance) diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouterImpl.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouterImpl.kt index 42f73db..080a36f 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouterImpl.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouterImpl.kt @@ -5,11 +5,11 @@ import kotlinx.coroutines.withContext import ru.astrainteractive.astramarket.core.di.BukkitCoreModule import ru.astrainteractive.astramarket.core.di.CoreModule import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.di.AuctionGuiDependencies import ru.astrainteractive.astramarket.gui.players.PlayersGui import ru.astrainteractive.astramarket.gui.slots.SlotsGui import ru.astrainteractive.astramarket.market.di.MarketViewModule import ru.astrainteractive.astramarket.players.di.PlayersMarketViewModule +import ru.astrainteractive.klibs.kstorage.api.getValue internal class GuiRouterImpl( private val coreModule: CoreModule, @@ -17,12 +17,7 @@ internal class GuiRouterImpl( private val bukkitCoreModule: BukkitCoreModule, private val playersMarketViewModule: PlayersMarketViewModule ) : GuiRouter { - private val dependencies = AuctionGuiDependencies.Default( - coreModule = coreModule, - marketViewDomainModule = marketViewModule.marketViewDomainModule, - bukkitCoreModule = bukkitCoreModule, - router = this@GuiRouterImpl - ) + private val buttonContext = ButtonContext.Default( coreModule = coreModule, marketViewDomainModule = marketViewModule.marketViewDomainModule, @@ -36,7 +31,11 @@ internal class GuiRouterImpl( is GuiRouter.Route.Slots -> { SlotsGui( player = route.player, - dependencies = dependencies, + configKrate = coreModule.configKrate, + translationKrate = coreModule.pluginTranslationKrate, + dispatchers = coreModule.dispatchers, + router = this@GuiRouterImpl, + kyoriKrate = coreModule.kyoriKrate, buttonContext = buttonContext, auctionComponent = marketViewModule.createAuctionComponent( playerUUID = route.player.uuid, @@ -49,7 +48,11 @@ internal class GuiRouterImpl( is GuiRouter.Route.Players -> { PlayersGui( player = route.player, - dependencies = dependencies, + configKrate = coreModule.configKrate, + translationKrate = coreModule.pluginTranslationKrate, + dispatchers = coreModule.dispatchers, + router = this@GuiRouterImpl, + kyoriKrate = coreModule.kyoriKrate, buttonContext = buttonContext, playersMarketComponent = playersMarketViewModule.createPlayersMarketComponent( isExpired = route.isExpired diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt index ffc6524..8cbf285 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt @@ -10,6 +10,7 @@ import org.bukkit.event.inventory.ClickType import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.InventoryCloseEvent import ru.astrainteractive.astralibs.kyori.KyoriComponentSerializer +import ru.astrainteractive.astralibs.kyori.unwrap import ru.astrainteractive.astralibs.menu.holder.DefaultPlayerHolder import ru.astrainteractive.astralibs.menu.inventory.PaginatedInventoryMenu import ru.astrainteractive.astralibs.menu.inventory.model.InventorySize @@ -25,7 +26,9 @@ import ru.astrainteractive.astralibs.server.permission.asKPermissible import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astralibs.server.player.OnlineKPlayer import ru.astrainteractive.astralibs.server.util.asOnlineMinecraftPlayer +import ru.astrainteractive.astramarket.core.PluginConfig import ru.astrainteractive.astramarket.core.PluginPermission +import ru.astrainteractive.astramarket.core.PluginTranslation import ru.astrainteractive.astramarket.gui.button.auctionSort import ru.astrainteractive.astramarket.gui.button.back import ru.astrainteractive.astramarket.gui.button.border @@ -35,22 +38,30 @@ import ru.astrainteractive.astramarket.gui.button.filterExpired import ru.astrainteractive.astramarket.gui.button.nextPage import ru.astrainteractive.astramarket.gui.button.prevPage import ru.astrainteractive.astramarket.gui.button.slotsType -import ru.astrainteractive.astramarket.gui.di.AuctionGuiDependencies import ru.astrainteractive.astramarket.gui.layout.AuctionSlotKey import ru.astrainteractive.astramarket.gui.layout.DefaultAuctionInventoryLayoutFactory import ru.astrainteractive.astramarket.gui.router.GuiRouter import ru.astrainteractive.astramarket.gui.util.ItemStackExt.playSound import ru.astrainteractive.astramarket.market.presentation.AuctionComponent +import ru.astrainteractive.klibs.kstorage.api.CachedKrate +import ru.astrainteractive.klibs.kstorage.api.getValue +import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers import ru.astrainteractive.klibs.mikro.core.util.cast internal class SlotsGui( player: OnlineKPlayer, - dependencies: AuctionGuiDependencies, + private val configKrate: CachedKrate, + private val translationKrate: CachedKrate, + private val dispatchers: KotlinDispatchers, + private val router: GuiRouter, + kyoriKrate: CachedKrate, private val buttonContext: ButtonContext, private val auctionComponent: AuctionComponent ) : PaginatedInventoryMenu(), - AuctionGuiDependencies by dependencies, - KyoriComponentSerializer by dependencies.kyoriComponentSerializer { + KyoriComponentSerializer by kyoriKrate.unwrap() { + private val config by configKrate + private val translation by translationKrate + override val playerHolder = DefaultPlayerHolder(player.cast().instance) override val title: Component = let { val playerNameComponent = auctionComponent.model.value @@ -59,7 +70,7 @@ internal class SlotsGui( ?.name ?.let { name -> Component.text(": $name") } ?: Component.empty() - pluginTranslation.menu.market.component.append(playerNameComponent) + translation.menu.market.component.append(playerNameComponent) } override val inventorySize: InventorySize = InventorySize.XL From c231a217945b15337fd57df0ac3526e6cf686faf Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 3 May 2026 20:22:31 +0300 Subject: [PATCH 05/10] [FIX] Remove dependencies interface --- .../astramarket/gui/players/PlayersGui.kt | 10 +++++----- .../astrainteractive/astramarket/gui/slots/SlotsGui.kt | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt index da7b7b0..7484dd2 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt @@ -42,14 +42,14 @@ import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers import ru.astrainteractive.klibs.mikro.core.util.cast internal class PlayersGui( - private val playersMarketComponent: PlayersMarketComponent, player: OnlineKPlayer, - private val configKrate: CachedKrate, - private val translationKrate: CachedKrate, + configKrate: CachedKrate, + kyoriKrate: CachedKrate, + translationKrate: CachedKrate, + private val buttonContext: ButtonContext, private val dispatchers: KotlinDispatchers, + private val playersMarketComponent: PlayersMarketComponent, private val router: GuiRouter, - kyoriKrate: CachedKrate, - private val buttonContext: ButtonContext ) : PaginatedInventoryMenu(), KyoriComponentSerializer by kyoriKrate.unwrap() { private val config by configKrate diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt index 8cbf285..2fbb79c 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt @@ -50,11 +50,11 @@ import ru.astrainteractive.klibs.mikro.core.util.cast internal class SlotsGui( player: OnlineKPlayer, - private val configKrate: CachedKrate, - private val translationKrate: CachedKrate, - private val dispatchers: KotlinDispatchers, - private val router: GuiRouter, + configKrate: CachedKrate, + translationKrate: CachedKrate, + dispatchers: KotlinDispatchers, kyoriKrate: CachedKrate, + private val router: GuiRouter, private val buttonContext: ButtonContext, private val auctionComponent: AuctionComponent ) : PaginatedInventoryMenu(), From 7a4826236ebf2a0c3f84b6bc4a08f7daf83f177e Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 3 May 2026 20:31:04 +0300 Subject: [PATCH 06/10] [FIX] Move InventoryLayout.kt to AstraLibs --- gradle/libs.versions.toml | 2 +- .../api/layout/DefaultInventoryLayout.kt | 37 ------------------- .../astramarket/api/layout/InventoryLayout.kt | 13 ------- .../api/layout/InventoryLayoutBuilder.kt | 28 -------------- .../DefaultAuctionInventoryLayoutFactory.kt | 2 +- 5 files changed, 2 insertions(+), 80 deletions(-) delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/DefaultInventoryLayout.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayout.kt delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayoutBuilder.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 323bd94..49999bb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ kotlin-serialization = "1.11.0" kotlin-serialization-kaml = "0.104.0" kotlin-version = "2.2.0" ktor = "3.4.3" -minecraft-astralibs = "3.36.2" +minecraft-astralibs = "3.37.0" minecraft-brigadier = "1.3.10" minecraft-bstats = "3.2.1" minecraft-bungee = "26.1-R0.1-SNAPSHOT" diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/DefaultInventoryLayout.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/DefaultInventoryLayout.kt deleted file mode 100644 index 3e0b871..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/DefaultInventoryLayout.kt +++ /dev/null @@ -1,37 +0,0 @@ -package ru.astrainteractive.astramarket.api.layout - -class DefaultInventoryLayout( - private val slots: List -) : InventoryLayout { - - override val size: Int get() = slots.size - - override fun keyAt(index: Int): KEY = slots[index] - - override fun indicesOf(key: KEY): List = slots.withIndex() - .filter { indexedValue -> indexedValue.value == key } - .map { indexedValue -> indexedValue.index } - - override fun firstIndexOf(key: KEY): Int = slots.indexOf(key) - .takeIf { index -> index != -1 } - ?: error("Key $key not found in layout") - - override fun count(key: KEY): Int = slots.count { slotKey -> slotKey == key } - - override fun mapSlotsNotNull( - key: KEY, - transform: (index: Int) -> SLOT? - ): List = indicesOf(key).mapNotNull(transform) -} - -@Suppress("FunctionNaming") -fun DefaultInventoryLayout(rows: List>): InventoryLayout { - if (rows.isEmpty()) return DefaultInventoryLayout(slots = emptyList()) - - val width = rows.first().size - require(rows.all { row -> row.size == width }) { - "All rows must have the same width" - } - - return DefaultInventoryLayout(slots = rows.flatten()) -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayout.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayout.kt deleted file mode 100644 index 77d239d..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayout.kt +++ /dev/null @@ -1,13 +0,0 @@ -package ru.astrainteractive.astramarket.api.layout - -interface InventoryLayout { - val size: Int - fun keyAt(index: Int): KEY - fun indicesOf(key: KEY): List - fun firstIndexOf(key: KEY): Int - fun count(key: KEY): Int - fun mapSlotsNotNull( - key: KEY, - transform: (index: Int) -> SLOT? - ): List -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayoutBuilder.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayoutBuilder.kt deleted file mode 100644 index 19bd3da..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/api/layout/InventoryLayoutBuilder.kt +++ /dev/null @@ -1,28 +0,0 @@ -package ru.astrainteractive.astramarket.api.layout - -import ru.astrainteractive.astralibs.menu.slot.InventorySlot - -class InventoryLayoutBuilder { - - private val rows = mutableListOf>() - - fun row(vararg keys: KEY) { - rows += keys.toList() - } - - fun row(size: Int, key: KEY) { - rows += List(size) { key } - } - - fun build(): InventoryLayout = DefaultInventoryLayout(rows) -} - -fun inventoryLayout( - block: InventoryLayoutBuilder.() -> Unit -): InventoryLayout = InventoryLayoutBuilder() - .apply(block) - .build() - -fun slotInventoryLayout( - block: InventoryLayoutBuilder.() -> Unit -) = inventoryLayout(block) diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt index a020a1b..dc617e7 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/layout/DefaultAuctionInventoryLayoutFactory.kt @@ -1,6 +1,6 @@ package ru.astrainteractive.astramarket.gui.layout -import ru.astrainteractive.astramarket.api.layout.slotInventoryLayout +import ru.astrainteractive.astralibs.menu.layout.slotInventoryLayout @Suppress("MagicNumber") internal object DefaultAuctionInventoryLayoutFactory { From 889fc71fa8766478b1ebc866303d7141b5487522 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 10 May 2026 08:58:50 +0300 Subject: [PATCH 07/10] [FIX] Update AstraLibs --- gradle/libs.versions.toml | 2 +- .../command/auction/AuctionCommandExecutor.kt | 4 +- .../astramarket/gui/router/GuiRouter.kt | 8 +- .../presentation/PlayersMarketComponent.kt | 3 +- .../gui/button/AuctionSortButton.kt | 13 +- .../astramarket/gui/button/BackButton.kt | 10 +- .../astramarket/gui/button/BorderButton.kt | 8 +- .../gui/button/DisplayTypeButton.kt | 12 +- .../gui/button/ExpiredSlotButton.kt | 13 +- .../gui/button/FilterExpiredButton.kt | 12 +- .../astramarket/gui/button/NextPageButton.kt | 10 +- .../gui/button/PlayerItemButton.kt | 12 +- .../gui/button/PlayersSortButton.kt | 12 +- .../astramarket/gui/button/PrevPageButton.kt | 10 +- .../button/util/InventorySlotBuilderExt.kt | 11 -- .../astramarket/gui/players/PlayersGui.kt | 116 +++++++-------- .../astramarket/gui/router/GuiRouterImpl.kt | 20 +-- .../astramarket/gui/slots/SlotsGui.kt | 136 +++++++++--------- .../astramarket/gui/util/DurationExt.kt | 24 ++-- .../astramarket/gui/util/ItemStackExt.kt | 17 +-- .../astramarket/gui/util/OnlineKPlayerExt.kt | 13 ++ .../astramarket/gui/util/PlayerExt.kt | 7 + 22 files changed, 238 insertions(+), 235 deletions(-) delete mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/util/InventorySlotBuilderExt.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/OnlineKPlayerExt.kt create mode 100644 modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/PlayerExt.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 49999bb..897cfd8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ kotlin-serialization = "1.11.0" kotlin-serialization-kaml = "0.104.0" kotlin-version = "2.2.0" ktor = "3.4.3" -minecraft-astralibs = "3.37.0" +minecraft-astralibs = "3.38.0" minecraft-brigadier = "1.3.10" minecraft-bstats = "3.2.1" minecraft-bungee = "26.1-R0.1-SNAPSHOT" diff --git a/modules/command-bukkit/src/main/kotlin/ru/astrainteractive/astramarket/command/auction/AuctionCommandExecutor.kt b/modules/command-bukkit/src/main/kotlin/ru/astrainteractive/astramarket/command/auction/AuctionCommandExecutor.kt index c2679aa..af2eaef 100644 --- a/modules/command-bukkit/src/main/kotlin/ru/astrainteractive/astramarket/command/auction/AuctionCommandExecutor.kt +++ b/modules/command-bukkit/src/main/kotlin/ru/astrainteractive/astramarket/command/auction/AuctionCommandExecutor.kt @@ -28,7 +28,7 @@ internal class AuctionCommandExecutor( when (input) { is AuctionCommand.Result.OpenSlots -> { val route = GuiRouter.Route.Slots( - player = input.player, + inventoryOwner = input.player, isExpired = input.isExpired, targetPlayerUUID = input.targetPlayerUUID ) @@ -37,7 +37,7 @@ internal class AuctionCommandExecutor( is AuctionCommand.Result.OpenPlayers -> { val route = GuiRouter.Route.Players( - player = input.player, + inventoryOwner = input.player, isExpired = input.isExpired ) router.navigate(route) diff --git a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouter.kt b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouter.kt index e1ca18c..229eb1e 100644 --- a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouter.kt +++ b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouter.kt @@ -5,19 +5,21 @@ import java.util.UUID interface GuiRouter { sealed interface Route { + val inventoryOwner: OnlineKPlayer + /** - * @param player player who opened route + * @param inventoryOwner player who opened route * @param isExpired expired auctions * @param targetPlayerUUID only this player auctions will be shown */ class Slots( - val player: OnlineKPlayer, + override val inventoryOwner: OnlineKPlayer, val isExpired: Boolean, val targetPlayerUUID: UUID? ) : Route class Players( - val player: OnlineKPlayer, + override val inventoryOwner: OnlineKPlayer, val isExpired: Boolean ) : Route } diff --git a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/players/presentation/PlayersMarketComponent.kt b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/players/presentation/PlayersMarketComponent.kt index 7e4f04b..02ae2b0 100644 --- a/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/players/presentation/PlayersMarketComponent.kt +++ b/modules/gui/api/src/main/kotlin/ru/astrainteractive/astramarket/players/presentation/PlayersMarketComponent.kt @@ -1,10 +1,11 @@ package ru.astrainteractive.astramarket.players.presentation +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import ru.astrainteractive.astramarket.api.market.model.PlayerAndSlots import ru.astrainteractive.astramarket.players.model.PlayerSort -interface PlayersMarketComponent { +interface PlayersMarketComponent : CoroutineScope { val model: StateFlow fun toggleExpired() diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/AuctionSortButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/AuctionSortButton.kt index 21a77df..4d7f03b 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/AuctionSortButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/AuctionSortButton.kt @@ -2,15 +2,14 @@ package ru.astrainteractive.astramarket.gui.button import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.addLore -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setDisplayName -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.addLore +import ru.astrainteractive.astralibs.menu.slot.setDisplayName +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astralibs.string.plus import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.button.util.InventorySlotBuilderExt.addLore -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.toItemStack +import ru.astrainteractive.astramarket.gui.util.toItemStack import ru.astrainteractive.astramarket.market.domain.model.AuctionSort internal fun ButtonContext.auctionSort( diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/BackButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/BackButton.kt index 5f03604..762bf79 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/BackButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/BackButton.kt @@ -2,12 +2,12 @@ package ru.astrainteractive.astramarket.gui.button import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.editMeta -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.editMeta +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.toItemStack +import ru.astrainteractive.astramarket.gui.util.toItemStack internal fun ButtonContext.back( index: Int, diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/BorderButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/BorderButton.kt index c7605b1..1e44ff2 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/BorderButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/BorderButton.kt @@ -1,11 +1,11 @@ package ru.astrainteractive.astramarket.gui.button import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setDisplayName -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setDisplayName +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.toItemStack +import ru.astrainteractive.astramarket.gui.util.toItemStack internal fun ButtonContext.border(index: Int) = InventorySlot.Builder() .setIndex(index) diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/DisplayTypeButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/DisplayTypeButton.kt index 4392be0..3848b2e 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/DisplayTypeButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/DisplayTypeButton.kt @@ -2,14 +2,14 @@ package ru.astrainteractive.astramarket.gui.button import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setDisplayName -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.addLore +import ru.astrainteractive.astralibs.menu.slot.setDisplayName +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astralibs.string.plus import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.button.util.InventorySlotBuilderExt.addLore -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.toItemStack +import ru.astrainteractive.astramarket.gui.util.toItemStack internal fun ButtonContext.slotsType( index: Int, diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/ExpiredSlotButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/ExpiredSlotButton.kt index 4805026..5f4adc4 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/ExpiredSlotButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/ExpiredSlotButton.kt @@ -3,15 +3,14 @@ package ru.astrainteractive.astramarket.gui.button import org.bukkit.Bukkit import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.addLore -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.addLore +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astramarket.api.market.model.MarketSlot import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.button.util.InventorySlotBuilderExt.addLore -import ru.astrainteractive.astramarket.gui.util.DurationExt.getTimeFormatted -import java.util.UUID +import ru.astrainteractive.astramarket.gui.util.getTimeFormatted +import java.util.* import kotlin.time.Duration.Companion.milliseconds @Suppress("LongParameterList") diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/FilterExpiredButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/FilterExpiredButton.kt index 5dbdbd0..0d72ac7 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/FilterExpiredButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/FilterExpiredButton.kt @@ -2,15 +2,15 @@ package ru.astrainteractive.astramarket.gui.button import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setDisplayName -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.addLore +import ru.astrainteractive.astralibs.menu.slot.setDisplayName +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astralibs.string.StringDesc import ru.astrainteractive.astralibs.string.plus import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.button.util.InventorySlotBuilderExt.addLore -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.toItemStack +import ru.astrainteractive.astramarket.gui.util.toItemStack internal fun ButtonContext.filterExpired( index: Int, diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/NextPageButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/NextPageButton.kt index 24ae525..b6e15f9 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/NextPageButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/NextPageButton.kt @@ -2,12 +2,12 @@ package ru.astrainteractive.astramarket.gui.button import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.editMeta -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.editMeta +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.toItemStack +import ru.astrainteractive.astramarket.gui.util.toItemStack internal fun ButtonContext.nextPage( index: Int, diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayerItemButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayerItemButton.kt index faba102..85220ba 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayerItemButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayerItemButton.kt @@ -6,14 +6,14 @@ import org.bukkit.Material import org.bukkit.inventory.meta.SkullMeta import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.editMeta -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setMaterial -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.addLore +import ru.astrainteractive.astralibs.menu.slot.editMeta +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setMaterial +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astramarket.api.market.model.PlayerAndSlots import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.button.util.InventorySlotBuilderExt.addLore -import ru.astrainteractive.astramarket.gui.util.DurationExt.getTimeFormatted +import ru.astrainteractive.astramarket.gui.util.getTimeFormatted import kotlin.time.Duration.Companion.milliseconds internal fun ButtonContext.playerItem( diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayersSortButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayersSortButton.kt index e410593..55be3a0 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayersSortButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayersSortButton.kt @@ -2,14 +2,14 @@ package ru.astrainteractive.astramarket.gui.button import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setDisplayName -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.addLore +import ru.astrainteractive.astralibs.menu.slot.setDisplayName +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astralibs.string.plus import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.button.util.InventorySlotBuilderExt.addLore -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.toItemStack +import ru.astrainteractive.astramarket.gui.util.toItemStack import ru.astrainteractive.astramarket.players.model.PlayerSort internal fun ButtonContext.playersSort( diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PrevPageButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PrevPageButton.kt index 377debf..c2a2378 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PrevPageButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PrevPageButton.kt @@ -2,12 +2,12 @@ package ru.astrainteractive.astramarket.gui.button import ru.astrainteractive.astralibs.menu.clicker.Click import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.editMeta -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setIndex -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setItemStack -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.setOnClickListener +import ru.astrainteractive.astralibs.menu.slot.editMeta +import ru.astrainteractive.astralibs.menu.slot.setIndex +import ru.astrainteractive.astralibs.menu.slot.setItemStack +import ru.astrainteractive.astralibs.menu.slot.setOnClickListener import ru.astrainteractive.astramarket.gui.button.di.ButtonContext -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.toItemStack +import ru.astrainteractive.astramarket.gui.util.toItemStack internal fun ButtonContext.prevPage( index: Int, diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/util/InventorySlotBuilderExt.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/util/InventorySlotBuilderExt.kt deleted file mode 100644 index f56d456..0000000 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/util/InventorySlotBuilderExt.kt +++ /dev/null @@ -1,11 +0,0 @@ -package ru.astrainteractive.astramarket.gui.button.util - -import net.kyori.adventure.text.Component -import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.menu.slot.util.InventorySlotBuilderExt.addLore - -object InventorySlotBuilderExt { - fun InventorySlot.Builder.addLore(component: () -> Component): InventorySlot.Builder { - return addLore(component.invoke()) - } -} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt index 7484dd2..c9c4771 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt @@ -1,26 +1,26 @@ package ru.astrainteractive.astramarket.gui.players -import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.withContext import net.kyori.adventure.text.Component import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.event.inventory.InventoryOpenEvent +import ru.astrainteractive.astralibs.coroutines.withTimings import ru.astrainteractive.astralibs.kyori.KyoriComponentSerializer import ru.astrainteractive.astralibs.kyori.unwrap -import ru.astrainteractive.astralibs.menu.holder.DefaultPlayerHolder -import ru.astrainteractive.astralibs.menu.inventory.PaginatedInventoryMenu +import ru.astrainteractive.astralibs.menu.core.setInventorySlot +import ru.astrainteractive.astralibs.menu.inventory.api.InventoryMenu import ru.astrainteractive.astralibs.menu.inventory.model.InventorySize -import ru.astrainteractive.astralibs.menu.inventory.model.PageContext -import ru.astrainteractive.astralibs.menu.inventory.util.PageContextExt.indexOfSlot -import ru.astrainteractive.astralibs.menu.inventory.util.PageContextExt.isFirstPage -import ru.astrainteractive.astralibs.menu.inventory.util.PageContextExt.isLastPage -import ru.astrainteractive.astralibs.menu.inventory.util.PaginatedInventoryMenuExt.showNextPage -import ru.astrainteractive.astralibs.menu.inventory.util.PaginatedInventoryMenuExt.showPage -import ru.astrainteractive.astralibs.menu.inventory.util.PaginatedInventoryMenuExt.showPrevPage +import ru.astrainteractive.astralibs.menu.paginator.api.DefaultPaginator +import ru.astrainteractive.astralibs.menu.paginator.api.context +import ru.astrainteractive.astralibs.menu.paginator.api.openNextPage +import ru.astrainteractive.astralibs.menu.paginator.api.openPrevPage +import ru.astrainteractive.astralibs.menu.paginator.model.indexOfSlot +import ru.astrainteractive.astralibs.menu.paginator.model.isFirstPage +import ru.astrainteractive.astralibs.menu.paginator.model.isLastPage import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astralibs.server.player.OnlineKPlayer -import ru.astrainteractive.astralibs.server.util.asOnlineMinecraftPlayer import ru.astrainteractive.astramarket.core.PluginConfig import ru.astrainteractive.astramarket.core.PluginTranslation import ru.astrainteractive.astramarket.gui.button.back @@ -34,58 +34,59 @@ import ru.astrainteractive.astramarket.gui.button.slotsType import ru.astrainteractive.astramarket.gui.layout.AuctionSlotKey import ru.astrainteractive.astramarket.gui.layout.DefaultAuctionInventoryLayoutFactory import ru.astrainteractive.astramarket.gui.router.GuiRouter -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.playSound +import ru.astrainteractive.astramarket.gui.util.closeInventory +import ru.astrainteractive.astramarket.gui.util.playSound import ru.astrainteractive.astramarket.players.presentation.PlayersMarketComponent import ru.astrainteractive.klibs.kstorage.api.CachedKrate import ru.astrainteractive.klibs.kstorage.api.getValue +import ru.astrainteractive.klibs.mikro.core.coroutines.CoroutineFeature import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers -import ru.astrainteractive.klibs.mikro.core.util.cast internal class PlayersGui( - player: OnlineKPlayer, configKrate: CachedKrate, kyoriKrate: CachedKrate, translationKrate: CachedKrate, + private val inventoryOwner: OnlineKPlayer, private val buttonContext: ButtonContext, private val dispatchers: KotlinDispatchers, private val playersMarketComponent: PlayersMarketComponent, private val router: GuiRouter, -) : PaginatedInventoryMenu(), +) : InventoryMenu(), KyoriComponentSerializer by kyoriKrate.unwrap() { private val config by configKrate private val translation by translationKrate override val inventorySize: InventorySize = InventorySize.XL + override val childComponents = listOf(playersMarketComponent) + override val menuScope = CoroutineFeature + .Default(dispatchers.Main) + .withTimings() private val inventoryMap by lazy { DefaultAuctionInventoryLayoutFactory.create(config.auction.useCompactDesign) } override val title: Component = translation.menu.market.component - override val playerHolder = DefaultPlayerHolder(player.cast().instance) - - override var pageContext: PageContext = PageContext( - page = 0, - maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AUCTION_ITEM), - maxItems = 0 + private val paginator = DefaultPaginator( + maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AUCTION_ITEM) ) - override val prevPageButton: InventorySlot + private val prevPageButton: InventorySlot get() = buttonContext.prevPage( index = inventoryMap.firstIndexOf(AuctionSlotKey.PREV_PAGE), click = { - playerHolder.player.playSound(config.sounds.open) - showPrevPage() + inventoryOwner.playSound(config.sounds.open) + paginator.openPrevPage() } ) - override val nextPageButton: InventorySlot + private val nextPageButton: InventorySlot get() = buttonContext.nextPage( index = inventoryMap.firstIndexOf(AuctionSlotKey.NEXT_PAGE), click = { - playerHolder.player.playSound(config.sounds.open) - showNextPage() + inventoryOwner.playSound(config.sounds.open) + paginator.openNextPage() } ) @@ -94,7 +95,7 @@ internal class PlayersGui( index = inventoryMap.firstIndexOf(AuctionSlotKey.SORT), sortType = playersMarketComponent.model.value.sort, click = { - playerHolder.player.playSound(config.sounds.open) + inventoryOwner.playSound(config.sounds.open) playersMarketComponent.onSortButtonClicked(it.isRightClick) } ) @@ -104,8 +105,8 @@ internal class PlayersGui( index = inventoryMap.firstIndexOf(AuctionSlotKey.FILTER_EXPIRED), isExpired = playersMarketComponent.model.value.isExpired, click = { - playerHolder.player.playSound(config.sounds.open) - showPage(0) + inventoryOwner.playSound(config.sounds.open) + paginator.openPage(0) playersMarketComponent.toggleExpired() } ) @@ -116,7 +117,7 @@ internal class PlayersGui( isGroupedByPlayers = true, click = { val route = GuiRouter.Route.Slots( - player = playerHolder.player.asOnlineMinecraftPlayer(), + inventoryOwner = inventoryOwner, isExpired = playersMarketComponent.model.value.isExpired, targetPlayerUUID = null ) @@ -127,7 +128,7 @@ internal class PlayersGui( private val closeButton: InventorySlot get() = buttonContext.back( index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), - click = { playerHolder.player.closeInventory() } + click = { inventoryOwner.closeInventory() } ) private val slots: List @@ -135,7 +136,7 @@ internal class PlayersGui( var itemIndex = 0 val isExpired = playersMarketComponent.model.value.isExpired return inventoryMap.mapSlotsNotNull(AuctionSlotKey.AUCTION_ITEM) { slotIndex -> - val index = pageContext.indexOfSlot(itemIndex) + val index = paginator.context.indexOfSlot(itemIndex) itemIndex++ val items = playersMarketComponent.model .value @@ -148,7 +149,7 @@ internal class PlayersGui( isExpired = playersMarketComponent.model.value.isExpired, click = { val route = GuiRouter.Route.Slots( - player = playerHolder.player.asOnlineMinecraftPlayer(), + inventoryOwner = inventoryOwner, isExpired = playersMarketComponent.model.value.isExpired, targetPlayerUUID = items.minecraftUUID ) @@ -158,35 +159,36 @@ internal class PlayersGui( } } - override fun onInventoryClicked(e: InventoryClickEvent) { - super.onInventoryClicked(e) - e.isCancelled = true - } - private fun updatePageContext(model: PlayersMarketComponent.Model) { - pageContext = pageContext.copy( - maxItems = model.playersAndSlots - .filter { it.slots.any { slot -> slot.expired == model.isExpired } } - .size - ) + paginator.update { paginatorContext -> + paginatorContext.copy( + maxItems = model.playersAndSlots + .filter { it.slots.any { slot -> slot.expired == model.isExpired } } + .size + ) + } } - override fun render() { - super.render() - if (!pageContext.isFirstPage) prevPageButton.setInventorySlot() - if (!pageContext.isLastPage) nextPageButton.setInventorySlot() - sortButton.setInventorySlot() - expiredButton.setInventorySlot() - closeButton.setInventorySlot() - allSlots.setInventorySlot() - slots.forEach { slot -> slot.setInventorySlot() } + override fun onInventoryClickEvent(e: InventoryClickEvent) { + super.onInventoryClickEvent(e) + e.isCancelled = true } - override fun onInventoryCreated() { + override fun onInventoryOpenEvent(e: InventoryOpenEvent) { playersMarketComponent.model .onEach { model -> updatePageContext(model) } - .onEach { render() } - .flowOn(dispatchers.IO) + .onEach { withContext(dispatchers.Main) { render() } } .launchIn(menuScope) } + + override fun render() { + super.render() + if (!paginator.context.isFirstPage) setInventorySlot(prevPageButton) + if (!paginator.context.isLastPage) setInventorySlot(nextPageButton) + setInventorySlot(sortButton) + setInventorySlot(expiredButton) + setInventorySlot(closeButton) + setInventorySlot(allSlots) + setInventorySlot(slots) + } } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouterImpl.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouterImpl.kt index 080a36f..61f8ef5 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouterImpl.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/router/GuiRouterImpl.kt @@ -1,7 +1,7 @@ package ru.astrainteractive.astramarket.gui.router import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astramarket.core.di.BukkitCoreModule import ru.astrainteractive.astramarket.core.di.CoreModule import ru.astrainteractive.astramarket.gui.button.di.ButtonContext @@ -9,7 +9,7 @@ import ru.astrainteractive.astramarket.gui.players.PlayersGui import ru.astrainteractive.astramarket.gui.slots.SlotsGui import ru.astrainteractive.astramarket.market.di.MarketViewModule import ru.astrainteractive.astramarket.players.di.PlayersMarketViewModule -import ru.astrainteractive.klibs.kstorage.api.getValue +import ru.astrainteractive.klibs.mikro.core.util.tryCast internal class GuiRouterImpl( private val coreModule: CoreModule, @@ -26,11 +26,11 @@ internal class GuiRouterImpl( ) override fun navigate(route: GuiRouter.Route) { - coreModule.ioScope.launch { - val gui = when (route) { + coreModule.ioScope.launch(coreModule.dispatchers.Main) { + val menu = when (route) { is GuiRouter.Route.Slots -> { SlotsGui( - player = route.player, + inventoryOwner = route.inventoryOwner, configKrate = coreModule.configKrate, translationKrate = coreModule.pluginTranslationKrate, dispatchers = coreModule.dispatchers, @@ -38,7 +38,7 @@ internal class GuiRouterImpl( kyoriKrate = coreModule.kyoriKrate, buttonContext = buttonContext, auctionComponent = marketViewModule.createAuctionComponent( - playerUUID = route.player.uuid, + playerUUID = route.inventoryOwner.uuid, isExpired = route.isExpired, targetPlayerUUID = route.targetPlayerUUID ) @@ -47,7 +47,7 @@ internal class GuiRouterImpl( is GuiRouter.Route.Players -> { PlayersGui( - player = route.player, + inventoryOwner = route.inventoryOwner, configKrate = coreModule.configKrate, translationKrate = coreModule.pluginTranslationKrate, dispatchers = coreModule.dispatchers, @@ -60,9 +60,9 @@ internal class GuiRouterImpl( ) } } - withContext(coreModule.dispatchers.Main) { - gui.open() - } + route.inventoryOwner.tryCast() + ?.instance + ?.openInventory(menu.inventory) } } } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt index 2fbb79c..396b1dc 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt @@ -1,31 +1,31 @@ package ru.astrainteractive.astramarket.gui.slots import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.withContext import net.kyori.adventure.text.Component import org.bukkit.Bukkit import org.bukkit.event.inventory.ClickType import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.InventoryCloseEvent +import org.bukkit.event.inventory.InventoryOpenEvent +import ru.astrainteractive.astralibs.coroutines.withTimings import ru.astrainteractive.astralibs.kyori.KyoriComponentSerializer import ru.astrainteractive.astralibs.kyori.unwrap -import ru.astrainteractive.astralibs.menu.holder.DefaultPlayerHolder -import ru.astrainteractive.astralibs.menu.inventory.PaginatedInventoryMenu +import ru.astrainteractive.astralibs.menu.core.setInventorySlot +import ru.astrainteractive.astralibs.menu.inventory.api.InventoryMenu import ru.astrainteractive.astralibs.menu.inventory.model.InventorySize -import ru.astrainteractive.astralibs.menu.inventory.model.PageContext -import ru.astrainteractive.astralibs.menu.inventory.util.PageContextExt.indexOfSlot -import ru.astrainteractive.astralibs.menu.inventory.util.PageContextExt.isFirstPage -import ru.astrainteractive.astralibs.menu.inventory.util.PageContextExt.isLastPage -import ru.astrainteractive.astralibs.menu.inventory.util.PaginatedInventoryMenuExt.showNextPage -import ru.astrainteractive.astralibs.menu.inventory.util.PaginatedInventoryMenuExt.showPage -import ru.astrainteractive.astralibs.menu.inventory.util.PaginatedInventoryMenuExt.showPrevPage +import ru.astrainteractive.astralibs.menu.paginator.api.DefaultPaginator +import ru.astrainteractive.astralibs.menu.paginator.api.context +import ru.astrainteractive.astralibs.menu.paginator.api.openNextPage +import ru.astrainteractive.astralibs.menu.paginator.api.openPrevPage +import ru.astrainteractive.astralibs.menu.paginator.api.setMaxItems +import ru.astrainteractive.astralibs.menu.paginator.model.indexOfSlot +import ru.astrainteractive.astralibs.menu.paginator.model.isFirstPage +import ru.astrainteractive.astralibs.menu.paginator.model.isLastPage import ru.astrainteractive.astralibs.menu.slot.InventorySlot -import ru.astrainteractive.astralibs.server.permission.asKPermissible -import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer import ru.astrainteractive.astralibs.server.player.OnlineKPlayer -import ru.astrainteractive.astralibs.server.util.asOnlineMinecraftPlayer import ru.astrainteractive.astramarket.core.PluginConfig import ru.astrainteractive.astramarket.core.PluginPermission import ru.astrainteractive.astramarket.core.PluginTranslation @@ -41,28 +41,28 @@ import ru.astrainteractive.astramarket.gui.button.slotsType import ru.astrainteractive.astramarket.gui.layout.AuctionSlotKey import ru.astrainteractive.astramarket.gui.layout.DefaultAuctionInventoryLayoutFactory import ru.astrainteractive.astramarket.gui.router.GuiRouter -import ru.astrainteractive.astramarket.gui.util.ItemStackExt.playSound +import ru.astrainteractive.astramarket.gui.util.closeInventory +import ru.astrainteractive.astramarket.gui.util.playSound import ru.astrainteractive.astramarket.market.presentation.AuctionComponent import ru.astrainteractive.klibs.kstorage.api.CachedKrate import ru.astrainteractive.klibs.kstorage.api.getValue +import ru.astrainteractive.klibs.mikro.core.coroutines.CoroutineFeature import ru.astrainteractive.klibs.mikro.core.dispatchers.KotlinDispatchers -import ru.astrainteractive.klibs.mikro.core.util.cast internal class SlotsGui( - player: OnlineKPlayer, configKrate: CachedKrate, translationKrate: CachedKrate, - dispatchers: KotlinDispatchers, kyoriKrate: CachedKrate, + private val inventoryOwner: OnlineKPlayer, private val router: GuiRouter, private val buttonContext: ButtonContext, - private val auctionComponent: AuctionComponent -) : PaginatedInventoryMenu(), + private val auctionComponent: AuctionComponent, + private val dispatchers: KotlinDispatchers, +) : InventoryMenu(), KyoriComponentSerializer by kyoriKrate.unwrap() { private val config by configKrate private val translation by translationKrate - override val playerHolder = DefaultPlayerHolder(player.cast().instance) override val title: Component = let { val playerNameComponent = auctionComponent.model.value .targetPlayerUUID @@ -72,16 +72,20 @@ internal class SlotsGui( ?: Component.empty() translation.menu.market.component.append(playerNameComponent) } + override val childComponents = listOf(auctionComponent) + + override val menuScope = CoroutineFeature + .Default(dispatchers.Main) + .withTimings() + override val inventorySize: InventorySize = InventorySize.XL private val inventoryMap by lazy { DefaultAuctionInventoryLayoutFactory.create(config.auction.useCompactDesign) } - override var pageContext: PageContext = PageContext( - page = 0, - maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AUCTION_ITEM), - maxItems = 0 + private val paginator = DefaultPaginator( + maxItemsPerPage = inventoryMap.count(AuctionSlotKey.AUCTION_ITEM) ) private val borderButtons: List @@ -90,13 +94,13 @@ internal class SlotsGui( transform = buttonContext::border ) - override val nextPageButton: InventorySlot + private val nextPageButton: InventorySlot get() = buttonContext.nextPage( index = inventoryMap.firstIndexOf(AuctionSlotKey.NEXT_PAGE), click = { onNextPageClicked() } ) - override val prevPageButton: InventorySlot + private val prevPageButton: InventorySlot get() = buttonContext.prevPage( index = inventoryMap.firstIndexOf(AuctionSlotKey.PREV_PAGE), click = { onPrevPageClicked() } @@ -107,7 +111,7 @@ internal class SlotsGui( index = inventoryMap.firstIndexOf(AuctionSlotKey.SORT), sortType = auctionComponent.model.value.sortType, click = { - showPage(0) + paginator.openPage(0) onSortButtonClicked(it.isRightClick) } ) @@ -117,8 +121,8 @@ internal class SlotsGui( index = inventoryMap.firstIndexOf(AuctionSlotKey.AUCTION_ITEM), isExpired = auctionComponent.model.value.isExpired, click = { - playerHolder.player.playSound(config.sounds.open) - showPage(0) + this@SlotsGui.inventoryOwner.playSound(config.sounds.open) + paginator.openPage(0) auctionComponent.toggleExpired() } ) @@ -128,7 +132,7 @@ internal class SlotsGui( index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), click = { val route = GuiRouter.Route.Players( - player = playerHolder.player.asOnlineMinecraftPlayer(), + inventoryOwner = this@SlotsGui.inventoryOwner, isExpired = auctionComponent.model.value.isExpired ) router.navigate(route) @@ -141,7 +145,7 @@ internal class SlotsGui( isGroupedByPlayers = false, click = { val route = GuiRouter.Route.Players( - player = playerHolder.player.asOnlineMinecraftPlayer(), + inventoryOwner = this@SlotsGui.inventoryOwner, isExpired = auctionComponent.model.value.isExpired ) router.navigate(route) @@ -151,54 +155,62 @@ internal class SlotsGui( private val closeButton: InventorySlot get() = buttonContext.back( index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), - click = { playerHolder.player.closeInventory() } + click = { this@SlotsGui.inventoryOwner.closeInventory() } ) private fun onNextPageClicked() { - playerHolder.player.playSound(config.sounds.open) - showNextPage() + this@SlotsGui.inventoryOwner.playSound(config.sounds.open) + paginator.openNextPage() } private fun onPrevPageClicked() { - playerHolder.player.playSound(config.sounds.open) - showPrevPage() + this@SlotsGui.inventoryOwner.playSound(config.sounds.open) + paginator.openPrevPage() } private fun onSortButtonClicked(isRightClick: Boolean) { - playerHolder.player.playSound(config.sounds.open) + this@SlotsGui.inventoryOwner.playSound(config.sounds.open) auctionComponent.onSortButtonClicked(isRightClick) - sortButton.setInventorySlot() + setInventorySlot(sortButton) } private val itemSlots: List get() { var itemIndex = 0 return inventoryMap.mapSlotsNotNull(AuctionSlotKey.AUCTION_ITEM) { slotIndex -> - val index = pageContext.indexOfSlot(itemIndex) + val index = paginator.context.indexOfSlot(itemIndex) itemIndex++ val auctionItem = auctionComponent.model .value .items .getOrNull(index) ?: return@mapSlotsNotNull null - val permissible = playerHolder.player.asKPermissible() + val permissible = this@SlotsGui.inventoryOwner buttonContext.expiredSlot( auctionItem = auctionItem, index = slotIndex, click = { onAuctionItemClicked(index, it.click) }, - isOwner = auctionItem.minecraftUuid == playerHolder.player.uniqueId.toString(), + isOwner = auctionItem.minecraftUuid == this@SlotsGui.inventoryOwner.uuid.toString(), hasExpirePermission = permissible.hasPermission(PluginPermission.Expire), hasRemovePermission = permissible.hasPermission(PluginPermission.RemoveSlot) ) } } - override fun onInventoryClosed(it: InventoryCloseEvent) { - super.onInventoryClosed(it) - playerHolder.player.playSound(config.sounds.close) + override fun onInventoryCloseEvent(e: InventoryCloseEvent) { + super.onInventoryCloseEvent(e) + this@SlotsGui.inventoryOwner.playSound(config.sounds.close) auctionComponent.cancel() } + override fun onInventoryOpenEvent(e: InventoryOpenEvent) { + this@SlotsGui.inventoryOwner.playSound(config.sounds.open) + auctionComponent.model + .onEach { paginator.setMaxItems(auctionComponent.model.value.items.size) } + .onEach { withContext(dispatchers.Main) { render() } } + .launchIn(menuScope) + } + private fun onAuctionItemClicked(i: Int, clickType: ClickType) { val sharedClickType = when (clickType) { ClickType.LEFT, @@ -213,38 +225,24 @@ internal class SlotsGui( auctionComponent.onAuctionItemClicked(i, sharedClickType) } - override fun onInventoryClicked(e: InventoryClickEvent) { - super.onInventoryClicked(e) + override fun onInventoryClickEvent(e: InventoryClickEvent) { + super.onInventoryClickEvent(e) e.isCancelled = true } override fun render() { super.render() - expiredSlotsButton.setInventorySlot() - if (!pageContext.isFirstPage) prevPageButton.setInventorySlot() - if (!pageContext.isLastPage) nextPageButton.setInventorySlot() + setInventorySlot(expiredSlotsButton) + if (!paginator.context.isFirstPage) setInventorySlot(prevPageButton) + if (!paginator.context.isLastPage) setInventorySlot(nextPageButton) if (auctionComponent.model.value.targetPlayerUUID != null) { - openPlayersButton.setInventorySlot() + setInventorySlot(openPlayersButton) } else { - closeButton.setInventorySlot() - playerSlots.setInventorySlot() + setInventorySlot(closeButton) + setInventorySlot(playerSlots) } - borderButtons.forEach { it.setInventorySlot() } - sortButton.setInventorySlot() - itemSlots.forEach { it.setInventorySlot() } - } - - private val drawDispatcher = dispatchers.IO.limitedParallelism(1) - override fun onInventoryCreated() { - playerHolder.player.playSound(config.sounds.open) - auctionComponent.model - .onEach { - pageContext = pageContext.copy( - maxItems = auctionComponent.model.value.items.size - ) - render() - } - .flowOn(drawDispatcher) - .launchIn(menuScope) + setInventorySlot(borderButtons) + setInventorySlot(sortButton) + setInventorySlot(itemSlots) } } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/DurationExt.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/DurationExt.kt index 40bc275..0017993 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/DurationExt.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/DurationExt.kt @@ -5,17 +5,15 @@ import ru.astrainteractive.astralibs.string.replace import java.util.concurrent.TimeUnit import kotlin.time.Duration -internal object DurationExt { - @Suppress("MagicNumber") - fun Duration.getTimeFormatted(format: StringDesc): StringDesc { - val time = System.currentTimeMillis().minus(inWholeMilliseconds) - val unit = TimeUnit.MILLISECONDS - val days = unit.toDays(time) - val hours = unit.toHours(time) - days * 24 - val minutes = unit.toMinutes(time) - unit.toHours(time) * 60 - return format - .replace("%days%", days.toString()) - .replace("%hours%", hours.toString()) - .replace("%minutes%", minutes.toString()) - } +@Suppress("MagicNumber") +fun Duration.getTimeFormatted(format: StringDesc): StringDesc { + val time = System.currentTimeMillis().minus(inWholeMilliseconds) + val unit = TimeUnit.MILLISECONDS + val days = unit.toDays(time) + val hours = unit.toHours(time) - days * 24 + val minutes = unit.toMinutes(time) - unit.toHours(time) * 60 + return format + .replace("%days%", days.toString()) + .replace("%hours%", hours.toString()) + .replace("%minutes%", minutes.toString()) } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/ItemStackExt.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/ItemStackExt.kt index 99ab7ae..424c18f 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/ItemStackExt.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/ItemStackExt.kt @@ -3,19 +3,14 @@ package ru.astrainteractive.astramarket.gui.util import org.bukkit.Material -import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack import ru.astrainteractive.astramarket.core.PluginConfig -internal object ItemStackExt { - fun Player.playSound(sound: String) { - playSound(location, sound, 1f, 1f) +fun PluginConfig.Button.toItemStack(): ItemStack { + val type = Material.getMaterial(material.uppercase()) ?: Material.PAPER + return ItemStack(type).apply { + val meta = itemMeta ?: error("ItemStack with material $type didn't have itemMeta") + meta.setCustomModelData(customModelData) + itemMeta = meta } - - fun PluginConfig.Button.toItemStack() = - ItemStack(Material.getMaterial(material.uppercase()) ?: Material.PAPER).apply { - val meta = itemMeta!! - meta.setCustomModelData(customModelData) - itemMeta = meta - } } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/OnlineKPlayerExt.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/OnlineKPlayerExt.kt new file mode 100644 index 0000000..4ecb6fc --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/OnlineKPlayerExt.kt @@ -0,0 +1,13 @@ +package ru.astrainteractive.astramarket.gui.util + +import ru.astrainteractive.astralibs.server.player.BukkitOnlineKPlayer +import ru.astrainteractive.astralibs.server.player.OnlineKPlayer +import ru.astrainteractive.klibs.mikro.core.util.tryCast + +internal fun OnlineKPlayer.playSound(sound: String) { + this.tryCast()?.instance?.playSound(sound) +} + +internal fun OnlineKPlayer.closeInventory() { + this.tryCast()?.instance?.closeInventory() +} diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/PlayerExt.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/PlayerExt.kt new file mode 100644 index 0000000..5347b53 --- /dev/null +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/PlayerExt.kt @@ -0,0 +1,7 @@ +package ru.astrainteractive.astramarket.gui.util + +import org.bukkit.entity.Player + +fun Player.playSound(sound: String) { + playSound(location, sound, 1f, 1f) +} From a348651633c053a375e9e31bcd17afb16975e2fe Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 10 May 2026 09:59:49 +0300 Subject: [PATCH 08/10] [TEST] Add tests --- modules/api-market/build.gradle.kts | 1 + .../astramarket/api/market/MarketApiTest.kt | 93 ------- .../api/market/impl/ExposedMarketApiTest.kt | 253 ++++++++++++++++++ .../api/market/impl/TestContext.kt | 49 ++++ 4 files changed, 303 insertions(+), 93 deletions(-) delete mode 100644 modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/MarketApiTest.kt create mode 100644 modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/impl/ExposedMarketApiTest.kt create mode 100644 modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/impl/TestContext.kt diff --git a/modules/api-market/build.gradle.kts b/modules/api-market/build.gradle.kts index dcc00cc..f308fcf 100644 --- a/modules/api-market/build.gradle.kts +++ b/modules/api-market/build.gradle.kts @@ -17,4 +17,5 @@ dependencies { testImplementation(libs.driver.h2) testImplementation(libs.tests.kotlin.test) + testImplementation(libs.kotlin.coroutines.test) } diff --git a/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/MarketApiTest.kt b/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/MarketApiTest.kt deleted file mode 100644 index ce652cd..0000000 --- a/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/MarketApiTest.kt +++ /dev/null @@ -1,93 +0,0 @@ -package ru.astrainteractive.astramarket.api.market - -import kotlinx.coroutines.runBlocking -import ru.astrainteractive.astralibs.encoding.model.EncodedObject -import ru.astrainteractive.astralibs.util.YamlStringFormat -import ru.astrainteractive.astramarket.api.market.model.MarketSlot -import ru.astrainteractive.astramarket.di.ApiMarketModule -import ru.astrainteractive.klibs.mikro.core.coroutines.CoroutineFeature -import ru.astrainteractive.klibs.mikro.core.dispatchers.DefaultKotlinDispatchers -import ru.astrainteractive.klibs.mikro.exposed.model.DatabaseConfiguration -import java.io.File -import java.nio.file.Files -import java.util.UUID -import kotlin.random.Random -import kotlin.test.AfterTest -import kotlin.test.BeforeTest -import kotlin.test.Test -import kotlin.test.assertEquals - -class MarketApiTest { - - private var module: ApiMarketModule? = null - private val marketApi: MarketApi - get() = module?.marketApi ?: error("Module is null") - private val tempDir: File - get() = Files.createTempDirectory("TMP_DIR").toFile() - - private val randomAuction: MarketSlot - get() = MarketSlot( - id = -1, - minecraftUuid = UUID.randomUUID().toString(), - time = System.currentTimeMillis(), - item = EncodedObject.ByteArray(ByteArray(0)), - price = Random.nextInt().toFloat(), - expired = false, - minecraftUsername = "romaroman" - ) - - @BeforeTest - fun setup(): Unit = runBlocking { - tempDir.deleteRecursively() - val module = ApiMarketModule.Default( - dispatchers = DefaultKotlinDispatchers, - yamlStringFormat = YamlStringFormat(), - dataFolder = tempDir.also { it.deleteOnExit() }, - ioScope = CoroutineFeature.Unconfined, - default = { DatabaseConfiguration.H2(tempDir.resolve("db").absolutePath) } - ) - module.lifecycle.onEnable() - this@MarketApiTest.module = module - } - - @AfterTest - fun destroy(): Unit = runBlocking { - tempDir.deleteRecursively() - module?.lifecycle?.onDisable() - module = null - } - - @Test - fun `Insert, fetch, expire same auction`(): Unit = runBlocking { - val auction = randomAuction - // Insert and fetch - val id = marketApi.insertSlot(auction)!! - var auctionDTO = marketApi.getSlot(id)!! - assertEquals(auctionDTO.minecraftUuid, auction.minecraftUuid) - // Get unexpiredAuctions - var amount = marketApi.getUserSlots(auctionDTO.minecraftUuid, false)!!.size - assertEquals(amount, 1) - // Expire - marketApi.expireSlot(auctionDTO) - assertEquals(auctionDTO.expired, false) - auctionDTO = marketApi.getSlot(id)!! - assertEquals(auctionDTO.expired, true) - // Get expiredAuctions - amount = marketApi.getUserSlots(auctionDTO.minecraftUuid, true)!!.size - assertEquals(amount, 1) - // Get unexpiredAuctions - amount = marketApi.getUserSlots(auctionDTO.minecraftUuid, false)!!.size - assertEquals(amount, 0) - // Count auctions - amount = marketApi.countPlayerSlots(auctionDTO.minecraftUuid)!! - assertEquals(amount, 1) - // Delete and count auction - marketApi.deleteSlot(auctionDTO) - amount = marketApi.countPlayerSlots(auctionDTO.minecraftUuid)!! - assertEquals(amount, 0) - val oldAuctionDTO = randomAuction.copy(time = 0) - marketApi.insertSlot(oldAuctionDTO) - amount = marketApi.getSlotsOlderThan(System.currentTimeMillis() - 1)!!.size - assertEquals(amount, 1) - } -} diff --git a/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/impl/ExposedMarketApiTest.kt b/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/impl/ExposedMarketApiTest.kt new file mode 100644 index 0000000..fcfd195 --- /dev/null +++ b/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/impl/ExposedMarketApiTest.kt @@ -0,0 +1,253 @@ +package ru.astrainteractive.astramarket.api.market.impl + +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue + +class ExposedMarketApiTest { + private suspend fun withTestContext(block: suspend TestContext.() -> Unit) { + val ctx = TestContext() + ctx.onStart() + try { + ctx.block() + } finally { + ctx.onDisable() + } + } + + @Test + fun GIVEN_emptyDatabase_WHEN_insertSlot_THEN_returnsNonNullId() { + runTest { + withTestContext { + val insertedId = marketApi.insertSlot(createMarketSlot()) + assertNotNull(insertedId) + } + } + } + + @Test + fun GIVEN_insertedSlot_WHEN_getSlotById_THEN_returnsSlotWithMatchingData() { + runTest { + withTestContext { + val slot = createMarketSlot(price = 250.0f, username = "Trader") + val insertedId = marketApi.insertSlot(slot) + assertNotNull(insertedId) + + val retrieved = marketApi.getSlot(insertedId) + assertNotNull(retrieved) + + assertEquals(slot.price, retrieved.price) + assertEquals(slot.minecraftUuid, retrieved.minecraftUuid) + assertEquals(slot.minecraftUsername, retrieved.minecraftUsername) + } + } + } + + @Test + fun GIVEN_nonExistentId_WHEN_getSlot_THEN_returnsNull() { + runTest { + withTestContext { + val retrieved = marketApi.getSlot(99999) + assertNull(retrieved) + } + } + } + + @Test + fun GIVEN_insertedActiveSlot_WHEN_getActiveSlots_THEN_slotAppearsInList() { + runTest { + withTestContext { + val slot = createMarketSlot(expired = false) + marketApi.insertSlot(slot) + + val activeSlots = marketApi.getSlots(isExpired = false) + assertNotNull(activeSlots) + + assertEquals(1, activeSlots.size) + assertEquals(slot.minecraftUuid, activeSlots.first().minecraftUuid) + } + } + } + + @Test + fun GIVEN_insertedActiveSlot_WHEN_getExpiredSlots_THEN_returnsEmptyList() { + runTest { + withTestContext { + marketApi.insertSlot(createMarketSlot(expired = false)) + + val expiredSlots = marketApi.getSlots(isExpired = true) + assertNotNull(expiredSlots) + + assertTrue(expiredSlots.isEmpty()) + } + } + } + + @Test + fun GIVEN_insertedActiveSlot_WHEN_expireSlot_THEN_slotMovesToExpiredList() { + runTest { + withTestContext { + val insertedId = marketApi.insertSlot(createMarketSlot(expired = false)) + assertNotNull(insertedId) + val activeSlot = marketApi.getSlot(insertedId) + assertNotNull(activeSlot) + + marketApi.expireSlot(activeSlot) + + val expiredSlots = marketApi.getSlots(isExpired = true) + assertNotNull(expiredSlots) + val activeSlots = marketApi.getSlots(isExpired = false) + assertNotNull(activeSlots) + assertEquals(1, expiredSlots.size) + assertTrue(activeSlots.isEmpty()) + } + } + } + + @Test + fun GIVEN_insertedSlot_WHEN_deleteSlot_THEN_slotCannotBeRetrieved() { + runTest { + withTestContext { + val insertedId = marketApi.insertSlot(createMarketSlot()) + assertNotNull(insertedId) + val insertedSlot = marketApi.getSlot(insertedId) + assertNotNull(insertedSlot) + + marketApi.deleteSlot(insertedSlot) + + val retrieved = marketApi.getSlot(insertedId) + assertNull(retrieved) + } + } + } + + @Test + fun GIVEN_deletedSlot_WHEN_getSlots_THEN_deletedSlotIsAbsent() { + runTest { + withTestContext { + val insertedId = marketApi.insertSlot(createMarketSlot()) + assertNotNull(insertedId) + val insertedSlot = marketApi.getSlot(insertedId) + assertNotNull(insertedSlot) + + marketApi.deleteSlot(insertedSlot) + + val allSlots = marketApi.getSlots(isExpired = false) + assertNotNull(allSlots) + assertTrue(allSlots.none { it.id == insertedId }) + } + } + } + + @Test + fun GIVEN_multipleSlotsForPlayer_WHEN_countPlayerSlots_THEN_returnsExactCount() { + runTest { + withTestContext { + val uuid = "550e8400-e29b-41d4-a716-446655440001" + repeat(3) { marketApi.insertSlot(createMarketSlot(uuid = uuid)) } + + val count = marketApi.countPlayerSlots(uuid) + + assertEquals(3, count) + } + } + } + + @Test + fun GIVEN_noSlotsForPlayer_WHEN_countPlayerSlots_THEN_returnsZero() { + runTest { + withTestContext { + val uuid = "550e8400-e29b-41d4-a716-446655440001" + + val count = marketApi.countPlayerSlots(uuid) + + assertEquals(0, count) + } + } + } + + @Test + fun GIVEN_slotsForTwoPlayers_WHEN_getUserSlots_THEN_returnsOnlyRequestedPlayerSlots() { + runTest { + withTestContext { + val firstPlayerUuid = "550e8400-e29b-41d4-a716-446655440001" + val secondPlayerUuid = "550e8400-e29b-41d4-a716-446655440002" + repeat(2) { marketApi.insertSlot(createMarketSlot(uuid = firstPlayerUuid)) } + marketApi.insertSlot(createMarketSlot(uuid = secondPlayerUuid)) + + val firstPlayerSlots = marketApi.getUserSlots(firstPlayerUuid, isExpired = false) + assertNotNull(firstPlayerSlots) + + assertEquals(2, firstPlayerSlots.size) + assertTrue(firstPlayerSlots.all { it.minecraftUuid == firstPlayerUuid }) + } + } + } + + @Test + fun GIVEN_activeAndExpiredSlotsForPlayer_WHEN_getUserActiveSlots_THEN_returnsOnlyActiveSlots() { + runTest { + withTestContext { + val uuid = "550e8400-e29b-41d4-a716-446655440001" + marketApi.insertSlot(createMarketSlot(uuid = uuid, expired = false)) + marketApi.insertSlot(createMarketSlot(uuid = uuid, expired = true)) + + val activeUserSlots = marketApi.getUserSlots(uuid, isExpired = false) + assertNotNull(activeUserSlots) + + assertEquals(1, activeUserSlots.size) + assertTrue(activeUserSlots.all { !it.expired }) + } + } + } + + @Test + fun GIVEN_slotCreatedLongAgo_WHEN_getSlotsOlderThan_THEN_slotIsIncluded() { + runTest { + withTestContext { + val oneHourInMillis = 60 * 60 * 1000L + marketApi.insertSlot(createMarketSlot(timeOffset = -oneHourInMillis * 2)) + + val oldSlots = marketApi.getSlotsOlderThan(oneHourInMillis) + assertNotNull(oldSlots) + + assertEquals(1, oldSlots.size) + } + } + } + + @Test + fun GIVEN_recentlyCreatedSlot_WHEN_getSlotsOlderThan_THEN_slotIsNotIncluded() { + runTest { + withTestContext { + val oneHourInMillis = 60 * 60 * 1000L + marketApi.insertSlot(createMarketSlot(timeOffset = 0L)) + + val oldSlots = marketApi.getSlotsOlderThan(oneHourInMillis) + assertNotNull(oldSlots) + + assertTrue(oldSlots.isEmpty()) + } + } + } + + @Test + fun GIVEN_mixOfOldAndNewSlots_WHEN_getSlotsOlderThan_THEN_returnsOnlyOldSlots() { + runTest { + withTestContext { + val oneHourInMillis = 60 * 60 * 1000L + marketApi.insertSlot(createMarketSlot(timeOffset = -oneHourInMillis * 2)) + marketApi.insertSlot(createMarketSlot(timeOffset = -oneHourInMillis * 3)) + marketApi.insertSlot(createMarketSlot(timeOffset = 0L)) + + val oldSlots = marketApi.getSlotsOlderThan(oneHourInMillis) + assertNotNull(oldSlots) + + assertEquals(2, oldSlots.size) + } + } + } +} diff --git a/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/impl/TestContext.kt b/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/impl/TestContext.kt new file mode 100644 index 0000000..7fb8251 --- /dev/null +++ b/modules/api-market/src/test/java/ru/astrainteractive/astramarket/api/market/impl/TestContext.kt @@ -0,0 +1,49 @@ +package ru.astrainteractive.astramarket.api.market.impl + +import kotlinx.coroutines.flow.flowOf +import org.jetbrains.exposed.v1.jdbc.Database +import org.jetbrains.exposed.v1.jdbc.SchemaUtils +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import ru.astrainteractive.astralibs.encoding.model.EncodedObject +import ru.astrainteractive.astramarket.api.market.model.MarketSlot +import ru.astrainteractive.astramarket.db.market.entity.AuctionTable +import ru.astrainteractive.klibs.mikro.core.dispatchers.DefaultKotlinDispatchers +import java.nio.file.Files + +internal class TestContext { + private val tempDir = Files.createTempDirectory("astra-market-test").toFile() + val database = Database.connect( + url = "jdbc:h2:${tempDir.absolutePath}/test", + driver = "org.h2.Driver" + ) + val marketApi = ExposedMarketApi( + databaseFlow = flowOf(database), + dispatchers = DefaultKotlinDispatchers + ) + + fun onStart() { + transaction(database) { + SchemaUtils.create(AuctionTable) + } + } + + fun onDisable() { + tempDir.deleteRecursively() + } + + fun createMarketSlot( + uuid: String = "550e8400-e29b-41d4-a716-446655440000", + username: String = "TestPlayer", + price: Float = 100.0f, + expired: Boolean = false, + timeOffset: Long = 0L + ): MarketSlot = MarketSlot( + id = 0, + minecraftUuid = uuid, + minecraftUsername = username, + time = System.currentTimeMillis() + timeOffset, + item = EncodedObject.ByteArray("test_item".toByteArray()), + price = price, + expired = expired + ) +} From 4bb5bbb12fad70ad26b3ed917c95069f2505eb55 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 10 May 2026 11:40:56 +0300 Subject: [PATCH 09/10] [FIX] Buttons location --- .../astramarket/core/PluginTranslation.kt | 12 ++-- .../gui/button/ExpiredSlotButton.kt | 6 +- .../gui/button/PlayerItemButton.kt | 6 +- .../astramarket/gui/players/PlayersGui.kt | 12 ++-- .../astramarket/gui/slots/SlotsGui.kt | 62 +++++++------------ .../astramarket/gui/util/DurationExt.kt | 11 +++- 6 files changed, 56 insertions(+), 53 deletions(-) diff --git a/modules/core/src/main/kotlin/ru/astrainteractive/astramarket/core/PluginTranslation.kt b/modules/core/src/main/kotlin/ru/astrainteractive/astramarket/core/PluginTranslation.kt index 8f3579e..6244180 100644 --- a/modules/core/src/main/kotlin/ru/astrainteractive/astramarket/core/PluginTranslation.kt +++ b/modules/core/src/main/kotlin/ru/astrainteractive/astramarket/core/PluginTranslation.kt @@ -125,9 +125,7 @@ data class PluginTranslation( .plus("&#f55442У вас уже макстимальное число лотов") .toRaw(), @SerialName("auction_by") - private val auctionBy: StringDesc.Raw = PREFIX - .plus("&7Выставил: &#d6a213%player_owner%") - .toRaw(), + private val auctionBy: StringDesc.Raw = StringDesc.Raw("&7Выставил: &#d6a213%player_owner%"), @SerialName("auction_created_ago") private val auctionCreatedAgo: StringDesc.Raw = StringDesc.Raw("&7Время: &#d6a213%time%"), @SerialName("auction_last") @@ -232,8 +230,12 @@ data class PluginTranslation( val unexpectedError: StringDesc.Raw = PREFIX .plus("&#f55442Произошла непредвиденная ошибка") .toRaw(), - @SerialName("time_format") - val timeAgoFormat: StringDesc.Raw = StringDesc.Raw("%days%дн. %hours%ч. %minutes%м. назад") + @SerialName("time_format_dhm") + val timeAgoFormatDHM: StringDesc.Raw = StringDesc.Raw("%days%дн. %hours%ч. %minutes%м. назад"), + @SerialName("time_format_hm") + val timeAgoFormatHM: StringDesc.Raw = StringDesc.Raw("%hours%ч. %minutes%м. назад"), + @SerialName("time_format_m") + val timeAgoFormatM: StringDesc.Raw = StringDesc.Raw("%minutes%м. назад") ) companion object { diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/ExpiredSlotButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/ExpiredSlotButton.kt index 5f4adc4..11b130a 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/ExpiredSlotButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/ExpiredSlotButton.kt @@ -48,7 +48,11 @@ internal fun ButtonContext.expiredSlot( pluginTranslation.auction.auctionBy(ownerName).component } .addLore { - val time = auctionItem.time.milliseconds.getTimeFormatted(pluginTranslation.general.timeAgoFormat).raw + val time = auctionItem.time.milliseconds.getTimeFormatted( + pluginTranslation.general.timeAgoFormatDHM, + pluginTranslation.general.timeAgoFormatHM, + pluginTranslation.general.timeAgoFormatM + ).raw pluginTranslation.auction.auctionCreatedAgo(time).component } .addLore { diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayerItemButton.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayerItemButton.kt index 85220ba..5e3df72 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayerItemButton.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/button/PlayerItemButton.kt @@ -48,7 +48,11 @@ internal fun ButtonContext.playerItem( val time = playerAndSlots.slots .maxBy { it.time } .time.milliseconds - .getTimeFormatted(pluginTranslation.general.timeAgoFormat).raw + .getTimeFormatted( + pluginTranslation.general.timeAgoFormatDHM, + pluginTranslation.general.timeAgoFormatHM, + pluginTranslation.general.timeAgoFormatM + ).raw pluginTranslation.auction.auctionLast(time).component } .setOnClickListener(click) diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt index c9c4771..b844d26 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/players/PlayersGui.kt @@ -100,7 +100,7 @@ internal class PlayersGui( } ) - private val expiredButton: InventorySlot + private val filterExpiredButton: InventorySlot get() = buttonContext.filterExpired( index = inventoryMap.firstIndexOf(AuctionSlotKey.FILTER_EXPIRED), isExpired = playersMarketComponent.model.value.isExpired, @@ -111,7 +111,7 @@ internal class PlayersGui( } ) - private val allSlots: InventorySlot + private val displayTypeButton: InventorySlot get() = buttonContext.slotsType( index = inventoryMap.firstIndexOf(AuctionSlotKey.DISPLAY_TYPE), isGroupedByPlayers = true, @@ -125,7 +125,7 @@ internal class PlayersGui( } ) - private val closeButton: InventorySlot + private val backButton: InventorySlot get() = buttonContext.back( index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), click = { inventoryOwner.closeInventory() } @@ -186,9 +186,9 @@ internal class PlayersGui( if (!paginator.context.isFirstPage) setInventorySlot(prevPageButton) if (!paginator.context.isLastPage) setInventorySlot(nextPageButton) setInventorySlot(sortButton) - setInventorySlot(expiredButton) - setInventorySlot(closeButton) - setInventorySlot(allSlots) + setInventorySlot(filterExpiredButton) + setInventorySlot(backButton) + setInventorySlot(displayTypeButton) setInventorySlot(slots) } } diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt index 396b1dc..26727ef 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/slots/SlotsGui.kt @@ -116,9 +116,9 @@ internal class SlotsGui( } ) - private val expiredSlotsButton: InventorySlot + private val filterExpiredButton: InventorySlot get() = buttonContext.filterExpired( - index = inventoryMap.firstIndexOf(AuctionSlotKey.AUCTION_ITEM), + index = inventoryMap.firstIndexOf(AuctionSlotKey.FILTER_EXPIRED), isExpired = auctionComponent.model.value.isExpired, click = { this@SlotsGui.inventoryOwner.playSound(config.sounds.open) @@ -127,19 +127,7 @@ internal class SlotsGui( } ) - private val openPlayersButton: InventorySlot - get() = buttonContext.back( - index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), - click = { - val route = GuiRouter.Route.Players( - inventoryOwner = this@SlotsGui.inventoryOwner, - isExpired = auctionComponent.model.value.isExpired - ) - router.navigate(route) - } - ) - - private val playerSlots: InventorySlot + private val displayTypeButton: InventorySlot get() = buttonContext.slotsType( index = inventoryMap.firstIndexOf(AuctionSlotKey.DISPLAY_TYPE), isGroupedByPlayers = false, @@ -152,28 +140,12 @@ internal class SlotsGui( } ) - private val closeButton: InventorySlot + private val backButton: InventorySlot get() = buttonContext.back( index = inventoryMap.firstIndexOf(AuctionSlotKey.BACK), click = { this@SlotsGui.inventoryOwner.closeInventory() } ) - private fun onNextPageClicked() { - this@SlotsGui.inventoryOwner.playSound(config.sounds.open) - paginator.openNextPage() - } - - private fun onPrevPageClicked() { - this@SlotsGui.inventoryOwner.playSound(config.sounds.open) - paginator.openPrevPage() - } - - private fun onSortButtonClicked(isRightClick: Boolean) { - this@SlotsGui.inventoryOwner.playSound(config.sounds.open) - auctionComponent.onSortButtonClicked(isRightClick) - setInventorySlot(sortButton) - } - private val itemSlots: List get() { var itemIndex = 0 @@ -197,6 +169,22 @@ internal class SlotsGui( } } + private fun onNextPageClicked() { + this@SlotsGui.inventoryOwner.playSound(config.sounds.open) + paginator.openNextPage() + } + + private fun onPrevPageClicked() { + this@SlotsGui.inventoryOwner.playSound(config.sounds.open) + paginator.openPrevPage() + } + + private fun onSortButtonClicked(isRightClick: Boolean) { + this@SlotsGui.inventoryOwner.playSound(config.sounds.open) + auctionComponent.onSortButtonClicked(isRightClick) + setInventorySlot(sortButton) + } + override fun onInventoryCloseEvent(e: InventoryCloseEvent) { super.onInventoryCloseEvent(e) this@SlotsGui.inventoryOwner.playSound(config.sounds.close) @@ -232,15 +220,11 @@ internal class SlotsGui( override fun render() { super.render() - setInventorySlot(expiredSlotsButton) if (!paginator.context.isFirstPage) setInventorySlot(prevPageButton) if (!paginator.context.isLastPage) setInventorySlot(nextPageButton) - if (auctionComponent.model.value.targetPlayerUUID != null) { - setInventorySlot(openPlayersButton) - } else { - setInventorySlot(closeButton) - setInventorySlot(playerSlots) - } + setInventorySlot(filterExpiredButton) + setInventorySlot(displayTypeButton) + setInventorySlot(backButton) setInventorySlot(borderButtons) setInventorySlot(sortButton) setInventorySlot(itemSlots) diff --git a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/DurationExt.kt b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/DurationExt.kt index 0017993..c83096f 100644 --- a/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/DurationExt.kt +++ b/modules/gui/bukkit/src/main/kotlin/ru/astrainteractive/astramarket/gui/util/DurationExt.kt @@ -6,12 +6,21 @@ import java.util.concurrent.TimeUnit import kotlin.time.Duration @Suppress("MagicNumber") -fun Duration.getTimeFormatted(format: StringDesc): StringDesc { +fun Duration.getTimeFormatted( + formatDHM: StringDesc, + formatHM: StringDesc, + formatM: StringDesc +): StringDesc { val time = System.currentTimeMillis().minus(inWholeMilliseconds) val unit = TimeUnit.MILLISECONDS val days = unit.toDays(time) val hours = unit.toHours(time) - days * 24 val minutes = unit.toMinutes(time) - unit.toHours(time) * 60 + val format = when { + days == 0L && hours == 0L -> formatM + days == 0L -> formatHM + else -> formatDHM + } return format .replace("%days%", days.toString()) .replace("%hours%", hours.toString()) From 9d82575f09bd8d766720fc0e738d47a83b1bf996 Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Sun, 10 May 2026 11:46:56 +0300 Subject: [PATCH 10/10] [FIX] Up version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 33acc36..2f0469e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ klibs.java.ktarget=21 # Project klibs.project.name=AstraMarket klibs.project.group=ru.astrainteractive.astramarket -klibs.project.version.string=1.24.0 +klibs.project.version.string=1.25.0 klibs.project.description=Market plugin for EmpireSMP klibs.project.developers=makeevrserg|Makeev Roman|makeevrserg@gmail.com klibs.project.url=https://empireprojekt.ru