add xp rename cost and fix non vanilla anvil beavior. but keep some protection to avoid useless fuse.

This commit is contained in:
alexcrea 2024-02-03 13:25:18 +01:00
parent 760cdef6ad
commit bd28c5b71c
4 changed files with 115 additions and 68 deletions

View file

@ -29,6 +29,8 @@ class AnvilEventListener : Listener {
companion object { companion object {
// Anvil's output slot // Anvil's output slot
private const val ANVIL_INPUT_LEFT = 0
private const val ANVIL_INPUT_RIGHT = 1
private const val ANVIL_OUTPUT_SLOT = 2 private const val ANVIL_OUTPUT_SLOT = 2
} }
@ -38,19 +40,15 @@ class AnvilEventListener : Listener {
@EventHandler(priority = HIGHEST) @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(ANVIL_INPUT_LEFT) ?: return
val second = inventory.getItem(1) ?: return val second = inventory.getItem(ANVIL_INPUT_RIGHT) ?: return
if (first.canMergeWith(second)) { if (first.canMergeWith(second)) {
// Try to find player // Try to find player
val player = event.view.player val player = event.view.player
val newEnchants = first.findEnchantments() val newEnchants = first.findEnchantments()
.combineWith(second.findEnchantments(),player) .combineWith(second.findEnchantments(), first.type, player)
val resultItem = first.clone() val resultItem = first.clone()
resultItem.itemMeta?.let {
it.setDisplayName(inventory.renameText)
resultItem.itemMeta = it
}
resultItem.setEnchantmentsUnsafe(newEnchants) resultItem.setEnchantmentsUnsafe(newEnchants)
var repairCost: Int var repairCost: Int
if (!first.isBook() && !second.isBook()) { if (!first.isBook() && !second.isBook()) {
@ -61,17 +59,26 @@ class AnvilEventListener : Listener {
repairCost = resultItem.repairCost repairCost = resultItem.repairCost
} }
// Test if nothing change and stop.
if(first == resultItem){
event.result = null
return
}
// Rename item and add renaming cost
resultItem.itemMeta?.let {
if(!it.displayName.contentEquals(inventory.renameText)){
it.setDisplayName(inventory.renameText)
resultItem.itemMeta = it
repairCost += 1
}
}
if (ConfigOptions.limitRepairCost) { if (ConfigOptions.limitRepairCost) {
repairCost = min(repairCost, ConfigOptions.limitRepairValue) repairCost = min(repairCost, ConfigOptions.limitRepairValue)
} }
// Set object only if allowed
if(itemAllowed(resultItem,player)){
event.result = resultItem event.result = resultItem
} else{
event.result = null
return
}
/* Because Minecraft likes to have the final say in the repair cost displayed /* 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 need to wait for the event to end before overriding it, this ensures that
@ -94,29 +101,16 @@ class AnvilEventListener : Listener {
*/ */
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
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
if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return } if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return }
val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return
// Should be true most of the time // Is true if there was no change. probably when there are conflict
// But if permissions change in the anvil it can be false if(output == inventory.getItem(ANVIL_INPUT_LEFT)){
if(!itemAllowed(output,player)){
event.result = Event.Result.DENY event.result = Event.Result.DENY
return return
} }
event.result = Event.Result.ALLOW event.result = Event.Result.ALLOW
} }
private fun itemAllowed(item: ItemStack, player: HumanEntity): Boolean{
if(player.hasPermission(UnsafeEnchants.bypassFusePermission)) return true
if(player.hasPermission(UnsafeEnchants.unsafePermission)){
if(UnsafeEnchants.conflictManager.isConflicting(item))
return false
}else if (item.findEnchantments().hasConflicts()){
return false
}
return true
}
} }

View file

@ -1,6 +1,7 @@
package io.delilaheve.util package io.delilaheve.util
import io.delilaheve.UnsafeEnchants import io.delilaheve.UnsafeEnchants
import org.bukkit.Material
import org.bukkit.enchantments.Enchantment import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.HumanEntity import org.bukkit.entity.HumanEntity
import kotlin.math.max import kotlin.math.max
@ -21,30 +22,45 @@ object EnchantmentUtil {
* Combine 2 sets of enchantments according to our configuration * Combine 2 sets of enchantments according to our configuration
*/ */
fun Map<Enchantment, Int>.combineWith( fun Map<Enchantment, Int>.combineWith(
other: Map<Enchantment, Int>, player: HumanEntity other: Map<Enchantment, Int>,
mat: Material,
player: HumanEntity
) = mutableMapOf<Enchantment, Int>().apply { ) = mutableMapOf<Enchantment, Int>().apply {
putAll(this@combineWith) putAll(this@combineWith)
other.forEach { (enchantment, level) -> other.forEach { (enchantment, level) ->
when {
// Enchantment not yet in result list // Enchantment not yet in result list
!containsKey(enchantment) -> { if (!containsKey(enchantment)) {
// Add the enchantment if it doesn't have conflicts, or, if we're allowing unsafe enchantments if(player.hasPermission(UnsafeEnchants.unsafePermission)){
if (!keys.any { enchantment.conflictsWith(it) } || ConfigOptions.allowUnsafe) { // Add the enchantment if it doesn't have conflicts, or, if player is allowed to bypass enchantment restrictions
this[enchantment] = level
if(!player.hasPermission(UnsafeEnchants.bypassFusePermission) &&
UnsafeEnchants.conflictManager.isConflicting(this.keys,mat,enchantment)){
this.remove(enchantment)
}
}else if(!keys.any { enchantment.conflictsWith(it) }){
this[enchantment] = level this[enchantment] = level
} }
} }
// Enchantment already in result list... // Enchantment already in result list
else -> when { else{
// ... and they are conflicting
if(UnsafeEnchants.conflictManager.isConflicting(this.keys,mat,enchantment)
&& !player.hasPermission(UnsafeEnchants.bypassFusePermission)){
return@forEach
}
// ... and they're not the same level // ... and they're not the same level
this[enchantment] != other[enchantment] -> { if(this[enchantment] != other[enchantment]){
val newLevel = max(this[enchantment] ?: 0, other[enchantment] ?: 0) val newLevel = max(this[enchantment] ?: 0, other[enchantment] ?: 0)
// apply the greater of the two if non-zero // apply the greater of the two if non-zero
if (newLevel > 0) { this[enchantment] = newLevel } if (newLevel > 0) { this[enchantment] = newLevel }
} }
// ... and they're the same level // ... and they're the same level
else -> { else {
// try to increase the enchantment level by 1 // try to increase the enchantment level by 1
var newLevel = this[enchantment]?.plus(1) ?: 0 var newLevel = this[enchantment]!! +1
// Get max level or 255 if player can bypass
val maxLevel = if(player.hasPermission(UnsafeEnchants.bypassLevelPermission)){ val maxLevel = if(player.hasPermission(UnsafeEnchants.bypassLevelPermission)){
255 255
}else{ }else{
@ -56,7 +72,7 @@ object EnchantmentUtil {
} }
} }
} }
}
/** /**
* Check if a set of enchantments has any conflicts * Check if a set of enchantments has any conflicts

View file

@ -1,10 +1,11 @@
package xyz.alexcrea.group package xyz.alexcrea.group
import io.delilaheve.util.ItemUtil.findEnchantments import io.delilaheve.util.ItemUtil.findEnchantments
import org.bukkit.Material
import org.bukkit.enchantments.Enchantment import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class EnchantConflictGroup(val cantConflict: AbstractMaterialGroup, val minBeforeBlock: Int){ class EnchantConflictGroup(private val cantConflict: AbstractMaterialGroup, private val minBeforeBlock: Int){
private val enchantments = HashSet<Enchantment>() private val enchantments = HashSet<Enchantment>()
@ -12,7 +13,7 @@ class EnchantConflictGroup(val cantConflict: AbstractMaterialGroup, val minBefor
enchantments.add(ench) enchantments.add(ench)
} }
fun allow(item: ItemStack) : Boolean{ fun allowed(item: ItemStack) : Boolean{
if(enchantments.size < minBeforeBlock){ if(enchantments.size < minBeforeBlock){
return true return true
} }
@ -21,22 +22,27 @@ class EnchantConflictGroup(val cantConflict: AbstractMaterialGroup, val minBefor
return true return true
} }
return allowed(item.enchantments.keys, item.type)
}
fun allowed(enchants: Set<Enchantment>, mat: Material) : Boolean{
if(cantConflict.contain(mat)){
return true
}
// Count the amount of enchantment that are in the list // Count the amount of enchantment that are in the list
var enchantAmount = 0 var enchantAmount = 0
for (enchantment in item.findEnchantments().keys) { for (enchantment in enchants) {
if(enchantment !in enchantments) continue if(enchantment !in enchantments) continue
if(++enchantAmount > minBeforeBlock){ if(++enchantAmount > minBeforeBlock){
return false return false
} }
} }
return true return true
} }
fun isEnchantEmpty(): Boolean { fun getEnchants(): HashSet<Enchantment> {
return enchantments.size == 0 return enchantments
} }
} }

View file

@ -1,6 +1,7 @@
package xyz.alexcrea.group package xyz.alexcrea.group
import io.delilaheve.UnsafeEnchants import io.delilaheve.UnsafeEnchants
import org.bukkit.Material
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
import org.bukkit.configuration.ConfigurationSection import org.bukkit.configuration.ConfigurationSection
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
@ -26,23 +27,34 @@ class EnchantConflictManager {
private const val DEFAULT_GROUP_NAME = "joinedGroup" private const val DEFAULT_GROUP_NAME = "joinedGroup"
} }
private lateinit var conflictList: ArrayList<EnchantConflictGroup> private lateinit var conflictMap: HashMap<Enchantment, ArrayList<EnchantConflictGroup>>
// Read and prepare all conflict // Read and prepare all conflict
fun prepareConflicts(config: YamlConfiguration, itemManager: ItemGroupManager){ fun prepareConflicts(config: YamlConfiguration, itemManager: ItemGroupManager){
conflictList = ArrayList() conflictMap = HashMap()
val keys = config.getKeys(false) val keys = config.getKeys(false)
for (key in keys) { for (key in keys) {
val section = config.getConfigurationSection(key)!! val section = config.getConfigurationSection(key)!!
val conflict = createConflict(section,itemManager,key) val conflict = createConflict(section,itemManager,key)
if(conflict != null){ if(conflict != null){
conflictList.add(conflict) addToMap(conflict)
}
} }
} }
}
// Add the conflict to the map
private fun addToMap(conflict: EnchantConflictGroup){
conflict.getEnchants().forEach{ enchant ->
if(!conflictMap.containsKey(enchant)){
conflictMap[enchant] = ArrayList()
}
conflictMap[enchant]!!.add(conflict)
}
}
// create and read a conflict from a yaml section // create and read a conflict from a yaml section
private fun createConflict(section: ConfigurationSection, private fun createConflict(section: ConfigurationSection,
itemManager: ItemGroupManager, itemManager: ItemGroupManager,
@ -64,7 +76,7 @@ class EnchantConflictManager {
} }
conflict.addEnchantment(enchant) conflict.addEnchantment(enchant)
} }
if(conflict.isEnchantEmpty()){ if(conflict.getEnchants().size == 0){
if(!futureUse){ if(!futureUse){
UnsafeEnchants.instance.logger.warning("Conflict $conflictName do not have valid enchantment, it will not work") UnsafeEnchants.instance.logger.warning("Conflict $conflictName do not have valid enchantment, it will not work")
} }
@ -112,8 +124,27 @@ class EnchantConflictManager {
} }
fun isConflicting(item: ItemStack): Boolean{ fun isConflicting(item: ItemStack): Boolean{
val toTest = HashSet<EnchantConflictGroup>()
item.enchantments.forEach{enchant ->
val conflictList = conflictMap[enchant.key]
if(conflictList != null){
toTest.addAll(conflictList)
}
}
for (conflict in toTest) {
if(!conflict.allowed(item)) {
return true
}
}
return false
}
fun isConflicting(base: Set<Enchantment>,mat: Material, newEnchant: Enchantment): Boolean{
val conflictList = conflictMap[newEnchant] ?: return false
for (conflict in conflictList) { for (conflict in conflictList) {
if(!conflict.allow(item)) { if(!conflict.allowed(base,mat)) {
return true return true
} }
} }