mirror of
https://github.com/alexcrea/CustomAnvil.git
synced 2026-06-23 08:14:00 +02:00
Lot of internal change and monetary cost (#116)
Internal changes this big was not intentional but had to do it for monetary cost excluding that: - add monetary cost, with dependency on rename dialogue - also change some a bit rename dialog
This commit is contained in:
commit
380b0de92f
40 changed files with 1702 additions and 717 deletions
|
|
@ -40,11 +40,14 @@ repositories {
|
||||||
// ItemsAdder
|
// ItemsAdder
|
||||||
maven(url = "https://maven.devs.beer/")
|
maven(url = "https://maven.devs.beer/")
|
||||||
|
|
||||||
// for fast stats
|
// For fast stats
|
||||||
maven {
|
maven {
|
||||||
name = "thenextlvlReleases"
|
name = "thenextlvlReleases"
|
||||||
url = uri("https://repo.thenextlvl.net/releases")
|
url = uri("https://repo.thenextlvl.net/releases")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For vault unlocked
|
||||||
|
maven { url = uri("https://repo.codemc.io/repository/creatorfromhell/") }
|
||||||
}
|
}
|
||||||
|
|
||||||
val reobfNMS = providers.gradleProperty("subprojects.reobfnms")
|
val reobfNMS = providers.gradleProperty("subprojects.reobfnms")
|
||||||
|
|
@ -103,6 +106,9 @@ dependencies {
|
||||||
// ItemsAdder API
|
// ItemsAdder API
|
||||||
compileOnly("dev.lone:api-itemsadder:4.0.10")
|
compileOnly("dev.lone:api-itemsadder:4.0.10")
|
||||||
|
|
||||||
|
// Vault api
|
||||||
|
compileOnly("net.milkbowl.vault:VaultUnlockedAPI:2.16")
|
||||||
|
|
||||||
// Include nms
|
// Include nms
|
||||||
implementation(project(":nms:nms-common"))
|
implementation(project(":nms:nms-common"))
|
||||||
implementation(project(":nms:nms-paper"))
|
implementation(project(":nms:nms-paper"))
|
||||||
|
|
|
||||||
|
|
@ -430,6 +430,33 @@ lore_edit:
|
||||||
allow_hexadecimal_color: false
|
allow_hexadecimal_color: false
|
||||||
allow_minimessage: true
|
allow_minimessage: true
|
||||||
|
|
||||||
|
# Allow to replace the xp cost by a monetary cost
|
||||||
|
# If enabled it will not be bound to the experience level limits
|
||||||
|
#
|
||||||
|
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||||
|
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||||
|
#
|
||||||
|
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||||
|
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||||
|
#
|
||||||
|
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||||
|
monetary_cost:
|
||||||
|
enabled: false
|
||||||
|
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||||
|
# default being the default currency
|
||||||
|
currency: default
|
||||||
|
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||||
|
multipliers:
|
||||||
|
# global multipliers. all usage type will be multiplied by this value
|
||||||
|
global: 1.0
|
||||||
|
# usage specific type. it will only apply for specific xp "reason"
|
||||||
|
enchantment: 1.0 # related to enchantments level
|
||||||
|
repair: 1.0 # for repairing via unit repair (per unit)
|
||||||
|
rename: 1.0 # for renaming the item
|
||||||
|
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||||
|
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||||
|
recipe: 1.0 # for custom anvil recipe cost
|
||||||
|
|
||||||
# Whether to show debug logging
|
# Whether to show debug logging
|
||||||
debug_log: false
|
debug_log: false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -450,6 +450,33 @@ lore_edit:
|
||||||
allow_hexadecimal_color: false
|
allow_hexadecimal_color: false
|
||||||
allow_minimessage: true
|
allow_minimessage: true
|
||||||
|
|
||||||
|
# Allow to replace the xp cost by a monetary cost
|
||||||
|
# If enabled it will not be bound to the experience level limits
|
||||||
|
#
|
||||||
|
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||||
|
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||||
|
#
|
||||||
|
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||||
|
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||||
|
#
|
||||||
|
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||||
|
monetary_cost:
|
||||||
|
enabled: false
|
||||||
|
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||||
|
# default being the default currency
|
||||||
|
currency: default
|
||||||
|
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||||
|
multipliers:
|
||||||
|
# global multipliers. all usage type will be multiplied by this value
|
||||||
|
global: 1.0
|
||||||
|
# usage specific type. it will only apply for specific xp "reason"
|
||||||
|
enchantment: 1.0 # related to enchantments level
|
||||||
|
repair: 1.0 # for repairing via unit repair (per unit)
|
||||||
|
rename: 1.0 # for renaming the item
|
||||||
|
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||||
|
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||||
|
recipe: 1.0 # for custom anvil recipe cost
|
||||||
|
|
||||||
# Whether to show debug logging
|
# Whether to show debug logging
|
||||||
debug_log: false
|
debug_log: false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -442,6 +442,33 @@ lore_edit:
|
||||||
allow_hexadecimal_color: false
|
allow_hexadecimal_color: false
|
||||||
allow_minimessage: true
|
allow_minimessage: true
|
||||||
|
|
||||||
|
# Allow to replace the xp cost by a monetary cost
|
||||||
|
# If enabled it will not be bound to the experience level limits
|
||||||
|
#
|
||||||
|
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||||
|
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||||
|
#
|
||||||
|
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||||
|
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||||
|
#
|
||||||
|
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||||
|
monetary_cost:
|
||||||
|
enabled: false
|
||||||
|
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||||
|
# default being the default currency
|
||||||
|
currency: default
|
||||||
|
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||||
|
multipliers:
|
||||||
|
# global multipliers. all usage type will be multiplied by this value
|
||||||
|
global: 1.0
|
||||||
|
# usage specific type. it will only apply for specific xp "reason"
|
||||||
|
enchantment: 1.0 # related to enchantments level
|
||||||
|
repair: 1.0 # for repairing via unit repair (per unit)
|
||||||
|
rename: 1.0 # for renaming the item
|
||||||
|
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||||
|
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||||
|
recipe: 1.0 # for custom anvil recipe cost
|
||||||
|
|
||||||
# Whether to show debug logging
|
# Whether to show debug logging
|
||||||
debug_log: false
|
debug_log: false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -430,6 +430,33 @@ lore_edit:
|
||||||
allow_hexadecimal_color: false
|
allow_hexadecimal_color: false
|
||||||
allow_minimessage: true
|
allow_minimessage: true
|
||||||
|
|
||||||
|
# Allow to replace the xp cost by a monetary cost
|
||||||
|
# If enabled it will not be bound to the experience level limits
|
||||||
|
#
|
||||||
|
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||||
|
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||||
|
#
|
||||||
|
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||||
|
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||||
|
#
|
||||||
|
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||||
|
monetary_cost:
|
||||||
|
enabled: false
|
||||||
|
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||||
|
# default being the default currency
|
||||||
|
currency: default
|
||||||
|
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||||
|
multipliers:
|
||||||
|
# global multipliers. all usage type will be multiplied by this value
|
||||||
|
global: 1.0
|
||||||
|
# usage specific type. it will only apply for specific xp "reason"
|
||||||
|
enchantment: 1.0 # related to enchantments level
|
||||||
|
repair: 1.0 # for repairing via unit repair (per unit)
|
||||||
|
rename: 1.0 # for renaming the item
|
||||||
|
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||||
|
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||||
|
recipe: 1.0 # for custom anvil recipe cost
|
||||||
|
|
||||||
# Whether to show debug logging
|
# Whether to show debug logging
|
||||||
debug_log: false
|
debug_log: false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,6 @@ interface AnvilRenameDialog {
|
||||||
|
|
||||||
fun currentText(player: HumanEntity): String?
|
fun currentText(player: HumanEntity): String?
|
||||||
|
|
||||||
|
fun isOpenFor(player: HumanEntity): Boolean
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventoryView
|
||||||
import org.bukkit.craftbukkit.inventory.view.CraftAnvilView
|
import org.bukkit.craftbukkit.inventory.view.CraftAnvilView
|
||||||
import org.bukkit.entity.HumanEntity
|
import org.bukkit.entity.HumanEntity
|
||||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||||
|
import org.bukkit.inventory.InventoryView
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.persistence.PersistentDataType
|
import org.bukkit.persistence.PersistentDataType
|
||||||
import org.bukkit.plugin.Plugin
|
import org.bukkit.plugin.Plugin
|
||||||
|
|
@ -32,7 +33,7 @@ class AnvilRenameDialogImpl(
|
||||||
val keepUserPreviousDialog: Supplier<Boolean>,
|
val keepUserPreviousDialog: Supplier<Boolean>,
|
||||||
val maxLength: Supplier<Int>,
|
val maxLength: Supplier<Int>,
|
||||||
val plugin: Plugin,
|
val plugin: Plugin,
|
||||||
): AnvilRenameDialog {
|
) : AnvilRenameDialog {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val RENAME_TEXT_KEY = "rename"
|
private const val RENAME_TEXT_KEY = "rename"
|
||||||
|
|
@ -43,16 +44,28 @@ class AnvilRenameDialogImpl(
|
||||||
|
|
||||||
// Need to be able to translate it later !
|
// Need to be able to translate it later !
|
||||||
private val USER_FACING_RENAME_TITLE = Component.text("Rename Your Item")
|
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" +
|
private val USER_FACING_WARNING = Component.text(
|
||||||
"But the name will be correctly applied")
|
"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_CONFIRM = Component.text("Confirm").color(TextColor.fromHexString("#40FF40"))
|
||||||
private val USER_FACING_CANCEL = Component.text("Cancel").color(TextColor.fromHexString("#FF4040"))
|
private val USER_FACING_CANCEL = Component.text("Cancel").color(TextColor.fromHexString("#FF4040"))
|
||||||
|
|
||||||
|
fun itemDefaultName(item: ItemStack?): String? {
|
||||||
|
return PLAIN_TEXT_SERIALIZER.serializeOrNull(item?.effectiveName())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val lastNames = HashMap<UUID, String>()
|
private val lastNames = HashMap<UUID, String>()
|
||||||
|
private val lastRenames = HashMap<UUID, String>()
|
||||||
|
|
||||||
|
|
||||||
private val lastLeftItem = HashMap<UUID, String>()
|
private val lastLeftItem = HashMap<UUID, String>()
|
||||||
private val runTaskMap = HashMap<UUID, ScheduledTask>()
|
private val runTaskMap = HashMap<UUID, ScheduledTask>()
|
||||||
|
|
||||||
|
// For monetary cost
|
||||||
|
val hasUiOpen = HashSet<UUID>()
|
||||||
|
|
||||||
private val containerField = CraftInventoryView::class.java.getDeclaredField("container")
|
private val containerField = CraftInventoryView::class.java.getDeclaredField("container")
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
@ -63,14 +76,15 @@ class AnvilRenameDialogImpl(
|
||||||
return true
|
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 maxLength = this.maxLength.get()
|
||||||
val initialFinal = initial?.take(maxLength)
|
val initialFinal = initial?.take(maxLength)
|
||||||
|
|
||||||
val baseBuilder = DialogBase.builder(USER_FACING_RENAME_TITLE)
|
val baseBuilder = DialogBase.builder(USER_FACING_RENAME_TITLE)
|
||||||
.canCloseWithEscape(true)
|
.canCloseWithEscape(true)
|
||||||
.afterAction(DialogBase.DialogAfterAction.CLOSE)
|
.afterAction(DialogBase.DialogAfterAction.CLOSE)
|
||||||
.inputs(listOf(
|
.inputs(
|
||||||
|
listOf(
|
||||||
DialogInput.text(RENAME_TEXT_KEY, Component.text("Rename text"))
|
DialogInput.text(RENAME_TEXT_KEY, Component.text("Rename text"))
|
||||||
.maxLength(maxLength)
|
.maxLength(maxLength)
|
||||||
.initial(initialFinal ?: "")
|
.initial(initialFinal ?: "")
|
||||||
|
|
@ -79,56 +93,73 @@ class AnvilRenameDialogImpl(
|
||||||
.build(),
|
.build(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
baseBuilder.body(listOf(
|
baseBuilder.body(
|
||||||
|
listOf(
|
||||||
DialogBody.plainMessage(USER_FACING_WARNING, MAX_WIDTH)
|
DialogBody.plainMessage(USER_FACING_WARNING, MAX_WIDTH)
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return Dialog.create { builder -> builder.empty()
|
return Dialog.create { builder ->
|
||||||
|
builder.empty()
|
||||||
.base(baseBuilder.build())
|
.base(baseBuilder.build())
|
||||||
.type(DialogType.confirmation(
|
.type(
|
||||||
|
DialogType.confirmation(
|
||||||
ActionButton.builder(USER_FACING_CONFIRM)
|
ActionButton.builder(USER_FACING_CONFIRM)
|
||||||
.action(DialogAction.customClick({ response, _ ->
|
.action(DialogAction.customClick({ response, _ ->
|
||||||
|
hasUiOpen.remove(playerID)
|
||||||
val text = response.getText(RENAME_TEXT_KEY)!!
|
val text = response.getText(RENAME_TEXT_KEY)!!
|
||||||
callback.accept(text)
|
callback.accept(text)
|
||||||
}, ClickCallback.Options.builder().build()))
|
}, ClickCallback.Options.builder().build()))
|
||||||
.build(),
|
.build(),
|
||||||
ActionButton.builder(USER_FACING_CANCEL)
|
ActionButton.builder(USER_FACING_CANCEL)
|
||||||
|
.action(DialogAction.customClick({ response, _ ->
|
||||||
|
hasUiOpen.remove(playerID)
|
||||||
|
}, ClickCallback.Options.builder().build()))
|
||||||
.build(),
|
.build(),
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setResult(player: HumanEntity, view: CraftAnvilView, result: String?) {
|
private fun setResult(player: HumanEntity, view: InventoryView, result: String?) {
|
||||||
val defaultName = PLAIN_TEXT_SERIALIZER.serializeOrNull(view.getItem(0)?.effectiveName())
|
val defaultName = itemDefaultName(view.getItem(0))
|
||||||
if(defaultName == result) {
|
if (defaultName == result) {
|
||||||
setName(player, view, "")
|
setName(player, view, "", null)
|
||||||
if(defaultName != null) lastNames[player.uniqueId] = defaultName
|
if (defaultName != null) lastNames[player.uniqueId] = defaultName
|
||||||
}
|
} else setName(player, view, result, result)
|
||||||
else setName(player, view, result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setName(player: HumanEntity, view: CraftAnvilView, name: String?) {
|
private fun setName(player: HumanEntity, view: InventoryView, name: String?, rename: String?) {
|
||||||
val menu = (containerField.get(view) as AnvilMenu)
|
val menu = (containerField.get(view) as AnvilMenu)
|
||||||
menu.itemName = name
|
val isSameName = menu.itemName == name
|
||||||
|
menu.itemName = rename
|
||||||
|
|
||||||
if(name == null)
|
if (name == null)
|
||||||
lastNames.remove(player.uniqueId)
|
lastNames.remove(player.uniqueId)
|
||||||
else
|
else
|
||||||
lastNames[player.uniqueId] = name
|
lastNames[player.uniqueId] = name
|
||||||
|
|
||||||
|
if (rename == null)
|
||||||
|
lastRenames.remove(player.uniqueId)
|
||||||
|
else
|
||||||
|
lastRenames[player.uniqueId] = rename
|
||||||
|
|
||||||
|
if (!isSameName)
|
||||||
CraftEventFactory.callPrepareResultEvent(menu, 2);
|
CraftEventFactory.callPrepareResultEvent(menu, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nameFromItem(player: HumanEntity, item: ItemStack?): String? {
|
private fun nameFromItem(player: HumanEntity, item: ItemStack?): String? {
|
||||||
// Already has text
|
// Already has text
|
||||||
if(item?.hasItemMeta() != true || !item.itemMeta.hasCustomName())
|
if (item?.hasItemMeta() != true || !item.itemMeta.hasCustomName())
|
||||||
return PLAIN_TEXT_SERIALIZER.serializeOrNull(item?.effectiveName())
|
return PLAIN_TEXT_SERIALIZER.serializeOrNull(item?.effectiveName())
|
||||||
|
|
||||||
if(keepUserPreviousDialog.get() && item.hasItemMeta()) {
|
if (keepUserPreviousDialog.get() && item.hasItemMeta()) {
|
||||||
val lastName = item.itemMeta.persistentDataContainer.get(
|
val lastName = item.itemMeta.persistentDataContainer.get(
|
||||||
AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY,
|
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())
|
return fromFormated.apply(player, item.effectiveName())
|
||||||
|
|
@ -136,33 +167,37 @@ class AnvilRenameDialogImpl(
|
||||||
|
|
||||||
private fun tryShowDialogScheduled(player: HumanEntity, event: PrepareAnvilEvent) {
|
private fun tryShowDialogScheduled(player: HumanEntity, event: PrepareAnvilEvent) {
|
||||||
val view = event.view
|
val view = event.view
|
||||||
if(view !is CraftAnvilView) return
|
if (view !is CraftAnvilView) return
|
||||||
|
|
||||||
val renameText = view.renameText
|
val renameText = view.renameText
|
||||||
val leftItem = view.getItem(0)
|
val leftItem = view.getItem(0)
|
||||||
val leftItemStr = leftItem?.toString()
|
val leftItemStr = leftItem?.toString()
|
||||||
val lastName = lastNames.getOrDefault(player.uniqueId, null)
|
|
||||||
|
|
||||||
if(lastLeftItem.getOrDefault(player.uniqueId, null) != leftItemStr) {
|
val lastName = lastNames.getOrDefault(player.uniqueId, null)
|
||||||
if(leftItemStr == null)
|
val lastRename = lastRenames.getOrDefault(player.uniqueId, null)
|
||||||
|
|
||||||
|
if (lastLeftItem.getOrDefault(player.uniqueId, null) != leftItemStr) {
|
||||||
|
if (leftItemStr == null)
|
||||||
lastLeftItem.remove(player.uniqueId)
|
lastLeftItem.remove(player.uniqueId)
|
||||||
else lastLeftItem[player.uniqueId] = leftItemStr
|
else lastLeftItem[player.uniqueId] = leftItemStr
|
||||||
|
|
||||||
setName(player, view, nameFromItem(player, leftItem))
|
setName(player, view, renameText, nameFromItem(player, leftItem))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lastName == renameText)
|
if (lastName == renameText || lastRename == renameText)
|
||||||
return
|
return
|
||||||
|
|
||||||
if(renameText?.isBlank() == true) {
|
if (renameText?.isBlank() == true || renameText == itemDefaultName(leftItem)) {
|
||||||
setName(player, view, lastNames[player.uniqueId])
|
setName(player, view, lastName, lastRename)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val dialog = makeDialog(lastName)
|
val dialog = makeDialog(player.uniqueId, lastRename)
|
||||||
{ result -> setResult(player, view, result) }
|
{ result -> setResult(player, view, result) }
|
||||||
player.showDialog(dialog)
|
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
|
// We need to wait for a short time as changing item will change the name BEFORE the item change
|
||||||
|
|
@ -178,13 +213,14 @@ class AnvilRenameDialogImpl(
|
||||||
{},
|
{},
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
if(task == null) return
|
if (task == null) return
|
||||||
|
|
||||||
runTaskMap[player.uniqueId] = task
|
runTaskMap[player.uniqueId] = task
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun closeInventory(player: HumanEntity) {
|
override fun closeInventory(player: HumanEntity) {
|
||||||
lastNames.remove(player.uniqueId)
|
lastNames.remove(player.uniqueId)
|
||||||
|
lastRenames.remove(player.uniqueId)
|
||||||
lastLeftItem.remove(player.uniqueId)
|
lastLeftItem.remove(player.uniqueId)
|
||||||
runTaskMap.remove(player.uniqueId)?.cancel()
|
runTaskMap.remove(player.uniqueId)?.cancel()
|
||||||
}
|
}
|
||||||
|
|
@ -193,4 +229,8 @@ class AnvilRenameDialogImpl(
|
||||||
return lastNames[player.uniqueId]
|
return lastNames[player.uniqueId]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isOpenFor(player: HumanEntity): Boolean {
|
||||||
|
return hasUiOpen.contains(player.uniqueId)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +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
|
||||||
|
|
||||||
|
object AnvilTitleUtil {
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package xyz.alexcrea.cuanvil.util
|
||||||
|
|
||||||
|
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||||
|
import org.bukkit.inventory.InventoryView
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.inventory.view.AnvilView
|
||||||
|
|
||||||
|
object ModernPrepareAnvilCreator {
|
||||||
|
fun createPrepareAnvil(view: InventoryView, item: ItemStack?): PrepareAnvilEvent {
|
||||||
|
return PrepareAnvilEvent(view as AnvilView, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
* Most of the time you would likely need {@link CAPreAnvilBypassEvent} or {@link CAEarlyPreAnvilBypassEvent}
|
* Most of the time you would likely need {@link CAPreAnvilBypassEvent} or {@link CAEarlyPreAnvilBypassEvent}
|
||||||
* for this event to be useful.
|
* for this event to be useful.
|
||||||
* <p>
|
* <p>
|
||||||
* There is also {@link CATreatAnvilResultEvent} that may be better for some use case.
|
* There is also {@link CATreatAnvilResult2Event} that may be better for some use case.
|
||||||
*/
|
*/
|
||||||
public class CAClickResultBypassEvent extends Event implements Cancellable {
|
public class CAClickResultBypassEvent extends Event implements Cancellable {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
* <p>
|
* <p>
|
||||||
* You should also use {@link CAClickResultBypassEvent} if you want to use this event for something useful.
|
* You should also use {@link CAClickResultBypassEvent} if you want to use this event for something useful.
|
||||||
* <p>
|
* <p>
|
||||||
* It is also recommended that you read about {@link CAPreAnvilBypassEvent} and {@link CATreatAnvilResultEvent}
|
* It is also recommended that you read about {@link CAPreAnvilBypassEvent} and {@link CATreatAnvilResult2Event}
|
||||||
* as your use case may be more prone to use theses.
|
* as your use case may be more prone to use theses.
|
||||||
*/
|
*/
|
||||||
public class CAEarlyPreAnvilBypassEvent extends Event implements Cancellable {
|
public class CAEarlyPreAnvilBypassEvent extends Event implements Cancellable {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
* <p>
|
* <p>
|
||||||
* You should also use {@link CAClickResultBypassEvent} if you want to use this event for something useful.
|
* You should also use {@link CAClickResultBypassEvent} if you want to use this event for something useful.
|
||||||
* <p>
|
* <p>
|
||||||
* It is also recommended that you read about {@link CAEarlyPreAnvilBypassEvent} and {@link CATreatAnvilResultEvent}
|
* It is also recommended that you read about {@link CAEarlyPreAnvilBypassEvent} and {@link CATreatAnvilResult2Event}
|
||||||
* as your use case may be more prone to use theses.
|
* as your use case may be more prone to use theses.
|
||||||
*/
|
*/
|
||||||
public class CAPreAnvilBypassEvent extends Event implements Cancellable {
|
public class CAPreAnvilBypassEvent extends Event implements Cancellable {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
package xyz.alexcrea.cuanvil.api.event.listener;
|
||||||
|
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost;
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after custom anvil processed the click on the result on the anvil inventory.
|
||||||
|
* This event should be used to modify the result of an anvil use.
|
||||||
|
* <p>
|
||||||
|
* You may also want to check {@link CAClickResultBypassEvent},
|
||||||
|
* {@link CAPreAnvilBypassEvent}
|
||||||
|
* and {@link CAEarlyPreAnvilBypassEvent} for your use case
|
||||||
|
* <p>
|
||||||
|
* A null result will cancel this event
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class CATreatAnvilResult2Event extends Event {
|
||||||
|
|
||||||
|
private static final HandlerList HANDLERS = new HandlerList();
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return HANDLERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull HandlerList getHandlers() {
|
||||||
|
return HANDLERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final InventoryView view;
|
||||||
|
|
||||||
|
private final AnvilUseType useType;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final ItemStack left;
|
||||||
|
@Nullable
|
||||||
|
private final ItemStack right;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ItemStack result;
|
||||||
|
|
||||||
|
private final AnvilCost cost;
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public CATreatAnvilResult2Event(
|
||||||
|
@NotNull InventoryView view,
|
||||||
|
Inventory inv,
|
||||||
|
AnvilUseType useType,
|
||||||
|
@Nullable ItemStack result,
|
||||||
|
AnvilCost cost) {
|
||||||
|
this.view = view;
|
||||||
|
this.useType = useType;
|
||||||
|
|
||||||
|
this.left = inv.getItem(0); // TODO use view here
|
||||||
|
this.right = inv.getItem(1);
|
||||||
|
this.result = result;
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the bukkit inventory view.
|
||||||
|
* <p>
|
||||||
|
* Temporarily marked as internal as it will get changed to anvil view on legacy removal
|
||||||
|
* so signature will change
|
||||||
|
*
|
||||||
|
* @return The inventory view of this event.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public @NotNull InventoryView getView() {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of use source of the result.
|
||||||
|
*
|
||||||
|
* @return The craft use type.
|
||||||
|
*/
|
||||||
|
public AnvilUseType getUseType() {
|
||||||
|
return useType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the left item of the anvil use
|
||||||
|
*
|
||||||
|
* @return the left item
|
||||||
|
*/
|
||||||
|
public @Nullable ItemStack getLeftItem() {
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the right item of the anvil use
|
||||||
|
*
|
||||||
|
* @return the right item
|
||||||
|
*/
|
||||||
|
public @Nullable ItemStack getRightItem() {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current result
|
||||||
|
* <p>
|
||||||
|
* note that it will not be null unless another listener previously set it to null.
|
||||||
|
*
|
||||||
|
* @return The current result.
|
||||||
|
*/
|
||||||
|
public @Nullable ItemStack getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current result
|
||||||
|
* <p>
|
||||||
|
* note that a null result will cancel this anvil use.
|
||||||
|
*
|
||||||
|
* @param result The new result
|
||||||
|
*/
|
||||||
|
public void setResult(@Nullable ItemStack result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the level cost displayed on the anvil.
|
||||||
|
* <h3>Important note:</h3>
|
||||||
|
* the final price are re calculated on click for the following use case:
|
||||||
|
* <ul>
|
||||||
|
* <li>Custom craft</li>
|
||||||
|
* <li>Unit repair</li>
|
||||||
|
* <li>Lore edit</li>
|
||||||
|
* </ul>
|
||||||
|
* This value will be used as final price for:
|
||||||
|
* <li>Item merge</li>
|
||||||
|
* <li>Item rename</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @return The current cost.
|
||||||
|
* @deprecated use #{@link #getCost()} instead
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||||
|
public int getLevelCost() {
|
||||||
|
return cost.asXpCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the level cost displayed on the anvil.
|
||||||
|
* <h3>Important note:</h3>
|
||||||
|
* the final price are re calculated on click for the following use case:
|
||||||
|
* <ul>
|
||||||
|
* <li>Custom craft</li>
|
||||||
|
* <li>Unit repair</li>
|
||||||
|
* <li>Lore edit</li>
|
||||||
|
* </ul>
|
||||||
|
* This value will be used as final price for:
|
||||||
|
* <li>Item merge</li>
|
||||||
|
* <li>Item rename</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param levelCost The new cost.
|
||||||
|
* @deprecated use #{@link #getCost()} and set value on this instead
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||||
|
public void setLevelCost(int levelCost) {
|
||||||
|
cost.setGeneric(levelCost - cost.getGeneric() - cost.asXpCost());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow access to the current cost of the event
|
||||||
|
* Note that modifying this object will change the event resulting cost
|
||||||
|
*
|
||||||
|
* <h3>Important note:</h3>
|
||||||
|
* the final price are re calculated on click for the following use case:
|
||||||
|
* <ul>
|
||||||
|
* <li>Custom craft</li>
|
||||||
|
* <li>Unit repair</li>
|
||||||
|
* <li>Lore edit</li>
|
||||||
|
* </ul>
|
||||||
|
* This value will be used as final price for:
|
||||||
|
* <li>Item merge</li>
|
||||||
|
* <li>Item rename</li>
|
||||||
|
*
|
||||||
|
* @return the current anvil cost
|
||||||
|
*/
|
||||||
|
public AnvilCost getCost() {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,8 @@ import org.bukkit.event.inventory.PrepareAnvilEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost;
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after custom anvil processed the click on the result on the anvil inventory.
|
* Called after custom anvil processed the click on the result on the anvil inventory.
|
||||||
|
|
@ -17,8 +18,12 @@ import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
||||||
* and {@link CAEarlyPreAnvilBypassEvent} for your use case
|
* and {@link CAEarlyPreAnvilBypassEvent} for your use case
|
||||||
* <p>
|
* <p>
|
||||||
* A null result will cancel this pre anvil event
|
* A null result will cancel this pre anvil event
|
||||||
|
*
|
||||||
|
* @deprecated Prepare anvil Event cannot be provided as it can be called on result and therefore not have prepared anvil event
|
||||||
|
* use {@link CATreatAnvilResult2Event} instead
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||||
public class CATreatAnvilResultEvent extends Event {
|
public class CATreatAnvilResultEvent extends Event {
|
||||||
|
|
||||||
private static final HandlerList HANDLERS = new HandlerList();
|
private static final HandlerList HANDLERS = new HandlerList();
|
||||||
|
|
@ -40,13 +45,13 @@ public class CATreatAnvilResultEvent extends Event {
|
||||||
@Nullable
|
@Nullable
|
||||||
private ItemStack result;
|
private ItemStack result;
|
||||||
|
|
||||||
private int levelCost;
|
private final AnvilCost cost;
|
||||||
|
|
||||||
public CATreatAnvilResultEvent(@NotNull PrepareAnvilEvent event, AnvilUseType useType, @Nullable ItemStack result, int levelCost) {
|
public CATreatAnvilResultEvent(@NotNull PrepareAnvilEvent event, AnvilUseType useType, @Nullable ItemStack result, AnvilCost cost) {
|
||||||
this.event = event;
|
this.event = event;
|
||||||
this.useType = useType;
|
this.useType = useType;
|
||||||
this.result = result;
|
this.result = result;
|
||||||
this.levelCost = levelCost;
|
this.cost = cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -104,9 +109,11 @@ public class CATreatAnvilResultEvent extends Event {
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @return The current cost.
|
* @return The current cost.
|
||||||
|
* @deprecated use #{@link #getCost()} instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||||
public int getLevelCost() {
|
public int getLevelCost() {
|
||||||
return levelCost;
|
return cost.asXpCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -124,8 +131,32 @@ public class CATreatAnvilResultEvent extends Event {
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param levelCost The new cost.
|
* @param levelCost The new cost.
|
||||||
|
* @deprecated use #{@link #getCost()} and set value on this instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "1.17.0")
|
||||||
public void setLevelCost(int levelCost) {
|
public void setLevelCost(int levelCost) {
|
||||||
this.levelCost = levelCost;
|
cost.setGeneric(levelCost - cost.getGeneric() - cost.asXpCost());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow access to the current cost of the event
|
||||||
|
* Note that modifying this object will change the event resulting cost
|
||||||
|
*
|
||||||
|
* <h3>Important note:</h3>
|
||||||
|
* the final price are re calculated on click for the following use case:
|
||||||
|
* <ul>
|
||||||
|
* <li>Custom craft</li>
|
||||||
|
* <li>Unit repair</li>
|
||||||
|
* <li>Lore edit</li>
|
||||||
|
* </ul>
|
||||||
|
* This value will be used as final price for:
|
||||||
|
* <li>Item merge</li>
|
||||||
|
* <li>Item rename</li>
|
||||||
|
*
|
||||||
|
* @return the current anvil cost
|
||||||
|
*/
|
||||||
|
public AnvilCost getCost() {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package xyz.alexcrea.cuanvil.config;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||||
|
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@ import org.bukkit.entity.HumanEntity;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||||
import xyz.alexcrea.cuanvil.config.ConfigHolder;
|
import xyz.alexcrea.cuanvil.config.ConfigHolder;
|
||||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType;
|
import xyz.alexcrea.cuanvil.config.WorkPenaltyType;
|
||||||
import xyz.alexcrea.cuanvil.gui.config.global.BasicConfigGui;
|
import xyz.alexcrea.cuanvil.gui.config.global.BasicConfigGui;
|
||||||
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
|
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ package xyz.alexcrea.cuanvil.update.plugin;
|
||||||
|
|
||||||
import io.delilaheve.util.ConfigOptions;
|
import io.delilaheve.util.ConfigOptions;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType;
|
||||||
import xyz.alexcrea.cuanvil.config.ConfigHolder;
|
import xyz.alexcrea.cuanvil.config.ConfigHolder;
|
||||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType;
|
import xyz.alexcrea.cuanvil.config.WorkPenaltyType;
|
||||||
import xyz.alexcrea.cuanvil.gui.config.settings.WorkPenaltyTypeSettingGui;
|
import xyz.alexcrea.cuanvil.gui.config.settings.WorkPenaltyTypeSettingGui;
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import xyz.alexcrea.cuanvil.command.ReloadExecutor
|
||||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||||
import xyz.alexcrea.cuanvil.dependency.MinecraftVersionUtil
|
import xyz.alexcrea.cuanvil.dependency.MinecraftVersionUtil
|
||||||
|
import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager
|
||||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
|
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
|
||||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
|
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
|
||||||
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui
|
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui
|
||||||
|
|
@ -259,9 +260,11 @@ open class CustomAnvil : JavaPlugin() {
|
||||||
MainConfigGui.getInstance().init(DependencyManager.packetManager)
|
MainConfigGui.getInstance().init(DependencyManager.packetManager)
|
||||||
GuiSharedConstant.loadConstants()
|
GuiSharedConstant.loadConstants()
|
||||||
|
|
||||||
|
// Prepare economy if possible
|
||||||
|
EconomyManager.setupEconomy(this)
|
||||||
|
|
||||||
// Finally, re add default we may be missing
|
// Finally, re add default we may be missing
|
||||||
PluginSetDefault.reAddMissingDefault()
|
PluginSetDefault.reAddMissingDefault()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reloadResource(
|
fun reloadResource(
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,16 @@ package io.delilaheve.util
|
||||||
import io.delilaheve.CustomAnvil
|
import io.delilaheve.CustomAnvil
|
||||||
import io.delilaheve.util.EnchantmentUtil.enchantmentName
|
import io.delilaheve.util.EnchantmentUtil.enchantmentName
|
||||||
import org.bukkit.NamespacedKey
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.HumanEntity
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType
|
||||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType
|
import xyz.alexcrea.cuanvil.config.WorkPenaltyType
|
||||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType.WorkPenaltyPart
|
import xyz.alexcrea.cuanvil.config.WorkPenaltyType.WorkPenaltyPart
|
||||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||||
|
import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager
|
||||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
|
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType
|
import xyz.alexcrea.cuanvil.util.dialog.AnvilRenameDialogUtil
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -72,6 +76,11 @@ object ConfigOptions {
|
||||||
|
|
||||||
const val IMMUTABLE_ENCHANTMENT_LIST = "immutable_enchantments"
|
const val IMMUTABLE_ENCHANTMENT_LIST = "immutable_enchantments"
|
||||||
|
|
||||||
|
// Monetary configs
|
||||||
|
const val MONETARY_USAGE_ROOT = "monetary_cost"
|
||||||
|
const val SHOULD_USE_MONEY = "$MONETARY_USAGE_ROOT.enabled"
|
||||||
|
const val MONEY_CURRENCY = "$MONETARY_USAGE_ROOT.currency"
|
||||||
|
const val MONETARY_MULTIPLIER_ROOT = "$MONETARY_USAGE_ROOT.multipliers"
|
||||||
|
|
||||||
// Keys for specific enchantment values
|
// Keys for specific enchantment values
|
||||||
private const val KEY_BOOK = "book"
|
private const val KEY_BOOK = "book"
|
||||||
|
|
@ -110,6 +119,11 @@ object ConfigOptions {
|
||||||
|
|
||||||
const val DEFAULT_PER_COLOR_CODE_PERMISSION = false
|
const val DEFAULT_PER_COLOR_CODE_PERMISSION = false
|
||||||
|
|
||||||
|
// Monetary configs
|
||||||
|
const val DEFAULT_SHOULD_USE_MONEY = false
|
||||||
|
const val DEFAULT_MONEY_CURRENCY = "default"
|
||||||
|
const val DEFAULT_MONEY_MULTIPLIER = 1.0
|
||||||
|
|
||||||
// Debug flag
|
// Debug flag
|
||||||
private const val DEFAULT_DEBUG_LOG = false
|
private const val DEFAULT_DEBUG_LOG = false
|
||||||
private const val DEFAULT_VERBOSE_DEBUG_LOG = false
|
private const val DEFAULT_VERBOSE_DEBUG_LOG = false
|
||||||
|
|
@ -164,6 +178,11 @@ object ConfigOptions {
|
||||||
// Default max before merge disabled (negative mean enabled)
|
// Default max before merge disabled (negative mean enabled)
|
||||||
const val DEFAULT_MAX_BEFORE_MERGE_DISABLED = -1
|
const val DEFAULT_MAX_BEFORE_MERGE_DISABLED = -1
|
||||||
|
|
||||||
|
// -----------
|
||||||
|
// Permissions
|
||||||
|
// -----------
|
||||||
|
private const val RENAME_DIALOG_PERMISSION = "ca.rename.dialog"
|
||||||
|
|
||||||
// -------------
|
// -------------
|
||||||
// Get methods
|
// Get methods
|
||||||
// -------------
|
// -------------
|
||||||
|
|
@ -452,6 +471,13 @@ object ConfigOptions {
|
||||||
.getBoolean(DIALOG_RENAME_USE_PERMISSION, DEFAULT_DIALOG_RENAME_USE_PERMISSION)
|
.getBoolean(DIALOG_RENAME_USE_PERMISSION, DEFAULT_DIALOG_RENAME_USE_PERMISSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun canUseDialogRename(player: HumanEntity): Boolean {
|
||||||
|
if(!doRenameDialog || !AnvilRenameDialogUtil.anvilRenameDialog.canSendDialog()) return false
|
||||||
|
if(doRenameDialogUsePermission && !player.hasPermission(RENAME_DIALOG_PERMISSION)) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do the dialog menu require permission
|
* Do the dialog menu require permission
|
||||||
*/
|
*/
|
||||||
|
|
@ -625,4 +651,29 @@ object ConfigOptions {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Monetary configs (only for 1.21.6+)
|
||||||
|
* Also require dialog rename
|
||||||
|
*/
|
||||||
|
fun shouldUseMoney(player: HumanEntity): Boolean {
|
||||||
|
return EconomyManager.economy?.initialized() == true &&
|
||||||
|
canUseDialogRename(player) &&
|
||||||
|
ConfigHolder.DEFAULT_CONFIG
|
||||||
|
.config
|
||||||
|
.getBoolean(SHOULD_USE_MONEY, DEFAULT_SHOULD_USE_MONEY)
|
||||||
|
}
|
||||||
|
|
||||||
|
val usedCurrency: String
|
||||||
|
get() {
|
||||||
|
return ConfigHolder.DEFAULT_CONFIG
|
||||||
|
.config
|
||||||
|
.getString(MONEY_CURRENCY, DEFAULT_MONEY_CURRENCY)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMonetaryMultiplier(type: String): BigDecimal {
|
||||||
|
return BigDecimal(ConfigHolder.DEFAULT_CONFIG
|
||||||
|
.config
|
||||||
|
.getDouble("$MONETARY_MULTIPLIER_ROOT.$type", DEFAULT_MONEY_MULTIPLIER))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
src/main/kotlin/xyz/alexcrea/cuanvil/anvil/AnvilCost.kt
Normal file
55
src/main/kotlin/xyz/alexcrea/cuanvil/anvil/AnvilCost.kt
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
package xyz.alexcrea.cuanvil.anvil
|
||||||
|
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import io.delilaheve.util.ConfigOptions.getMonetaryMultiplier as moneyMultiplier
|
||||||
|
|
||||||
|
open class AnvilCost {
|
||||||
|
private val isAlone: Boolean
|
||||||
|
var valid = true // Get set as invalid if cost can be satisfied
|
||||||
|
var isMonetary = false
|
||||||
|
|
||||||
|
var generic = 0
|
||||||
|
var enchantment = 0
|
||||||
|
var repair = 0
|
||||||
|
var rename = 0
|
||||||
|
var lore = 0
|
||||||
|
var illegalPenalty = 0
|
||||||
|
var workPenalty = 0
|
||||||
|
var recipe = 0
|
||||||
|
|
||||||
|
constructor(generic: Int) {
|
||||||
|
this.generic = generic
|
||||||
|
isAlone = true
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
isAlone = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun asXpCost(): Int {
|
||||||
|
return generic + enchantment + repair + rename + lore + illegalPenalty + workPenalty + recipe
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun asMonetaryCost(): BigDecimal {
|
||||||
|
// multiply by per use type multipliers
|
||||||
|
return BigDecimal(generic)
|
||||||
|
.add(BigDecimal(enchantment).multiply(moneyMultiplier("enchantment")))
|
||||||
|
.add(BigDecimal(repair).multiply(moneyMultiplier("repair")))
|
||||||
|
.add(BigDecimal(rename).multiply(moneyMultiplier("rename")))
|
||||||
|
.add(BigDecimal(lore).multiply(moneyMultiplier("lore_edit")))
|
||||||
|
.add(BigDecimal(enchantment).multiply(moneyMultiplier("enchantment")))
|
||||||
|
.add(BigDecimal(illegalPenalty).multiply(moneyMultiplier("work_penalty")))
|
||||||
|
.add(BigDecimal(workPenalty).multiply(moneyMultiplier("work_penalty")))
|
||||||
|
.add(BigDecimal(recipe).multiply(moneyMultiplier("recipe")))
|
||||||
|
.multiply(moneyMultiplier("global"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomCraftCost(val rawCost: Int): AnvilCost() {
|
||||||
|
|
||||||
|
override fun asMonetaryCost(): BigDecimal {
|
||||||
|
return BigDecimal(rawCost)
|
||||||
|
.multiply(moneyMultiplier("global"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
331
src/main/kotlin/xyz/alexcrea/cuanvil/anvil/AnvilMergeLogic.kt
Normal file
331
src/main/kotlin/xyz/alexcrea/cuanvil/anvil/AnvilMergeLogic.kt
Normal file
|
|
@ -0,0 +1,331 @@
|
||||||
|
package xyz.alexcrea.cuanvil.anvil
|
||||||
|
|
||||||
|
import io.delilaheve.CustomAnvil
|
||||||
|
import io.delilaheve.util.ConfigOptions
|
||||||
|
import io.delilaheve.util.EnchantmentUtil.combineWith
|
||||||
|
import io.delilaheve.util.ItemUtil.findEnchantments
|
||||||
|
import io.delilaheve.util.ItemUtil.isEnchantedBook
|
||||||
|
import io.delilaheve.util.ItemUtil.repairFrom
|
||||||
|
import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe
|
||||||
|
import io.delilaheve.util.ItemUtil.unitRepair
|
||||||
|
import org.bukkit.ChatColor
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.entity.HumanEntity
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.inventory.AnvilInventory
|
||||||
|
import org.bukkit.inventory.InventoryView
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||||
|
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
|
||||||
|
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
|
||||||
|
import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe
|
||||||
|
import xyz.alexcrea.cuanvil.util.CasedStringUtil
|
||||||
|
import xyz.alexcrea.cuanvil.util.CustomRecipeUtil
|
||||||
|
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
|
||||||
|
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
|
||||||
|
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
|
||||||
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilColorUtil
|
||||||
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilLoreEditUtil
|
||||||
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilXpUtil
|
||||||
|
import xyz.alexcrea.cuanvil.util.config.LoreEditType
|
||||||
|
import xyz.alexcrea.cuanvil.util.dialog.AnvilRenameDialogUtil
|
||||||
|
|
||||||
|
object AnvilMergeLogic {
|
||||||
|
|
||||||
|
open class AnvilResult {
|
||||||
|
companion object {
|
||||||
|
val EMPTY = AnvilResult(null, AnvilCost())
|
||||||
|
}
|
||||||
|
|
||||||
|
val item: ItemStack?
|
||||||
|
val cost: AnvilCost
|
||||||
|
val ignoreXpRules: Boolean
|
||||||
|
|
||||||
|
constructor(item: ItemStack?, cost: AnvilCost, ignoreXpRules: Boolean = false) {
|
||||||
|
this.item = item
|
||||||
|
this.cost = cost
|
||||||
|
this.ignoreXpRules = ignoreXpRules
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isEmpty(): Boolean {
|
||||||
|
return item == null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnitRepairResult : AnvilResult {
|
||||||
|
companion object {
|
||||||
|
val EMPTY = UnitRepairResult(null, AnvilCost(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val repairAmount: Int
|
||||||
|
|
||||||
|
constructor(item: ItemStack?, cost: AnvilCost, repairAmount: Int) : super(item, cost) {
|
||||||
|
this.repairAmount = repairAmount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomCraftResult : AnvilResult {
|
||||||
|
companion object {
|
||||||
|
val EMPTY = CustomCraftResult(null, CustomCraftCost(0), 0, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
val customCraftCost: CustomCraftCost
|
||||||
|
val amount: Int
|
||||||
|
val recipe: AnvilCustomRecipe?
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
item: ItemStack?, cost: CustomCraftCost,
|
||||||
|
amount: Int, recipe: AnvilCustomRecipe?
|
||||||
|
) : super(item, cost, true) {
|
||||||
|
this.customCraftCost = cost
|
||||||
|
this.amount = amount
|
||||||
|
this.recipe = recipe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoreEditResult : AnvilResult {
|
||||||
|
companion object {
|
||||||
|
val EMPTY = LoreEditResult(null, AnvilCost(), LoreEditType.APPEND_PAPER)
|
||||||
|
}
|
||||||
|
|
||||||
|
val type: LoreEditType
|
||||||
|
|
||||||
|
constructor(item: ItemStack?, cost: AnvilCost, type: LoreEditType) : super(item, cost) {
|
||||||
|
this.type = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doRenaming(
|
||||||
|
view: InventoryView, //TODO use anvil view
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player, first: ItemStack
|
||||||
|
): AnvilResult {
|
||||||
|
val resultItem = DependencyManager.cloneItem(player, first)
|
||||||
|
val cost = AnvilCost()
|
||||||
|
cost.rename = handleRename(resultItem, inventory, player)
|
||||||
|
|
||||||
|
// Test/stop if nothing changed.
|
||||||
|
if (first == resultItem) {
|
||||||
|
CustomAnvil.log("no right item, But input is same as output")
|
||||||
|
return AnvilResult.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
cost.workPenalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.RENAME_ONLY)
|
||||||
|
val result =
|
||||||
|
DependencyManager.tryTreatAnvilResult(view, inventory, player, resultItem, AnvilUseType.RENAME_ONLY, cost)
|
||||||
|
|
||||||
|
return AnvilResult(result, cost)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processDialogPCD(meta: ItemMeta, player: HumanEntity) {
|
||||||
|
val text = AnvilRenameDialogUtil.anvilRenameDialog.currentText(player)
|
||||||
|
return processPCD(meta, player, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processPCD(meta: ItemMeta, player: HumanEntity, text: String?) {
|
||||||
|
val keepDialog = ConfigOptions.canUseDialogRename(player) && ConfigOptions.shouldKeepRenameText
|
||||||
|
|
||||||
|
val pdc = meta.persistentDataContainer
|
||||||
|
if (!keepDialog)
|
||||||
|
pdc.remove(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY)
|
||||||
|
else {
|
||||||
|
if (text == null || text.isBlank())
|
||||||
|
pdc.remove(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY)
|
||||||
|
else pdc.set(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY, PersistentDataType.STRING, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int {
|
||||||
|
// Can be null
|
||||||
|
var renameText = ChatColor.stripColor(inventory.renameText)
|
||||||
|
|
||||||
|
var sumCost = 0
|
||||||
|
var useColor = false
|
||||||
|
if (ConfigOptions.renameColorPossible && renameText != null) {
|
||||||
|
val component = AnvilColorUtil.handleColor(
|
||||||
|
renameText,
|
||||||
|
AnvilColorUtil.renamePermission(player)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (component != null) {
|
||||||
|
renameText = MiniMessageUtil.legacy_mm.serialize(component)
|
||||||
|
|
||||||
|
sumCost += ConfigOptions.useOfColorCost
|
||||||
|
useColor = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename item and add renaming cost
|
||||||
|
resultItem.itemMeta?.let {
|
||||||
|
val hasDisplayName = it.hasDisplayName()
|
||||||
|
val displayName = if (!hasDisplayName) null
|
||||||
|
else if (useColor) it.displayName
|
||||||
|
else ChatColor.stripColor(it.displayName)
|
||||||
|
|
||||||
|
|
||||||
|
if (!displayName.contentEquals(renameText) && !(displayName == null &&
|
||||||
|
renameText == "" ||
|
||||||
|
//TODO on recent paper check effective name instead
|
||||||
|
renameText == CasedStringUtil.snakeToUpperSpacedCase(resultItem.type.name.lowercase())
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
it.setDisplayName(renameText)
|
||||||
|
processDialogPCD(it, player)
|
||||||
|
resultItem.itemMeta = it
|
||||||
|
|
||||||
|
sumCost += ConfigOptions.itemRenameCost
|
||||||
|
}
|
||||||
|
|
||||||
|
return sumCost
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doMerge(
|
||||||
|
view: InventoryView, //TODO use anvil view instead
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player,
|
||||||
|
first: ItemStack, second: ItemStack
|
||||||
|
): AnvilResult {
|
||||||
|
val newEnchants = first.findEnchantments()
|
||||||
|
.combineWith(second.findEnchantments(), first, player)
|
||||||
|
var hasChanged = !isIdentical(first.findEnchantments(), newEnchants)
|
||||||
|
|
||||||
|
val resultItem = DependencyManager.cloneItem(player, first)
|
||||||
|
val cost = AnvilCost()
|
||||||
|
if (hasChanged) {
|
||||||
|
resultItem.setEnchantmentsUnsafe(newEnchants)
|
||||||
|
// Calculate enchantment cost
|
||||||
|
AnvilXpUtil.getRightValues(second, resultItem, cost)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate repair cost
|
||||||
|
if (!first.isEnchantedBook() && !second.isEnchantedBook()) {
|
||||||
|
// we only need to be concerned with repair when neither item is a book
|
||||||
|
val repaired = resultItem.repairFrom(first, second)
|
||||||
|
cost.repair = if (repaired) ConfigOptions.itemRepairCost else 0
|
||||||
|
hasChanged = hasChanged || repaired
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test/stop if nothing changed.
|
||||||
|
if (!hasChanged) {
|
||||||
|
CustomAnvil.log("Mergeable with second, But input is same as output")
|
||||||
|
return AnvilResult.EMPTY
|
||||||
|
}
|
||||||
|
// As calculatePenalty edit result, we need to calculate penalty after checking equality
|
||||||
|
cost.workPenalty = AnvilXpUtil.calculatePenalty(first, second, resultItem, AnvilUseType.MERGE)
|
||||||
|
// Calculate rename cost
|
||||||
|
cost.rename = handleRename(resultItem, inventory, player)
|
||||||
|
|
||||||
|
val result =
|
||||||
|
DependencyManager.tryTreatAnvilResult(view, inventory, player, resultItem, AnvilUseType.MERGE, cost)
|
||||||
|
|
||||||
|
return AnvilResult(result, cost)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isIdentical(
|
||||||
|
firstEnchants: MutableMap<CAEnchantment, Int>,
|
||||||
|
resultEnchants: MutableMap<CAEnchantment, Int>
|
||||||
|
): Boolean {
|
||||||
|
if (firstEnchants.size != resultEnchants.size) return false
|
||||||
|
for (entry in resultEnchants) {
|
||||||
|
if (firstEnchants.getOrDefault(entry.key, entry.value - 1) != entry.value) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if a custom recipe exist with these ingredients
|
||||||
|
fun testCustomRecipe(
|
||||||
|
view: InventoryView, //TODO use anvil view instead
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player,
|
||||||
|
first: ItemStack, second: ItemStack?
|
||||||
|
): CustomCraftResult {
|
||||||
|
val recipe = CustomRecipeUtil.getCustomRecipe(first, second)
|
||||||
|
CustomAnvil.verboseLog("custom recipe not null? ${recipe != null}")
|
||||||
|
if (recipe == null) return CustomCraftResult.EMPTY
|
||||||
|
|
||||||
|
val amount = CustomRecipeUtil.getCustomRecipeAmount(recipe, first, second)
|
||||||
|
|
||||||
|
val resultItem: ItemStack = DependencyManager.cloneItem(player, recipe.resultItem!!)
|
||||||
|
resultItem.amount *= amount
|
||||||
|
|
||||||
|
// Maybe add an option on custom craft to ignore/not ignore penalty ??
|
||||||
|
val xpCost = recipe.determineCost(amount, first, resultItem)
|
||||||
|
|
||||||
|
val cost = CustomCraftCost(xpCost)
|
||||||
|
// This is for displayed cost
|
||||||
|
cost.recipe = if (recipe.removeExactLinearXp) AnvilXpUtil.calculateMinimumLevelForXp(xpCost)
|
||||||
|
else AnvilXpUtil.calculateLevelForXp(xpCost)
|
||||||
|
|
||||||
|
val result =
|
||||||
|
DependencyManager.tryTreatAnvilResult(view, inventory, player, resultItem, AnvilUseType.CUSTOM_CRAFT, cost)
|
||||||
|
return CustomCraftResult(result, cost, amount, recipe)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testUnitRepair(
|
||||||
|
view: InventoryView, //TODO use anvil view
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player,
|
||||||
|
first: ItemStack, second: ItemStack
|
||||||
|
): UnitRepairResult {
|
||||||
|
val unitRepairAmount = first.getRepair(second) ?: return UnitRepairResult.EMPTY
|
||||||
|
|
||||||
|
return testUnitRepair(view, inventory, player, first, second, unitRepairAmount)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testUnitRepair(
|
||||||
|
view: InventoryView, //TODO use anvil view instead
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player,
|
||||||
|
first: ItemStack, second: ItemStack,
|
||||||
|
unitRepairAmount: Double
|
||||||
|
): UnitRepairResult {
|
||||||
|
val resultItem = DependencyManager.cloneItem(player, first)
|
||||||
|
val cost = AnvilCost()
|
||||||
|
cost.rename = handleRename(resultItem, inventory, player)
|
||||||
|
|
||||||
|
val repairAmount = resultItem.unitRepair(second.amount, unitRepairAmount)
|
||||||
|
if (repairAmount > 0)
|
||||||
|
cost.repair = repairAmount * ConfigOptions.unitRepairCost
|
||||||
|
|
||||||
|
// We do not care about right item penalty for unit repair
|
||||||
|
cost.workPenalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.UNIT_REPAIR)
|
||||||
|
|
||||||
|
// Test/stop if nothing changed.
|
||||||
|
if (first == resultItem) {
|
||||||
|
CustomAnvil.log("unit repair, But input is same as output")
|
||||||
|
return UnitRepairResult.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
val result =
|
||||||
|
DependencyManager.tryTreatAnvilResult(view, inventory, player, resultItem, AnvilUseType.UNIT_REPAIR, cost)
|
||||||
|
return UnitRepairResult(result, cost, repairAmount)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testLoreEdit(
|
||||||
|
player: Player,
|
||||||
|
first: ItemStack, second: ItemStack
|
||||||
|
): LoreEditResult {
|
||||||
|
val type = second.type
|
||||||
|
|
||||||
|
val result = if (Material.WRITABLE_BOOK == type)
|
||||||
|
AnvilLoreEditUtil.tryLoreEditByBook(player, first, second)
|
||||||
|
else if (Material.PAPER == type)
|
||||||
|
AnvilLoreEditUtil.tryLoreEditByPaper(player, first, second)
|
||||||
|
else LoreEditResult.EMPTY
|
||||||
|
|
||||||
|
if (result.isEmpty()) return result
|
||||||
|
|
||||||
|
if (result.item!!.isAir || first == result.item) {
|
||||||
|
CustomAnvil.log("lore edit, But input is same as output")
|
||||||
|
return LoreEditResult.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,60 +1,60 @@
|
||||||
package xyz.alexcrea.cuanvil.util
|
package xyz.alexcrea.cuanvil.anvil
|
||||||
|
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import xyz.alexcrea.cuanvil.config.WorkPenaltyType.WorkPenaltyPart
|
import xyz.alexcrea.cuanvil.config.WorkPenaltyType
|
||||||
import xyz.alexcrea.cuanvil.util.config.LoreEditType
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilUseTypeUtil
|
||||||
|
|
||||||
enum class AnvilUseType(
|
enum class AnvilUseType(
|
||||||
val typeName: String, val path: String,
|
val typeName: String, val path: String,
|
||||||
val defaultPenalty: WorkPenaltyPart,
|
val defaultPenalty: WorkPenaltyType.WorkPenaltyPart,
|
||||||
val displayName: String, val displayMat: Material
|
val displayName: String, val displayMat: Material
|
||||||
) {
|
) {
|
||||||
|
|
||||||
RENAME_ONLY(
|
RENAME_ONLY(
|
||||||
"rename_only",
|
"rename_only",
|
||||||
WorkPenaltyPart(false, true),
|
WorkPenaltyType.WorkPenaltyPart(false, true),
|
||||||
"Rename Only", Material.NAME_TAG
|
"Rename Only", Material.NAME_TAG
|
||||||
),
|
),
|
||||||
MERGE(
|
MERGE(
|
||||||
"merge",
|
"merge",
|
||||||
WorkPenaltyPart(true, true),
|
WorkPenaltyType.WorkPenaltyPart(true, true),
|
||||||
"Merge", Material.ANVIL
|
"Merge", Material.ANVIL
|
||||||
),
|
),
|
||||||
UNIT_REPAIR(
|
UNIT_REPAIR(
|
||||||
"unit_repair",
|
"unit_repair",
|
||||||
WorkPenaltyPart(true, true),
|
WorkPenaltyType.WorkPenaltyPart(true, true),
|
||||||
"Unit Repair", Material.DIAMOND
|
"Unit Repair", Material.DIAMOND
|
||||||
),
|
),
|
||||||
CUSTOM_CRAFT(
|
CUSTOM_CRAFT(
|
||||||
"custom_craft",
|
"custom_craft",
|
||||||
WorkPenaltyPart(false, false),
|
WorkPenaltyType.WorkPenaltyPart(false, false),
|
||||||
"Custom Craft", Material.CRAFTING_TABLE
|
"Custom Craft", Material.CRAFTING_TABLE
|
||||||
),
|
),
|
||||||
LORE_EDIT_BOOK_APPEND(
|
LORE_EDIT_BOOK_APPEND(
|
||||||
"lore_edit_book_append", "lore_edit.book_and_quil.append",
|
"lore_edit_book_append", "lore_edit.book_and_quil.append",
|
||||||
WorkPenaltyPart(false, false),
|
WorkPenaltyType.WorkPenaltyPart(false, false),
|
||||||
"Book Add", Material.WRITABLE_BOOK
|
"Book Add", Material.WRITABLE_BOOK
|
||||||
),
|
),
|
||||||
LORE_EDIT_BOOK_REMOVE(
|
LORE_EDIT_BOOK_REMOVE(
|
||||||
"lore_edit_book_remove", "lore_edit.book_and_quil.remove",
|
"lore_edit_book_remove", "lore_edit.book_and_quil.remove",
|
||||||
WorkPenaltyPart(false, false),
|
WorkPenaltyType.WorkPenaltyPart(false, false),
|
||||||
"Book Remove", Material.WRITABLE_BOOK
|
"Book Remove", Material.WRITABLE_BOOK
|
||||||
),
|
),
|
||||||
LORE_EDIT_PAPER_APPEND(
|
LORE_EDIT_PAPER_APPEND(
|
||||||
"lore_edit_paper_append", "lore_edit.paper.append_line",
|
"lore_edit_paper_append", "lore_edit.paper.append_line",
|
||||||
WorkPenaltyPart(false, false),
|
WorkPenaltyType.WorkPenaltyPart(false, false),
|
||||||
"Paper Add", Material.WRITABLE_BOOK
|
"Paper Add", Material.WRITABLE_BOOK
|
||||||
),
|
),
|
||||||
LORE_EDIT_PAPER_REMOVE(
|
LORE_EDIT_PAPER_REMOVE(
|
||||||
"lore_edit_paper_remove", "lore_edit.paper.remove_line",
|
"lore_edit_paper_remove", "lore_edit.paper.remove_line",
|
||||||
WorkPenaltyPart(false, false),
|
WorkPenaltyType.WorkPenaltyPart(false, false),
|
||||||
"Paper Remove", Material.WRITABLE_BOOK
|
"Paper Remove", Material.WRITABLE_BOOK
|
||||||
),
|
),
|
||||||
;
|
;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
typeName: String,
|
typeName: String,
|
||||||
defaultPenalty: WorkPenaltyPart,
|
defaultPenalty: WorkPenaltyType.WorkPenaltyPart,
|
||||||
displayName: String, displayMat: Material
|
displayName: String, displayMat: Material
|
||||||
) :
|
) :
|
||||||
this(
|
this(
|
||||||
|
|
@ -7,15 +7,19 @@ import org.bukkit.Bukkit
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.command.CommandSender
|
import org.bukkit.command.CommandSender
|
||||||
import org.bukkit.entity.HumanEntity
|
import org.bukkit.entity.HumanEntity
|
||||||
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||||
import org.bukkit.inventory.AnvilInventory
|
import org.bukkit.inventory.AnvilInventory
|
||||||
import org.bukkit.inventory.Inventory
|
import org.bukkit.inventory.Inventory
|
||||||
|
import org.bukkit.inventory.InventoryView
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType
|
||||||
import xyz.alexcrea.cuanvil.api.event.listener.CAClickResultBypassEvent
|
import xyz.alexcrea.cuanvil.api.event.listener.CAClickResultBypassEvent
|
||||||
import xyz.alexcrea.cuanvil.api.event.listener.CAEarlyPreAnvilBypassEvent
|
import xyz.alexcrea.cuanvil.api.event.listener.CAEarlyPreAnvilBypassEvent
|
||||||
import xyz.alexcrea.cuanvil.api.event.listener.CAPreAnvilBypassEvent
|
import xyz.alexcrea.cuanvil.api.event.listener.CAPreAnvilBypassEvent
|
||||||
import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResultEvent
|
import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResult2Event
|
||||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||||
import xyz.alexcrea.cuanvil.dependency.datapack.DataPackDependency
|
import xyz.alexcrea.cuanvil.dependency.datapack.DataPackDependency
|
||||||
import xyz.alexcrea.cuanvil.dependency.gui.GenericExternGuiTester
|
import xyz.alexcrea.cuanvil.dependency.gui.GenericExternGuiTester
|
||||||
|
|
@ -29,7 +33,6 @@ import xyz.alexcrea.cuanvil.dependency.scheduler.TaskScheduler
|
||||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
|
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
|
||||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore
|
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore
|
||||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
|
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType
|
|
||||||
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
|
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
|
|
||||||
|
|
@ -198,7 +201,7 @@ object DependencyManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if should bypass (either by a dependency or error)
|
// Return true if should bypass (either by a dependency or error)
|
||||||
fun tryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
fun tryEventPreAnvilBypass(event: PrepareAnvilEvent, player: Player): Boolean {
|
||||||
try {
|
try {
|
||||||
return unsafeTryEventPreAnvilBypass(event, player)
|
return unsafeTryEventPreAnvilBypass(event, player)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
@ -207,7 +210,7 @@ object DependencyManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unsafeTryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
private fun unsafeTryEventPreAnvilBypass(event: PrepareAnvilEvent, player: Player): Boolean {
|
||||||
// Run the event
|
// Run the event
|
||||||
val bypassEvent = CAPreAnvilBypassEvent(event)
|
val bypassEvent = CAPreAnvilBypassEvent(event)
|
||||||
Bukkit.getPluginManager().callEvent(bypassEvent)
|
Bukkit.getPluginManager().callEvent(bypassEvent)
|
||||||
|
|
@ -232,22 +235,24 @@ object DependencyManager {
|
||||||
|
|
||||||
// Return null if there was an issue
|
// Return null if there was an issue
|
||||||
fun tryTreatAnvilResult(
|
fun tryTreatAnvilResult(
|
||||||
event: PrepareAnvilEvent,
|
view: InventoryView,
|
||||||
|
inventory: Inventory, // TODO REMOVE, use view instead on legacy removal
|
||||||
|
player: HumanEntity,
|
||||||
result: ItemStack,
|
result: ItemStack,
|
||||||
useType: AnvilUseType,
|
useType: AnvilUseType,
|
||||||
cost: Int
|
cost: AnvilCost
|
||||||
): CATreatAnvilResultEvent? {
|
): ItemStack? {
|
||||||
val treatEvent = CATreatAnvilResultEvent(event, useType, result, cost)
|
val treatEvent = CATreatAnvilResult2Event(view, inventory, useType, result, cost)
|
||||||
try {
|
try {
|
||||||
unsafeTryTreatAnvilResult(treatEvent)
|
unsafeTryTreatAnvilResult(treatEvent)
|
||||||
return treatEvent;
|
return treatEvent.result
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logExceptionAndClear(event.view.player, event.inventory, e)
|
logExceptionAndClear(player, inventory, e)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unsafeTryTreatAnvilResult(event: CATreatAnvilResultEvent) {
|
private fun unsafeTryTreatAnvilResult(event: CATreatAnvilResult2Event) {
|
||||||
Bukkit.getPluginManager().callEvent(event)
|
Bukkit.getPluginManager().callEvent(event)
|
||||||
|
|
||||||
excellentEnchantsCompatibility?.treatAnvilResult(event)
|
excellentEnchantsCompatibility?.treatAnvilResult(event)
|
||||||
|
|
@ -293,11 +298,11 @@ object DependencyManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone item and use plugin specific clone if needed
|
// Clone item and use plugin specific clone if needed
|
||||||
fun cloneItem(event: PrepareAnvilEvent, item: ItemStack): ItemStack {
|
fun cloneItem(player: HumanEntity, item: ItemStack): ItemStack {
|
||||||
try {
|
try {
|
||||||
return unsafeCloneItem(item)
|
return unsafeCloneItem(item)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logException(event.view.player, e)
|
logException(player, e)
|
||||||
return item.clone()
|
return item.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package xyz.alexcrea.cuanvil.dependency.economy
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
interface EconomyManager {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var economy: EconomyManager? = null
|
||||||
|
|
||||||
|
fun setupEconomy(plugin: Plugin) {
|
||||||
|
if (plugin.server.pluginManager.getPlugin("Vault") == null)
|
||||||
|
return
|
||||||
|
if (UnlockedEconomyManager.unlockedAvailable())
|
||||||
|
economy = UnlockedEconomyManager(plugin)
|
||||||
|
|
||||||
|
if (economy == null || !economy!!.initialized())
|
||||||
|
economy = VaultEconomyManager(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initialized(): Boolean
|
||||||
|
|
||||||
|
// We assume "initialized" got checked before these function get called
|
||||||
|
fun has(player: Player, money: BigDecimal): Boolean
|
||||||
|
fun remove(player: Player, money: BigDecimal): Boolean
|
||||||
|
|
||||||
|
fun format(money: BigDecimal): String;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
package xyz.alexcrea.cuanvil.dependency.economy
|
||||||
|
|
||||||
|
import io.delilaheve.util.ConfigOptions
|
||||||
|
import net.milkbowl.vault2.economy.Economy
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
class UnlockedEconomyManager : EconomyManager {
|
||||||
|
|
||||||
|
val plugin: String
|
||||||
|
val economy: Economy?
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun unlockedAvailable(): Boolean {
|
||||||
|
try {
|
||||||
|
Class.forName("net.milkbowl.vault2.economy.Economy")
|
||||||
|
return true
|
||||||
|
} catch (_: ClassNotFoundException) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(plugin: Plugin) {
|
||||||
|
this.plugin = plugin.name
|
||||||
|
|
||||||
|
val rsp = plugin.server.servicesManager.getRegistration(Economy::class.java)
|
||||||
|
economy = rsp?.getProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initialized(): Boolean {
|
||||||
|
return economy != null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun currency(): String {
|
||||||
|
val configured = ConfigOptions.usedCurrency
|
||||||
|
|
||||||
|
return if ("default".equals(configured, true))
|
||||||
|
economy!!.getDefaultCurrency(plugin)
|
||||||
|
else configured
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun has(player: Player, money: BigDecimal): Boolean {
|
||||||
|
if (money.signum() <= 0) return true
|
||||||
|
|
||||||
|
return economy!!.has(
|
||||||
|
plugin,
|
||||||
|
player.uniqueId,
|
||||||
|
player.world.name,
|
||||||
|
currency(),
|
||||||
|
money
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(player: Player, money: BigDecimal): Boolean {
|
||||||
|
if (money.signum() <= 0) return true
|
||||||
|
|
||||||
|
return economy!!.withdraw(
|
||||||
|
plugin,
|
||||||
|
player.uniqueId,
|
||||||
|
player.world.name,
|
||||||
|
currency(),
|
||||||
|
money
|
||||||
|
)
|
||||||
|
.transactionSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun format(money: BigDecimal): String {
|
||||||
|
return economy!!.format(plugin, money, currency())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package xyz.alexcrea.cuanvil.dependency.economy
|
||||||
|
|
||||||
|
import net.milkbowl.vault.economy.Economy
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
class VaultEconomyManager : EconomyManager {
|
||||||
|
|
||||||
|
val economy: Economy?
|
||||||
|
|
||||||
|
constructor(plugin: Plugin) {
|
||||||
|
val rsp = plugin.server.servicesManager.getRegistration(Economy::class.java)
|
||||||
|
economy = rsp?.getProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initialized(): Boolean {
|
||||||
|
return economy != null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun has(player: Player, money: BigDecimal): Boolean {
|
||||||
|
if (money.signum() <= 0) return true
|
||||||
|
|
||||||
|
return economy!!.has(player, money.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(player: Player, money: BigDecimal): Boolean {
|
||||||
|
if (money.signum() <= 0) return true
|
||||||
|
|
||||||
|
return economy!!.withdrawPlayer(player, money.toDouble()).transactionSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun format(money: BigDecimal): String {
|
||||||
|
return economy!!.format(money.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -8,15 +8,16 @@ import com.jankominek.disenchantment.events.ShatterEvent
|
||||||
import com.jankominek.disenchantment.listeners.DisenchantClickListener
|
import com.jankominek.disenchantment.listeners.DisenchantClickListener
|
||||||
import com.jankominek.disenchantment.listeners.ShatterClickListener
|
import com.jankominek.disenchantment.listeners.ShatterClickListener
|
||||||
import io.delilaheve.CustomAnvil
|
import io.delilaheve.CustomAnvil
|
||||||
import org.bukkit.entity.HumanEntity
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||||
import org.bukkit.inventory.AnvilInventory
|
import org.bukkit.inventory.AnvilInventory
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost
|
||||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
|
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
|
|
||||||
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
|
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
|
||||||
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilXpUtil
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
@ -50,7 +51,7 @@ class DisenchantmentDependency {
|
||||||
InventoryClickEvent.getHandlerList().unregister(listener)
|
InventoryClickEvent.getHandlerList().unregister(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testPrepareAnvil(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
fun testPrepareAnvil(event: PrepareAnvilEvent, player: Player): Boolean {
|
||||||
val previousResult = event.result
|
val previousResult = event.result
|
||||||
event.result = null
|
event.result = null
|
||||||
|
|
||||||
|
|
@ -58,14 +59,14 @@ class DisenchantmentDependency {
|
||||||
DisenchantEvent.onEvent(event)
|
DisenchantEvent.onEvent(event)
|
||||||
if (event.result != null) {
|
if (event.result != null) {
|
||||||
CustomAnvil.log("Detected pre anvil item extract bypass.")
|
CustomAnvil.log("Detected pre anvil item extract bypass.")
|
||||||
AnvilXpUtil.setAnvilInvXp(event.inventory, event.view, player, event.inventory.repairCost)
|
AnvilXpUtil.setAnvilInvCost(event.inventory, event.view, player, AnvilCost(event.inventory.repairCost))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
ShatterEvent.onEvent(event)
|
ShatterEvent.onEvent(event)
|
||||||
if (event.result != null) {
|
if (event.result != null) {
|
||||||
CustomAnvil.log("Detected pre anvil split enchant bypass.")
|
CustomAnvil.log("Detected pre anvil split enchant bypass.")
|
||||||
AnvilXpUtil.setAnvilInvXp(event.inventory, event.view, player, event.inventory.repairCost)
|
AnvilXpUtil.setAnvilInvCost(event.inventory, event.view, player, AnvilCost(event.inventory.repairCost))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,12 @@ import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.plugin.RegisteredListener
|
import org.bukkit.plugin.RegisteredListener
|
||||||
import xyz.alexcrea.cuanvil.api.EnchantmentApi
|
import xyz.alexcrea.cuanvil.api.EnchantmentApi
|
||||||
import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResultEvent
|
import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResult2Event
|
||||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEPreV5Enchantment
|
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEPreV5Enchantment
|
||||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5Enchantment
|
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5Enchantment
|
||||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5_4Enchantment
|
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5_4Enchantment
|
||||||
import xyz.alexcrea.cuanvil.enchant.wrapped.CALegacyEEEnchantment
|
import xyz.alexcrea.cuanvil.enchant.wrapped.CALegacyEEEnchantment
|
||||||
|
import xyz.alexcrea.cuanvil.util.ModernPrepareAnvilCreator
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import su.nightexpress.excellentenchants.api.EnchantRegistry as V5EnchantRegistry
|
import su.nightexpress.excellentenchants.api.EnchantRegistry as V5EnchantRegistry
|
||||||
import su.nightexpress.excellentenchants.enchantment.impl.universal.CurseOfFragilityEnchant as LegacyCurseOfFragilityEnchant
|
import su.nightexpress.excellentenchants.enchantment.impl.universal.CurseOfFragilityEnchant as LegacyCurseOfFragilityEnchant
|
||||||
|
|
@ -218,14 +219,20 @@ class ExcellentEnchantsDependency {
|
||||||
return handleRechargeMethod.invoke(this.usedAnvilListener, event, first, second) as Boolean
|
return handleRechargeMethod.invoke(this.usedAnvilListener, event, first, second) as Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
fun treatAnvilResult(event: CATreatAnvilResultEvent) {
|
fun treatAnvilResult(event: CATreatAnvilResult2Event) {
|
||||||
val result = event.result
|
val result = event.result ?: return
|
||||||
if (result == null) return
|
|
||||||
|
|
||||||
val first: ItemStack = treatInput(event.event.inventory.getItem(0))
|
val first: ItemStack = treatInput(event.leftItem)
|
||||||
val second: ItemStack = treatInput(event.event.inventory.getItem(1))
|
val second: ItemStack = treatInput(event.rightItem)
|
||||||
|
val fakeEvent: PrepareAnvilEvent = try {
|
||||||
|
//TODO remove this on legacy removal
|
||||||
|
PrepareAnvilEvent(event.view, result)
|
||||||
|
} catch (_: NoSuchMethodError) {
|
||||||
|
ModernPrepareAnvilCreator.createPrepareAnvil(event.view, result)
|
||||||
|
}
|
||||||
|
handleCombineMethod.invoke(this.usedAnvilListener, fakeEvent, first, second, result)
|
||||||
|
|
||||||
handleCombineMethod.invoke(this.usedAnvilListener, event.event, first, second, result)
|
event.result = fakeEvent.result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testAnvilResult(event: InventoryClickEvent): Any {
|
fun testAnvilResult(event: InventoryClickEvent): Any {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package xyz.alexcrea.cuanvil.dependency.plugins
|
package xyz.alexcrea.cuanvil.dependency.plugins
|
||||||
|
|
||||||
import io.delilaheve.CustomAnvil
|
import io.delilaheve.CustomAnvil
|
||||||
import org.bukkit.entity.HumanEntity
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||||
import org.bukkit.inventory.AnvilInventory
|
import org.bukkit.inventory.AnvilInventory
|
||||||
|
|
@ -9,8 +9,9 @@ import org.bukkit.plugin.RegisteredListener
|
||||||
import valorless.havenbags.HavenBags
|
import valorless.havenbags.HavenBags
|
||||||
import valorless.havenbags.features.BagSkin
|
import valorless.havenbags.features.BagSkin
|
||||||
import valorless.havenbags.features.BagUpgrade
|
import valorless.havenbags.features.BagUpgrade
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost
|
||||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
|
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilXpUtil
|
||||||
|
|
||||||
class HavenBagsDependency {
|
class HavenBagsDependency {
|
||||||
|
|
||||||
|
|
@ -45,7 +46,7 @@ class HavenBagsDependency {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testPrepareAnvil(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
fun testPrepareAnvil(event: PrepareAnvilEvent, player: Player): Boolean {
|
||||||
val previousResult = event.result
|
val previousResult = event.result
|
||||||
event.result = null
|
event.result = null
|
||||||
|
|
||||||
|
|
@ -53,14 +54,14 @@ class HavenBagsDependency {
|
||||||
bagSkin.onPrepareAnvil(event)
|
bagSkin.onPrepareAnvil(event)
|
||||||
if (event.result != null) {
|
if (event.result != null) {
|
||||||
CustomAnvil.log("Detected pre anvil heaven bag anvil skin.")
|
CustomAnvil.log("Detected pre anvil heaven bag anvil skin.")
|
||||||
AnvilXpUtil.setAnvilInvXp(event.inventory, event.view, player, event.inventory.repairCost)
|
AnvilXpUtil.setAnvilInvCost(event.inventory, event.view, player, AnvilCost(event.inventory.repairCost))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
bagUpgrade.onPrepareAnvil(event)
|
bagUpgrade.onPrepareAnvil(event)
|
||||||
if (event.result != null) {
|
if (event.result != null) {
|
||||||
CustomAnvil.log("Detected pre anvil heaven bag anvil upgrade.")
|
CustomAnvil.log("Detected pre anvil heaven bag anvil upgrade.")
|
||||||
AnvilXpUtil.setAnvilInvXp(event.inventory, event.view, player, event.inventory.repairCost)
|
AnvilXpUtil.setAnvilInvCost(event.inventory, event.view, player, AnvilCost(event.inventory.repairCost))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package xyz.alexcrea.cuanvil.listener
|
||||||
import io.delilaheve.CustomAnvil
|
import io.delilaheve.CustomAnvil
|
||||||
import io.delilaheve.util.ConfigOptions
|
import io.delilaheve.util.ConfigOptions
|
||||||
import io.delilaheve.util.ItemUtil.canMergeWith
|
import io.delilaheve.util.ItemUtil.canMergeWith
|
||||||
import io.delilaheve.util.ItemUtil.unitRepair
|
|
||||||
import org.bukkit.GameMode
|
import org.bukkit.GameMode
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
|
@ -16,22 +15,25 @@ import org.bukkit.inventory.AnvilInventory
|
||||||
import org.bukkit.inventory.InventoryView
|
import org.bukkit.inventory.InventoryView
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.inventory.meta.BookMeta
|
import org.bukkit.inventory.meta.BookMeta
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.AnvilResult
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.CustomCraftResult
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.LoreEditResult
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.UnitRepairResult
|
||||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||||
|
import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager
|
||||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setComponentDisplayName
|
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setComponentDisplayName
|
||||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_LEFT
|
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_LEFT
|
||||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_RIGHT
|
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_RIGHT
|
||||||
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
|
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
|
||||||
import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe
|
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilLoreEditUtil
|
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType
|
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
|
|
||||||
import xyz.alexcrea.cuanvil.util.CustomRecipeUtil
|
import xyz.alexcrea.cuanvil.util.CustomRecipeUtil
|
||||||
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
|
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
|
||||||
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilLoreEditUtil
|
||||||
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilXpUtil
|
||||||
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil
|
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil
|
||||||
import xyz.alexcrea.cuanvil.util.config.LoreEditType
|
import xyz.alexcrea.cuanvil.util.config.LoreEditType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
@ -50,6 +52,7 @@ class AnvilResultListener : Listener {
|
||||||
fun anvilExtractionCheck(event: InventoryClickEvent) {
|
fun anvilExtractionCheck(event: InventoryClickEvent) {
|
||||||
val player = event.whoClicked as? Player ?: return
|
val player = event.whoClicked as? Player ?: return
|
||||||
val inventory = event.inventory as? AnvilInventory ?: return
|
val inventory = event.inventory as? AnvilInventory ?: return
|
||||||
|
val view = event.view
|
||||||
|
|
||||||
if (event.rawSlot != ANVIL_OUTPUT_SLOT) {
|
if (event.rawSlot != ANVIL_OUTPUT_SLOT) {
|
||||||
return
|
return
|
||||||
|
|
@ -64,84 +67,104 @@ class AnvilResultListener : Listener {
|
||||||
val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
|
val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
|
||||||
val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT)
|
val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT)
|
||||||
|
|
||||||
if (GameMode.CREATIVE != player.gameMode && inventory.repairCost >= inventory.maximumRepairCost) {
|
// Deny by default. allow if working
|
||||||
event.result = Event.Result.DENY
|
event.result = Event.Result.DENY
|
||||||
|
if (GameMode.CREATIVE != player.gameMode && inventory.repairCost >= inventory.maximumRepairCost) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test custom recipe
|
// Test custom recipe
|
||||||
val recipe = CustomRecipeUtil.getCustomRecipe(leftItem, rightItem)
|
val customRecipeResult = AnvilMergeLogic.testCustomRecipe(view, inventory, player, leftItem, rightItem)
|
||||||
if (recipe != null) {
|
if (!customRecipeResult.isEmpty()) {
|
||||||
event.result = Event.Result.ALLOW
|
|
||||||
onCustomCraft(
|
onCustomCraft(
|
||||||
event, recipe, player,
|
event, player, inventory,
|
||||||
leftItem, rightItem, output, inventory
|
leftItem, rightItem, customRecipeResult
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not continue if there was no change
|
// Do not continue if there was no change
|
||||||
if ((output == inventory.getItem(ANVIL_INPUT_LEFT))) {
|
if ((output == inventory.getItem(ANVIL_INPUT_LEFT))) {
|
||||||
event.result = Event.Result.DENY
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename
|
// Rename
|
||||||
if (rightItem == null) {
|
if (rightItem == null) {
|
||||||
event.result = Event.Result.ALLOW
|
val result = AnvilMergeLogic.doRenaming(view, inventory, player, leftItem)
|
||||||
|
if (result.isEmpty()) return
|
||||||
|
|
||||||
|
extractAnvilResult(
|
||||||
|
event, player, inventory,
|
||||||
|
null, 0,
|
||||||
|
null, 0,
|
||||||
|
result
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge
|
// Merge
|
||||||
val canMerge = leftItem.canMergeWith(rightItem)
|
val canMerge = leftItem.canMergeWith(rightItem)
|
||||||
if (canMerge) {
|
if (canMerge) {
|
||||||
event.result = Event.Result.ALLOW
|
val result = AnvilMergeLogic.doMerge(view, inventory, player, leftItem, rightItem)
|
||||||
|
|
||||||
|
extractAnvilResult(
|
||||||
|
event, player, inventory,
|
||||||
|
null, 0,
|
||||||
|
null, 0,
|
||||||
|
result
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unit repair
|
// Unit repair
|
||||||
val unitRepairResult = leftItem.getRepair(rightItem)
|
val unitRepairResult = AnvilMergeLogic.testUnitRepair(
|
||||||
if (unitRepairResult != null) {
|
view, inventory, player,
|
||||||
|
leftItem, rightItem
|
||||||
|
)
|
||||||
|
if (unitRepairResult.isEmpty()) {
|
||||||
onUnitRepairExtract(
|
onUnitRepairExtract(
|
||||||
leftItem, rightItem, output,
|
rightItem, event, player, inventory,
|
||||||
unitRepairResult, event, player, inventory
|
unitRepairResult
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// For lore edit
|
// For lore edit
|
||||||
if (handleBookLoreEdit(event, inventory, player, leftItem, rightItem, output)) {
|
val loreResult = AnvilMergeLogic.testLoreEdit(player, leftItem, rightItem)
|
||||||
return
|
if (!loreResult.isEmpty()) {
|
||||||
} else if (handlePaperLoreEdit(event, inventory, player, leftItem, rightItem, output)) {
|
if (loreResult.type.isBook)
|
||||||
|
handleBookLoreEdit(event, inventory, player, leftItem, rightItem, loreResult)
|
||||||
|
else
|
||||||
|
handlePaperLoreEdit(event, inventory, player, leftItem, rightItem, loreResult)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Else there was no working situation somehow so we deny
|
|
||||||
event.result = Event.Result.DENY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onCustomCraft(
|
private fun onCustomCraft(
|
||||||
event: InventoryClickEvent,
|
event: InventoryClickEvent,
|
||||||
recipe: AnvilCustomRecipe,
|
|
||||||
player: Player,
|
player: Player,
|
||||||
|
inventory: AnvilInventory,
|
||||||
leftItem: ItemStack,
|
leftItem: ItemStack,
|
||||||
rightItem: ItemStack?,
|
rightItem: ItemStack?,
|
||||||
output: ItemStack,
|
result: CustomCraftResult,
|
||||||
inventory: AnvilInventory
|
|
||||||
) {
|
) {
|
||||||
event.result = Event.Result.DENY
|
val recipe = result.recipe!!
|
||||||
|
val rawCost = result.customCraftCost.rawCost
|
||||||
if (recipe.leftItem == null) return // in case it changed
|
|
||||||
|
|
||||||
val amount = CustomRecipeUtil.getCustomRecipeAmount(recipe, leftItem, rightItem)
|
|
||||||
val xpCost = recipe.determineCost(amount, leftItem, output)
|
|
||||||
val finalCost =
|
val finalCost =
|
||||||
if (recipe.removeExactLinearXp) xpCost
|
if (recipe.removeExactLinearXp) rawCost
|
||||||
else AnvilXpUtil.calculateLevelForXp(xpCost)
|
else AnvilXpUtil.calculateLevelForXp(rawCost)
|
||||||
|
|
||||||
|
CustomAnvil.log(
|
||||||
|
"gamemode: ${player.gameMode != GameMode.CREATIVE}, " +
|
||||||
|
"cost: $finalCost, level: ${player.level}, " +
|
||||||
|
"result: ${player.totalExperience < finalCost} ${player.level < finalCost}"
|
||||||
|
)
|
||||||
|
|
||||||
CustomAnvil.log("gamemode: ${player.gameMode != GameMode.CREATIVE}, cost: $finalCost, level: ${player.level}, result: ${player.totalExperience < finalCost} ${player.level < finalCost}")
|
|
||||||
if (player.gameMode != GameMode.CREATIVE) {
|
if (player.gameMode != GameMode.CREATIVE) {
|
||||||
if (recipe.removeExactLinearXp) {
|
if (ConfigOptions.shouldUseMoney(player)) {
|
||||||
|
result.cost.isMonetary = true
|
||||||
|
if (!EconomyManager.economy!!.has(player, result.cost.asMonetaryCost())) return
|
||||||
|
} else if (recipe.removeExactLinearXp) {
|
||||||
val levelXp = AnvilXpUtil.calculateXpForLevel(player.level)
|
val levelXp = AnvilXpUtil.calculateXpForLevel(player.level)
|
||||||
val delta = AnvilXpUtil.calculateXpForLevel(player.level + 1) - levelXp
|
val delta = AnvilXpUtil.calculateXpForLevel(player.level + 1) - levelXp
|
||||||
val totalXp = levelXp + player.exp * delta
|
val totalXp = levelXp + player.exp * delta
|
||||||
|
|
@ -158,31 +181,31 @@ class AnvilResultListener : Listener {
|
||||||
if (event.click != ClickType.MIDDLE &&
|
if (event.click != ClickType.MIDDLE &&
|
||||||
!handleCustomCraftClick(
|
!handleCustomCraftClick(
|
||||||
event,
|
event,
|
||||||
recipe,
|
|
||||||
inventory,
|
inventory,
|
||||||
player,
|
player,
|
||||||
leftItem,
|
leftItem,
|
||||||
rightItem,
|
rightItem,
|
||||||
amount,
|
result
|
||||||
finalCost,
|
|
||||||
recipe.removeExactLinearXp
|
|
||||||
)
|
)
|
||||||
) return
|
) return
|
||||||
|
|
||||||
// Finally, we add the item to the player
|
// Finally, we add the item to the player
|
||||||
if (slotDestination.type == SlotType.CURSOR) {
|
if (slotDestination.type == SlotType.CURSOR) {
|
||||||
player.setItemOnCursor(output)
|
player.setItemOnCursor(result.item)
|
||||||
} else {// We assume SlotType == SlotType.INVENTORY
|
} else {// We assume SlotType == SlotType.INVENTORY
|
||||||
player.inventory.setItem(slotDestination.slot, output)
|
player.inventory.setItem(slotDestination.slot, result.item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleCustomCraftClick(
|
private fun handleCustomCraftClick(
|
||||||
event: InventoryClickEvent, recipe: AnvilCustomRecipe,
|
event: InventoryClickEvent,
|
||||||
inventory: AnvilInventory, player: Player,
|
inventory: AnvilInventory, player: Player,
|
||||||
leftItem: ItemStack, rightItem: ItemStack?,
|
leftItem: ItemStack, rightItem: ItemStack?,
|
||||||
amount: Int, xpCost: Int, linearCost: Boolean = false
|
result: CustomCraftResult
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
val amount = result.amount
|
||||||
|
val recipe = result.recipe!!
|
||||||
|
|
||||||
// We remove what should be removed
|
// We remove what should be removed
|
||||||
if (rightItem != null) {
|
if (rightItem != null) {
|
||||||
if (recipe.rightItem == null) return false// in case it changed
|
if (recipe.rightItem == null) return false// in case it changed
|
||||||
|
|
@ -194,25 +217,7 @@ class AnvilResultListener : Listener {
|
||||||
leftItem.amount -= amount * recipe.leftItem!!.amount
|
leftItem.amount -= amount * recipe.leftItem!!.amount
|
||||||
inventory.setItem(ANVIL_INPUT_LEFT, leftItem)
|
inventory.setItem(ANVIL_INPUT_LEFT, leftItem)
|
||||||
|
|
||||||
if (player.gameMode != GameMode.CREATIVE) {
|
removeCustomCraftCost(player, result)
|
||||||
if (linearCost) {
|
|
||||||
val levelXp = AnvilXpUtil.calculateXpForLevel(player.level)
|
|
||||||
val delta = AnvilXpUtil.calculateXpForLevel(player.level + 1) - levelXp
|
|
||||||
var totalXp = levelXp + player.exp * delta
|
|
||||||
totalXp -= xpCost
|
|
||||||
|
|
||||||
val newLevel = AnvilXpUtil.calculateLevelForXp(totalXp.toInt())
|
|
||||||
|
|
||||||
val newLevelXp = AnvilXpUtil.calculateXpForLevel(newLevel)
|
|
||||||
val newDelta = AnvilXpUtil.calculateXpForLevel(newLevel + 1) - newLevelXp
|
|
||||||
val xp = (totalXp - newLevelXp) / newDelta
|
|
||||||
|
|
||||||
player.level = newLevel
|
|
||||||
player.exp = xp / newDelta
|
|
||||||
} else {
|
|
||||||
player.level -= xpCost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then we try to find the new values for the anvil
|
// Then we try to find the new values for the anvil
|
||||||
val newAmount = CustomRecipeUtil.getCustomRecipeAmount(recipe, leftItem, rightItem)
|
val newAmount = CustomRecipeUtil.getCustomRecipeAmount(recipe, leftItem, rightItem)
|
||||||
|
|
@ -236,6 +241,47 @@ class AnvilResultListener : Listener {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun removeCustomCraftCost(player: Player, result: CustomCraftResult) {
|
||||||
|
if (player.gameMode == GameMode.CREATIVE) return
|
||||||
|
|
||||||
|
val rawCost = result.customCraftCost.rawCost
|
||||||
|
if (result.cost.isMonetary) {
|
||||||
|
EconomyManager.economy!!.remove(player, result.cost.asMonetaryCost())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.recipe!!.removeExactLinearXp) {
|
||||||
|
val levelXp = AnvilXpUtil.calculateXpForLevel(player.level)
|
||||||
|
val delta = AnvilXpUtil.calculateXpForLevel(player.level + 1) - levelXp
|
||||||
|
var totalXp = levelXp + player.exp * delta
|
||||||
|
totalXp -= rawCost
|
||||||
|
|
||||||
|
val newLevel = AnvilXpUtil.calculateLevelForXp(totalXp.toInt())
|
||||||
|
|
||||||
|
val newLevelXp = AnvilXpUtil.calculateXpForLevel(newLevel)
|
||||||
|
val newDelta = AnvilXpUtil.calculateXpForLevel(newLevel + 1) - newLevelXp
|
||||||
|
val xp = (totalXp - newLevelXp) / newDelta
|
||||||
|
|
||||||
|
player.level = newLevel
|
||||||
|
player.exp = xp / newDelta
|
||||||
|
} else {
|
||||||
|
player.level -= AnvilXpUtil.calculateLevelForXp(rawCost)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryRemoveCost(player: Player, cost: AnvilCost): Boolean {
|
||||||
|
if (player.gameMode == GameMode.CREATIVE) return true
|
||||||
|
if (cost.isMonetary) {
|
||||||
|
val result = EconomyManager.economy!!.remove(player, cost.asMonetaryCost())
|
||||||
|
if (!result) return false
|
||||||
|
} else {
|
||||||
|
player.level -= cost.asXpCost()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private fun extractAnvilResult(
|
private fun extractAnvilResult(
|
||||||
event: InventoryClickEvent,
|
event: InventoryClickEvent,
|
||||||
player: Player,
|
player: Player,
|
||||||
|
|
@ -244,15 +290,17 @@ class AnvilResultListener : Listener {
|
||||||
leftRemoveCount: Int,
|
leftRemoveCount: Int,
|
||||||
rightItem: ItemStack?,
|
rightItem: ItemStack?,
|
||||||
rightRemoveCount: Int,
|
rightRemoveCount: Int,
|
||||||
output: ItemStack,
|
result: AnvilResult
|
||||||
repairCost: Int,
|
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
if (result.isEmpty()) return false
|
||||||
|
|
||||||
// To avoid vanilla, we cancel the event
|
// To avoid vanilla, we cancel the event
|
||||||
event.result = Event.Result.DENY
|
event.result = Event.Result.DENY
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
val cost = result.cost
|
||||||
|
|
||||||
// Assumed if player do not have enough xp then it returned MIN_VALUE
|
processCost(inventory, player, cost)
|
||||||
if (repairCost == Int.MIN_VALUE) return false
|
if (!cost.valid && player.gameMode != GameMode.CREATIVE) return false
|
||||||
|
|
||||||
// Where should we get the item
|
// Where should we get the item
|
||||||
val slotDestination = getActionSlot(event, player)
|
val slotDestination = getActionSlot(event, player)
|
||||||
|
|
@ -260,6 +308,8 @@ class AnvilResultListener : Listener {
|
||||||
|
|
||||||
// If not creative middle click...
|
// If not creative middle click...
|
||||||
if (event.click != ClickType.MIDDLE) {
|
if (event.click != ClickType.MIDDLE) {
|
||||||
|
if (!tryRemoveCost(player, cost)) return false
|
||||||
|
|
||||||
// We remove what should be removed
|
// We remove what should be removed
|
||||||
if (leftItem != null) leftItem.amount -= leftRemoveCount
|
if (leftItem != null) leftItem.amount -= leftRemoveCount
|
||||||
inventory.setItem(ANVIL_INPUT_LEFT, leftItem)
|
inventory.setItem(ANVIL_INPUT_LEFT, leftItem)
|
||||||
|
|
@ -268,99 +318,58 @@ class AnvilResultListener : Listener {
|
||||||
inventory.setItem(ANVIL_INPUT_RIGHT, rightItem)
|
inventory.setItem(ANVIL_INPUT_RIGHT, rightItem)
|
||||||
|
|
||||||
inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||||
player.level -= repairCost
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, we add the item to the player
|
// Finally, we add the item to the player
|
||||||
if (SlotType.CURSOR == slotDestination.type) {
|
if (SlotType.CURSOR == slotDestination.type) {
|
||||||
player.setItemOnCursor(output)
|
player.setItemOnCursor(result.item)
|
||||||
} else {// We assume SlotType == SlotType.INVENTORY
|
} else {// We assume SlotType == SlotType.INVENTORY
|
||||||
player.inventory.setItem(slotDestination.slot, output)
|
player.inventory.setItem(slotDestination.slot, result.item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO probably anvil damage & sound here ??
|
// TODO probably anvil damage & sound here ??
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onUnitRepairExtract(
|
private fun processCost(inventory: AnvilInventory, player: Player, cost: AnvilCost) {
|
||||||
leftItem: ItemStack,
|
var sum = cost.repair
|
||||||
rightItem: ItemStack,
|
|
||||||
output: ItemStack,
|
|
||||||
unitRepairResult: Double,
|
|
||||||
event: InventoryClickEvent,
|
|
||||||
player: Player,
|
|
||||||
inventory: AnvilInventory
|
|
||||||
) {
|
|
||||||
val resultCopy = leftItem.clone()
|
|
||||||
val resultAmount = resultCopy.unitRepair(
|
|
||||||
rightItem.amount, unitRepairResult
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get repair cost
|
|
||||||
val repairCost = getUnitRepairCost(inventory, player, leftItem, output, resultCopy, resultAmount)
|
|
||||||
|
|
||||||
// And then we give the item manually
|
|
||||||
extractAnvilResult(
|
|
||||||
event, player, inventory,
|
|
||||||
null, 0,
|
|
||||||
rightItem, resultAmount,
|
|
||||||
resultCopy, repairCost
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getUnitRepairCost(
|
|
||||||
inventory: AnvilInventory, player: Player,
|
|
||||||
leftItem: ItemStack, output: ItemStack,
|
|
||||||
resultCopy: ItemStack, resultAmount: Int
|
|
||||||
): Int {
|
|
||||||
if (player.gameMode == GameMode.CREATIVE) return 0
|
|
||||||
|
|
||||||
var repairCost = 0
|
|
||||||
// Get repairCost
|
|
||||||
leftItem.itemMeta?.let { leftMeta ->
|
|
||||||
val leftName = leftMeta.displayName
|
|
||||||
output.itemMeta?.let {
|
|
||||||
// Rename cost
|
|
||||||
if (!leftName.contentEquals(it.displayName)) {
|
|
||||||
repairCost += ConfigOptions.itemRenameCost
|
|
||||||
|
|
||||||
// Color cost
|
|
||||||
if (it.displayName.contains('§')) {
|
|
||||||
repairCost += ConfigOptions.useOfColorCost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repairCost += AnvilXpUtil.calculatePenalty(leftItem, null, resultCopy, AnvilUseType.UNIT_REPAIR)
|
|
||||||
repairCost += resultAmount * ConfigOptions.unitRepairCost
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!ConfigOptions.doRemoveCostLimit &&
|
!ConfigOptions.doRemoveCostLimit &&
|
||||||
ConfigOptions.doCapCost
|
ConfigOptions.doCapCost
|
||||||
) {
|
) {
|
||||||
repairCost = min(repairCost, ConfigOptions.maxAnvilCost)
|
val final = min(sum, ConfigOptions.maxAnvilCost)
|
||||||
|
cost.generic += (final - sum)
|
||||||
|
|
||||||
|
sum = final
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((inventory.maximumRepairCost <= repairCost)
|
if (ConfigOptions.shouldUseMoney(player)) {
|
||||||
|| (player.level < repairCost)
|
cost.isMonetary = true
|
||||||
) return Int.MIN_VALUE
|
if (!EconomyManager.economy!!.has(player, cost.asMonetaryCost()))
|
||||||
|
cost.valid = false
|
||||||
return repairCost
|
} else {
|
||||||
|
if ((inventory.maximumRepairCost <= sum)
|
||||||
|
|| (player.level < sum)
|
||||||
|
) cost.valid = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFromLoreEditXpCost(
|
private fun onUnitRepairExtract(
|
||||||
xpCost: AtomicInteger,
|
rightItem: ItemStack,
|
||||||
|
event: InventoryClickEvent,
|
||||||
player: Player,
|
player: Player,
|
||||||
inventory: AnvilInventory,
|
inventory: AnvilInventory,
|
||||||
): Int {
|
result: UnitRepairResult,
|
||||||
if (GameMode.CREATIVE == player.gameMode) return 0
|
) {
|
||||||
|
// We give the item manually
|
||||||
val repairCost = xpCost.get()
|
extractAnvilResult(
|
||||||
return if ((inventory.maximumRepairCost <= repairCost)
|
event, player, inventory,
|
||||||
|| (player.level < repairCost)
|
null, 0,
|
||||||
) Int.MIN_VALUE
|
rightItem, result.repairAmount,
|
||||||
else repairCost
|
result
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleBookLoreEdit(
|
private fun handleBookLoreEdit(
|
||||||
|
|
@ -369,16 +378,22 @@ class AnvilResultListener : Listener {
|
||||||
player: Player,
|
player: Player,
|
||||||
leftItem: ItemStack,
|
leftItem: ItemStack,
|
||||||
rightItem: ItemStack,
|
rightItem: ItemStack,
|
||||||
output: ItemStack,
|
result: LoreEditResult
|
||||||
): Boolean {
|
) {
|
||||||
if (Material.WRITABLE_BOOK != rightItem.type) return false
|
if (result.type.isAppend)
|
||||||
val bookMeta = rightItem.itemMeta as BookMeta? ?: return false
|
handleBookLoreAppend(event, inventory, player, rightItem, result)
|
||||||
|
else
|
||||||
|
handleBookLoreRemove(event, inventory, player, leftItem, rightItem, result)
|
||||||
|
}
|
||||||
|
|
||||||
val editType = AnvilLoreEditUtil.bookLoreEditIsAppend(leftItem, rightItem) ?: return false
|
private fun handleBookLoreAppend(
|
||||||
|
event: InventoryClickEvent,
|
||||||
val xpCost = AtomicInteger()
|
inventory: AnvilInventory,
|
||||||
if (editType) {
|
player: Player,
|
||||||
if (output != AnvilLoreEditUtil.handleLoreAppendByBook(player, leftItem, bookMeta, xpCost)) return false
|
rightItem: ItemStack,
|
||||||
|
result: LoreEditResult
|
||||||
|
) {
|
||||||
|
val bookMeta = rightItem.itemMeta as BookMeta? ?: return
|
||||||
|
|
||||||
// Remove pages to book
|
// Remove pages to book
|
||||||
val clearedBook: ItemStack?
|
val clearedBook: ItemStack?
|
||||||
|
|
@ -390,18 +405,27 @@ class AnvilResultListener : Listener {
|
||||||
clearedBook.itemMeta = bookMeta
|
clearedBook.itemMeta = bookMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
return extractAnvilResult(
|
extractAnvilResult(
|
||||||
event, player, inventory,
|
event, player, inventory,
|
||||||
null, 0,
|
null, 0,
|
||||||
clearedBook, 0,
|
clearedBook, 0,
|
||||||
output, getFromLoreEditXpCost(xpCost, player, inventory)
|
result
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
if (output != AnvilLoreEditUtil.handleLoreRemoveByBook(player, leftItem, xpCost)) return false
|
|
||||||
|
private fun handleBookLoreRemove(
|
||||||
|
event: InventoryClickEvent,
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player,
|
||||||
|
leftItem: ItemStack,
|
||||||
|
rightItem: ItemStack,
|
||||||
|
result: LoreEditResult
|
||||||
|
) {
|
||||||
|
val bookMeta = rightItem.itemMeta as BookMeta? ?: return
|
||||||
|
|
||||||
// fill book meta
|
// fill book meta
|
||||||
val lore = DependencyManager.stripLore(leftItem)
|
val lore = DependencyManager.stripLore(leftItem)
|
||||||
if (lore.isEmpty()) return false
|
if (lore.isEmpty()) return
|
||||||
|
|
||||||
val rightCopy: ItemStack?
|
val rightCopy: ItemStack?
|
||||||
if (LoreEditType.REMOVE_BOOK.doConsume) {
|
if (LoreEditType.REMOVE_BOOK.doConsume) {
|
||||||
|
|
@ -413,7 +437,7 @@ class AnvilResultListener : Listener {
|
||||||
val bookPage = StringBuilder()
|
val bookPage = StringBuilder()
|
||||||
lore.forEach {
|
lore.forEach {
|
||||||
if (bookPage.isNotEmpty()) bookPage.append('\n')
|
if (bookPage.isNotEmpty()) bookPage.append('\n')
|
||||||
if(it == null) return@forEach
|
if (it == null) return@forEach
|
||||||
|
|
||||||
bookPage.append(MiniMessageUtil.plain_text_mm.serialize(it))
|
bookPage.append(MiniMessageUtil.plain_text_mm.serialize(it))
|
||||||
}
|
}
|
||||||
|
|
@ -426,14 +450,13 @@ class AnvilResultListener : Listener {
|
||||||
rightCopy.itemMeta = bookMeta
|
rightCopy.itemMeta = bookMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
return extractAnvilResult(
|
extractAnvilResult(
|
||||||
event, player, inventory,
|
event, player, inventory,
|
||||||
null, 0,
|
null, 0,
|
||||||
rightCopy, 0,
|
rightCopy, 0,
|
||||||
output, getFromLoreEditXpCost(xpCost, player, inventory)
|
result
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun handlePaperLoreEdit(
|
private fun handlePaperLoreEdit(
|
||||||
event: InventoryClickEvent,
|
event: InventoryClickEvent,
|
||||||
|
|
@ -441,16 +464,23 @@ class AnvilResultListener : Listener {
|
||||||
player: Player,
|
player: Player,
|
||||||
leftItem: ItemStack,
|
leftItem: ItemStack,
|
||||||
rightItem: ItemStack,
|
rightItem: ItemStack,
|
||||||
output: ItemStack,
|
result: LoreEditResult
|
||||||
): Boolean {
|
) {
|
||||||
if (Material.PAPER != rightItem.type) return false
|
if (result.type.isAppend)
|
||||||
val paperMeta = rightItem.itemMeta ?: return false
|
handlePaperLoreAppend(event, inventory, player, rightItem, result)
|
||||||
|
else
|
||||||
|
handlePaperLoreRemove(event, inventory, player, leftItem, rightItem, result)
|
||||||
|
}
|
||||||
|
|
||||||
val editTypeIsAppend = AnvilLoreEditUtil.paperLoreEditIsAppend(leftItem, rightItem) ?: return false
|
private fun handlePaperLoreAppend(
|
||||||
|
event: InventoryClickEvent,
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player,
|
||||||
|
rightItem: ItemStack,
|
||||||
|
result: LoreEditResult
|
||||||
|
) {
|
||||||
|
val paperMeta = rightItem.itemMeta ?: return
|
||||||
|
|
||||||
val xpCost = AtomicInteger()
|
|
||||||
if (editTypeIsAppend) {
|
|
||||||
if (output != AnvilLoreEditUtil.handleLoreAppendByPaper(player, leftItem, rightItem, xpCost)) return false
|
|
||||||
|
|
||||||
val paperCopy: ItemStack?
|
val paperCopy: ItemStack?
|
||||||
if (LoreEditType.APPEND_PAPER.doConsume) {
|
if (LoreEditType.APPEND_PAPER.doConsume) {
|
||||||
|
|
@ -460,31 +490,43 @@ class AnvilResultListener : Listener {
|
||||||
paperCopy = rightItem.clone()
|
paperCopy = rightItem.clone()
|
||||||
paperCopy.amount = 1
|
paperCopy.amount = 1
|
||||||
paperMeta.setComponentDisplayName(null)
|
paperMeta.setComponentDisplayName(null)
|
||||||
|
|
||||||
|
// Remove pcd name
|
||||||
|
AnvilMergeLogic.processPCD(paperMeta, player, null)
|
||||||
|
|
||||||
paperCopy.itemMeta = paperMeta
|
paperCopy.itemMeta = paperMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (rightItem.amount > 1) {
|
if (rightItem.amount > 1) {
|
||||||
extractAnvilResult(
|
extractAnvilResult(
|
||||||
event, player, inventory,
|
event, player, inventory,
|
||||||
paperCopy, 0,
|
paperCopy, 0,
|
||||||
rightItem, 1,
|
rightItem, 1,
|
||||||
output, getFromLoreEditXpCost(xpCost, player, inventory)
|
result
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
extractAnvilResult(
|
extractAnvilResult(
|
||||||
event, player, inventory,
|
event, player, inventory,
|
||||||
null, 0,
|
null, 0,
|
||||||
paperCopy, 0,
|
paperCopy, 0,
|
||||||
output, getFromLoreEditXpCost(xpCost, player, inventory)
|
result
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (output != AnvilLoreEditUtil.handleLoreRemoveByPaper(player, leftItem, xpCost)) return false
|
|
||||||
|
|
||||||
|
private fun handlePaperLoreRemove(
|
||||||
|
event: InventoryClickEvent,
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player,
|
||||||
|
leftItem: ItemStack,
|
||||||
|
rightItem: ItemStack,
|
||||||
|
result: LoreEditResult
|
||||||
|
) {
|
||||||
val leftMeta = leftItem.itemMeta
|
val leftMeta = leftItem.itemMeta
|
||||||
if (leftMeta == null || !leftMeta.hasLore()) return false
|
if (leftMeta == null || !leftMeta.hasLore()) return
|
||||||
|
|
||||||
val lore = DependencyManager.stripLore(leftItem)
|
val lore = DependencyManager.stripLore(leftItem)
|
||||||
if (lore.isEmpty()) return false
|
if (lore.isEmpty()) return
|
||||||
|
|
||||||
// Create result item
|
// Create result item
|
||||||
val rightClone: ItemStack?
|
val rightClone: ItemStack?
|
||||||
|
|
@ -502,30 +544,28 @@ class AnvilResultListener : Listener {
|
||||||
rightClone = rightItem.clone()
|
rightClone = rightItem.clone()
|
||||||
rightClone.amount = 1
|
rightClone.amount = 1
|
||||||
|
|
||||||
val resultMeta = rightClone.itemMeta ?: return false
|
val resultMeta = rightClone.itemMeta ?: return
|
||||||
resultMeta.setComponentDisplayName(ref.get())
|
resultMeta.setComponentDisplayName(ref.get())
|
||||||
rightClone.itemMeta = resultMeta
|
rightClone.itemMeta = resultMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (rightItem.amount > 1) {
|
if (rightItem.amount > 1) {
|
||||||
extractAnvilResult(
|
extractAnvilResult(
|
||||||
event, player, inventory,
|
event, player, inventory,
|
||||||
rightClone, 0,
|
rightClone, 0,
|
||||||
rightItem, 1,
|
rightItem, 1,
|
||||||
output, getFromLoreEditXpCost(xpCost, player, inventory)
|
result
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
extractAnvilResult(
|
extractAnvilResult(
|
||||||
event, player, inventory,
|
event, player, inventory,
|
||||||
null, 0,
|
null, 0,
|
||||||
rightClone, 0,
|
rightClone, 0,
|
||||||
output, getFromLoreEditXpCost(xpCost, player, inventory)
|
result
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the destination slot or "NO_SLOT" slot container if there is no slot available
|
* Get the destination slot or "NO_SLOT" slot container if there is no slot available
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,29 @@ package xyz.alexcrea.cuanvil.listener
|
||||||
import com.github.stefvanschie.inventoryframework.util.InventoryViewUtil
|
import com.github.stefvanschie.inventoryframework.util.InventoryViewUtil
|
||||||
import io.delilaheve.CustomAnvil
|
import io.delilaheve.CustomAnvil
|
||||||
import io.delilaheve.util.ConfigOptions
|
import io.delilaheve.util.ConfigOptions
|
||||||
import io.delilaheve.util.EnchantmentUtil.combineWith
|
|
||||||
import io.delilaheve.util.ItemUtil.canMergeWith
|
import io.delilaheve.util.ItemUtil.canMergeWith
|
||||||
import io.delilaheve.util.ItemUtil.findEnchantments
|
|
||||||
import io.delilaheve.util.ItemUtil.isEnchantedBook
|
|
||||||
import io.delilaheve.util.ItemUtil.repairFrom
|
|
||||||
import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe
|
|
||||||
import io.delilaheve.util.ItemUtil.unitRepair
|
|
||||||
import org.bukkit.ChatColor
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.entity.HumanEntity
|
import org.bukkit.entity.HumanEntity
|
||||||
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.EventPriority
|
import org.bukkit.event.EventPriority
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||||
import org.bukkit.inventory.AnvilInventory
|
import org.bukkit.inventory.AnvilInventory
|
||||||
|
import org.bukkit.inventory.InventoryView
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta
|
||||||
import org.bukkit.inventory.meta.ItemMeta
|
import org.bukkit.inventory.meta.ItemMeta
|
||||||
import org.bukkit.persistence.PersistentDataType
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.AnvilResult
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.doMerge
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.doRenaming
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.testCustomRecipe
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.testLoreEdit
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.testUnitRepair
|
||||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||||
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
|
|
||||||
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
|
|
||||||
import xyz.alexcrea.cuanvil.util.*
|
|
||||||
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
|
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
|
||||||
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilXpUtil
|
||||||
import xyz.alexcrea.cuanvil.util.dialog.AnvilRenameDialogUtil
|
import xyz.alexcrea.cuanvil.util.dialog.AnvilRenameDialogUtil
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener for anvil events
|
* Listener for anvil events
|
||||||
|
|
@ -44,8 +40,6 @@ class PrepareAnvilListener : Listener {
|
||||||
const val ANVIL_OUTPUT_SLOT = 2
|
const val ANVIL_OUTPUT_SLOT = 2
|
||||||
|
|
||||||
var IS_EMPTY_TEST = false
|
var IS_EMPTY_TEST = false
|
||||||
|
|
||||||
private const val RENAME_DIALOG_PERMISSION = "ca.rename.dialog"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -53,23 +47,27 @@ class PrepareAnvilListener : Listener {
|
||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
fun anvilCombineCheck(event: PrepareAnvilEvent) {
|
fun anvilCombineCheck(event: PrepareAnvilEvent) {
|
||||||
// Should find player
|
val view = event.view
|
||||||
val player: HumanEntity = InventoryViewUtil.getInstance().getPlayer(event.view)
|
|
||||||
val inventory = event.inventory
|
val inventory = event.inventory
|
||||||
|
|
||||||
|
val player = InventoryViewUtil.getInstance().getPlayer(view)
|
||||||
|
if(player !is Player) return
|
||||||
|
|
||||||
|
tryRenameDialog(player, event)
|
||||||
|
|
||||||
// Test if custom anvil is bypassed before immutability test
|
// Test if custom anvil is bypassed before immutability test
|
||||||
if (DependencyManager.earlyTryEventPreAnvilBypass(event, player)) {
|
if (DependencyManager.earlyTryEventPreAnvilBypass(event, player)) {
|
||||||
// even if we got bypassed we still want to set price
|
// even if we got bypassed we still want to set price
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, event.inventory.repairCost)
|
AnvilXpUtil.setAnvilInvCost(inventory, view, player, AnvilCost(event.inventory.repairCost))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
|
val first = inventory.getItem(ANVIL_INPUT_LEFT)
|
||||||
val second = inventory.getItem(ANVIL_INPUT_RIGHT)
|
val second = inventory.getItem(ANVIL_INPUT_RIGHT)
|
||||||
|
|
||||||
if(IS_EMPTY_TEST) {
|
if(IS_EMPTY_TEST) {
|
||||||
event.result = null
|
|
||||||
IS_EMPTY_TEST = false
|
IS_EMPTY_TEST = false
|
||||||
|
applyResult(event, player, AnvilResult.EMPTY)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,79 +79,69 @@ class PrepareAnvilListener : Listener {
|
||||||
if (isImmutable(first) || isImmutable(second)) {
|
if (isImmutable(first) || isImmutable(second)) {
|
||||||
CustomAnvil.verboseLog("Skipping anvil process as one of the two item is immutable")
|
CustomAnvil.verboseLog("Skipping anvil process as one of the two item is immutable")
|
||||||
|
|
||||||
event.result = null
|
applyResult(event, player, AnvilResult.EMPTY)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tryRenameDialog(player, event)
|
|
||||||
|
|
||||||
// Test if the event should bypass custom anvil.
|
// Test if the event should bypass custom anvil.
|
||||||
if (DependencyManager.tryEventPreAnvilBypass(event, player)) {
|
if (DependencyManager.tryEventPreAnvilBypass(event, player)) {
|
||||||
// even if we got bypassed we still want to set price
|
// even if we got bypassed we still want to set price
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, event.inventory.repairCost)
|
AnvilXpUtil.setAnvilInvCost(inventory, view, player, AnvilCost(event.inventory.repairCost))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return
|
if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return
|
||||||
|
|
||||||
|
val result = getResult(view, inventory, player, first, second)
|
||||||
|
applyResult(event, player, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getResult(
|
||||||
|
view: InventoryView, //TODO use anvil view
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
player: Player,
|
||||||
|
first: ItemStack?, second: ItemStack?) : AnvilResult
|
||||||
|
{
|
||||||
|
if(first == null)
|
||||||
|
return AnvilResult.EMPTY
|
||||||
|
|
||||||
// Test custom recipe
|
// Test custom recipe
|
||||||
if (testCustomRecipe(event, inventory, player, first, second)) return
|
var result: AnvilResult = testCustomRecipe(view, inventory, player, first, second)
|
||||||
|
if (!result.isEmpty())
|
||||||
|
return result
|
||||||
|
|
||||||
// Test rename lonely item
|
// Test rename lonely item
|
||||||
val isAir = second.isAir
|
val shouldTryRename = second.isAir
|
||||||
CustomAnvil.verboseLog("checking air in main logic: $isAir")
|
CustomAnvil.verboseLog("checking air in main logic: $shouldTryRename")
|
||||||
if (isAir) {
|
if (shouldTryRename)
|
||||||
doRenaming(event, inventory, player, first)
|
return doRenaming(view, inventory, player, first)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test for merge
|
// Test for merge
|
||||||
if (first.canMergeWith(second!!)) {
|
if (first.canMergeWith(second!!))
|
||||||
doMerge(event, inventory, player, first, second)
|
return doMerge(view, inventory, player, first, second)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test for unit repair
|
// Test for unit repair
|
||||||
if (testUnitRepair(event, inventory, player, first, second)) return
|
result = testUnitRepair(view, inventory, player, first, second)
|
||||||
|
if (!result.isEmpty())
|
||||||
|
return result
|
||||||
|
|
||||||
// Test for lore edit
|
// Test for lore edit
|
||||||
if (testLoreEdit(event, inventory, player, first, second)) return
|
result = testLoreEdit(player, first, second)
|
||||||
|
if (!result.isEmpty())
|
||||||
CustomAnvil.log("no anvil fuse type found")
|
return result
|
||||||
event.result = null
|
|
||||||
|
|
||||||
|
return AnvilResult.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryRenameDialog(
|
private fun tryRenameDialog(
|
||||||
player: HumanEntity,
|
player: HumanEntity,
|
||||||
event: PrepareAnvilEvent
|
event: PrepareAnvilEvent
|
||||||
) {
|
) {
|
||||||
if(!canUseRenameDialog(player)) return
|
if(!ConfigOptions.canUseDialogRename(player)) return
|
||||||
|
|
||||||
AnvilRenameDialogUtil.anvilRenameDialog.tryShowDialog(player, event)
|
AnvilRenameDialogUtil.anvilRenameDialog.tryShowDialog(player, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canUseRenameDialog(player: HumanEntity): Boolean {
|
|
||||||
if(!ConfigOptions.doRenameDialog || !AnvilRenameDialogUtil.anvilRenameDialog.canSendDialog()) return false
|
|
||||||
if(ConfigOptions.doRenameDialogUsePermission && !player.hasPermission(RENAME_DIALOG_PERMISSION)) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processDialogPCD(it: ItemMeta, player: HumanEntity) {
|
|
||||||
val keepDialog = canUseRenameDialog(player) && ConfigOptions.shouldKeepRenameText
|
|
||||||
|
|
||||||
val pdc = it.persistentDataContainer
|
|
||||||
if(!keepDialog)
|
|
||||||
pdc.remove(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY)
|
|
||||||
else {
|
|
||||||
val text = AnvilRenameDialogUtil.anvilRenameDialog.currentText(player)
|
|
||||||
if(text == null || text.isBlank())
|
|
||||||
pdc.remove(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY)
|
|
||||||
else pdc.set(AnvilRenameDialog.PCD_KEEP_RENAME_TEXT_KEY, PersistentDataType.STRING, text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isImmutable(item: ItemStack?): Boolean {
|
private fun isImmutable(item: ItemStack?): Boolean {
|
||||||
if (item.isAir) return false
|
if (item.isAir) return false
|
||||||
|
|
||||||
|
|
@ -180,221 +168,14 @@ class PrepareAnvilListener : Listener {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// return true if a custom recipe exist with these ingredients
|
private fun applyResult(event: PrepareAnvilEvent, player: Player, result: AnvilResult) {
|
||||||
private fun testCustomRecipe(
|
event.result = result.item
|
||||||
event: PrepareAnvilEvent, inventory: AnvilInventory,
|
|
||||||
player: HumanEntity,
|
|
||||||
first: ItemStack, second: ItemStack?
|
|
||||||
): Boolean {
|
|
||||||
val recipe = CustomRecipeUtil.getCustomRecipe(first, second)
|
|
||||||
CustomAnvil.verboseLog("custom recipe not null? ${recipe != null}")
|
|
||||||
if (recipe == null) return false
|
|
||||||
|
|
||||||
val amount = CustomRecipeUtil.getCustomRecipeAmount(recipe, first, second)
|
if(result.item == null) {
|
||||||
|
AnvilXpUtil.onNoResult(player, event.view)
|
||||||
val resultItem: ItemStack = DependencyManager.cloneItem(event, recipe.resultItem!!)
|
|
||||||
resultItem.amount *= amount
|
|
||||||
|
|
||||||
// Maybe add an option on custom craft to ignore/not ignore penalty ??
|
|
||||||
val xpCost = recipe.determineCost(amount, first, resultItem)
|
|
||||||
|
|
||||||
val levelCost =
|
|
||||||
if (recipe.removeExactLinearXp) AnvilXpUtil.calculateMinimumLevelForXp(xpCost)
|
|
||||||
else AnvilXpUtil.calculateLevelForXp(xpCost)
|
|
||||||
|
|
||||||
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.CUSTOM_CRAFT, levelCost)
|
|
||||||
if (finalResult == null) return false
|
|
||||||
|
|
||||||
event.result = finalResult.result
|
|
||||||
if (finalResult.result.isAir) return false
|
|
||||||
|
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost, true)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doRenaming(
|
|
||||||
event: PrepareAnvilEvent, inventory: AnvilInventory,
|
|
||||||
player: HumanEntity, first: ItemStack
|
|
||||||
) {
|
|
||||||
val resultItem = DependencyManager.cloneItem(event, first)
|
|
||||||
var anvilCost = handleRename(resultItem, inventory, player)
|
|
||||||
|
|
||||||
// Test/stop if nothing changed.
|
|
||||||
if (first == resultItem) {
|
|
||||||
CustomAnvil.log("no right item, But input is same as output")
|
|
||||||
event.result = null
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
AnvilXpUtil.setAnvilInvCost(event.inventory, event.view, player, result.cost, result.ignoreXpRules)
|
||||||
anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.RENAME_ONLY)
|
|
||||||
|
|
||||||
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.RENAME_ONLY, anvilCost)
|
|
||||||
if (finalResult == null) return
|
|
||||||
|
|
||||||
event.result = finalResult.result
|
|
||||||
if (finalResult.result.isAir) return
|
|
||||||
|
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int {
|
|
||||||
// Can be null
|
|
||||||
var renameText = ChatColor.stripColor(inventory.renameText)
|
|
||||||
|
|
||||||
var sumCost = 0
|
|
||||||
var useColor = false
|
|
||||||
if (ConfigOptions.renameColorPossible && renameText != null) {
|
|
||||||
val component = AnvilColorUtil.handleColor(
|
|
||||||
renameText,
|
|
||||||
AnvilColorUtil.renamePermission(player))
|
|
||||||
|
|
||||||
if (component != null) {
|
|
||||||
renameText = MiniMessageUtil.legacy_mm.serialize(component)
|
|
||||||
|
|
||||||
sumCost += ConfigOptions.useOfColorCost
|
|
||||||
useColor = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rename item and add renaming cost
|
|
||||||
resultItem.itemMeta?.let {
|
|
||||||
val hasDisplayName = it.hasDisplayName()
|
|
||||||
val displayName = if (!hasDisplayName) null
|
|
||||||
else if (useColor) it.displayName
|
|
||||||
else ChatColor.stripColor(it.displayName)
|
|
||||||
|
|
||||||
|
|
||||||
if (!displayName.contentEquals(renameText) && !(displayName == null &&
|
|
||||||
renameText == "" ||
|
|
||||||
//TODO on recent paper check effective name instead
|
|
||||||
renameText == CasedStringUtil.snakeToUpperSpacedCase(resultItem.type.name.lowercase())
|
|
||||||
)) {
|
|
||||||
it.setDisplayName(renameText)
|
|
||||||
processDialogPCD(it, player)
|
|
||||||
resultItem.itemMeta = it
|
|
||||||
|
|
||||||
sumCost += ConfigOptions.itemRenameCost
|
|
||||||
}
|
|
||||||
|
|
||||||
return sumCost
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doMerge(
|
|
||||||
event: PrepareAnvilEvent, inventory: AnvilInventory,
|
|
||||||
player: HumanEntity,
|
|
||||||
first: ItemStack, second: ItemStack
|
|
||||||
) {
|
|
||||||
val newEnchants = first.findEnchantments()
|
|
||||||
.combineWith(second.findEnchantments(), first, player)
|
|
||||||
var hasChanged = !isIdentical(first.findEnchantments(), newEnchants)
|
|
||||||
|
|
||||||
val resultItem = DependencyManager.cloneItem(event, first)
|
|
||||||
var anvilCost = 0
|
|
||||||
if(hasChanged){
|
|
||||||
resultItem.setEnchantmentsUnsafe(newEnchants)
|
|
||||||
// Calculate enchantment cost
|
|
||||||
anvilCost+= AnvilXpUtil.getRightValues(second, resultItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate repair cost
|
|
||||||
if (!first.isEnchantedBook() && !second.isEnchantedBook()) {
|
|
||||||
// we only need to be concerned with repair when neither item is a book
|
|
||||||
val repaired = resultItem.repairFrom(first, second)
|
|
||||||
anvilCost += if (repaired) ConfigOptions.itemRepairCost else 0
|
|
||||||
hasChanged = hasChanged || repaired
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test/stop if nothing changed.
|
|
||||||
if (!hasChanged) {
|
|
||||||
CustomAnvil.log("Mergable with second, But input is same as output")
|
|
||||||
event.result = null
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// As calculatePenalty edit result, we need to calculate penalty after checking equality
|
|
||||||
anvilCost += AnvilXpUtil.calculatePenalty(first, second, resultItem, AnvilUseType.MERGE)
|
|
||||||
// Calculate rename cost
|
|
||||||
anvilCost += handleRename(resultItem, inventory, player)
|
|
||||||
|
|
||||||
// Finally, we set result
|
|
||||||
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.MERGE, anvilCost)
|
|
||||||
if (finalResult == null) return
|
|
||||||
|
|
||||||
event.result = finalResult.result
|
|
||||||
if (finalResult.result.isAir) return
|
|
||||||
|
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isIdentical(
|
|
||||||
firstEnchants: MutableMap<CAEnchantment, Int>,
|
|
||||||
resultEnchants: MutableMap<CAEnchantment, Int>
|
|
||||||
): Boolean {
|
|
||||||
if(firstEnchants.size != resultEnchants.size) return false
|
|
||||||
for (entry in resultEnchants) {
|
|
||||||
if(firstEnchants.getOrDefault(entry.key, entry.value-1) != entry.value) return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if there is a valid unit repair with these ingredients
|
|
||||||
private fun testUnitRepair(
|
|
||||||
event: PrepareAnvilEvent, inventory: AnvilInventory, player: HumanEntity,
|
|
||||||
first: ItemStack, second: ItemStack
|
|
||||||
): Boolean {
|
|
||||||
val unitRepairAmount = first.getRepair(second) ?: return false
|
|
||||||
|
|
||||||
val resultItem = DependencyManager.cloneItem(event, first)
|
|
||||||
var anvilCost = handleRename(resultItem, inventory, player)
|
|
||||||
|
|
||||||
val repairAmount = resultItem.unitRepair(second.amount, unitRepairAmount)
|
|
||||||
if (repairAmount > 0) {
|
|
||||||
anvilCost += repairAmount * ConfigOptions.unitRepairCost
|
|
||||||
}
|
|
||||||
// We do not care about right item penalty for unit repair
|
|
||||||
anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.UNIT_REPAIR)
|
|
||||||
|
|
||||||
// Test/stop if nothing changed.
|
|
||||||
if (first == resultItem) {
|
|
||||||
CustomAnvil.log("unit repair, But input is same as output")
|
|
||||||
event.result = null
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.UNIT_REPAIR, anvilCost)
|
|
||||||
if (finalResult == null) return false
|
|
||||||
|
|
||||||
event.result = finalResult.result
|
|
||||||
if (finalResult.result.isAir) return false
|
|
||||||
|
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun testLoreEdit(
|
|
||||||
event: PrepareAnvilEvent, inventory: AnvilInventory, player: HumanEntity,
|
|
||||||
first: ItemStack, second: ItemStack
|
|
||||||
): Boolean {
|
|
||||||
val type = second.type
|
|
||||||
var result: ItemStack? = null
|
|
||||||
|
|
||||||
val xpCost = AtomicInteger()
|
|
||||||
if (Material.WRITABLE_BOOK == type) {
|
|
||||||
result = AnvilLoreEditUtil.tryLoreEditByBook(player, first, second, xpCost)
|
|
||||||
} else if (Material.PAPER == type) {
|
|
||||||
result = AnvilLoreEditUtil.tryLoreEditByPaper(player, first, second, xpCost)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.isAir || first == result) {
|
|
||||||
CustomAnvil.log("lore edit, But input is same as output")
|
|
||||||
event.result = null
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
event.result = result
|
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, xpCost.get())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -3,11 +3,11 @@ package xyz.alexcrea.cuanvil.recipe
|
||||||
import io.delilaheve.CustomAnvil
|
import io.delilaheve.CustomAnvil
|
||||||
import org.bukkit.configuration.ConfigurationSection
|
import org.bukkit.configuration.ConfigurationSection
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType
|
||||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||||
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant
|
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType
|
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
|
|
||||||
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
|
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
|
||||||
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilXpUtil
|
||||||
|
|
||||||
class AnvilCustomRecipe(
|
class AnvilCustomRecipe(
|
||||||
val name: String,
|
val name: String,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
package xyz.alexcrea.cuanvil.util
|
package xyz.alexcrea.cuanvil.util.anvil
|
||||||
|
|
||||||
import io.delilaheve.util.ConfigOptions
|
import io.delilaheve.util.ConfigOptions
|
||||||
import net.kyori.adventure.text.Component
|
import net.kyori.adventure.text.Component
|
||||||
import org.bukkit.permissions.Permissible
|
import org.bukkit.permissions.Permissible
|
||||||
|
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
|
||||||
import java.util.regex.Matcher
|
import java.util.regex.Matcher
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.text.indexOf
|
|
||||||
|
|
||||||
object AnvilColorUtil {
|
object AnvilColorUtil {
|
||||||
private val HEX_PATTERN: Pattern = Pattern.compile("#[A-Fa-f0-9]{6}") // pattern to find hexadecimal string
|
private val HEX_PATTERN: Pattern = Pattern.compile("#[A-Fa-f0-9]{6}") // pattern to find hexadecimal string
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
package xyz.alexcrea.cuanvil.util
|
package xyz.alexcrea.cuanvil.util.anvil
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component
|
import net.kyori.adventure.text.Component
|
||||||
import org.bukkit.entity.HumanEntity
|
import org.bukkit.entity.HumanEntity
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.inventory.meta.BookMeta
|
import org.bukkit.inventory.meta.BookMeta
|
||||||
import org.bukkit.permissions.Permissible
|
import org.bukkit.permissions.Permissible
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.LoreEditResult
|
||||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore
|
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore
|
||||||
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setComponentLore
|
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setComponentLore
|
||||||
|
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
|
||||||
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil
|
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil
|
||||||
import xyz.alexcrea.cuanvil.util.config.LoreEditType
|
import xyz.alexcrea.cuanvil.util.config.LoreEditType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
object AnvilLoreEditUtil {
|
object AnvilLoreEditUtil {
|
||||||
|
|
@ -31,7 +33,7 @@ object AnvilLoreEditUtil {
|
||||||
player: Permissible,
|
player: Permissible,
|
||||||
first: ItemStack,
|
first: ItemStack,
|
||||||
book: BookMeta,
|
book: BookMeta,
|
||||||
xpCost: AtomicInteger
|
cost: AnvilCost
|
||||||
): ItemStack? {
|
): ItemStack? {
|
||||||
if (!hasLoreEditByBookPermission(player)) return null
|
if (!hasLoreEditByBookPermission(player)) return null
|
||||||
|
|
||||||
|
|
@ -42,8 +44,10 @@ object AnvilLoreEditUtil {
|
||||||
val page = book.pages[0]
|
val page = book.pages[0]
|
||||||
val lines = ArrayList<String>(page.split("\n"))
|
val lines = ArrayList<String>(page.split("\n"))
|
||||||
val outLines = ArrayList<Component>(lines.size)
|
val outLines = ArrayList<Component>(lines.size)
|
||||||
val colorCost = colorLines(player, LoreEditType.APPEND_BOOK,
|
val colorCost = colorLines(
|
||||||
lines, outLines)
|
player, LoreEditType.APPEND_BOOK,
|
||||||
|
lines, outLines
|
||||||
|
)
|
||||||
|
|
||||||
lore.addAll(outLines)
|
lore.addAll(outLines)
|
||||||
|
|
||||||
|
|
@ -53,14 +57,14 @@ object AnvilLoreEditUtil {
|
||||||
if (result == first) return null
|
if (result == first) return null
|
||||||
|
|
||||||
// Handle xp
|
// Handle xp
|
||||||
xpCost.addAndGet(colorCost) // Cost of using color
|
cost.lore = colorCost // Cost of using color
|
||||||
xpCost.addAndGet(outLines.size * LoreEditType.APPEND_BOOK.perLineCost) // per line cost
|
cost.lore += outLines.size * LoreEditType.APPEND_BOOK.perLineCost // per line cost
|
||||||
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.APPEND_BOOK)) // Fixed cost and work penalty
|
baseEditLoreXpCost(cost, first, result, LoreEditType.APPEND_BOOK) // Fixed cost and work penalty
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleLoreRemoveByBook(player: Permissible, first: ItemStack, xpCost: AtomicInteger): ItemStack? {
|
fun handleLoreRemoveByBook(player: Permissible, first: ItemStack, cost: AnvilCost): ItemStack? {
|
||||||
if (!hasLoreEditByBookPermission(player)) return null
|
if (!hasLoreEditByBookPermission(player)) return null
|
||||||
|
|
||||||
// remove lore
|
// remove lore
|
||||||
|
|
@ -78,9 +82,9 @@ object AnvilLoreEditUtil {
|
||||||
if (result == first) return null
|
if (result == first) return null
|
||||||
|
|
||||||
// Handle xp
|
// Handle xp
|
||||||
xpCost.addAndGet(uncolorCost)
|
cost.lore = uncolorCost
|
||||||
xpCost.addAndGet(currentLore.size * LoreEditType.REMOVE_BOOK.perLineCost)
|
cost.lore += currentLore.size * LoreEditType.REMOVE_BOOK.perLineCost
|
||||||
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.REMOVE_BOOK))
|
baseEditLoreXpCost(cost, first, result, LoreEditType.REMOVE_BOOK)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
@ -116,12 +120,17 @@ object AnvilLoreEditUtil {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryLoreEditByBook(player: HumanEntity, first: ItemStack, second: ItemStack, xpCost: AtomicInteger): ItemStack? {
|
fun tryLoreEditByBook(player: HumanEntity, first: ItemStack, second: ItemStack): LoreEditResult {
|
||||||
val isAppend = bookLoreEditIsAppend(first, second) ?: return null
|
val isAppend = bookLoreEditIsAppend(first, second) ?: return LoreEditResult.EMPTY
|
||||||
|
val type = if (isAppend) LoreEditType.APPEND_BOOK else LoreEditType.REMOVE_BOOK
|
||||||
|
|
||||||
val meta = second.itemMeta as BookMeta
|
val meta = second.itemMeta as BookMeta
|
||||||
return if (isAppend) handleLoreAppendByBook(player, first, meta, xpCost)
|
val cost = AnvilCost()
|
||||||
else handleLoreRemoveByBook(player, first, xpCost)
|
val item = if (isAppend)
|
||||||
|
handleLoreAppendByBook(player, first, meta, cost)
|
||||||
|
else handleLoreRemoveByBook(player, first, cost)
|
||||||
|
|
||||||
|
return LoreEditResult(item, cost, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if appended, false if removed, null if neither
|
// Return true if appended, false if removed, null if neither
|
||||||
|
|
@ -147,7 +156,7 @@ object AnvilLoreEditUtil {
|
||||||
player: Permissible,
|
player: Permissible,
|
||||||
first: ItemStack,
|
first: ItemStack,
|
||||||
second: ItemStack,
|
second: ItemStack,
|
||||||
xpCost: AtomicInteger
|
cost: AnvilCost
|
||||||
): ItemStack? {
|
): ItemStack? {
|
||||||
if (!hasLoreEditByPaperPermission(player)) return null
|
if (!hasLoreEditByPaperPermission(player)) return null
|
||||||
|
|
||||||
|
|
@ -159,9 +168,11 @@ object AnvilLoreEditUtil {
|
||||||
|
|
||||||
// A bit overdone to color 1 line but hey
|
// A bit overdone to color 1 line but hey
|
||||||
val outList = ArrayList<Component>(1)
|
val outList = ArrayList<Component>(1)
|
||||||
val colorCost = colorLines(player, LoreEditType.APPEND_PAPER,
|
val colorCost = colorLines(
|
||||||
|
player, LoreEditType.APPEND_PAPER,
|
||||||
Collections.singletonList(second.itemMeta!!.displayName),
|
Collections.singletonList(second.itemMeta!!.displayName),
|
||||||
outList)
|
outList
|
||||||
|
)
|
||||||
|
|
||||||
val line = outList[0]
|
val line = outList[0]
|
||||||
if (appendEnd)
|
if (appendEnd)
|
||||||
|
|
@ -175,13 +186,13 @@ object AnvilLoreEditUtil {
|
||||||
if (result == first) return null
|
if (result == first) return null
|
||||||
|
|
||||||
// Handle xp
|
// Handle xp
|
||||||
xpCost.addAndGet(colorCost)
|
cost.lore = colorCost
|
||||||
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.APPEND_PAPER))
|
baseEditLoreXpCost(cost, first, result, LoreEditType.APPEND_PAPER)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleLoreRemoveByPaper(player: Permissible, first: ItemStack, xpCost: AtomicInteger): ItemStack? {
|
fun handleLoreRemoveByPaper(player: Permissible, first: ItemStack, cost: AnvilCost): ItemStack? {
|
||||||
if (!hasLoreEditByPaperPermission(player)) return null
|
if (!hasLoreEditByPaperPermission(player)) return null
|
||||||
|
|
||||||
// remove lore line
|
// remove lore line
|
||||||
|
|
@ -213,8 +224,8 @@ object AnvilLoreEditUtil {
|
||||||
val uncolorCost = uncolorLine(player, line, LoreEditType.REMOVE_PAPER)
|
val uncolorCost = uncolorLine(player, line, LoreEditType.REMOVE_PAPER)
|
||||||
|
|
||||||
// Handle other xp
|
// Handle other xp
|
||||||
xpCost.addAndGet(uncolorCost)
|
cost.lore = uncolorCost
|
||||||
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.REMOVE_PAPER))
|
baseEditLoreXpCost(cost, first, result, LoreEditType.REMOVE_PAPER)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
@ -222,33 +233,39 @@ object AnvilLoreEditUtil {
|
||||||
fun tryLoreEditByPaper(
|
fun tryLoreEditByPaper(
|
||||||
player: HumanEntity,
|
player: HumanEntity,
|
||||||
first: ItemStack,
|
first: ItemStack,
|
||||||
second: ItemStack,
|
second: ItemStack
|
||||||
xpCost: AtomicInteger
|
): LoreEditResult {
|
||||||
): ItemStack? {
|
val isAppend = paperLoreEditIsAppend(first, second) ?: return LoreEditResult.EMPTY
|
||||||
val isAppend = paperLoreEditIsAppend(first, second) ?: return null
|
val type = if (isAppend) LoreEditType.APPEND_BOOK else LoreEditType.REMOVE_BOOK
|
||||||
|
|
||||||
return if (isAppend) handleLoreAppendByPaper(player, first, second, xpCost)
|
val cost = AnvilCost()
|
||||||
else handleLoreRemoveByPaper(player, first, xpCost)
|
val item = if (isAppend)
|
||||||
|
handleLoreAppendByPaper(player, first, second, cost)
|
||||||
|
else handleLoreRemoveByPaper(player, first, cost)
|
||||||
|
|
||||||
|
return LoreEditResult(item, cost, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun baseEditLoreXpCost(
|
private fun baseEditLoreXpCost(
|
||||||
|
cost: AnvilCost,
|
||||||
first: ItemStack,
|
first: ItemStack,
|
||||||
result: ItemStack,
|
result: ItemStack,
|
||||||
editType: LoreEditType
|
editType: LoreEditType
|
||||||
): Int {
|
) {
|
||||||
var xpCost = editType.fixedCost
|
cost.lore += editType.fixedCost
|
||||||
|
|
||||||
xpCost += AnvilXpUtil.calculatePenalty(first, null, result, editType.useType)
|
cost.workPenalty = AnvilXpUtil.calculatePenalty(first, null, result, editType.useType)
|
||||||
return xpCost
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun colorPermission(player: Permissible, editType: LoreEditType): AnvilColorUtil.ColorPermissions {
|
fun colorPermission(player: Permissible, editType: LoreEditType): AnvilColorUtil.ColorPermissions {
|
||||||
return AnvilColorUtil.calculatePermissions(player,
|
return AnvilColorUtil.calculatePermissions(
|
||||||
|
player,
|
||||||
false,
|
false,
|
||||||
editType.allowColorCode,
|
editType.allowColorCode,
|
||||||
editType.allowHexColor,
|
editType.allowHexColor,
|
||||||
editType.allowMinimessage,
|
editType.allowMinimessage,
|
||||||
AnvilColorUtil.ColorUseType.LORE_EDIT)
|
AnvilColorUtil.ColorUseType.LORE_EDIT
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun colorLine(line: String, permission: AnvilColorUtil.ColorPermissions): Component? {
|
private fun colorLine(line: String, permission: AnvilColorUtil.ColorPermissions): Component? {
|
||||||
|
|
@ -258,8 +275,10 @@ object AnvilLoreEditUtil {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun colorLines(player: Permissible, editType: LoreEditType,
|
private fun colorLines(
|
||||||
lines: List<String>, outLines: MutableList<Component>): Int {
|
player: Permissible, editType: LoreEditType,
|
||||||
|
lines: List<String>, outLines: MutableList<Component>
|
||||||
|
): Int {
|
||||||
val permission = colorPermission(player, editType)
|
val permission = colorPermission(player, editType)
|
||||||
val colorCost = editType.useColorCost
|
val colorCost = editType.useColorCost
|
||||||
|
|
||||||
|
|
@ -286,7 +305,7 @@ object AnvilLoreEditUtil {
|
||||||
// Now handle color of each lines
|
// Now handle color of each lines
|
||||||
var hasUndidColor = false
|
var hasUndidColor = false
|
||||||
for ((index, line) in lines.withIndex()) {
|
for ((index, line) in lines.withIndex()) {
|
||||||
if(line == null){
|
if (line == null) {
|
||||||
lines[index] = null
|
lines[index] = null
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -330,7 +349,7 @@ object AnvilLoreEditUtil {
|
||||||
|
|
||||||
var hasUndidColor = false
|
var hasUndidColor = false
|
||||||
val result: String
|
val result: String
|
||||||
if(clearedLine != null){
|
if (clearedLine != null) {
|
||||||
hasUndidColor = true
|
hasUndidColor = true
|
||||||
result = clearedLine
|
result = clearedLine
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package xyz.alexcrea.cuanvil.util
|
package xyz.alexcrea.cuanvil.util.anvil
|
||||||
|
|
||||||
import io.delilaheve.util.ConfigOptions
|
import io.delilaheve.util.ConfigOptions
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package xyz.alexcrea.cuanvil.util
|
package xyz.alexcrea.cuanvil.util.anvil
|
||||||
|
|
||||||
import io.delilaheve.CustomAnvil
|
import io.delilaheve.CustomAnvil
|
||||||
import io.delilaheve.util.ConfigOptions
|
import io.delilaheve.util.ConfigOptions
|
||||||
|
|
@ -14,25 +14,48 @@ import org.bukkit.inventory.InventoryView
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.inventory.meta.Repairable
|
import org.bukkit.inventory.meta.Repairable
|
||||||
import org.bukkit.persistence.PersistentDataType
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilCost
|
||||||
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType
|
||||||
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
import xyz.alexcrea.cuanvil.config.ConfigHolder
|
||||||
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
import xyz.alexcrea.cuanvil.dependency.DependencyManager
|
||||||
|
import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager
|
||||||
import xyz.alexcrea.cuanvil.group.ConflictType
|
import xyz.alexcrea.cuanvil.group.ConflictType
|
||||||
|
import xyz.alexcrea.cuanvil.util.AnvilTitleUtil
|
||||||
|
import xyz.alexcrea.cuanvil.util.dialog.AnvilRenameDialogUtil
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
object AnvilXpUtil {
|
object AnvilXpUtil {
|
||||||
|
|
||||||
const val EXCLUSIVE_PENALTY_PREFIX = "repair_cost"
|
const val EXCLUSIVE_PENALTY_PREFIX = "repair_cost"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the required cost (either as xp or as )
|
||||||
|
*/
|
||||||
|
fun setAnvilInvCost(
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
view: InventoryView,
|
||||||
|
player: Player,
|
||||||
|
cost: AnvilCost,
|
||||||
|
ignoreRules: Boolean = false
|
||||||
|
) {
|
||||||
|
if (ConfigOptions.shouldUseMoney(player)) {
|
||||||
|
cost.isMonetary = true
|
||||||
|
setAnvilPrice(inventory, view, player, cost)
|
||||||
|
} else
|
||||||
|
setAnvilInvXp(inventory, view, player, cost.asXpCost(), ignoreRules)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display xp needed for the work on the anvil inventory
|
* Display xp needed for the work on the anvil inventory
|
||||||
*/
|
*/
|
||||||
fun setAnvilInvXp(
|
private fun setAnvilInvXp(
|
||||||
inventory: AnvilInventory,
|
inventory: AnvilInventory,
|
||||||
view: InventoryView,
|
view: InventoryView,
|
||||||
player: HumanEntity,
|
player: HumanEntity,
|
||||||
anvilCost: Int,
|
anvilCost: Int,
|
||||||
ignoreRules: Boolean = false
|
ignoreRules: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Test repair cost limit
|
// Test repair cost limit
|
||||||
val finalAnvilCost = if (
|
val finalAnvilCost = if (
|
||||||
!ignoreRules &&
|
!ignoreRules &&
|
||||||
|
|
@ -78,7 +101,51 @@ object AnvilXpUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
player.updateInventory()
|
player.updateInventory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display monetary cost needed for the work on the anvil inventory
|
||||||
|
*/
|
||||||
|
private fun setAnvilPrice(
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
view: InventoryView,
|
||||||
|
player: Player,
|
||||||
|
cost: AnvilCost,
|
||||||
|
) {
|
||||||
|
val finalCost = cost.asMonetaryCost()
|
||||||
|
|
||||||
|
val has = player.gameMode == GameMode.CREATIVE ||
|
||||||
|
EconomyManager.economy!!.has(player, finalCost)
|
||||||
|
|
||||||
|
val text = "Cost: " + (if (has) "§2" else "§4") +
|
||||||
|
EconomyManager.economy!!.format(finalCost)
|
||||||
|
AnvilTitleUtil.rename(
|
||||||
|
view, text,
|
||||||
|
player,
|
||||||
|
AnvilRenameDialogUtil.anvilRenameDialog,
|
||||||
|
CustomAnvil.instance
|
||||||
|
)
|
||||||
|
|
||||||
|
clearAnvilXpCost(inventory, view, player)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearAnvilXpCost(
|
||||||
|
inventory: AnvilInventory,
|
||||||
|
view: InventoryView,
|
||||||
|
player: HumanEntity,
|
||||||
|
) {
|
||||||
|
// TODO for 2.x.x use anvil view & set directly there
|
||||||
|
inventory.repairCost = 0
|
||||||
|
|
||||||
|
// retry after a tick
|
||||||
|
DependencyManager.scheduler.scheduleOnEntity(
|
||||||
|
CustomAnvil.instance, player
|
||||||
|
) {
|
||||||
|
inventory.repairCost = 0
|
||||||
|
|
||||||
|
if (player !is Player) return@scheduleOnEntity
|
||||||
|
player.updateInventory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,6 +195,16 @@ object AnvilXpUtil {
|
||||||
return resultSum
|
return resultSum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onNoResult(player: HumanEntity, view: InventoryView) {
|
||||||
|
if (ConfigOptions.shouldUseMoney(player))
|
||||||
|
AnvilTitleUtil.rename(
|
||||||
|
view, "Repair & Name",
|
||||||
|
player,
|
||||||
|
AnvilRenameDialogUtil.anvilRenameDialog,
|
||||||
|
CustomAnvil.instance
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun exclusivePenaltyKey(useType: AnvilUseType): NamespacedKey {
|
private fun exclusivePenaltyKey(useType: AnvilUseType): NamespacedKey {
|
||||||
return NamespacedKey(CustomAnvil.instance, "${EXCLUSIVE_PENALTY_PREFIX}_${useType.typeName}")
|
return NamespacedKey(CustomAnvil.instance, "${EXCLUSIVE_PENALTY_PREFIX}_${useType.typeName}")
|
||||||
}
|
}
|
||||||
|
|
@ -159,10 +236,8 @@ object AnvilXpUtil {
|
||||||
* Function to calculate right enchantment values
|
* Function to calculate right enchantment values
|
||||||
* it include enchantment placed on final item and conflicting enchantment
|
* it include enchantment placed on final item and conflicting enchantment
|
||||||
*/
|
*/
|
||||||
fun getRightValues(right: ItemStack, result: ItemStack): Int {
|
fun getRightValues(right: ItemStack, result: ItemStack, cost: AnvilCost) {
|
||||||
// Calculate right value and illegal enchant penalty
|
// Calculate right value and illegal enchant penalty
|
||||||
var illegalPenalty = 0
|
|
||||||
var rightValue = 0
|
|
||||||
|
|
||||||
val rightIsFormBook = right.isEnchantedBook()
|
val rightIsFormBook = right.isEnchantedBook()
|
||||||
val resultEnchs = result.findEnchantments()
|
val resultEnchs = result.findEnchantments()
|
||||||
|
|
@ -180,7 +255,7 @@ object AnvilXpUtil {
|
||||||
resultEnchsKeys.remove(enchantment.key)
|
resultEnchsKeys.remove(enchantment.key)
|
||||||
|
|
||||||
if (ConflictType.ENCHANTMENT_CONFLICT == conflictType) {
|
if (ConflictType.ENCHANTMENT_CONFLICT == conflictType) {
|
||||||
illegalPenalty += ConfigOptions.sacrificeIllegalCost
|
cost.illegalPenalty += ConfigOptions.sacrificeIllegalCost
|
||||||
CustomAnvil.verboseLog("Big conflict. Adding illegal price penalty")
|
CustomAnvil.verboseLog("Big conflict. Adding illegal price penalty")
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
@ -191,16 +266,14 @@ object AnvilXpUtil {
|
||||||
val enchantmentMultiplier = ConfigOptions.enchantmentValue(enchantment.key, rightIsFormBook)
|
val enchantmentMultiplier = ConfigOptions.enchantmentValue(enchantment.key, rightIsFormBook)
|
||||||
val value = resultLevel * enchantmentMultiplier
|
val value = resultLevel * enchantmentMultiplier
|
||||||
CustomAnvil.log("Value for ${enchantment.key.enchantmentName} level ${enchantment.value} is $value ($resultLevel * $enchantmentMultiplier)")
|
CustomAnvil.log("Value for ${enchantment.key.enchantmentName} level ${enchantment.value} is $value ($resultLevel * $enchantmentMultiplier)")
|
||||||
rightValue += value
|
cost.enchantment += value
|
||||||
|
|
||||||
}
|
}
|
||||||
CustomAnvil.log(
|
CustomAnvil.log(
|
||||||
"Calculated right values: " +
|
"Calculated right values: " +
|
||||||
"rightValue: $rightValue, " +
|
"rightValue: ${cost.enchantment}, " +
|
||||||
"illegalPenalty: $illegalPenalty"
|
"illegalPenalty: ${cost.illegalPenalty}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return rightValue + illegalPenalty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package xyz.alexcrea.cuanvil.util.config
|
package xyz.alexcrea.cuanvil.util.config
|
||||||
|
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilUseType
|
import xyz.alexcrea.cuanvil.anvil.AnvilUseType
|
||||||
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil.ALLOW_COLOR_CODE
|
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil.ALLOW_COLOR_CODE
|
||||||
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil.ALLOW_HEX_COLOR
|
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil.ALLOW_HEX_COLOR
|
||||||
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil.ALLOW_MINIMESSAGE
|
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil.ALLOW_MINIMESSAGE
|
||||||
|
|
@ -18,20 +18,23 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder.DEFAULT_CONFIG as CONFIG
|
||||||
enum class LoreEditType(
|
enum class LoreEditType(
|
||||||
val rootPath: String,
|
val rootPath: String,
|
||||||
val useType: AnvilUseType,
|
val useType: AnvilUseType,
|
||||||
|
val isBook: Boolean,
|
||||||
val isAppend: Boolean,
|
val isAppend: Boolean,
|
||||||
val isMultiLine: Boolean,
|
val isMultiLine: Boolean,
|
||||||
) {
|
) {
|
||||||
APPEND_BOOK(AnvilUseType.LORE_EDIT_BOOK_APPEND, true, true),
|
APPEND_BOOK(AnvilUseType.LORE_EDIT_BOOK_APPEND, true, true, true),
|
||||||
REMOVE_BOOK(AnvilUseType.LORE_EDIT_BOOK_REMOVE, false, true),
|
REMOVE_BOOK(AnvilUseType.LORE_EDIT_BOOK_REMOVE, true, false, true),
|
||||||
APPEND_PAPER(AnvilUseType.LORE_EDIT_PAPER_APPEND, true, false),
|
APPEND_PAPER(AnvilUseType.LORE_EDIT_PAPER_APPEND, false, true, false),
|
||||||
REMOVE_PAPER(AnvilUseType.LORE_EDIT_PAPER_REMOVE, false, false),
|
REMOVE_PAPER(AnvilUseType.LORE_EDIT_PAPER_REMOVE, false, false, false),
|
||||||
;
|
;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
useType: AnvilUseType,
|
useType: AnvilUseType,
|
||||||
|
isPaper: Boolean,
|
||||||
isAppend: Boolean,
|
isAppend: Boolean,
|
||||||
isMultiLine: Boolean,
|
isMultiLine: Boolean,
|
||||||
) : this(useType.path, useType, isAppend, isMultiLine)
|
) : this(useType.path, useType,
|
||||||
|
isPaper, isAppend, isMultiLine)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this edit type is enabled
|
* If this edit type is enabled
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
|
||||||
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
|
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
|
||||||
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialogImpl
|
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialogImpl
|
||||||
import xyz.alexcrea.cuanvil.update.UpdateUtils
|
import xyz.alexcrea.cuanvil.update.UpdateUtils
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilColorUtil
|
import xyz.alexcrea.cuanvil.util.anvil.AnvilColorUtil
|
||||||
|
|
||||||
object AnvilRenameDialogUtil {
|
object AnvilRenameDialogUtil {
|
||||||
|
|
||||||
|
|
@ -47,5 +47,9 @@ object AnvilRenameDialogUtil {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isOpenFor(player: HumanEntity): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -432,6 +432,34 @@ lore_edit:
|
||||||
allow_hexadecimal_color: false
|
allow_hexadecimal_color: false
|
||||||
allow_minimessage: true
|
allow_minimessage: true
|
||||||
|
|
||||||
|
# Allow to replace the xp cost by a monetary cost
|
||||||
|
# If enabled it will not be bound to the experience level limits
|
||||||
|
#
|
||||||
|
# It also requires to enable dialog rename (set "enable_dialog_rename: false" a bit higher)
|
||||||
|
# If dialog rename permission is enabled and player do not have the permission merge will fall back to vanilla xp cost
|
||||||
|
#
|
||||||
|
# If you are using custom craft I recommend using Linear Xp Cost with Exact Linear Xp as normal Xp Cost will act "weird"
|
||||||
|
# But Linear Xp will act as 1$ time global multiplier. In other word: like you expect
|
||||||
|
#
|
||||||
|
# As this feature require dialog rename, it can only be enabled starting with paper 1.21.6 and later
|
||||||
|
monetary_cost:
|
||||||
|
enabled: false
|
||||||
|
# If using vault unlocked this allow to specify what currency should be used for anvil usage
|
||||||
|
# default being the default currency
|
||||||
|
currency: default
|
||||||
|
# multiply the anvil cost by a value to allow to have price a big bigger than like 40
|
||||||
|
multipliers:
|
||||||
|
# global multipliers. all usage type will be multiplied by this value
|
||||||
|
global: 1.0
|
||||||
|
# usage specific type. it will only apply for specific xp "reason"
|
||||||
|
enchantment: 1.0 # related to enchantments level
|
||||||
|
repair: 1.0 # for repairing via unit repair (per unit)
|
||||||
|
rename: 1.0 # for renaming the item
|
||||||
|
lore_edit: 1.0 # for changing the lore of the item (only if lore edit is enabled)
|
||||||
|
illegal_penalty: 1.0 # for trying to combine illegal enchantment
|
||||||
|
work_penalty: 1.0 # for work penalty (aka use penalty)
|
||||||
|
recipe: 1.0 # for custom anvil recipe cost
|
||||||
|
|
||||||
# Whether to show debug logging
|
# Whether to show debug logging
|
||||||
debug_log: false
|
debug_log: false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ public class AnvilFuseTestUtil {
|
||||||
|
|
||||||
simulateClick(anvil, player, data.expectedResult());
|
simulateClick(anvil, player, data.expectedResult());
|
||||||
|
|
||||||
// Should have similated the click
|
// Should have simulated the click
|
||||||
assertEqual(data.leftItem(), anvil.getFirstItem());
|
assertEqual(data.leftItem(), anvil.getFirstItem());
|
||||||
assertEqual(data.rightItem(), anvil.getSecondItem());
|
assertEqual(data.rightItem(), anvil.getSecondItem());
|
||||||
assertEqual(data.resultSlotItem(), anvil.getResult());
|
assertEqual(data.resultSlotItem(), anvil.getResult());
|
||||||
|
|
@ -260,7 +260,7 @@ public class AnvilFuseTestUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAir(@Nullable ItemStack item) {
|
public static boolean isAir(@Nullable ItemStack item) {
|
||||||
return item == null || item.isEmpty();
|
return item == null || item.isEmpty() || item.getAmount() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertPriceEqual(Integer expectedPrice, int price) {
|
public static void assertPriceEqual(Integer expectedPrice, int price) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue