From 3c8810ed727cc6998a24d0295185c6ea2a85f7b1 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Tue, 20 Aug 2024 03:05:26 +0200 Subject: [PATCH 1/6] Add Disenchantment as dependency --- build.gradle.kts | 3 +++ settings.gradle.kts | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index f663dbc..e43a23d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -36,6 +36,9 @@ dependencies { compileOnly("com.willfp:EcoEnchants:12.5.1") compileOnly("com.willfp:eco:6.70.1") + // Disenchantment + compileOnly("cz.kominekjan:Disenchantment:v5.3.1") + // Include nms implementation(project(":nms:nms-common")) implementation(project(":nms:v1_17R1", configuration = "reobf")) diff --git a/settings.gradle.kts b/settings.gradle.kts index 4ccc5cc..e661a74 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,14 @@ +import java.net.URI + rootProject.name = "CustomAnvil" +// for Disenchantment dependency +sourceControl { + gitRepository(URI.create("https://github.com/H7KZ/Disenchantment.git")) { + producesModule("cz.kominekjan:Disenchantment") + } +} + // NMS subproject include("nms:nms-common") findProject(":nms:nms-common")?.name = "nms-common" From 804c11a7f4a5978ad6fde38c0ad93ae6d34f931a Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Wed, 21 Aug 2024 03:13:58 +0200 Subject: [PATCH 2/6] Do not continue anvil process if Disenchantment done something. --- .../io/delilaheve/AnvilEventListener.kt | 75 +++-------- .../cuanvil/dependency/DependencyManager.kt | 26 ++++ .../dependency/DisenchantmentDependency.kt | 121 ++++++++++++++++++ .../xyz/alexcrea/cuanvil/util/XpSetterUtil.kt | 67 ++++++++++ src/main/resources/plugin.yml | 1 + 5 files changed, 231 insertions(+), 59 deletions(-) create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/util/XpSetterUtil.kt diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index 576963e..f5f3888 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -27,10 +27,12 @@ import org.bukkit.inventory.InventoryView.Property.REPAIR_COST import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.Repairable import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.dependency.packet.PacketManager import xyz.alexcrea.cuanvil.group.ConflictType import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair +import xyz.alexcrea.cuanvil.util.XpSetterUtil.setAnvilInvXp import java.util.regex.Matcher import java.util.regex.Pattern import kotlin.math.min @@ -43,9 +45,9 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { companion object { // 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 + const val ANVIL_INPUT_LEFT = 0 + const val ANVIL_INPUT_RIGHT = 1 + const val ANVIL_OUTPUT_SLOT = 2 // static slot container private val NO_SLOT = SlotContainer(SlotType.NO_SLOT, 0) @@ -57,6 +59,9 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { */ @EventHandler(priority = HIGHEST) fun anvilCombineCheck(event: PrepareAnvilEvent) { + // Test if the event should bypass custom anvil. + if(DependencyManager.tryEventPreAnvilBypass(event)) return + val inventory = event.inventory val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val second = inventory.getItem(ANVIL_INPUT_RIGHT) @@ -75,7 +80,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { resultItem.amount *= amount event.result = resultItem - handleAnvilXp(inventory, event, recipe.xpCostPerCraft * amount, true) + setAnvilInvXp(inventory, event.view, recipe.xpCostPerCraft * amount, true) return } @@ -96,7 +101,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { anvilCost += calculatePenalty(first, null, resultItem) - handleAnvilXp(inventory, event, anvilCost) + setAnvilInvXp(inventory, event.view, anvilCost) return } @@ -130,7 +135,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { // Finally, we set result event.result = resultItem - handleAnvilXp(inventory, event, anvilCost) + setAnvilInvXp(inventory, event.view, anvilCost) return } @@ -155,7 +160,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { } event.result = resultItem - handleAnvilXp(inventory, event, anvilCost) + setAnvilInvXp(inventory, event.view, anvilCost) } else { CustomAnvil.log("no anvil fuse type found") event.result = null @@ -282,9 +287,13 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { val player = event.whoClicked as? Player ?: return if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return val inventory = event.inventory as? AnvilInventory ?: return + if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return } + // Test if the event should bypass custom anvil. + if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return + val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) @@ -638,58 +647,6 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { } - /** - * Display xp needed for the work on the anvil inventory - */ - private fun handleAnvilXp( - inventory: AnvilInventory, - event: PrepareAnvilEvent, - anvilCost: Int, - ignoreRules: Boolean = false - ) { - // Test repair cost limit - val finalAnvilCost = if ( - !ignoreRules && - !ConfigOptions.doRemoveCostLimit && - ConfigOptions.doCapCost) { - min(anvilCost, ConfigOptions.maxAnvilCost) - } else { - anvilCost - } - - /* 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. */ - CustomAnvil.instance - .server - .scheduler - .runTask(CustomAnvil.instance, Runnable { - inventory.maximumRepairCost = - if (ConfigOptions.doRemoveCostLimit || ignoreRules) - { Int.MAX_VALUE } - else - { ConfigOptions.maxAnvilCost + 1 } - - val player = event.view.player - - inventory.repairCost = finalAnvilCost - event.view.setProperty(REPAIR_COST, finalAnvilCost) - player.openInventory.setProperty(REPAIR_COST, finalAnvilCost) - - if(player is Player){ - if(player.gameMode != GameMode.CREATIVE ){ - val bypassToExpensive = (ConfigOptions.doReplaceTooExpensive) && - (finalAnvilCost >= 40) && - finalAnvilCost < inventory.maximumRepairCost - - packetManager.setInstantBuild(player, bypassToExpensive) - } - - player.updateInventory() - } - }) - } - @EventHandler fun onAnvilClose(event: InventoryCloseEvent){ val player = event.player diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt index 9fccff6..749f10b 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt @@ -1,6 +1,9 @@ package xyz.alexcrea.cuanvil.dependency import org.bukkit.Bukkit +import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.event.inventory.PrepareAnvilEvent +import org.bukkit.inventory.AnvilInventory import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.dependency.packet.PacketManager import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector @@ -10,6 +13,7 @@ object DependencyManager { lateinit var packetManager: PacketManager var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null var ecoEnchantCompatibility: EcoEnchantDependency? = null + var disenchantmentCompatibility: DisenchantmentDependency? = null fun loadDependency(){ val pluginManager = Bukkit.getPluginManager() @@ -30,6 +34,12 @@ object DependencyManager { ecoEnchantCompatibility!!.disableAnvilListener() } + // Disenchantment dependency + if(pluginManager.isPluginEnabled("Disenchantment")){ + disenchantmentCompatibility = DisenchantmentDependency() + disenchantmentCompatibility!!.redirectListeners() + } + } fun handleCompatibilityConfig() { @@ -52,4 +62,20 @@ object DependencyManager { } + fun tryEventPreAnvilBypass(event: PrepareAnvilEvent): Boolean { + var bypass = false + + if(disenchantmentCompatibility?.testPrepareAnvil(event) == true) bypass = true + + return bypass + } + + fun tryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean { + var bypass = false + + if(disenchantmentCompatibility?.testAnvilResult(event, inventory) == true) bypass = true + + return bypass + } + } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt new file mode 100644 index 0000000..302fc5a --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt @@ -0,0 +1,121 @@ +package xyz.alexcrea.cuanvil.dependency + +import cz.kominekjan.disenchantment.events.ItemClickEvent +import cz.kominekjan.disenchantment.events.ItemEvent +import cz.kominekjan.disenchantment.events.SplitBookClickEvent +import cz.kominekjan.disenchantment.events.SplitBookEvent +import io.delilaheve.AnvilEventListener +import io.delilaheve.CustomAnvil +import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.event.inventory.PrepareAnvilEvent +import org.bukkit.inventory.AnvilInventory +import org.bukkit.inventory.ItemStack +import org.bukkit.plugin.RegisteredListener +import xyz.alexcrea.cuanvil.util.XpSetterUtil + +class DisenchantmentDependency { + + init { + CustomAnvil.instance.logger.info("Disenchantment Detected !") + } + + private lateinit var splitEvent: SplitBookEvent + private lateinit var itemEvent: ItemEvent + + private lateinit var splitBookClickEvent: SplitBookClickEvent + private lateinit var itemClickEvent: ItemClickEvent + + fun redirectListeners() { + + val toUnregister = ArrayList() + // get required PrepareAnvilEvent listener + for (registeredListener in PrepareAnvilEvent.getHandlerList().registeredListeners) { + val listener = registeredListener.listener + + if(listener is SplitBookEvent){ + this.splitEvent = listener + toUnregister.add(registeredListener) + } + + if(listener is ItemEvent){ + itemEvent = listener + toUnregister.add(registeredListener) + } + + } + + for (listener in toUnregister) { + PrepareAnvilEvent.getHandlerList().unregister(listener) + } + toUnregister.clear() + + // get required InventoryClickEvent listener + for (registeredListener in InventoryClickEvent.getHandlerList().registeredListeners) { + val listener = registeredListener.listener + + if(listener is SplitBookClickEvent){ + splitBookClickEvent = listener + toUnregister.add(registeredListener) + } + + if(listener is ItemClickEvent){ + itemClickEvent = listener + toUnregister.add(registeredListener) + } + + } + + for (listener in toUnregister) { + InventoryClickEvent.getHandlerList().unregister(listener) + } + + } + + fun testPrepareAnvil(event: PrepareAnvilEvent): Boolean { + val previousResult = event.result + event.result = null + + // Test if event change the result + itemEvent.onDisenchantmentEvent(event) + + if(event.result != null) { + CustomAnvil.log("Detected pre anvil item extract bypass.") + return true + } + + splitEvent.onDisenchantmentEvent(event) + if(event.result != null) { + CustomAnvil.log("Detected pre anvil split enchant bypass.") + return true + } + + event.result = previousResult + return false + } + + fun testAnvilResult(event: InventoryClickEvent, inventory: AnvilInventory): Boolean { + val previousResultSlot = inventory.getItem(AnvilEventListener.ANVIL_OUTPUT_SLOT)?.clone() + + // Test event if change the result + itemClickEvent.onDisenchantmentClickEvent(event) + if(!testAnvilInventoryChange(inventory, previousResultSlot) || event.isCancelled) { + CustomAnvil.log("Detected anvil click item extract bypass.") + return true + } + + splitBookClickEvent.onDisenchantmentClickEvent(event) + if(!testAnvilInventoryChange(inventory, previousResultSlot) || event.isCancelled) { + CustomAnvil.log("Detected anvil click split enchant bypass.") + return true + } + + return false + } + + private fun testAnvilInventoryChange(inventory: AnvilInventory, previous: ItemStack?): Boolean { + val currentResult = inventory.getItem(AnvilEventListener.ANVIL_OUTPUT_SLOT) + + return currentResult == previous + } + +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/XpSetterUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/XpSetterUtil.kt new file mode 100644 index 0000000..d334099 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/XpSetterUtil.kt @@ -0,0 +1,67 @@ +package xyz.alexcrea.cuanvil.util + +import io.delilaheve.CustomAnvil +import io.delilaheve.util.ConfigOptions +import org.bukkit.GameMode +import org.bukkit.entity.Player +import org.bukkit.inventory.AnvilInventory +import org.bukkit.inventory.InventoryView +import org.bukkit.inventory.InventoryView.Property.REPAIR_COST +import xyz.alexcrea.cuanvil.dependency.DependencyManager +import kotlin.math.min + +object XpSetterUtil { + + /** + * Display xp needed for the work on the anvil inventory + */ + fun setAnvilInvXp( + inventory: AnvilInventory, + view: InventoryView, + anvilCost: Int, + ignoreRules: Boolean = false + ) { + // Test repair cost limit + val finalAnvilCost = if ( + !ignoreRules && + !ConfigOptions.doRemoveCostLimit && + ConfigOptions.doCapCost) { + min(anvilCost, ConfigOptions.maxAnvilCost) + } else { + anvilCost + } + + /* 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. */ + CustomAnvil.instance + .server + .scheduler + .runTask(CustomAnvil.instance, Runnable { + inventory.maximumRepairCost = + if (ConfigOptions.doRemoveCostLimit || ignoreRules) + { Int.MAX_VALUE } + else + { ConfigOptions.maxAnvilCost + 1 } + + val player = view.player + + inventory.repairCost = finalAnvilCost + view.setProperty(REPAIR_COST, finalAnvilCost) + player.openInventory.setProperty(REPAIR_COST, finalAnvilCost) + + if(player is Player){ + if(player.gameMode != GameMode.CREATIVE ){ + val bypassToExpensive = (ConfigOptions.doReplaceTooExpensive) && + (finalAnvilCost >= 40) && + finalAnvilCost < inventory.maximumRepairCost + + DependencyManager.packetManager.setInstantBuild(player, bypassToExpensive) + } + + player.updateInventory() + } + }) + } + +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 037c1cc..cfc2abc 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -53,6 +53,7 @@ permissions: softdepend: - UnsafeEnchantsPlus - ProtocolLib + - Disenchantment - EnchantsSquared - EcoEnchants - eco \ No newline at end of file From aa860bdbf07870a793037d36ac9c972a65c38738 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Wed, 21 Aug 2024 03:16:31 +0200 Subject: [PATCH 3/6] Override Disenchantment xp. This allows to use Custom Anvil xp settings ! --- .../xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt index 302fc5a..e050a68 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt @@ -80,12 +80,14 @@ class DisenchantmentDependency { if(event.result != null) { CustomAnvil.log("Detected pre anvil item extract bypass.") + XpSetterUtil.setAnvilInvXp(event.inventory, event.view, event.inventory.repairCost) return true } splitEvent.onDisenchantmentEvent(event) if(event.result != null) { CustomAnvil.log("Detected pre anvil split enchant bypass.") + XpSetterUtil.setAnvilInvXp(event.inventory, event.view, event.inventory.repairCost) return true } From 92dcfd87cfc6a052d17c743137b5f62eb2cc38fb Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Wed, 21 Aug 2024 03:41:07 +0200 Subject: [PATCH 4/6] Moved some other function to the new util. --- .../wrapped/CAEnchantSquaredEnchantment.java | 1 - .../cuanvil/gui/util/GuiSharedConstant.java | 3 +- .../io/delilaheve/AnvilEventListener.kt | 97 +---------- .../dependency/DisenchantmentDependency.kt | 6 +- .../xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt | 163 ++++++++++++++++++ .../xyz/alexcrea/cuanvil/util/XpSetterUtil.kt | 67 ------- 6 files changed, 171 insertions(+), 166 deletions(-) create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt delete mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/util/XpSetterUtil.kt diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEnchantSquaredEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEnchantSquaredEnchantment.java index 56b4bc7..ee5b9c0 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEnchantSquaredEnchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEnchantSquaredEnchantment.java @@ -3,7 +3,6 @@ package xyz.alexcrea.cuanvil.enchant.wrapped; import me.athlaeos.enchantssquared.enchantments.CustomEnchant; import me.athlaeos.enchantssquared.managers.CustomEnchantManager; import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiSharedConstant.java b/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiSharedConstant.java index f5b8a2e..66dd1bd 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiSharedConstant.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiSharedConstant.java @@ -9,7 +9,8 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import xyz.alexcrea.cuanvil.gui.config.MainConfigGui; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; public class GuiSharedConstant { diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index f5f3888..e2f92e9 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -2,7 +2,6 @@ package io.delilaheve import io.delilaheve.util.ConfigOptions import io.delilaheve.util.EnchantmentUtil.combineWith -import io.delilaheve.util.EnchantmentUtil.enchantmentName import io.delilaheve.util.ItemUtil.canMergeWith import io.delilaheve.util.ItemUtil.findEnchantments import io.delilaheve.util.ItemUtil.isEnchantedBook @@ -25,14 +24,14 @@ import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.InventoryView.Property.REPAIR_COST import org.bukkit.inventory.ItemStack -import org.bukkit.inventory.meta.Repairable import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.dependency.packet.PacketManager -import xyz.alexcrea.cuanvil.group.ConflictType import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe +import xyz.alexcrea.cuanvil.util.AnvilXpUtil.calculatePenalty +import xyz.alexcrea.cuanvil.util.AnvilXpUtil.getRightValues +import xyz.alexcrea.cuanvil.util.AnvilXpUtil.setAnvilInvXp import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair -import xyz.alexcrea.cuanvil.util.XpSetterUtil.setAnvilInvXp import java.util.regex.Matcher import java.util.regex.Pattern import kotlin.math.min @@ -513,96 +512,6 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { } } - /** - * Function to calculate work penalty of anvil work - * Also change result work penalty if right item is not null - */ - private fun calculatePenalty(left: ItemStack, right: ItemStack?, result: ItemStack): Int { - return calculatePenalty(left, right, result, false) - } - - /** - * Function to calculate work penalty of anvil work - * Also change result work penalty if right item is not null - */ - private fun calculatePenalty(left: ItemStack, right: ItemStack?, result: ItemStack, unitRepair: Boolean): Int { - // Extracted From https://minecraft.fandom.com/wiki/Anvil_mechanics#Enchantment_equation - // Calculate work penalty - val leftPenalty = (left.itemMeta as? Repairable)?.repairCost ?: 0 - val rightPenalty = - if (right == null) { - 0 - } else { - (right.itemMeta as? Repairable)?.repairCost ?: 0 - } - - // Increase penalty on fusing or unit repair - if(right != null || unitRepair){ - result.itemMeta?.let { - (it as? Repairable)?.repairCost = leftPenalty * 2 + 1 - result.itemMeta = it - - } - } - - CustomAnvil.log( - "Calculated penalty: " + - "leftPenalty: $leftPenalty, " + - "rightPenalty: $rightPenalty, " + - "result penalty: ${(result.itemMeta as? Repairable)?.repairCost ?: "none"}" - ) - - return leftPenalty + rightPenalty - } - - /** - * Function to calculate right enchantment values - * it include enchantment placed on final item and conflicting enchantment - */ - private fun getRightValues(right: ItemStack, result: ItemStack): Int { - // Calculate right value and illegal enchant penalty - var illegalPenalty = 0 - var rightValue = 0 - - val rightIsFormBook = right.isEnchantedBook() - val resultEnchs = result.findEnchantments() - val resultEnchsKeys = HashMap(resultEnchs) - - for (enchantment in right.findEnchantments()) { - // count enchant as illegal enchant if it conflicts with another enchant or not in result - if ((enchantment.key !in resultEnchsKeys)) { - resultEnchsKeys[enchantment.key] = enchantment.value - val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting( - resultEnchsKeys, - result, - enchantment.key - ) - resultEnchsKeys.remove(enchantment.key) - - if (ConflictType.ENCHANTMENT_CONFLICT == conflictType) { - illegalPenalty += ConfigOptions.sacrificeIllegalCost - CustomAnvil.verboseLog("Big conflict. Adding illegal price penalty") - } - continue - } - // We know "enchantment.key in resultEnchs" true - val resultLevel = resultEnchs[enchantment.key]!! - - val enchantmentMultiplier = ConfigOptions.enchantmentValue(enchantment.key, rightIsFormBook) - val value = resultLevel * enchantmentMultiplier - CustomAnvil.log("Value for ${enchantment.key.enchantmentName} level ${enchantment.value} is $value ($resultLevel * $enchantmentMultiplier)") - rightValue += value - - } - CustomAnvil.log( - "Calculated right values: " + - "rightValue: $rightValue, " + - "illegalPenalty: $illegalPenalty" - ) - - return rightValue + illegalPenalty - } - private fun getCustomRecipe ( leftItem: ItemStack, rightItem: ItemStack?) : AnvilCustomRecipe? { diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt index e050a68..278e3ef 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DisenchantmentDependency.kt @@ -11,7 +11,7 @@ import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.ItemStack import org.bukkit.plugin.RegisteredListener -import xyz.alexcrea.cuanvil.util.XpSetterUtil +import xyz.alexcrea.cuanvil.util.AnvilXpUtil class DisenchantmentDependency { @@ -80,14 +80,14 @@ class DisenchantmentDependency { if(event.result != null) { CustomAnvil.log("Detected pre anvil item extract bypass.") - XpSetterUtil.setAnvilInvXp(event.inventory, event.view, event.inventory.repairCost) + AnvilXpUtil.setAnvilInvXp(event.inventory, event.view, event.inventory.repairCost) return true } splitEvent.onDisenchantmentEvent(event) if(event.result != null) { CustomAnvil.log("Detected pre anvil split enchant bypass.") - XpSetterUtil.setAnvilInvXp(event.inventory, event.view, event.inventory.repairCost) + AnvilXpUtil.setAnvilInvXp(event.inventory, event.view, event.inventory.repairCost) return true } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt new file mode 100644 index 0000000..8b949ab --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt @@ -0,0 +1,163 @@ +package xyz.alexcrea.cuanvil.util + +import io.delilaheve.CustomAnvil +import io.delilaheve.util.ConfigOptions +import io.delilaheve.util.EnchantmentUtil.enchantmentName +import io.delilaheve.util.ItemUtil.findEnchantments +import io.delilaheve.util.ItemUtil.isEnchantedBook +import org.bukkit.GameMode +import org.bukkit.entity.Player +import org.bukkit.inventory.AnvilInventory +import org.bukkit.inventory.InventoryView +import org.bukkit.inventory.InventoryView.Property.REPAIR_COST +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.Repairable +import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.dependency.DependencyManager +import xyz.alexcrea.cuanvil.group.ConflictType +import kotlin.math.min + +object AnvilXpUtil { + + /** + * Display xp needed for the work on the anvil inventory + */ + fun setAnvilInvXp( + inventory: AnvilInventory, + view: InventoryView, + anvilCost: Int, + ignoreRules: Boolean = false + ) { + // Test repair cost limit + val finalAnvilCost = if ( + !ignoreRules && + !ConfigOptions.doRemoveCostLimit && + ConfigOptions.doCapCost) { + min(anvilCost, ConfigOptions.maxAnvilCost) + } else { + anvilCost + } + + /* 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. */ + CustomAnvil.instance + .server + .scheduler + .runTask(CustomAnvil.instance, Runnable { + inventory.maximumRepairCost = + if (ConfigOptions.doRemoveCostLimit || ignoreRules) + { Int.MAX_VALUE } + else + { ConfigOptions.maxAnvilCost + 1 } + + val player = view.player + + inventory.repairCost = finalAnvilCost + view.setProperty(REPAIR_COST, finalAnvilCost) + player.openInventory.setProperty(REPAIR_COST, finalAnvilCost) + + if(player is Player){ + if(player.gameMode != GameMode.CREATIVE ){ + val bypassToExpensive = (ConfigOptions.doReplaceTooExpensive) && + (finalAnvilCost >= 40) && + finalAnvilCost < inventory.maximumRepairCost + + DependencyManager.packetManager.setInstantBuild(player, bypassToExpensive) + } + + player.updateInventory() + } + }) + } + /** + * Function to calculate work penalty of anvil work + * Also change result work penalty if right item is not null + */ + fun calculatePenalty(left: ItemStack, right: ItemStack?, result: ItemStack): Int { + return calculatePenalty(left, right, result, false) + } + + /** + * Function to calculate work penalty of anvil work + * Also change result work penalty if right item is not null + */ + fun calculatePenalty(left: ItemStack, right: ItemStack?, result: ItemStack, unitRepair: Boolean): Int { + // Extracted From https://minecraft.fandom.com/wiki/Anvil_mechanics#Enchantment_equation + // Calculate work penalty + val leftPenalty = (left.itemMeta as? Repairable)?.repairCost ?: 0 + val rightPenalty = + if (right == null) { + 0 + } else { + (right.itemMeta as? Repairable)?.repairCost ?: 0 + } + + // Increase penalty on fusing or unit repair + if(right != null || unitRepair){ + result.itemMeta?.let { + (it as? Repairable)?.repairCost = leftPenalty * 2 + 1 + result.itemMeta = it + + } + } + + CustomAnvil.log( + "Calculated penalty: " + + "leftPenalty: $leftPenalty, " + + "rightPenalty: $rightPenalty, " + + "result penalty: ${(result.itemMeta as? Repairable)?.repairCost ?: "none"}" + ) + + return leftPenalty + rightPenalty + } + + /** + * Function to calculate right enchantment values + * it include enchantment placed on final item and conflicting enchantment + */ + fun getRightValues(right: ItemStack, result: ItemStack): Int { + // Calculate right value and illegal enchant penalty + var illegalPenalty = 0 + var rightValue = 0 + + val rightIsFormBook = right.isEnchantedBook() + val resultEnchs = result.findEnchantments() + val resultEnchsKeys = HashMap(resultEnchs) + + for (enchantment in right.findEnchantments()) { + // count enchant as illegal enchant if it conflicts with another enchant or not in result + if ((enchantment.key !in resultEnchsKeys)) { + resultEnchsKeys[enchantment.key] = enchantment.value + val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting( + resultEnchsKeys, + result, + enchantment.key + ) + resultEnchsKeys.remove(enchantment.key) + + if (ConflictType.ENCHANTMENT_CONFLICT == conflictType) { + illegalPenalty += ConfigOptions.sacrificeIllegalCost + CustomAnvil.verboseLog("Big conflict. Adding illegal price penalty") + } + continue + } + // We know "enchantment.key in resultEnchs" true + val resultLevel = resultEnchs[enchantment.key]!! + + val enchantmentMultiplier = ConfigOptions.enchantmentValue(enchantment.key, rightIsFormBook) + val value = resultLevel * enchantmentMultiplier + CustomAnvil.log("Value for ${enchantment.key.enchantmentName} level ${enchantment.value} is $value ($resultLevel * $enchantmentMultiplier)") + rightValue += value + + } + CustomAnvil.log( + "Calculated right values: " + + "rightValue: $rightValue, " + + "illegalPenalty: $illegalPenalty" + ) + + return rightValue + illegalPenalty + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/XpSetterUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/XpSetterUtil.kt deleted file mode 100644 index d334099..0000000 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/util/XpSetterUtil.kt +++ /dev/null @@ -1,67 +0,0 @@ -package xyz.alexcrea.cuanvil.util - -import io.delilaheve.CustomAnvil -import io.delilaheve.util.ConfigOptions -import org.bukkit.GameMode -import org.bukkit.entity.Player -import org.bukkit.inventory.AnvilInventory -import org.bukkit.inventory.InventoryView -import org.bukkit.inventory.InventoryView.Property.REPAIR_COST -import xyz.alexcrea.cuanvil.dependency.DependencyManager -import kotlin.math.min - -object XpSetterUtil { - - /** - * Display xp needed for the work on the anvil inventory - */ - fun setAnvilInvXp( - inventory: AnvilInventory, - view: InventoryView, - anvilCost: Int, - ignoreRules: Boolean = false - ) { - // Test repair cost limit - val finalAnvilCost = if ( - !ignoreRules && - !ConfigOptions.doRemoveCostLimit && - ConfigOptions.doCapCost) { - min(anvilCost, ConfigOptions.maxAnvilCost) - } else { - anvilCost - } - - /* 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. */ - CustomAnvil.instance - .server - .scheduler - .runTask(CustomAnvil.instance, Runnable { - inventory.maximumRepairCost = - if (ConfigOptions.doRemoveCostLimit || ignoreRules) - { Int.MAX_VALUE } - else - { ConfigOptions.maxAnvilCost + 1 } - - val player = view.player - - inventory.repairCost = finalAnvilCost - view.setProperty(REPAIR_COST, finalAnvilCost) - player.openInventory.setProperty(REPAIR_COST, finalAnvilCost) - - if(player is Player){ - if(player.gameMode != GameMode.CREATIVE ){ - val bypassToExpensive = (ConfigOptions.doReplaceTooExpensive) && - (finalAnvilCost >= 40) && - finalAnvilCost < inventory.maximumRepairCost - - DependencyManager.packetManager.setInstantBuild(player, bypassToExpensive) - } - - player.updateInventory() - } - }) - } - -} \ No newline at end of file From 1b7560b1a09807fe0ac34b093336cdf41b767c8f Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Wed, 21 Aug 2024 03:57:52 +0200 Subject: [PATCH 5/6] Add Disenchantment to readme. --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0a824cd..45d3518 100644 --- a/README.md +++ b/README.md @@ -47,18 +47,22 @@ under 1.2.0 replace ca prefix by ue and use ue.unsafe. some permission/features anvilconfigreload or carl: Reload every config of this plugin customanvilconfig or configanvil: open a menu for administrator to edit plugin's config in game ``` -### Custom Enchantment Plugins -Custom Anvil can be compatible with some custom enchant plugins. \ -Currently, there is not a lot of compatible plugin +### Supported Plugins +Custom Anvil can be compatible with some custom enchant and anvil mechanics plugins. -Here is a list of supported plugins with support status: +Here is a list of supported custom enchantment plugins with support status: - [Enchantment²](https://www.spigotmc.org/resources/enchants-squared-the-enchantsplus-rewrite-custom-enchantments-that-act-like-vanilla-ones.86747/): Officially supported by Custom Anvil but still experimental. Automatic configuration. -- [EcoEnchant](https://www.spigotmc.org/resources/50-sale-%E2%8C%9B-ecoenchants-%E2%AD%95-250-enchantments-%E2%9C%85-create-custom-enchants-%E2%9C%A8-essentials-cmi-support.79573/): -Officially supported by Custom Anvil but still experimental. Need to use /anvilconfigreload or a server restart to add newly added enchantment. -Use EcoEnchant restriction system by default.​ -If you like Custom Anvil to support a specific custom enchantment plugin. +- [EcoEnchant](https://www.spigotmc.org/resources/ecoenchants-%E2%AD%95-250-enchantments-%E2%9C%85-create-custom-enchants-%E2%9C%A8-essentials-cmi-support.79573/): +Officially supported by Custom Anvil but still experimental. Need to use /anvilconfigreload or a server restart to add newly added enchantment. +Use EcoEnchant restriction system by default. + +Here is a list of supported anvil mechanic plugins with support status: +- [Disenchantment](https://www.spigotmc.org/resources/disenchantment-1-21-1-1-20-6-new-book-splitting-mechanics.110741/) +Officially supported by Custom Anvil but still experimental. mostly use Custom Anvil xp settings. + +If you like Custom Anvil to support a specific plugin (custom enchant or anvil mechanic). You can ask, but please note implementing compatibility will be considered as low priority as I work for the plugin on my free time for free. From 1b2561195828efc5d384d34acfa0da624063d0f9 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:11:57 +0200 Subject: [PATCH 6/6] version up. (1.6.0) --- build.gradle.kts | 2 +- src/main/resources/plugin.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index e43a23d..a2fafdb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,7 +14,7 @@ plugins { } group = "xyz.alexcrea" -version = "1.5.5" +version = "1.6.0" repositories { // EcoEnchants diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index cfc2abc..9446af8 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ main: io.delilaheve.CustomAnvil name: CustomAnvil prefix: "Custom Anvil" -version: 1.5.5 +version: 1.6.0 description: Allow to customise anvil mechanics api-version: 1.16 load: POSTWORLD