This commit is contained in:
alexcrea 2026-05-29 00:39:12 +02:00
parent 171a8cad6d
commit 7aac325c70
Signed by: alexcrea
GPG key ID: E346CD16413450E3
6 changed files with 130 additions and 56 deletions

View file

@ -18,4 +18,6 @@ interface AnvilRenameDialog {
fun currentText(player: HumanEntity): String?
fun isOpenFor(player: HumanEntity): Boolean
}

View file

@ -32,7 +32,7 @@ class AnvilRenameDialogImpl(
val keepUserPreviousDialog: Supplier<Boolean>,
val maxLength: Supplier<Int>,
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<UUID, String>()
private val lastRenames = HashMap<UUID, String>()
private val lastLeftItem = HashMap<UUID, String>()
private val runTaskMap = HashMap<UUID, ScheduledTask>()
// For monetary cost
val hasUiOpen = HashSet<UUID>()
private val containerField = CraftInventoryView::class.java.getDeclaredField("container")
init {
@ -63,75 +71,90 @@ class AnvilRenameDialogImpl(
return true
}
fun makeDialog(initial: String?, callback: Consumer<String?>): Dialog {
fun makeDialog(playerID: UUID, initial: String?, callback: Consumer<String?>): 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)
}
}

View file

@ -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<UUID, ScheduledTask>()
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
}
}

View file

@ -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(

View file

@ -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 {

View file

@ -47,5 +47,9 @@ object AnvilRenameDialogUtil {
return null
}
override fun isOpenFor(player: HumanEntity): Boolean {
return false
}
}
}