fix durability repair and item naming

This commit is contained in:
DelilahEve 2022-08-24 11:49:29 -04:00
parent 745ebcde29
commit af99913eae
7 changed files with 97 additions and 29 deletions

View file

@ -4,7 +4,7 @@ plugins {
} }
group = "io.delilaheve" group = "io.delilaheve"
version = "1.0.1" version = "1.0.2"
repositories { repositories {
mavenCentral() mavenCentral()

View file

@ -1,22 +1,23 @@
package io.delilaheve package io.delilaheve
import io.delilaheve.util.ConfigOptions import io.delilaheve.util.ConfigOptions
import io.delilaheve.util.EnchantmentUtil.calculateValue
import io.delilaheve.util.EnchantmentUtil.combineWith import io.delilaheve.util.EnchantmentUtil.combineWith
import io.delilaheve.util.EnchantmentUtil.hasConflicts import io.delilaheve.util.EnchantmentUtil.hasConflicts
import io.delilaheve.util.ItemUtil.canMergeWith import io.delilaheve.util.ItemUtil.canMergeWith
import io.delilaheve.util.ItemUtil.findEnchantments import io.delilaheve.util.ItemUtil.findEnchantments
import io.delilaheve.util.ItemUtil.isBook import io.delilaheve.util.ItemUtil.isBook
import io.delilaheve.util.ItemUtil.repairCost
import io.delilaheve.util.ItemUtil.repairFrom
import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe
import org.bukkit.Material
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.Event import org.bukkit.event.Event
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority.HIGHEST
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.InventoryView import org.bukkit.inventory.InventoryView.Property.REPAIR_COST
import org.bukkit.permissions.Permission import org.bukkit.permissions.Permission
import kotlin.math.min import kotlin.math.min
@ -26,8 +27,6 @@ import kotlin.math.min
class AnvilEventListener : Listener { class AnvilEventListener : Listener {
companion object { companion object {
// Vanilla repair cost limit
private const val VANILLA_REPAIR_LIMIT = 40
// Anvil's output slot // Anvil's output slot
private const val ANVIL_OUTPUT_SLOT = 2 private const val ANVIL_OUTPUT_SLOT = 2
} }
@ -39,34 +38,42 @@ class AnvilEventListener : Listener {
/** /**
* Event handler logic for when an anvil contains items to be combined * Event handler logic for when an anvil contains items to be combined
*/ */
@EventHandler @EventHandler(priority = HIGHEST)
fun anvilCombineCheck(event: PrepareAnvilEvent) { fun anvilCombineCheck(event: PrepareAnvilEvent) {
val inventory = event.inventory val inventory = event.inventory
val first = inventory.getItem(0) ?: return val first = inventory.getItem(0) ?: return
val second = inventory.getItem(1) ?: return val second = inventory.getItem(1) ?: return
if (first.canMergeWith(second)) { if (first.canMergeWith(second)) {
val firstEnchants = first.findEnchantments().toMutableMap() val newEnchants = first.findEnchantments()
val secondEnchants = second.findEnchantments().toMutableMap() .combineWith(second.findEnchantments())
if (ConfigOptions.removeRepairLimit) {
inventory.maximumRepairCost = Int.MAX_VALUE
}
val newEnchants = firstEnchants.combineWith(secondEnchants)
val enchantsString = newEnchants.map { "${it.key.key} ${it.value}" }.joinToString(", ")
UnsafeEnchants.log("New enchants for this item: $enchantsString")
val resultItem = first.clone() val resultItem = first.clone()
resultItem.itemMeta?.let {
it.setDisplayName(inventory.renameText)
resultItem.itemMeta = it
}
resultItem.setEnchantmentsUnsafe(newEnchants) resultItem.setEnchantmentsUnsafe(newEnchants)
val firstValue = firstEnchants.calculateValue(first.isBook()) if (!first.isBook() && !second.isBook()) {
val secondValue = secondEnchants.calculateValue(second.isBook()) // we only need to be concerned with repair when neither item is a book
var repairCost = firstValue + secondValue resultItem.repairFrom(first, second)
if (first.isBook() && second.isBook()) {
repairCost = firstEnchants.values.sum() + secondEnchants.values.sum()
} }
var repairCost = first.repairCost + second.repairCost
if (ConfigOptions.limitRepairCost) { if (ConfigOptions.limitRepairCost) {
repairCost = min(repairCost, VANILLA_REPAIR_LIMIT) repairCost = min(repairCost, ConfigOptions.limitRepairValue)
} }
inventory.repairCost = repairCost
event.view.setProperty(InventoryView.Property.REPAIR_COST, repairCost)
event.result = resultItem event.result = resultItem
/* Because Minecraft likes to have the final say in the repair cost displayed
* we need to wait for the event to end before overriding it, this ensures that
* we have the final say in the process. */
UnsafeEnchants.instance
.server
.scheduler
.runTask(UnsafeEnchants.instance, Runnable {
if (ConfigOptions.removeRepairLimit) {
inventory.maximumRepairCost = Int.MAX_VALUE
}
inventory.repairCost = repairCost
event.view.setProperty(REPAIR_COST, repairCost)
})
} }
} }
@ -80,8 +87,6 @@ class AnvilEventListener : Listener {
val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return
if (output.findEnchantments().hasConflicts() && !player.hasPermission(requirePermission)) { return } if (output.findEnchantments().hasConflicts() && !player.hasPermission(requirePermission)) { return }
if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return } if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return }
if (output.type == Material.AIR) { return }
if (player.level < inventory.repairCost) { return }
event.result = Event.Result.ALLOW event.result = Event.Result.ALLOW
} }

View file

@ -15,6 +15,8 @@ object ConfigOptions {
private const val ALLOW_UNSAFE_PATH = "allow_unsafe" private const val ALLOW_UNSAFE_PATH = "allow_unsafe"
// Path for limiting repair cost // Path for limiting repair cost
private const val LIMIT_REPAIR_COST = "limit_repair_cost" private const val LIMIT_REPAIR_COST = "limit_repair_cost"
// Path for repair value limit
private const val LIMIT_REPAIR_VALUE = "limit_repair_value"
// Path for removing repair cost limits // Path for removing repair cost limits
private const val REMOVE_REPAIR_LIMIT = "remove_repair_limit" private const val REMOVE_REPAIR_LIMIT = "remove_repair_limit"
// Root path for enchantment limits // Root path for enchantment limits
@ -33,6 +35,10 @@ object ConfigOptions {
private const val DEFAULT_ALLOW_UNSAFE = true private const val DEFAULT_ALLOW_UNSAFE = true
// Default value for limiting repair cost // Default value for limiting repair cost
private const val DEFAULT_LIMIT_REPAIR = true private const val DEFAULT_LIMIT_REPAIR = true
// Default value for repair cost limit
private const val DEFAULT_LIMIT_REPAIR_VALUE = 39
// Valid range for repair cost limit
private val REPAIR_LIMIT_RANGE = 1..39
// Default for removing repair cost limits // Default for removing repair cost limits
private const val DEFAULT_REMOVE_LIMIT = false private const val DEFAULT_REMOVE_LIMIT = false
// Valid range for an enchantment limit // Valid range for an enchantment limit
@ -72,6 +78,18 @@ object ConfigOptions {
.getBoolean(LIMIT_REPAIR_COST, DEFAULT_LIMIT_REPAIR) .getBoolean(LIMIT_REPAIR_COST, DEFAULT_LIMIT_REPAIR)
} }
/**
* Value to limit repair costs to
*/
val limitRepairValue: Int
get() {
return UnsafeEnchants.instance
.config
.getInt(LIMIT_REPAIR_VALUE, DEFAULT_LIMIT_REPAIR_VALUE)
.takeIf { it in REPAIR_LIMIT_RANGE }
?: DEFAULT_LIMIT_REPAIR_VALUE
}
/** /**
* Whether to remove repair cost limit * Whether to remove repair cost limit
*/ */

View file

@ -19,8 +19,8 @@ object EnchantmentUtil {
/** /**
* Combine 2 sets of enchantments according to our configuration * Combine 2 sets of enchantments according to our configuration
*/ */
fun MutableMap<Enchantment, Int>.combineWith( fun Map<Enchantment, Int>.combineWith(
other: MutableMap<Enchantment, Int> other: Map<Enchantment, Int>
) = mutableMapOf<Enchantment, Int>().apply { ) = mutableMapOf<Enchantment, Int>().apply {
putAll(this@combineWith) putAll(this@combineWith)
other.forEach { (enchantment, level) -> other.forEach { (enchantment, level) ->

View file

@ -1,17 +1,36 @@
package io.delilaheve.util package io.delilaheve.util
import io.delilaheve.UnsafeEnchants import io.delilaheve.UnsafeEnchants
import io.delilaheve.util.EnchantmentUtil.calculateValue
import io.delilaheve.util.ItemUtil.isBook
import org.bukkit.Material.BOOK import org.bukkit.Material.BOOK
import org.bukkit.Material.ENCHANTED_BOOK import org.bukkit.Material.ENCHANTED_BOOK
import org.bukkit.enchantments.Enchantment import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Damageable
import org.bukkit.inventory.meta.EnchantmentStorageMeta import org.bukkit.inventory.meta.EnchantmentStorageMeta
import org.bukkit.inventory.meta.ItemMeta
import org.bukkit.inventory.meta.Repairable
import kotlin.math.min
/** /**
* Item manipulation utilities * Item manipulation utilities
*/ */
object ItemUtil { object ItemUtil {
/**
* Determine the value of an item for repair
*
* ToDo - use native repair cost
*/
val ItemStack.repairCost: Int
get() {
val nativeCost = (itemMeta as? Repairable)?.repairCost
val pluginCost = findEnchantments().calculateValue(isBook())
UnsafeEnchants.log("Native Cost: $nativeCost; Plugin Cost: $pluginCost")
return nativeCost.takeIf { it != 0 } ?: pluginCost
}
/** /**
* Check if this [ItemStack] is a [BOOK] or [ENCHANTED_BOOK] * Check if this [ItemStack] is a [BOOK] or [ENCHANTED_BOOK]
*/ */
@ -72,6 +91,25 @@ object ItemUtil {
} }
} }
/**
* Set this [ItemStack]s durability from a combination of the
* [first] and [second] item's durability values
*/
fun ItemStack.repairFrom(
first: ItemStack,
second: ItemStack
) {
(itemMeta as? Damageable)?.let {
val maxDurability = type.maxDurability.toInt()
val firstDurability = (first.itemMeta as? Damageable)?.damage ?: 0
val secondDurability = (second.itemMeta as? Damageable)?.damage ?: 0
var newDurability = firstDurability + secondDurability
newDurability = min(maxDurability, newDurability)
it.damage = newDurability
itemMeta = it as ItemMeta
}
}
/** /**
* Check that this [ItemStack] can merge with the [other] * Check that this [ItemStack] can merge with the [other]
* *

View file

@ -11,9 +11,16 @@ default_limit: 10
# i.e. Protection and Blast Protection can be on the same piece of armour # i.e. Protection and Blast Protection can be on the same piece of armour
allow_unsafe: true allow_unsafe: true
# Whether all anvil actions should be capped to the vanilla repair limit (40 levels) # Whether all anvil actions should be capped
#
# If true, all anvil repairs will max out at the value of limit_repair_value
limit_repair_cost: true limit_repair_cost: true
# Value to limit repair costs to when limit_repair_cost is true
#
# Valid range of 1 - 39 (vanilla will consider 40+ as "too expensive")
limit_repair_value: 39
# Whether the anvil's repair limit should be removed entirely # Whether the anvil's repair limit should be removed entirely
# #
# The anvil will still visually display "too expensive" however the action will be completable # The anvil will still visually display "too expensive" however the action will be completable

View file

@ -1,6 +1,6 @@
main: io.delilaheve.UnsafeEnchants main: io.delilaheve.UnsafeEnchants
name: UnsafeEnchants name: UnsafeEnchants
version: 1.0.1 version: 1.0.2
description: Allow all enchants to be combined description: Allow all enchants to be combined
api-version: 1.18 api-version: 1.18
load: POSTWORLD load: POSTWORLD