From 7aac325c709b3cd73d46cac94f5873cbacdd86e6 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Fri, 29 May 2026 00:39:12 +0200 Subject: [PATCH] hell --- .../cuanvil/dialog/AnvilRenameDialog.kt | 2 + .../cuanvil/dialog/AnvilRenameDialogImpl.kt | 127 +++++++++++------- .../alexcrea/cuanvil/util/AnvilTitleUtil.kt | 37 ++++- .../cuanvil/listener/PrepareAnvilListener.kt | 6 +- .../xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt | 10 +- .../util/dialog/AnvilRenameDialogUtil.kt | 4 + 6 files changed, 130 insertions(+), 56 deletions(-) diff --git a/nms/nms-common/src/main/kotlin/xyz/alexcrea/cuanvil/dialog/AnvilRenameDialog.kt b/nms/nms-common/src/main/kotlin/xyz/alexcrea/cuanvil/dialog/AnvilRenameDialog.kt index 62e1cf0..df6e883 100644 --- a/nms/nms-common/src/main/kotlin/xyz/alexcrea/cuanvil/dialog/AnvilRenameDialog.kt +++ b/nms/nms-common/src/main/kotlin/xyz/alexcrea/cuanvil/dialog/AnvilRenameDialog.kt @@ -18,4 +18,6 @@ interface AnvilRenameDialog { fun currentText(player: HumanEntity): String? + fun isOpenFor(player: HumanEntity): Boolean + } \ No newline at end of file diff --git a/nms/nms-paper/src/main/kotlin/xyz/alexcrea/cuanvil/dialog/AnvilRenameDialogImpl.kt b/nms/nms-paper/src/main/kotlin/xyz/alexcrea/cuanvil/dialog/AnvilRenameDialogImpl.kt index fb5fa0c..c6973f1 100644 --- a/nms/nms-paper/src/main/kotlin/xyz/alexcrea/cuanvil/dialog/AnvilRenameDialogImpl.kt +++ b/nms/nms-paper/src/main/kotlin/xyz/alexcrea/cuanvil/dialog/AnvilRenameDialogImpl.kt @@ -32,7 +32,7 @@ class AnvilRenameDialogImpl( val keepUserPreviousDialog: Supplier, val maxLength: Supplier, val plugin: Plugin, -): AnvilRenameDialog { +) : AnvilRenameDialog { companion object { private const val RENAME_TEXT_KEY = "rename" @@ -43,16 +43,24 @@ class AnvilRenameDialogImpl( // Need to be able to translate it later ! private val USER_FACING_RENAME_TITLE = Component.text("Rename Your Item") - private val USER_FACING_WARNING = Component.text("Note that the repair text will appear blank after Confirm\n" + - "But the name will be correctly applied") + private val USER_FACING_WARNING = Component.text( + "Note that the repair text will appear blank after Confirm\n" + + "But the name will be correctly applied" + ) private val USER_FACING_CONFIRM = Component.text("Confirm").color(TextColor.fromHexString("#40FF40")) private val USER_FACING_CANCEL = Component.text("Cancel").color(TextColor.fromHexString("#FF4040")) } private val lastNames = HashMap() + private val lastRenames = HashMap() + + private val lastLeftItem = HashMap() private val runTaskMap = HashMap() + // For monetary cost + val hasUiOpen = HashSet() + private val containerField = CraftInventoryView::class.java.getDeclaredField("container") init { @@ -63,75 +71,90 @@ class AnvilRenameDialogImpl( return true } - fun makeDialog(initial: String?, callback: Consumer): Dialog { + fun makeDialog(playerID: UUID, initial: String?, callback: Consumer): Dialog { val maxLength = this.maxLength.get() val initialFinal = initial?.take(maxLength) val baseBuilder = DialogBase.builder(USER_FACING_RENAME_TITLE) - .canCloseWithEscape(true) + .canCloseWithEscape(false) .afterAction(DialogBase.DialogAfterAction.CLOSE) - .inputs(listOf( - DialogInput.text(RENAME_TEXT_KEY, Component.text("Rename text")) - .maxLength(maxLength) - .initial(initialFinal ?: "") - .labelVisible(false) - .width(MAX_WIDTH) - .build(), + .inputs( + listOf( + DialogInput.text(RENAME_TEXT_KEY, Component.text("Rename text")) + .maxLength(maxLength) + .initial(initialFinal ?: "") + .labelVisible(false) + .width(MAX_WIDTH) + .build(), ), ) - baseBuilder.body(listOf( + baseBuilder.body( + listOf( DialogBody.plainMessage(USER_FACING_WARNING, MAX_WIDTH) - )) + ) + ) - return Dialog.create { builder -> builder.empty() - .base(baseBuilder.build()) - .type(DialogType.confirmation( - ActionButton.builder(USER_FACING_CONFIRM) - .action(DialogAction.customClick({ response, _ -> - val text = response.getText(RENAME_TEXT_KEY)!! - callback.accept(text) - }, ClickCallback.Options.builder().build())) - .build(), - ActionButton.builder(USER_FACING_CANCEL) - .build(), - )) + return Dialog.create { builder -> + builder.empty() + .base(baseBuilder.build()) + .type( + DialogType.confirmation( + ActionButton.builder(USER_FACING_CONFIRM) + .action(DialogAction.customClick({ response, _ -> + hasUiOpen.remove(playerID) + val text = response.getText(RENAME_TEXT_KEY)!! + callback.accept(text) + }, ClickCallback.Options.builder().build())) + .build(), + ActionButton.builder(USER_FACING_CANCEL) + .action(DialogAction.customClick({ response, _ -> + hasUiOpen.remove(playerID) + }, ClickCallback.Options.builder().build())) + .build(), + ) + ) } } private fun setResult(player: HumanEntity, view: CraftAnvilView, result: String?) { val defaultName = PLAIN_TEXT_SERIALIZER.serializeOrNull(view.getItem(0)?.effectiveName()) - if(defaultName == result) { - setName(player, view, "") - if(defaultName != null) lastNames[player.uniqueId] = defaultName - } - else setName(player, view, result) + if (defaultName == result) { + setName(player, view, "", null) + if (defaultName != null) lastNames[player.uniqueId] = defaultName + } else setName(player, view, lastNames[player.uniqueId], result) } - private fun setName(player: HumanEntity, view: CraftAnvilView, name: String?) { + private fun setName(player: HumanEntity, view: CraftAnvilView, name: String?, rename: String?) { val menu = (containerField.get(view) as AnvilMenu) val isSameName = menu.itemName == name menu.itemName = name - if(name == null) + if (name == null) lastNames.remove(player.uniqueId) else lastNames[player.uniqueId] = name - if(!isSameName) + if (rename == null) + lastRenames.remove(player.uniqueId) + else + lastRenames[player.uniqueId] = rename + + if (!isSameName) CraftEventFactory.callPrepareResultEvent(menu, 2); } private fun nameFromItem(player: HumanEntity, item: ItemStack?): String? { // Already has text - if(item?.hasItemMeta() != true || !item.itemMeta.hasCustomName()) + if (item?.hasItemMeta() != true || !item.itemMeta.hasCustomName()) return PLAIN_TEXT_SERIALIZER.serializeOrNull(item?.effectiveName()) - if(keepUserPreviousDialog.get() && item.hasItemMeta()) { + if (keepUserPreviousDialog.get() && item.hasItemMeta()) { val lastName = item.itemMeta.persistentDataContainer.get( AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY, - PersistentDataType.STRING) + PersistentDataType.STRING + ) - if(lastName != null) return lastName + if (lastName != null) return lastName } return fromFormated.apply(player, item.effectiveName()) @@ -139,33 +162,37 @@ class AnvilRenameDialogImpl( private fun tryShowDialogScheduled(player: HumanEntity, event: PrepareAnvilEvent) { val view = event.view - if(view !is CraftAnvilView) return + if (view !is CraftAnvilView) return val renameText = view.renameText val leftItem = view.getItem(0) val leftItemStr = leftItem?.toString() - val lastName = lastNames.getOrDefault(player.uniqueId, null) - if(lastLeftItem.getOrDefault(player.uniqueId, null) != leftItemStr) { - if(leftItemStr == null) + val lastName = lastNames.getOrDefault(player.uniqueId, null) + val lastRename = lastRenames.getOrDefault(player.uniqueId, null) + + if (lastLeftItem.getOrDefault(player.uniqueId, null) != leftItemStr) { + if (leftItemStr == null) lastLeftItem.remove(player.uniqueId) else lastLeftItem[player.uniqueId] = leftItemStr - setName(player, view, nameFromItem(player, leftItem)) + setName(player, view, renameText, nameFromItem(player, leftItem)) return } - if(lastName == renameText) + if (lastName == renameText) return - if(renameText?.isBlank() == true) { - setName(player, view, lastNames[player.uniqueId]) + if (renameText?.isBlank() == true) { + setName(player, view, lastName, lastRename) return } - val dialog = makeDialog(lastName) + val dialog = makeDialog(player.uniqueId, lastRename) { result -> setResult(player, view, result) } player.showDialog(dialog) + + hasUiOpen.add(player.uniqueId) } // We need to wait for a short time as changing item will change the name BEFORE the item change @@ -181,7 +208,7 @@ class AnvilRenameDialogImpl( {}, 2 ) - if(task == null) return + if (task == null) return runTaskMap[player.uniqueId] = task } @@ -196,4 +223,8 @@ class AnvilRenameDialogImpl( return lastNames[player.uniqueId] } + override fun isOpenFor(player: HumanEntity): Boolean { + return hasUiOpen.contains(player.uniqueId) + } + } \ No newline at end of file diff --git a/nms/nms-paper/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilTitleUtil.kt b/nms/nms-paper/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilTitleUtil.kt index cc92b78..e40e7ed 100644 --- a/nms/nms-paper/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilTitleUtil.kt +++ b/nms/nms-paper/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilTitleUtil.kt @@ -1,14 +1,45 @@ package xyz.alexcrea.cuanvil.util +import io.papermc.paper.threadedregions.scheduler.ScheduledTask +import org.bukkit.entity.HumanEntity import org.bukkit.inventory.InventoryView +import org.bukkit.plugin.Plugin +import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog +import java.util.HashMap +import java.util.UUID -// TODO yet another cleanup to do on legacy removal branch object AnvilTitleUtil { - fun rename(view: InventoryView, name: String) { - if(view.title == name) return + private val runTaskMap = HashMap() + + private fun actualRename(view: InventoryView, name: String, player: HumanEntity, anvilDialog: AnvilRenameDialog) { + runTaskMap.remove(player.uniqueId) + if (view.title == name) return + + // We assume rename impl is used + if (anvilDialog.isOpenFor(player)) return view.title = name } + // We don't want to rename instantly it is causing issue with rename text + // especially as it can "override" current ui when it is rename ui time but rename ui also need some delay + fun rename(view: InventoryView, name: String, player: HumanEntity, anvilDialog: AnvilRenameDialog, plugin: Plugin) { + runTaskMap.remove(player.uniqueId)?.cancel() + + val task = player.scheduler.runDelayed( + plugin, + { _ -> + run { actualRename(view, name, player, anvilDialog) } + }, + { + runTaskMap.remove(player.uniqueId) + }, + 2 + ) + + if (task == null) return + runTaskMap[player.uniqueId] = task + } + } \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt index fc04dcf..5ef3e27 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt @@ -59,6 +59,8 @@ class PrepareAnvilListener : Listener { if(player !is Player) return val inventory = event.inventory + tryRenameDialog(player, event) + // Test if custom anvil is bypassed before immutability test if (DependencyManager.earlyTryEventPreAnvilBypass(event, player)) { // even if we got bypassed we still want to set price @@ -87,8 +89,6 @@ class PrepareAnvilListener : Listener { return } - tryRenameDialog(player, event) - // Test if the event should bypass custom anvil. if (DependencyManager.tryEventPreAnvilBypass(event, player)) { // even if we got bypassed we still want to set price @@ -127,7 +127,7 @@ class PrepareAnvilListener : Listener { private fun setNoResult(event: PrepareAnvilEvent, view: InventoryView) { event.result = null - AnvilXpUtil.onNoResult(view) + // TODO AnvilXpUtil.onNoResult(view) } private fun tryRenameDialog( diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt index c8829f3..2d7bf0c 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt @@ -157,7 +157,10 @@ object AnvilXpUtil { val text = "Cost: " + (if(has) "§2" else "§4") + EconomyManager.economy!!.format(finalCost) - AnvilTitleUtil.rename(view, text) + AnvilTitleUtil.rename(view, text, + player, + AnvilRenameDialogUtil.anvilRenameDialog, + CustomAnvil.instance) clearAnvilXpCost(inventory, view, player) } @@ -229,7 +232,10 @@ object AnvilXpUtil { fun onNoResult(player: HumanEntity, view: InventoryView) { if (ConfigOptions.shouldUseMoney(player)) - AnvilTitleUtil.rename(view, "") + AnvilTitleUtil.rename(view, "", + player, + AnvilRenameDialogUtil.anvilRenameDialog, + CustomAnvil.instance) } private fun exclusivePenaltyKey(useType: AnvilUseType): NamespacedKey { diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/dialog/AnvilRenameDialogUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/dialog/AnvilRenameDialogUtil.kt index dbff77b..a83d8b0 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/util/dialog/AnvilRenameDialogUtil.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/dialog/AnvilRenameDialogUtil.kt @@ -47,5 +47,9 @@ object AnvilRenameDialogUtil { return null } + override fun isOpenFor(player: HumanEntity): Boolean { + return false + } + } } \ No newline at end of file