per type xp cost

This commit is contained in:
alexcrea 2026-05-23 18:04:46 +02:00
parent b18cf1fd59
commit d67380da1a
Signed by: alexcrea
GPG key ID: E346CD16413450E3
8 changed files with 150 additions and 79 deletions

View file

@ -7,6 +7,7 @@ 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.util.AnvilUseType;
import xyz.alexcrea.cuanvil.util.AnvilXpUtil.AnvilCost;
/** /**
* 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.
@ -40,13 +41,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;
} }
/** /**
@ -103,10 +104,12 @@ public class CATreatAnvilResultEvent extends Event {
* <li>Item rename</li> * <li>Item rename</li>
* </ul> * </ul>
* *
* @deprecated use #{@link #getCost()} instead
* @return The current cost. * @return The current cost.
*/ */
@Deprecated(forRemoval = true, since = "1.17.0")
public int getLevelCost() { public int getLevelCost() {
return levelCost; return cost.sum();
} }
/** /**
@ -123,9 +126,33 @@ public class CATreatAnvilResultEvent extends Event {
* <li>Item rename</li> * <li>Item rename</li>
* </ul> * </ul>
* *
* @deprecated use #{@link #getCost()} and set value on this instead
* @param levelCost The new cost. * @param levelCost The new cost.
*/ */
@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.sum());
} }
/**
* 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;
}
} }

View file

@ -30,6 +30,7 @@ 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.AnvilUseType
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
import java.util.logging.Level import java.util.logging.Level
@ -235,12 +236,12 @@ object DependencyManager {
event: PrepareAnvilEvent, event: PrepareAnvilEvent,
result: ItemStack, result: ItemStack,
useType: AnvilUseType, useType: AnvilUseType,
cost: Int cost: AnvilXpUtil.AnvilCost
): CATreatAnvilResultEvent? { ): CATreatAnvilResultEvent? {
val treatEvent = CATreatAnvilResultEvent(event, useType, result, cost) val treatEvent = CATreatAnvilResultEvent(event, useType, result, cost)
try { try {
unsafeTryTreatAnvilResult(treatEvent) unsafeTryTreatAnvilResult(treatEvent)
return treatEvent; return treatEvent
} catch (e: Exception) { } catch (e: Exception) {
logExceptionAndClear(event.view.player, event.inventory, e) logExceptionAndClear(event.view.player, event.inventory, e)
return null return null

View file

@ -16,6 +16,7 @@ import org.bukkit.inventory.AnvilInventory
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
import xyz.alexcrea.cuanvil.util.AnvilXpUtil import xyz.alexcrea.cuanvil.util.AnvilXpUtil
import xyz.alexcrea.cuanvil.util.AnvilXpUtil.AnvilCost
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
import java.util.logging.Level import java.util.logging.Level
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -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
} }

View file

@ -11,6 +11,7 @@ import valorless.havenbags.features.BagSkin
import valorless.havenbags.features.BagUpgrade import valorless.havenbags.features.BagUpgrade
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
import xyz.alexcrea.cuanvil.util.AnvilXpUtil import xyz.alexcrea.cuanvil.util.AnvilXpUtil
import xyz.alexcrea.cuanvil.util.AnvilXpUtil.AnvilCost
class HavenBagsDependency { class HavenBagsDependency {
@ -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
} }

View file

@ -25,6 +25,7 @@ import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe
import xyz.alexcrea.cuanvil.util.AnvilLoreEditUtil import xyz.alexcrea.cuanvil.util.AnvilLoreEditUtil
import xyz.alexcrea.cuanvil.util.AnvilUseType import xyz.alexcrea.cuanvil.util.AnvilUseType
import xyz.alexcrea.cuanvil.util.AnvilXpUtil import xyz.alexcrea.cuanvil.util.AnvilXpUtil
import xyz.alexcrea.cuanvil.util.AnvilXpUtil.AnvilCost
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.UnitRepairUtil.getRepair
@ -350,13 +351,13 @@ class AnvilResultListener : Listener {
} }
private fun getFromLoreEditXpCost( private fun getFromLoreEditXpCost(
xpCost: AtomicInteger, cost: AnvilCost,
player: Player, player: Player,
inventory: AnvilInventory, inventory: AnvilInventory,
): Int { ): Int {
if (GameMode.CREATIVE == player.gameMode) return 0 if (GameMode.CREATIVE == player.gameMode) return 0
val repairCost = xpCost.get() val repairCost = cost.sum()
return if ((inventory.maximumRepairCost <= repairCost) return if ((inventory.maximumRepairCost <= repairCost)
|| (player.level < repairCost) || (player.level < repairCost)
) Int.MIN_VALUE ) Int.MIN_VALUE
@ -376,9 +377,9 @@ class AnvilResultListener : Listener {
val editType = AnvilLoreEditUtil.bookLoreEditIsAppend(leftItem, rightItem) ?: return false val editType = AnvilLoreEditUtil.bookLoreEditIsAppend(leftItem, rightItem) ?: return false
val xpCost = AtomicInteger() val cost = AnvilCost()
if (editType) { if (editType) {
if (output != AnvilLoreEditUtil.handleLoreAppendByBook(player, leftItem, bookMeta, xpCost)) return false if (output != AnvilLoreEditUtil.handleLoreAppendByBook(player, leftItem, bookMeta, cost)) return false
// Remove pages to book // Remove pages to book
val clearedBook: ItemStack? val clearedBook: ItemStack?
@ -394,10 +395,10 @@ class AnvilResultListener : Listener {
event, player, inventory, event, player, inventory,
null, 0, null, 0,
clearedBook, 0, clearedBook, 0,
output, getFromLoreEditXpCost(xpCost, player, inventory) output, getFromLoreEditXpCost(cost, player, inventory)
) )
} else { } else {
if (output != AnvilLoreEditUtil.handleLoreRemoveByBook(player, leftItem, xpCost)) return false if (output != AnvilLoreEditUtil.handleLoreRemoveByBook(player, leftItem, cost)) return false
// fill book meta // fill book meta
val lore = DependencyManager.stripLore(leftItem) val lore = DependencyManager.stripLore(leftItem)
@ -430,7 +431,7 @@ class AnvilResultListener : Listener {
event, player, inventory, event, player, inventory,
null, 0, null, 0,
rightCopy, 0, rightCopy, 0,
output, getFromLoreEditXpCost(xpCost, player, inventory) output, getFromLoreEditXpCost(cost, player, inventory)
) )
} }
} }
@ -448,9 +449,9 @@ class AnvilResultListener : Listener {
val editTypeIsAppend = AnvilLoreEditUtil.paperLoreEditIsAppend(leftItem, rightItem) ?: return false val editTypeIsAppend = AnvilLoreEditUtil.paperLoreEditIsAppend(leftItem, rightItem) ?: return false
val xpCost = AtomicInteger() val cost = AnvilCost()
if (editTypeIsAppend) { if (editTypeIsAppend) {
if (output != AnvilLoreEditUtil.handleLoreAppendByPaper(player, leftItem, rightItem, xpCost)) return false if (output != AnvilLoreEditUtil.handleLoreAppendByPaper(player, leftItem, rightItem, cost)) return false
val paperCopy: ItemStack? val paperCopy: ItemStack?
if (LoreEditType.APPEND_PAPER.doConsume) { if (LoreEditType.APPEND_PAPER.doConsume) {
@ -468,18 +469,18 @@ class AnvilResultListener : Listener {
event, player, inventory, event, player, inventory,
paperCopy, 0, paperCopy, 0,
rightItem, 1, rightItem, 1,
output, getFromLoreEditXpCost(xpCost, player, inventory) output, getFromLoreEditXpCost(cost, player, inventory)
) )
} else { } else {
extractAnvilResult( extractAnvilResult(
event, player, inventory, event, player, inventory,
null, 0, null, 0,
paperCopy, 0, paperCopy, 0,
output, getFromLoreEditXpCost(xpCost, player, inventory) output, getFromLoreEditXpCost(cost, player, inventory)
) )
} }
} else { } else {
if (output != AnvilLoreEditUtil.handleLoreRemoveByPaper(player, leftItem, xpCost)) return false if (output != AnvilLoreEditUtil.handleLoreRemoveByPaper(player, leftItem, cost)) return false
val leftMeta = leftItem.itemMeta val leftMeta = leftItem.itemMeta
if (leftMeta == null || !leftMeta.hasLore()) return false if (leftMeta == null || !leftMeta.hasLore()) return false
@ -512,14 +513,14 @@ class AnvilResultListener : Listener {
event, player, inventory, event, player, inventory,
rightClone, 0, rightClone, 0,
rightItem, 1, rightItem, 1,
output, getFromLoreEditXpCost(xpCost, player, inventory) output, getFromLoreEditXpCost(cost, player, inventory)
) )
} else { } else {
extractAnvilResult( extractAnvilResult(
event, player, inventory, event, player, inventory,
null, 0, null, 0,
rightClone, 0, rightClone, 0,
output, getFromLoreEditXpCost(xpCost, player, inventory) output, getFromLoreEditXpCost(cost, player, inventory)
) )
} }
} }

View file

@ -26,10 +26,10 @@ import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
import xyz.alexcrea.cuanvil.enchant.CAEnchantment import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.util.* import xyz.alexcrea.cuanvil.util.*
import xyz.alexcrea.cuanvil.util.AnvilXpUtil.AnvilCost
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.UnitRepairUtil.getRepair
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
@ -60,7 +60,7 @@ class PrepareAnvilListener : Listener {
// 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, event.view, player, AnvilCost(event.inventory.repairCost))
return return
} }
@ -90,7 +90,7 @@ class PrepareAnvilListener : Listener {
// 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, event.view, player, AnvilCost(event.inventory.repairCost))
return return
} }
@ -198,17 +198,17 @@ class PrepareAnvilListener : Listener {
// Maybe add an option on custom craft to ignore/not ignore penalty ?? // Maybe add an option on custom craft to ignore/not ignore penalty ??
val xpCost = recipe.determineCost(amount, first, resultItem) val xpCost = recipe.determineCost(amount, first, resultItem)
val levelCost = val cost = AnvilCost()
if (recipe.removeExactLinearXp) AnvilXpUtil.calculateMinimumLevelForXp(xpCost) cost.recipe = if (recipe.removeExactLinearXp) AnvilXpUtil.calculateMinimumLevelForXp(xpCost)
else AnvilXpUtil.calculateLevelForXp(xpCost) else AnvilXpUtil.calculateLevelForXp(xpCost)
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.CUSTOM_CRAFT, levelCost) val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.CUSTOM_CRAFT, cost)
if (finalResult == null) return false if (finalResult == null) return false
event.result = finalResult.result event.result = finalResult.result
if (finalResult.result.isAir) return false if (finalResult.result.isAir) return false
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost, true) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost, true)
return true return true
} }
@ -217,7 +217,8 @@ class PrepareAnvilListener : Listener {
player: HumanEntity, first: ItemStack player: HumanEntity, first: ItemStack
) { ) {
val resultItem = DependencyManager.cloneItem(event, first) val resultItem = DependencyManager.cloneItem(event, first)
var anvilCost = handleRename(resultItem, inventory, player) val cost = AnvilCost()
cost.rename = handleRename(resultItem, inventory, player)
// Test/stop if nothing changed. // Test/stop if nothing changed.
if (first == resultItem) { if (first == resultItem) {
@ -226,15 +227,15 @@ class PrepareAnvilListener : Listener {
return return
} }
anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.RENAME_ONLY) cost.penalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.RENAME_ONLY)
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.RENAME_ONLY, anvilCost) val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.RENAME_ONLY, cost)
if (finalResult == null) return if (finalResult == null) return
event.result = finalResult.result event.result = finalResult.result
if (finalResult.result.isAir) return if (finalResult.result.isAir) return
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost)
} }
private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int { private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int {
@ -291,18 +292,18 @@ class PrepareAnvilListener : Listener {
var hasChanged = !isIdentical(first.findEnchantments(), newEnchants) var hasChanged = !isIdentical(first.findEnchantments(), newEnchants)
val resultItem = DependencyManager.cloneItem(event, first) val resultItem = DependencyManager.cloneItem(event, first)
var anvilCost = 0 val cost = AnvilCost()
if(hasChanged){ if(hasChanged){
resultItem.setEnchantmentsUnsafe(newEnchants) resultItem.setEnchantmentsUnsafe(newEnchants)
// Calculate enchantment cost // Calculate enchantment cost
anvilCost+= AnvilXpUtil.getRightValues(second, resultItem) cost.enchantment = AnvilXpUtil.getRightValues(second, resultItem)
} }
// Calculate repair cost // Calculate repair cost
if (!first.isEnchantedBook() && !second.isEnchantedBook()) { if (!first.isEnchantedBook() && !second.isEnchantedBook()) {
// we only need to be concerned with repair when neither item is a book // we only need to be concerned with repair when neither item is a book
val repaired = resultItem.repairFrom(first, second) val repaired = resultItem.repairFrom(first, second)
anvilCost += if (repaired) ConfigOptions.itemRepairCost else 0 cost.repair = if (repaired) ConfigOptions.itemRepairCost else 0
hasChanged = hasChanged || repaired hasChanged = hasChanged || repaired
} }
@ -313,18 +314,18 @@ class PrepareAnvilListener : Listener {
return return
} }
// As calculatePenalty edit result, we need to calculate penalty after checking equality // As calculatePenalty edit result, we need to calculate penalty after checking equality
anvilCost += AnvilXpUtil.calculatePenalty(first, second, resultItem, AnvilUseType.MERGE) cost.penalty = AnvilXpUtil.calculatePenalty(first, second, resultItem, AnvilUseType.MERGE)
// Calculate rename cost // Calculate rename cost
anvilCost += handleRename(resultItem, inventory, player) cost.rename = handleRename(resultItem, inventory, player)
// Finally, we set result // Finally, we set result
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.MERGE, anvilCost) val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.MERGE, cost)
if (finalResult == null) return if (finalResult == null) return
event.result = finalResult.result event.result = finalResult.result
if (finalResult.result.isAir) return if (finalResult.result.isAir) return
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost)
} }
private fun isIdentical( private fun isIdentical(
@ -347,14 +348,15 @@ class PrepareAnvilListener : Listener {
val unitRepairAmount = first.getRepair(second) ?: return false val unitRepairAmount = first.getRepair(second) ?: return false
val resultItem = DependencyManager.cloneItem(event, first) val resultItem = DependencyManager.cloneItem(event, first)
var anvilCost = handleRename(resultItem, inventory, player) val cost = AnvilCost()
cost.rename = handleRename(resultItem, inventory, player)
val repairAmount = resultItem.unitRepair(second.amount, unitRepairAmount) val repairAmount = resultItem.unitRepair(second.amount, unitRepairAmount)
if (repairAmount > 0) { if (repairAmount > 0) {
anvilCost += repairAmount * ConfigOptions.unitRepairCost cost.repair = repairAmount * ConfigOptions.unitRepairCost
} }
// We do not care about right item penalty for unit repair // We do not care about right item penalty for unit repair
anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.UNIT_REPAIR) cost.penalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.UNIT_REPAIR)
// Test/stop if nothing changed. // Test/stop if nothing changed.
if (first == resultItem) { if (first == resultItem) {
@ -363,13 +365,13 @@ class PrepareAnvilListener : Listener {
return true return true
} }
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.UNIT_REPAIR, anvilCost) val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.UNIT_REPAIR, cost)
if (finalResult == null) return false if (finalResult == null) return false
event.result = finalResult.result event.result = finalResult.result
if (finalResult.result.isAir) return false if (finalResult.result.isAir) return false
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost)
return true return true
} }
@ -380,11 +382,11 @@ class PrepareAnvilListener : Listener {
val type = second.type val type = second.type
var result: ItemStack? = null var result: ItemStack? = null
val xpCost = AtomicInteger() val cost = AnvilCost()
if (Material.WRITABLE_BOOK == type) { if (Material.WRITABLE_BOOK == type) {
result = AnvilLoreEditUtil.tryLoreEditByBook(player, first, second, xpCost) result = AnvilLoreEditUtil.tryLoreEditByBook(player, first, second, cost)
} else if (Material.PAPER == type) { } else if (Material.PAPER == type) {
result = AnvilLoreEditUtil.tryLoreEditByPaper(player, first, second, xpCost) result = AnvilLoreEditUtil.tryLoreEditByPaper(player, first, second, cost)
} }
if (result.isAir || first == result) { if (result.isAir || first == result) {
@ -394,7 +396,7 @@ class PrepareAnvilListener : Listener {
} }
event.result = result event.result = result
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, xpCost.get()) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost)
return true return true
} }
} }

View file

@ -8,10 +8,10 @@ import org.bukkit.permissions.Permissible
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.AnvilXpUtil.AnvilCost
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 +31,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
@ -53,14 +53,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 +78,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 +116,12 @@ 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, cost: AnvilCost): ItemStack? {
val isAppend = bookLoreEditIsAppend(first, second) ?: return null val isAppend = bookLoreEditIsAppend(first, second) ?: return null
val meta = second.itemMeta as BookMeta val meta = second.itemMeta as BookMeta
return if (isAppend) handleLoreAppendByBook(player, first, meta, xpCost) return if (isAppend) handleLoreAppendByBook(player, first, meta, cost)
else handleLoreRemoveByBook(player, first, xpCost) else handleLoreRemoveByBook(player, first, cost)
} }
// Return true if appended, false if removed, null if neither // Return true if appended, false if removed, null if neither
@ -147,7 +147,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
@ -175,13 +175,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 +213,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
} }
@ -223,23 +223,23 @@ object AnvilLoreEditUtil {
player: HumanEntity, player: HumanEntity,
first: ItemStack, first: ItemStack,
second: ItemStack, second: ItemStack,
xpCost: AtomicInteger cost: AnvilCost
): ItemStack? { ): ItemStack? {
val isAppend = paperLoreEditIsAppend(first, second) ?: return null val isAppend = paperLoreEditIsAppend(first, second) ?: return null
return if (isAppend) handleLoreAppendByPaper(player, first, second, xpCost) return if (isAppend) handleLoreAppendByPaper(player, first, second, cost)
else handleLoreRemoveByPaper(player, first, xpCost) else handleLoreRemoveByPaper(player, first, cost)
} }
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.penalty = 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 {

View file

@ -23,16 +23,55 @@ object AnvilXpUtil {
const val EXCLUSIVE_PENALTY_PREFIX = "repair_cost" const val EXCLUSIVE_PENALTY_PREFIX = "repair_cost"
class AnvilCost {
private val isAlone: Boolean
var generic = 0
var enchantment = 0
var repair = 0
var rename = 0
var lore = 0
var penalty = 0
var recipe = 0
fun sum(): Int {
return generic + enchantment + repair + rename + lore + penalty + recipe
}
constructor(generic: Int) {
this.generic = generic
isAlone = true
}
constructor() {
isAlone = false
}
}
/**
* Display the required cost (either as xp or as )
*/
fun setAnvilInvCost(
inventory: AnvilInventory,
view: InventoryView,
player: HumanEntity,
cost: AnvilCost,
ignoreRules: Boolean = false
) {
// TODO check require money or xp cost & display appropriately
setAnvilInvXp(inventory, view, player, cost.sum(), 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 +117,6 @@ object AnvilXpUtil {
} }
player.updateInventory() player.updateInventory()
} }
} }