diff --git a/build.gradle.kts b/build.gradle.kts index e10c058..45ea74c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ plugins { } group = "xyz.alexcrea" -version = "1.7.0" +version = "1.7.1" repositories { // EcoEnchants diff --git a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt index f192ff9..dc47bc6 100644 --- a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt +++ b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt @@ -48,8 +48,8 @@ object ConfigOptions { private const val KEY_ITEM = "item" // Debug flag - private const val DEBUG_LOGGING = "debug_log" - private const val VERBOSE_DEBUG_LOGGING = "debug_log_verbose" + const val DEBUG_LOGGING = "debug_log" + const val VERBOSE_DEBUG_LOGGING = "debug_log_verbose" // ---------------------- // Default config values diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt index e97744e..437f3d5 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt @@ -2,6 +2,7 @@ package xyz.alexcrea.cuanvil.dependency import io.delilaheve.CustomAnvil import org.bukkit.Bukkit +import org.bukkit.ChatColor import org.bukkit.entity.HumanEntity import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.PrepareAnvilEvent @@ -15,6 +16,8 @@ import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector import xyz.alexcrea.cuanvil.dependency.scheduler.BukkitScheduler import xyz.alexcrea.cuanvil.dependency.scheduler.FoliaScheduler import xyz.alexcrea.cuanvil.dependency.scheduler.TaskScheduler +import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT +import java.util.logging.Level object DependencyManager { @@ -96,10 +99,25 @@ object DependencyManager { // Then handle plugin reload ecoEnchantCompatibility?.handleConfigReload() - } + // Return true if should bypass (either by a dependency or error) fun tryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean { + try { + return unsafeTryEventPreAnvilBypass(event, player) + } catch (e: Exception){ + CustomAnvil.instance.logger.log(Level.SEVERE, "Error while trying to handle custom anvil supported plugin: ", e) + + // Just in case to avoid illegal items + event.inventory.setItem(ANVIL_OUTPUT_SLOT, null) + + // Finally, warn the player, maybe a lot of time but better warn than do nothing + event.view.player.sendMessage(ChatColor.RED.toString() + "Error while handling the anvil.") + return true + } + } + + private fun unsafeTryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean { var bypass = false // Test if disenchantment used prepare anvil @@ -118,11 +136,44 @@ object DependencyManager { return bypass } - fun treatAnvilResult(event: PrepareAnvilEvent, result: ItemStack) { + // Return true only if error occurred (and so should bypass rest) + fun tryTreatAnvilResult(event: PrepareAnvilEvent, result: ItemStack): Boolean { + try { + unsafeTryTreatAnvilResult(event, result) + return false + } catch (e: Exception){ + CustomAnvil.instance.logger.log(Level.SEVERE, "Error while trying to handle custom anvil supported plugin: ", e) + + // Just in case to avoid illegal items + event.inventory.setItem(ANVIL_OUTPUT_SLOT, null) + + // Finally, warn the player, maybe a lot of time but better warn than do nothing + event.view.player.sendMessage(ChatColor.RED.toString() + "Error while handling the anvil.") + return true + } + } + + private fun unsafeTryTreatAnvilResult(event: PrepareAnvilEvent, result: ItemStack) { excellentEnchantsCompatibility?.treatAnvilResult(event, result) } + // Return true if should bypass (either by a dependency or error) fun tryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean { + try { + return unsafeTryClickAnvilResultBypass(event, inventory) + } catch (e: Exception){ + CustomAnvil.instance.logger.log(Level.SEVERE, "Error while trying to handle custom anvil supported plugin: ", e) + + // Just in case to avoid illegal items + event.inventory.setItem(ANVIL_OUTPUT_SLOT, null) + + // Finally, warn the player, maybe a lot of time but better warn than do nothing + event.whoClicked.sendMessage(ChatColor.RED.toString() + "Error while handling the anvil.") + return true + } + } + + private fun unsafeTryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean { var bypass = false // Test if disenchantment used event click diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt index 6622767..1153248 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt @@ -45,6 +45,7 @@ class AnvilResultListener: Listener { if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return } + // Test if the event should bypass custom anvil. if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return @@ -52,7 +53,7 @@ class AnvilResultListener: Listener { val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) - if(!GameMode.CREATIVE.equals(player.gameMode) && inventory.repairCost >= inventory.maximumRepairCost) { + if(GameMode.CREATIVE != player.gameMode && inventory.repairCost >= inventory.maximumRepairCost) { event.result = Event.Result.DENY return } @@ -96,7 +97,6 @@ class AnvilResultListener: Listener { } } - private fun onCustomCraft(event: InventoryClickEvent, recipe: AnvilCustomRecipe, player: Player, @@ -122,7 +122,7 @@ class AnvilResultListener: Listener { // Handle not creative middle click... if (event.click != ClickType.MIDDLE && - !handleCustomCraftClick(event, recipe, inventory, player, leftItem, rightItem, amount, xpCost)) return; + !handleCustomCraftClick(event, recipe, inventory, player, leftItem, rightItem, amount, xpCost)) return // Finally, we add the item to the player if (slotDestination.type == SlotType.CURSOR) { @@ -222,7 +222,7 @@ class AnvilResultListener: Listener { resultCopy: ItemStack, resultAmount: Int): Int { if (player.gameMode == GameMode.CREATIVE) return 0 - var repairCost = 0; + var repairCost = 0 // Get repairCost leftItem.itemMeta?.let { leftMeta -> val leftName = leftMeta.displayName diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt index 68370d4..f37a193 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt @@ -22,6 +22,7 @@ import xyz.alexcrea.cuanvil.util.AnvilColorUtil import xyz.alexcrea.cuanvil.util.AnvilXpUtil import xyz.alexcrea.cuanvil.util.CustomRecipeUtil import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair +import java.util.logging.Level /** * Listener for anvil events @@ -45,7 +46,7 @@ class PrepareAnvilListener : Listener { val player: HumanEntity = event.viewers.first() // Test if the event should bypass custom anvil. - if(DependencyManager.tryEventPreAnvilBypass(event, player)) return + if (DependencyManager.tryEventPreAnvilBypass(event, player)) return val inventory = event.inventory val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return @@ -76,6 +77,7 @@ class PrepareAnvilListener : Listener { } + // return true if a custom recipe exist with these ingredient private fun testCustomRecipe(event: PrepareAnvilEvent, inventory: AnvilInventory, player: HumanEntity, first: ItemStack, second: ItemStack?): Boolean { @@ -89,7 +91,7 @@ class PrepareAnvilListener : Listener { resultItem.amount *= amount event.result = resultItem - DependencyManager.treatAnvilResult(event, resultItem) + if(DependencyManager.tryTreatAnvilResult(event, resultItem)) return true AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, recipe.xpCostPerCraft * amount, true) return true @@ -108,7 +110,7 @@ class PrepareAnvilListener : Listener { } event.result = resultItem - DependencyManager.treatAnvilResult(event, resultItem) + if(DependencyManager.tryTreatAnvilResult(event, resultItem)) return anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem) @@ -116,27 +118,30 @@ class PrepareAnvilListener : Listener { } private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int { - // Rename item and add renaming cost - resultItem.itemMeta?.let { - val displayName = ChatColor.stripColor(it.displayName) - var inventoryName = ChatColor.stripColor(inventory.renameText) + // Can be null + var inventoryName = ChatColor.stripColor(inventory.renameText) - var sumCost = 0 + var sumCost = 0 + var useColor = false + if(ConfigOptions.renameColorPossible && inventoryName != null){ + val resultString = StringBuilder(inventoryName) - var useColor = false - if(ConfigOptions.renameColorPossible){ - val resultString = StringBuilder(inventoryName) + useColor = AnvilColorUtil.handleRenamingColor(resultString, player) - useColor = AnvilColorUtil.handleRenamingColor(resultString, player) + if(useColor) { + inventoryName = resultString.toString() - if(useColor) { - inventoryName = resultString.toString() - - sumCost+= ConfigOptions.useOfColorCost - } + sumCost+= ConfigOptions.useOfColorCost } + } + + // Rename item and add renaming cost + resultItem.itemMeta?.let { + val displayName = + if (useColor) it.displayName + else ChatColor.stripColor(it.displayName) - if ((!useColor && (!displayName.contentEquals(inventoryName))) || (useColor && !(it.displayName).contentEquals(inventoryName))) { + if (!displayName.contentEquals(inventoryName)) { it.setDisplayName(inventoryName) resultItem.itemMeta = it @@ -178,11 +183,12 @@ class PrepareAnvilListener : Listener { // Finally, we set result event.result = resultItem - DependencyManager.treatAnvilResult(event, resultItem) + if(DependencyManager.tryTreatAnvilResult(event, resultItem)) return AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, anvilCost) } + // return true if there is a valid unit repair with these ingredients private fun testUnitRepair(event: PrepareAnvilEvent, inventory: AnvilInventory, player: HumanEntity, first: ItemStack, second: ItemStack): Boolean { val unitRepairAmount = first.getRepair(second) ?: return false @@ -204,7 +210,7 @@ class PrepareAnvilListener : Listener { return true } event.result = resultItem - DependencyManager.treatAnvilResult(event, resultItem) + if(DependencyManager.tryTreatAnvilResult(event, resultItem)) return true AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, anvilCost) return true diff --git a/src/test/java/xyz/alexcrea/cuanvil/anvil/AnvilFuseTests.java b/src/test/java/xyz/alexcrea/cuanvil/anvil/AnvilFuseTests.java index fde2a68..16a01e3 100644 --- a/src/test/java/xyz/alexcrea/cuanvil/anvil/AnvilFuseTests.java +++ b/src/test/java/xyz/alexcrea/cuanvil/anvil/AnvilFuseTests.java @@ -1,11 +1,15 @@ package xyz.alexcrea.cuanvil.anvil; +import io.delilaheve.util.ConfigOptions; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.AnvilInventory; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.Repairable; +import org.eclipse.aether.util.ConfigUtils; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -32,8 +36,9 @@ public static void setUp() { AnvilFuseTests.anvil = (AnvilInventory) anvil; player.openInventory(anvil); - ConfigHolder.DEFAULT_CONFIG.getConfig().set("debug_log", true); - ConfigHolder.DEFAULT_CONFIG.getConfig().set("debug_log_verbose", true); + ConfigHolder.DEFAULT_CONFIG.getConfig().set(ConfigOptions.DEBUG_LOGGING, true); + ConfigHolder.DEFAULT_CONFIG.getConfig().set(ConfigOptions.VERBOSE_DEBUG_LOGGING, true); + ConfigHolder.DEFAULT_CONFIG.getConfig().set(ConfigOptions.ALLOW_COLOR_CODE, true); // For rename test } @BeforeEach @@ -100,4 +105,23 @@ public void underFuseTest(){ AnvilFuseTestUtil.executeAnvilTest(anvil, player, data); } + // Note: currently anvil can only have null name. maybe handle differently later + @Test + public void nullNameResetTest(){ + ItemStack base = new ItemStack(Material.NETHERITE_SWORD); + ItemStack expected = base.clone(); + + ItemMeta meta = expected.getItemMeta(); + meta.displayName(Component.text("test")); + base.setItemMeta(meta); + + AnvilFuseTestData data = new AnvilFuseTestData( + base, null, + expected, expected, null + // TODO add expected price + ); + + AnvilFuseTestUtil.executeAnvilTest(anvil, player, data); + } + } diff --git a/src/test/java/xyz/alexcrea/cuanvil/util/AnvilFuseTestData.java b/src/test/java/xyz/alexcrea/cuanvil/util/AnvilFuseTestData.java index 2268d44..cc042f2 100644 --- a/src/test/java/xyz/alexcrea/cuanvil/util/AnvilFuseTestData.java +++ b/src/test/java/xyz/alexcrea/cuanvil/util/AnvilFuseTestData.java @@ -36,4 +36,19 @@ public AnvilFuseTestData( this(leftItem, rightItem, expectedResult, null ); } + + public AnvilFuseTestData( + @Nullable ItemStack leftItem, + @Nullable ItemStack rightItem, + @Nullable ItemStack expectedResult, + + @Nullable ItemStack expectedAfterLeftPlaced, + @Nullable ItemStack expectedAfterRightPlaced + ){ + this(leftItem, rightItem, + expectedResult, expectedAfterLeftPlaced, expectedAfterRightPlaced, + null, null, null + ); + } + }