add monetary config and generic progress

This commit is contained in:
alexcrea 2026-05-24 20:47:26 +02:00
parent 2c3e43cb84
commit 856c1e08bd
Signed by: alexcrea
GPG key ID: E346CD16413450E3
15 changed files with 230 additions and 75 deletions

View file

@ -430,6 +430,25 @@ 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
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

View file

@ -450,6 +450,25 @@ 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
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

View file

@ -442,6 +442,25 @@ 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
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

View file

@ -430,6 +430,25 @@ 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
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

View file

@ -12,7 +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.econmy.EconomyManager 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

View file

@ -72,6 +72,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 +115,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
@ -625,4 +635,27 @@ object ConfigOptions {
return false return false
} }
/*
* Monetary configs
*/
val shouldUseMoney: Boolean
get() {
return 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): Double {
return ConfigHolder.DEFAULT_CONFIG
.config
.getDouble("$MONETARY_MULTIPLIER_ROOT.$type", DEFAULT_MONEY_MULTIPLIER)
}
} }

View file

@ -237,11 +237,11 @@ object DependencyManager {
result: ItemStack, result: ItemStack,
useType: AnvilUseType, useType: AnvilUseType,
cost: AnvilXpUtil.AnvilCost cost: AnvilXpUtil.AnvilCost
): CATreatAnvilResultEvent? { ): ItemStack? {
val treatEvent = CATreatAnvilResultEvent(event, useType, result, cost) val treatEvent = CATreatAnvilResultEvent(event, 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(event.view.player, event.inventory, e)
return null return null

View file

@ -1,31 +0,0 @@
package xyz.alexcrea.cuanvil.dependency.econmy
import net.milkbowl.vault.economy.Economy
import org.bukkit.OfflinePlayer
import org.bukkit.plugin.Plugin
import org.bukkit.plugin.RegisteredServiceProvider
object EconomyManager {
private var economy: Economy? = null
fun setupEconomy(plugin: Plugin) {
if (economy != null) return
if (plugin.server.pluginManager.getPlugin("Vault") == null)
return
val rsp: RegisteredServiceProvider<Economy?>? =
plugin.server.servicesManager.getRegistration(Economy::class.java)
if (rsp == null) return
economy = rsp.getProvider()
}
fun has(player: OfflinePlayer, amount: Double): Boolean {
return economy?.has(player, amount) == true
}
}

View file

@ -0,0 +1,27 @@
package xyz.alexcrea.cuanvil.dependency.economy
import org.bukkit.plugin.Plugin
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
}

View file

@ -0,0 +1,35 @@
package xyz.alexcrea.cuanvil.dependency.economy
import net.milkbowl.vault2.economy.Economy
import org.bukkit.plugin.Plugin
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
}
}

View file

@ -0,0 +1,19 @@
package xyz.alexcrea.cuanvil.dependency.economy
import net.milkbowl.vault.economy.Economy
import org.bukkit.plugin.Plugin
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
}
}

View file

@ -202,12 +202,7 @@ class PrepareAnvilListener : Listener {
cost.recipe = 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, cost) event.result = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.CUSTOM_CRAFT, cost)
if (finalResult == null) return false
event.result = finalResult.result
if (finalResult.result.isAir) return false
AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost, true) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost, true)
return true return true
} }
@ -227,14 +222,9 @@ class PrepareAnvilListener : Listener {
return return
} }
cost.penalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.RENAME_ONLY) cost.workPenalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.RENAME_ONLY)
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.RENAME_ONLY, cost)
if (finalResult == null) return
event.result = finalResult.result
if (finalResult.result.isAir) return
event.result = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.RENAME_ONLY, cost)
AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost)
} }
@ -296,7 +286,7 @@ class PrepareAnvilListener : Listener {
if(hasChanged){ if(hasChanged){
resultItem.setEnchantmentsUnsafe(newEnchants) resultItem.setEnchantmentsUnsafe(newEnchants)
// Calculate enchantment cost // Calculate enchantment cost
cost.enchantment = AnvilXpUtil.getRightValues(second, resultItem) AnvilXpUtil.getRightValues(second, resultItem, cost)
} }
// Calculate repair cost // Calculate repair cost
@ -309,22 +299,17 @@ class PrepareAnvilListener : Listener {
// Test/stop if nothing changed. // Test/stop if nothing changed.
if (!hasChanged) { if (!hasChanged) {
CustomAnvil.log("Mergable with second, But input is same as output") CustomAnvil.log("Mergeable with second, But input is same as output")
event.result = null event.result = null
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
cost.penalty = AnvilXpUtil.calculatePenalty(first, second, resultItem, AnvilUseType.MERGE) cost.workPenalty = AnvilXpUtil.calculatePenalty(first, second, resultItem, AnvilUseType.MERGE)
// Calculate rename cost // Calculate rename cost
cost.rename = 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, cost) event.result = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.MERGE, cost)
if (finalResult == null) return
event.result = finalResult.result
if (finalResult.result.isAir) return
AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost)
} }
@ -356,7 +341,7 @@ class PrepareAnvilListener : Listener {
cost.repair = 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
cost.penalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.UNIT_REPAIR) cost.workPenalty = AnvilXpUtil.calculatePenalty(first, null, resultItem, AnvilUseType.UNIT_REPAIR)
// Test/stop if nothing changed. // Test/stop if nothing changed.
if (first == resultItem) { if (first == resultItem) {
@ -365,12 +350,7 @@ class PrepareAnvilListener : Listener {
return true return true
} }
val finalResult = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.UNIT_REPAIR, cost) event.result = DependencyManager.tryTreatAnvilResult(event, resultItem, AnvilUseType.UNIT_REPAIR, cost)
if (finalResult == null) return false
event.result = finalResult.result
if (finalResult.result.isAir) return false
AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost) AnvilXpUtil.setAnvilInvCost(inventory, event.view, player, cost)
return true return true
} }

View file

@ -239,7 +239,7 @@ object AnvilLoreEditUtil {
) { ) {
cost.lore+= editType.fixedCost cost.lore+= editType.fixedCost
cost.penalty = AnvilXpUtil.calculatePenalty(first, null, result, editType.useType) cost.workPenalty = AnvilXpUtil.calculatePenalty(first, null, result, editType.useType)
} }
fun colorPermission(player: Permissible, editType: LoreEditType): AnvilColorUtil.ColorPermissions { fun colorPermission(player: Permissible, editType: LoreEditType): AnvilColorUtil.ColorPermissions {

View file

@ -31,11 +31,12 @@ object AnvilXpUtil {
var repair = 0 var repair = 0
var rename = 0 var rename = 0
var lore = 0 var lore = 0
var penalty = 0 var illegalPenalty = 0
var workPenalty = 0
var recipe = 0 var recipe = 0
fun sum(): Int { fun sum(): Int {
return generic + enchantment + repair + rename + lore + penalty + recipe return generic + enchantment + repair + rename + lore + illegalPenalty + workPenalty + recipe
} }
constructor(generic: Int) { constructor(generic: Int) {
@ -197,10 +198,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()
@ -218,7 +217,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
@ -229,16 +228,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
} }
/** /**

View file

@ -432,6 +432,25 @@ 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
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