From 5b00b5119361be7dc7308fcdbe29f001d6e1486b Mon Sep 17 00:00:00 2001 From: TDSTOS Date: Sat, 28 Mar 2026 17:32:23 +0100 Subject: [PATCH] Update GUI-System The GUI-System now gets its messages from the en_US.yml file for better customizability --- .../speedhg/gui/anvil/AnvilSearchMenu.kt | 87 ++---------- .../speedhg/gui/factory/KitItemFactory.kt | 128 ++++++++---------- .../speedhg/gui/menu/KitSelectorMenu.kt | 127 +++++++---------- .../club/mcscrims/speedhg/gui/menu/Menu.kt | 5 +- src/main/resources/languages/en_US.yml | 22 +++ 5 files changed, 141 insertions(+), 228 deletions(-) diff --git a/src/main/kotlin/club/mcscrims/speedhg/gui/anvil/AnvilSearchMenu.kt b/src/main/kotlin/club/mcscrims/speedhg/gui/anvil/AnvilSearchMenu.kt index c71667a..b1e7956 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/gui/anvil/AnvilSearchMenu.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/gui/anvil/AnvilSearchMenu.kt @@ -12,107 +12,53 @@ import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.ItemStack import org.bukkit.inventory.view.AnvilView -/** - * Suchmenü auf Basis der **Paper Anvil-API** (kein NMS!). - * - * ## Wie Paper's Anvil-API funktioniert - * - * Paper stellt `player.openAnvil(location, force)` bereit. Diese Methode - * gibt eine `InventoryView` zurück. Da wir uns nicht für die physische Position - * interessieren (nur das Inventar-UI), übergeben wir `null` als Ort und - * `true` als Force-Flag (öffnet auch ohne physischen Amboss in der Nähe). - * - * ``` - * Slot 0 (INPUT_LEFT) → Das "Such-Icon" mit dem Placeholder-Text - * Slot 1 (INPUT_RIGHT) → Leer (wird vom Spieler nicht benutzt) - * Slot 2 (OUTPUT) → Das Ergebnis-Item → Klick bestätigt die Suche - * ``` - * - * Der Spieler schreibt in das Umbenennen-Feld des Amboss. Wir lesen den - * eingegebenen Text über `AnvilView.renameText` aus. Paper aktualisiert - * diesen Wert in Echtzeit. Beim Klick auf Slot 2 (Output) schließen wir - * den Amboss und übergeben den Text an [KitSelectorMenu.applySearch]. - * - * **Warum kein `PrepareAnvilEvent` + Fake-Item?** - * Für unsere reine Text-Eingabe brauchen wir kein Live-Feedback im Output-Slot. - * Wir setzen ein statisches Bestätigungs-Item und lesen den Rename-Text beim - * Klick aus. Das ist einfacher und stabiler. - * - * @param player Der suchende Spieler. - * @param returnMenu Das [KitSelectorMenu] zu dem wir nach der Suche zurückspringen. - * @param initialText Vorausgefüllter Text (wird als Rename-Text gesetzt). - */ @Suppress("DEPRECATION") class AnvilSearchMenu( private val player: Player, private val returnMenu: KitSelectorMenu, private val initialText: String = "" ) { - private val plugin = SpeedHG.instance + private val plugin get() = SpeedHG.instance + private val lm get() = plugin.languageManager private val mm = MiniMessage.miniMessage() - /** Öffnet das Anvil-Inventar. */ fun open(player: Player) { - // Paper API: öffnet einen Amboss ohne physischen Block - val view = player.openAnvil(null, true) ?: return + val view = player.openAnvil(null, true) ?: return val anvilInv = view.topInventory as? AnvilInventory ?: return - // ── Slot 0: Such-Icon (Input) ────────────────────────────────────── anvilInv.setItem(0, buildInputItem()) - - // ── Slot 2: Bestätigungs-Icon (Output) ──────────────────────────── anvilInv.setItem(2, buildConfirmItem()) - - // Kosten auf 0 setzen — Spieler soll kein XP zahlen anvilInv.repairCost = 0 - // Klick-Listener merken uns über die AnvilTracker-Map AnvilSearchTracker.register(player, this) } - /** - * Verarbeitet einen Klick im Anvil-Inventory. - * Wird vom [MenuListener] über [AnvilSearchTracker] weitergeleitet. - * - * @param event Das Click-Event (bereits gecancelt). - * @param view Die geöffnete [AnvilView] mit dem Eingabetext. - */ fun onClick(event: InventoryClickEvent, view: AnvilView) { event.isCancelled = true - - // Nur Klick auf Output-Slot (Slot 2) bestätigt die Suche if (event.rawSlot != 2) return val query = view.renameText ?: "" - - // Amboss schließen und zurück zum Kit-Menü player.closeInventory() AnvilSearchTracker.unregister(player) - - // Suchbegriff anwenden → öffnet KitSelectorMenu neu returnMenu.applySearch(query) } - /** Cleanup wenn Spieler Amboss schließt ohne zu bestätigen. */ fun onClose() { AnvilSearchTracker.unregister(player) - // Zurück zum Kit-Menü ohne Suchbegriff zu ändern - // Einen Tick warten, damit das aktuelle Close-Event fertig ist plugin.server.scheduler.runTask(plugin) { -> returnMenu.open(player) } } - // ------------------------------------------------------------------------- - // Item-Builder - // ------------------------------------------------------------------------- + // ── Item-Builder ────────────────────────────────────────────────────────── private fun buildInputItem(): ItemStack { + val rawPlaceholder = initialText.ifEmpty { lm.getRawMessage(player, "gui.anvil_search.input_placeholder") } + val item = ItemStack(Material.NAME_TAG) item.editMeta { meta -> meta.displayName( - // Der Name des Input-Items wird als Placeholder-Text im Umbenennungsfeld angezeigt - mm.deserialize(initialText.ifEmpty { "Suchbegriff eingeben..." }) + mm.deserialize(rawPlaceholder) .decoration(TextDecoration.ITALIC, false) ) } @@ -123,31 +69,24 @@ class AnvilSearchMenu( val item = ItemStack(Material.NAME_TAG) item.editMeta { meta -> meta.displayName( - mm.deserialize("✔ Suche bestätigen") + mm.deserialize(lm.getRawMessage(player, "gui.anvil_search.confirm_name")) .decoration(TextDecoration.ITALIC, false) ) - val lore = listOf( + meta.lore(listOf( Component.empty(), - mm.deserialize("Klicken um zu suchen") + mm.deserialize(lm.getRawMessage(player, "gui.anvil_search.confirm_click")) .decoration(TextDecoration.ITALIC, false), Component.empty() - ) - meta.lore(lore) + )) } return item } } -/** - * Hält die Zuordnung `Player → AnvilSearchMenu` für alle aktuell offenen - * Anvil-Suchen. Wird benötigt, weil Anvil-Inventories keinen eigenen - * [MenuHolder] haben — sie werden direkt von Bukkit verwaltet. - * - * Die Map wird im [MenuListener] abgefragt. - */ object AnvilSearchTracker { - private val openSearches = java.util.concurrent.ConcurrentHashMap() + private val openSearches = + java.util.concurrent.ConcurrentHashMap() fun register(player: Player, menu: AnvilSearchMenu) { openSearches[player.uniqueId] = menu diff --git a/src/main/kotlin/club/mcscrims/speedhg/gui/factory/KitItemFactory.kt b/src/main/kotlin/club/mcscrims/speedhg/gui/factory/KitItemFactory.kt index 954d198..bb23200 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/gui/factory/KitItemFactory.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/gui/factory/KitItemFactory.kt @@ -1,94 +1,69 @@ package club.mcscrims.speedhg.gui.factory +import club.mcscrims.speedhg.SpeedHG import club.mcscrims.speedhg.kit.Kit import club.mcscrims.speedhg.kit.Playstyle import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextDecoration import net.kyori.adventure.text.minimessage.MiniMessage +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder +import org.bukkit.Material import org.bukkit.enchantments.Enchantment +import org.bukkit.entity.Player import org.bukkit.inventory.ItemFlag import org.bukkit.inventory.ItemStack -/** - * Erstellt dynamisch die [ItemStack]s für das Kit-Auswahl-Menü. - * - * ## Warum eine eigene Factory? - * - * Die Item-Generierung (Icon, Name, Lore, Enchants) ist von [KitSelectorMenu] - * trennbar und testbar. Außerdem kann sie wiederverwendet werden (z.B. für - * Hotbar-Items oder Chat-Vorschauen). - * - * ## Lore-Aufbau - * ``` - * ───────────────────────── - * - * - * - * Playstyle: ► Aggressive - * - * [L-Klick] Kit auswählen - * [R-Klick] Playstyle wechseln - * ───────────────────────── - * ``` - */ object KitItemFactory { + private val plugin get() = SpeedHG.instance private val mm = MiniMessage.miniMessage() - /** - * Baut das vollständige Kit-Item inklusive dynamischer Lore. - * - * @param kit Das Kit, das dargestellt werden soll. - * @param currentStyle Der aktuell gewählte [Playstyle] des Spielers. - * @param isSelected Ob dieses Kit gerade das aktiv gewählte ist. - */ + // ── Kit-Item ────────────────────────────────────────────────────────────── + fun buildKitItem( kit: Kit, currentStyle: Playstyle, - isSelected: Boolean + isSelected: Boolean, + player: Player ): ItemStack { + val lm = plugin.languageManager val item = ItemStack(kit.icon) item.editMeta { meta -> - // ── Name ────────────────────────────────────────────────────────── meta.displayName( - kit.displayName - .decoration(TextDecoration.ITALIC, false) + kit.displayName.decoration(TextDecoration.ITALIC, false) ) - // ── Lore ────────────────────────────────────────────────────────── val lore = mutableListOf() - // Trennlinie lore += separator() - // Kit-eigene Lore-Zeilen kit.lore.forEach { line -> - lore += mm.deserialize(line) - .decoration(TextDecoration.ITALIC, false) + lore += mm.deserialize(line).decoration(TextDecoration.ITALIC, false) } lore += Component.empty() - // Playstyle-Anzeige lore += mm.deserialize( - "Playstyle: ► ${currentStyle.displayName}" + lm.getRawMessage(player, "gui.kit_selector.kit_item.playstyle"), + Placeholder.parsed("playstyle", currentStyle.displayName) ).decoration(TextDecoration.ITALIC, false) lore += Component.empty() - // Interaktions-Hints - lore += mm.deserialize("[L-Click] Select Kit") - .decoration(TextDecoration.ITALIC, false) - lore += mm.deserialize("[R-Click] Change playstyle") - .decoration(TextDecoration.ITALIC, false) + lore += mm.deserialize( + lm.getRawMessage(player, "gui.kit_selector.kit_item.left_click") + ).decoration(TextDecoration.ITALIC, false) + + lore += mm.deserialize( + lm.getRawMessage(player, "gui.kit_selector.kit_item.right_click") + ).decoration(TextDecoration.ITALIC, false) lore += separator() meta.lore(lore) - // ── Ausgewählt-Effekt ────────────────────────────────────────────── if (isSelected) { meta.addEnchant(Enchantment.UNBREAKING, 1, true) meta.addItemFlags(ItemFlag.HIDE_ENCHANTS) @@ -103,66 +78,77 @@ object KitItemFactory { return item } - // ── Dekorations-Items ───────────────────────────────────────────────────── + // ── Dekorations- und Navigations-Items ─────────────────────────────────── fun buildFillerItem(): ItemStack { - val item = ItemStack(org.bukkit.Material.GRAY_STAINED_GLASS_PANE) + val item = ItemStack(Material.GRAY_STAINED_GLASS_PANE) item.editMeta { meta -> - meta.displayName(Component.text(" ").decoration(TextDecoration.ITALIC, false)) + meta.displayName( + Component.text(" ").decoration(TextDecoration.ITALIC, false) + ) } return item } - fun buildPrevPageItem(): ItemStack = buildNavItem( - org.bukkit.Material.ARROW, - "◄ Previous" + fun buildPrevPageItem(player: Player): ItemStack = buildNavItem( + Material.ARROW, + plugin.languageManager.getRawMessage(player, "gui.kit_selector.prev_page") ) - fun buildNextPageItem(): ItemStack = buildNavItem( - org.bukkit.Material.ARROW, - "Next ►" + fun buildNextPageItem(player: Player): ItemStack = buildNavItem( + Material.ARROW, + plugin.languageManager.getRawMessage(player, "gui.kit_selector.next_page") ) - fun buildSearchItem(currentQuery: String): ItemStack { - val item = ItemStack(org.bukkit.Material.NAME_TAG) + fun buildSearchItem(currentQuery: String, player: Player): ItemStack { + val lm = plugin.languageManager + val item = ItemStack(Material.NAME_TAG) + item.editMeta { meta -> meta.displayName( - mm.deserialize("🔍 Search") + mm.deserialize(lm.getRawMessage(player, "gui.kit_selector.search.name")) .decoration(TextDecoration.ITALIC, false) ) + val lore = mutableListOf() lore += separator() + if (currentQuery.isNotEmpty()) { - lore += mm.deserialize("Current: \"$currentQuery\"") - .decoration(TextDecoration.ITALIC, false) + lore += mm.deserialize( + lm.getRawMessage(player, "gui.kit_selector.search.current"), + Placeholder.parsed("query", currentQuery) + ).decoration(TextDecoration.ITALIC, false) lore += Component.empty() } - lore += mm.deserialize("Click to search") - .decoration(TextDecoration.ITALIC, false) + + lore += mm.deserialize( + lm.getRawMessage(player, "gui.kit_selector.search.click") + ).decoration(TextDecoration.ITALIC, false) + lore += separator() meta.lore(lore) } + return item } - fun buildClearSearchItem(): ItemStack = buildNavItem( - org.bukkit.Material.BARRIER, - "✕ Reset search" + fun buildClearSearchItem(player: Player): ItemStack = buildNavItem( + Material.BARRIER, + plugin.languageManager.getRawMessage(player, "gui.kit_selector.clear_search") ) - fun buildCloseItem(): ItemStack = buildNavItem( - org.bukkit.Material.DARK_OAK_DOOR, - "✕ Close" + fun buildCloseItem(player: Player): ItemStack = buildNavItem( + Material.DARK_OAK_DOOR, + plugin.languageManager.getRawMessage(player, "gui.kit_selector.close") ) // ── Interne Hilfsmittel ─────────────────────────────────────────────────── - private fun buildNavItem(material: org.bukkit.Material, title: String): ItemStack { + private fun buildNavItem(material: Material, rawTitle: String): ItemStack { val item = ItemStack(material) item.editMeta { meta -> meta.displayName( - mm.deserialize(title) - .decoration(TextDecoration.ITALIC, false) + mm.deserialize(rawTitle).decoration(TextDecoration.ITALIC, false) ) meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ADDITIONAL_TOOLTIP) } diff --git a/src/main/kotlin/club/mcscrims/speedhg/gui/menu/KitSelectorMenu.kt b/src/main/kotlin/club/mcscrims/speedhg/gui/menu/KitSelectorMenu.kt index a998438..f97dd00 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/gui/menu/KitSelectorMenu.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/gui/menu/KitSelectorMenu.kt @@ -5,7 +5,7 @@ import club.mcscrims.speedhg.gui.anvil.AnvilSearchMenu import club.mcscrims.speedhg.gui.factory.KitItemFactory import club.mcscrims.speedhg.kit.Kit import club.mcscrims.speedhg.kit.Playstyle -import net.kyori.adventure.text.minimessage.MiniMessage +import club.mcscrims.speedhg.util.trans import org.bukkit.entity.Player import org.bukkit.event.inventory.ClickType import org.bukkit.event.inventory.InventoryClickEvent @@ -32,23 +32,19 @@ import org.bukkit.inventory.Inventory class KitSelectorMenu( private val player: Player, private var searchQuery: String = "" -) : Menu(rows = 6, title = "Kit-Auswahl") { +) : Menu( + rows = 6, + title = player.trans( "gui.kit_selector.title" ) +) { - private val plugin = SpeedHG.instance - private val mm = MiniMessage.miniMessage() + private val plugin get() = SpeedHG.instance + private val lm get() = plugin.languageManager // Pagination private val kitSlots = 45 // Slots 0–44 für Kits private var currentPage = 0 // ── Slot-Konstanten ──────────────────────────────────────────────────────── - private val slotPrevPage = 45 - private val slotSearch = 48 - private val slotClearSearch = 50 - private val slotClose = 53 - private val slotNextPage = 53 // wird durch slotClose ersetzt wenn letzte Seite - - // ── Navigation-Slots ────────────────────────────────────────────────────── private val navSlotPrev = 45 private val navSlotSearch = 48 private val navSlotClear = 50 @@ -59,7 +55,7 @@ class KitSelectorMenu( // ------------------------------------------------------------------------- override fun build(): Inventory { - val inv = createInventory(mm.deserialize(title)) + val inv = createInventory(title) // title ist jetzt bereits ein Component populate(inv) return inv } @@ -67,70 +63,65 @@ class KitSelectorMenu( private fun populate(inv: Inventory) { inv.clear() - // ── Filler ──────────────────────────────────────────────────────────── + // Filler-Reihe val filler = KitItemFactory.buildFillerItem() (45 until 54).forEach { inv.setItem(it, filler) } - // ── Kits ────────────────────────────────────────────────────────────── + // Kits val filteredKits = getFilteredKits() - val totalPages = ((filteredKits.size - 1) / kitSlots + 1).coerceAtLeast(1) + val totalPages = ((filteredKits.size - 1) / kitSlots + 1).coerceAtLeast(1) - // Seiten-Clamp: wenn Suche Kits reduziert, nicht auf nicht-existenter Seite bleiben currentPage = currentPage.coerceIn(0, totalPages - 1) val pageStart = currentPage * kitSlots - val pageKits = filteredKits.subList( + val pageKits = filteredKits.subList( pageStart.coerceAtMost(filteredKits.size), (pageStart + kitSlots).coerceAtMost(filteredKits.size) ) pageKits.forEachIndexed { slotIndex, kit -> val currentStyle = plugin.kitManager.getSelectedPlaystyle(player) - val selectedKit = plugin.kitManager.getSelectedKit(player) - inv.setItem(slotIndex, KitItemFactory.buildKitItem(kit, currentStyle, selectedKit?.id == kit.id)) + val selectedKit = plugin.kitManager.getSelectedKit(player) + inv.setItem( + slotIndex, + KitItemFactory.buildKitItem(kit, currentStyle, selectedKit?.id == kit.id, player) + ) } - // ── Navigation ──────────────────────────────────────────────────────── + // Navigation if (currentPage > 0) - inv.setItem(navSlotPrev, KitItemFactory.buildPrevPageItem()) + inv.setItem(navSlotPrev, KitItemFactory.buildPrevPageItem(player)) if (currentPage < totalPages - 1) - inv.setItem(navSlotNext, KitItemFactory.buildNextPageItem()) + inv.setItem(navSlotNext, KitItemFactory.buildNextPageItem(player)) - inv.setItem(navSlotSearch, KitItemFactory.buildSearchItem(searchQuery)) + inv.setItem(navSlotSearch, KitItemFactory.buildSearchItem(searchQuery, player)) if (searchQuery.isNotEmpty()) - inv.setItem(navSlotClear, KitItemFactory.buildClearSearchItem()) + inv.setItem(navSlotClear, KitItemFactory.buildClearSearchItem(player)) } - // ------------------------------------------------------------------------- - // Klick-Handling - // ------------------------------------------------------------------------- + // ── Klick-Handling ──────────────────────────────────────────────────────── override fun onClick(event: InventoryClickEvent, player: Player) { val slot = event.rawSlot if (slot !in 0.. handlePrevPage() - navSlotNext -> handleNextPage() - navSlotSearch -> handleSearchClick() - navSlotClear -> handleClearSearch() - in 0 until kitSlots -> handleKitClick(slot, event.click) + navSlotPrev -> handlePrevPage() + navSlotNext -> handleNextPage() + navSlotSearch -> handleSearchClick() + navSlotClear -> handleClearSearch() + in 0 until kitSlots -> handleKitClick(slot, event.click) } } - // ------------------------------------------------------------------------- - // Kit-Interaktionen - // ------------------------------------------------------------------------- + // ── Kit-Interaktionen ───────────────────────────────────────────────────── private fun handleKitClick(slot: Int, clickType: ClickType) { val kit = getKitAtSlot(slot) ?: return - when { - // Linksklick → Kit auswählen clickType.isLeftClick -> selectKit(kit) - // Rechtsklick → Playstyle toggeln (und Menü refreshen) clickType.isRightClick -> togglePlaystyle(kit) } } @@ -138,27 +129,27 @@ class KitSelectorMenu( private fun selectKit(kit: Kit) { plugin.kitManager.selectKit(player, kit) player.sendActionBar( - MiniMessage.miniMessage().deserialize( - "Kit ${kit.displayName} gewählt!" + lm.getComponent( + player, "gui.kit_selector.kit_selected", + mapOf(), mapOf("kit" to kit.displayName) ) ) - // Menü aktualisieren um Auswahl-Glanz zu zeigen refresh() } private fun togglePlaystyle(kit: Kit) { val current = plugin.kitManager.getSelectedPlaystyle(player) - val next = when (current) { + val next = when (current) { Playstyle.AGGRESSIVE -> Playstyle.DEFENSIVE Playstyle.DEFENSIVE -> Playstyle.AGGRESSIVE } plugin.kitManager.selectPlaystyle(player, next) - // Wenn dieses Kit gerade ausgewählt ist, Playstyle-Änderung übernehmen if (plugin.kitManager.getSelectedKit(player)?.id == kit.id) { player.sendActionBar( - MiniMessage.miniMessage().deserialize( - "Playstyle: ► ${next.displayName}" + lm.getComponent( + player, "gui.kit_selector.playstyle_changed", + mapOf("playstyle" to next.displayName) ) ) } @@ -166,32 +157,20 @@ class KitSelectorMenu( refresh() } - // ------------------------------------------------------------------------- - // Navigation - // ------------------------------------------------------------------------- + // ── Navigation ──────────────────────────────────────────────────────────── private fun handlePrevPage() { - if (currentPage > 0) { - currentPage-- - refresh() - } + if (currentPage > 0) { currentPage--; refresh() } } private fun handleNextPage() { val totalPages = ((getFilteredKits().size - 1) / kitSlots + 1).coerceAtLeast(1) - if (currentPage < totalPages - 1) { - currentPage++ - refresh() - } + if (currentPage < totalPages - 1) { currentPage++; refresh() } } private fun handleSearchClick() { - // Öffne das Anvil-Suchmenü; schließt dieses Menü temporär - AnvilSearchMenu( - player = player, - returnMenu = this, - initialText = searchQuery - ).open(player) + AnvilSearchMenu(player = player, returnMenu = this, initialText = searchQuery) + .open(player) } private fun handleClearSearch() { @@ -200,23 +179,14 @@ class KitSelectorMenu( refresh() } - // ------------------------------------------------------------------------- - // Hilfsmittel - // ------------------------------------------------------------------------- + // ── Hilfsmittel ─────────────────────────────────────────────────────────── - /** Aktualisiert das geöffnete Inventory in-place ohne es neu zu öffnen. */ - fun refresh() { - populate(inventory) - } + fun refresh() { populate(inventory) } - /** - * Aktualisiert den Suchbegriff und baut das Menü neu auf. - * Wird vom [AnvilSearchMenu] aufgerufen nachdem der Spieler einen Begriff eingegeben hat. - */ fun applySearch(query: String) { searchQuery = query.trim() currentPage = 0 - open(player) // neu öffnen (Anvil hat das vorherige Inventory geschlossen) + open(player) } private fun getFilteredKits(): List { @@ -225,19 +195,14 @@ class KitSelectorMenu( val q = searchQuery.lowercase() return allKits.filter { kit -> - // Suche im Plain-Text des Adventure-Components kit.id.lowercase().contains(q) || net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer - .plainText() - .serialize(kit.displayName) - .lowercase() - .contains(q) + .plainText().serialize(kit.displayName).lowercase().contains(q) } } private fun getKitAtSlot(slot: Int): Kit? { - val filteredKits = getFilteredKits() val absoluteIndex = currentPage * kitSlots + slot - return filteredKits.getOrNull(absoluteIndex) + return getFilteredKits().getOrNull(absoluteIndex) } } \ No newline at end of file diff --git a/src/main/kotlin/club/mcscrims/speedhg/gui/menu/Menu.kt b/src/main/kotlin/club/mcscrims/speedhg/gui/menu/Menu.kt index 1504fc7..ef94cf9 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/gui/menu/Menu.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/gui/menu/Menu.kt @@ -1,5 +1,6 @@ package club.mcscrims.speedhg.gui.menu +import net.kyori.adventure.text.Component import org.bukkit.Bukkit import org.bukkit.entity.Player import org.bukkit.event.inventory.InventoryClickEvent @@ -25,7 +26,7 @@ import org.bukkit.inventory.Inventory */ abstract class Menu( protected val rows: Int, - protected val title: String + protected val title: Component ) { protected val size: Int = rows * 9 internal lateinit var inventory: Inventory @@ -56,7 +57,7 @@ abstract class Menu( * Erstellt ein Inventory mit dem korrekten [MenuHolder]. * Immer statt `Bukkit.createInventory(null, ...)` verwenden. */ - protected fun createInventory(parsedTitle: net.kyori.adventure.text.Component): Inventory { + protected fun createInventory(parsedTitle: Component): Inventory { val holder = MenuHolder(this) val inv = Bukkit.createInventory(holder, size, parsedTitle) holder.bind(inv) diff --git a/src/main/resources/languages/en_US.yml b/src/main/resources/languages/en_US.yml index 7616e86..77d7ee3 100644 --- a/src/main/resources/languages/en_US.yml +++ b/src/main/resources/languages/en_US.yml @@ -95,6 +95,28 @@ scoreboard: - "" - "play.mcscrims.club" +gui: + kit_selector: + title: 'Kit Selection' + kit_selected: 'Kit selected!' + playstyle_changed: 'Playstyle: ' + prev_page: '◄ Previous' + next_page: 'Next ►' + clear_search: '✕ Reset Search' + close: '✕ Close' + kit_item: + playstyle: 'Playstyle: ' + left_click: '[L-Click] Select Kit' + right_click: '[R-Click] Change Playstyle' + search: + name: '🔍 Search' + current: 'Current: ""' + click: 'Click to search' + anvil_search: + input_placeholder: 'Enter search term...' + confirm_name: '✔ Confirm Search' + confirm_click: 'Click to confirm' + kits: backup: name: 'Backup'