diff --git a/build.gradle.kts b/build.gradle.kts index da11be5..a8211b0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,6 +37,9 @@ repositories { // ExcellentEnchants maven(url = "https://repo.nightexpressdev.com/releases") + // ItemsAdder + maven(url = "https://maven.devs.beer/") + // for fast stats maven { name = "thenextlvlReleases" @@ -97,6 +100,9 @@ dependencies { // SuperEnchants compileOnly(files("libs/SuperEnchants-4.6.2-all.jar")) + // ItemsAdder API + compileOnly("dev.lone:api-itemsadder:4.0.10") + // Include nms implementation(project(":nms:nms-common")) implementation(project(":nms:nms-paper")) diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEEV5_4Enchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEEV5_4Enchantment.java index a86877f..7fb8627 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEEV5_4Enchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEEV5_4Enchantment.java @@ -1,6 +1,5 @@ package xyz.alexcrea.cuanvil.enchant.wrapped; -import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.jetbrains.annotations.NotNull; import su.nightexpress.excellentenchants.api.enchantment.CustomEnchantment; diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt index df2fbce..0b5f396 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt @@ -5,10 +5,12 @@ import io.delilaheve.CustomAnvil import net.kyori.adventure.text.Component import org.bukkit.Bukkit import org.bukkit.ChatColor +import org.bukkit.command.CommandSender import org.bukkit.entity.HumanEntity import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.inventory.AnvilInventory +import org.bukkit.inventory.Inventory import org.bukkit.inventory.ItemStack import xyz.alexcrea.cuanvil.api.event.listener.CAClickResultBypassEvent import xyz.alexcrea.cuanvil.api.event.listener.CAEarlyPreAnvilBypassEvent @@ -46,6 +48,8 @@ object DependencyManager { var axPlayerWarpsCompatibility: AxPlayerWarpsDependency? = null + var itemsAdderCompatibility: ItemsAdderDependency? = null + val genericDependencies = ArrayList() fun loadDependency() { @@ -98,6 +102,12 @@ object DependencyManager { axPlayerWarpsCompatibility = AxPlayerWarpsDependency() } + if (pluginManager.isPluginEnabled("ItemsAdder")){ + val dependency = ItemsAdderDependency(pluginManager.getPlugin("ItemsAdder")!!) + itemsAdderCompatibility = dependency + genericDependencies.add(dependency) + } + // "Generic" dependencies if (pluginManager.isPluginEnabled("ToolStats")) genericDependencies.add(ToolStatsDependency(pluginManager.getPlugin("ToolStats")!!)) @@ -138,27 +148,35 @@ object DependencyManager { ecoEnchantCompatibility?.handleConfigReload() } + private fun logException(target: CommandSender, e: Exception) { + CustomAnvil.instance.logger.log( + Level.SEVERE, + "Error while trying to handle custom anvil supported plugin: ", + e + ) + trackError(e) + + // Finally, warn the player + target.sendMessage( + "[" + ChatColor.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " + + ChatColor.RED.toString() + "Error while handling the anvil." + ) + } + + private fun logExceptionAndClear(target: CommandSender, inventory: Inventory, e: Exception) { + // Just in case to avoid illegal items + inventory.setItem(ANVIL_OUTPUT_SLOT, null) + + logException(target, e) + } + // Return true if should bypass (either by a dependency or error) // called before immutability test fun earlyTryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean { try { return earlyUnsafeTryEventPreAnvilBypass(event, player) } catch (e: Exception) { - CustomAnvil.instance.logger.log( - Level.SEVERE, - "Error while trying to handle custom anvil supported plugin: ", - e - ) - trackError(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.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " + - ChatColor.RED.toString() + "Error while handling the anvil." - ) + logExceptionAndClear(event.view.player, event.inventory, e) return true } } @@ -184,21 +202,7 @@ object DependencyManager { try { return unsafeTryEventPreAnvilBypass(event, player) } catch (e: Exception) { - CustomAnvil.instance.logger.log( - Level.SEVERE, - "Error while trying to handle custom anvil supported plugin: ", - e - ) - trackError(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.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " + - ChatColor.RED.toString() + "Error while handling the anvil." - ) + logExceptionAndClear(event.view.player, event.inventory, e) return true } } @@ -238,21 +242,7 @@ object DependencyManager { unsafeTryTreatAnvilResult(treatEvent) return treatEvent; } catch (e: Exception) { - CustomAnvil.instance.logger.log( - Level.SEVERE, - "Error while trying to handle custom anvil supported plugin: ", - e - ) - trackError(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.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " + - ChatColor.RED.toString() + "Error while handling the anvil." - ) + logExceptionAndClear(event.view.player, event.inventory, e) return null } } @@ -268,21 +258,7 @@ object DependencyManager { try { return unsafeTryClickAnvilResultBypass(event, inventory) } catch (e: Exception) { - CustomAnvil.instance.logger.log( - Level.SEVERE, - "Error while trying to handle custom anvil supported plugin: ", - e - ) - trackError(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.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " + - ChatColor.RED.toString() + "Error while handling the anvil." - ) + logExceptionAndClear(event.view.player, event.inventory, e) return true } } @@ -316,6 +292,23 @@ object DependencyManager { return bypass } + // Clone item and use plugin specific clone if needed + fun cloneItem(event: PrepareAnvilEvent, item: ItemStack): ItemStack { + try { + return unsafeCloneItem(item) + } catch (e: Exception) { + logException(event.view.player, e) + return item.clone() + } + } + + private fun unsafeCloneItem(item: ItemStack): ItemStack { + val cloned = itemsAdderCompatibility?.tryClone(item) + if(cloned != null) return cloned + + return item.clone() + } + fun stripLore(item: ItemStack): MutableList { val dummy = item.clone() diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/plugins/EcoItemDependencyUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/plugins/EcoItemDependencyUtil.kt index 14c7d9f..7e84231 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/plugins/EcoItemDependencyUtil.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/plugins/EcoItemDependencyUtil.kt @@ -31,4 +31,8 @@ object EcoItemDependencyUtil { return ecoi.itemStack } + fun getItems(): List { + return EcoItems.values().map { item -> item.id } + } + } \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/plugins/ItemsAdderDependency.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/plugins/ItemsAdderDependency.kt new file mode 100644 index 0000000..7f977e1 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/plugins/ItemsAdderDependency.kt @@ -0,0 +1,42 @@ +package xyz.alexcrea.cuanvil.dependency.plugins + +import dev.lone.itemsadder.api.CustomStack +import dev.lone.itemsadder.api.ItemsAdder +import org.bukkit.NamespacedKey +import org.bukkit.inventory.ItemStack +import org.bukkit.plugin.Plugin + +class ItemsAdderDependency(plugin: Plugin) : GenericPluginDependency(plugin) { + var isLoaded: Boolean = false + get() { + if (field) return true + + // We can't be sure the event is registered before being triggered so we need to use this function + field = ItemsAdder.areItemsLoaded() + return field + } + + fun tryClone(item: ItemStack): ItemStack? { + if(!isLoaded) return null + val customItem = CustomStack.byItemStack(item) ?: return null + + return CustomStack.getInstance(customItem.namespacedID)?.itemStack + } + + fun fromKey(key: NamespacedKey): ItemStack? { + if(!isLoaded) return null + return CustomStack.getInstance(key.toString())?.itemStack + } + + fun getKey(item: ItemStack) : NamespacedKey? { + if(!isLoaded) return null + val customItem = CustomStack.byItemStack(item) ?: return null + + return NamespacedKey.fromString(customItem.namespacedID) + } + + fun idsCount(): Set { + return CustomStack.getNamespacedIdsInRegistry() + } + +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/ExcludeGroup.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/ExcludeGroup.kt index 58ea48c..d752db5 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/ExcludeGroup.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/ExcludeGroup.kt @@ -6,7 +6,7 @@ import java.util.* class ExcludeGroup(name: String) : AbstractMaterialGroup(name) { override fun createDefaultSet(): MutableSet { - return NegativeSet(HashSet()) + return NegativeMaterialSet() } private var includedGroup: MutableSet = HashSet() diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/NegativeMaterialSet.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/NegativeMaterialSet.kt new file mode 100644 index 0000000..d87004d --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/NegativeMaterialSet.kt @@ -0,0 +1,22 @@ +package xyz.alexcrea.cuanvil.group + +import org.bukkit.NamespacedKey +import xyz.alexcrea.cuanvil.util.MaterialUtil +import xyz.alexcrea.cuanvil.util.NegativeSet + +class NegativeMaterialSet: NegativeSet() { + + override fun iterator(): MutableIterator { + val materials = MaterialUtil.getMaterials() + materials.removeIf { negate.contains(it) } + + return materials.iterator() + } + + override fun isEmpty(): Boolean { + return negate.size >= MaterialUtil.getMaterialCount() + } + + override val size get() = MaterialUtil.getMaterialCount() - negate.size + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt index 7126dd9..03865f0 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt @@ -155,7 +155,7 @@ class PrepareAnvilListener : Listener { val amount = CustomRecipeUtil.getCustomRecipeAmount(recipe, first, second) - val resultItem: ItemStack = recipe.resultItem!!.clone() + val resultItem: ItemStack = DependencyManager.cloneItem(event, recipe.resultItem!!) resultItem.amount *= amount // Maybe add an option on custom craft to ignore/not ignore penalty ?? @@ -179,7 +179,7 @@ class PrepareAnvilListener : Listener { event: PrepareAnvilEvent, inventory: AnvilInventory, player: HumanEntity, first: ItemStack ) { - val resultItem = first.clone() + val resultItem = DependencyManager.cloneItem(event, first) var anvilCost = handleRename(resultItem, inventory, player) // Test/stop if nothing changed. @@ -251,7 +251,7 @@ class PrepareAnvilListener : Listener { .combineWith(second.findEnchantments(), first, player) var hasChanged = !isIdentical(first.findEnchantments(), newEnchants) - val resultItem = first.clone() + val resultItem = DependencyManager.cloneItem(event, first) var anvilCost = 0 if(hasChanged){ resultItem.setEnchantmentsUnsafe(newEnchants) @@ -307,7 +307,7 @@ class PrepareAnvilListener : Listener { ): Boolean { val unitRepairAmount = first.getRepair(second) ?: return false - val resultItem = first.clone() + val resultItem = DependencyManager.cloneItem(event, first) var anvilCost = handleRename(resultItem, inventory, player) val repairAmount = resultItem.unitRepair(second.amount, unitRepairAmount) diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/MaterialUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/MaterialUtil.kt index c4907c8..6b55662 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/util/MaterialUtil.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/MaterialUtil.kt @@ -4,6 +4,7 @@ import org.bukkit.Bukkit import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.inventory.ItemStack +import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.dependency.plugins.EcoItemDependencyUtil object MaterialUtil { @@ -18,15 +19,19 @@ object MaterialUtil { return Material.AIR.key == this } - private val HasEcoItem = Bukkit.getPluginManager().isPluginEnabled("EcoItems") - val ItemStack.customType: NamespacedKey get() { - if(HasEcoItem) { + if(DependencyManager.ecoEnchantCompatibility != null) { val result = EcoItemDependencyUtil.ecoItemNamespace(this) if(result != null) return result } + val itemAdder = DependencyManager.itemsAdderCompatibility + if(itemAdder != null) { + val result = itemAdder.getKey(this) + if (result != null) return result + } + return this.type.key } @@ -36,20 +41,32 @@ object MaterialUtil { } fun getMatFromKey(key: NamespacedKey): Material? { - if(HasEcoItem) { + if(DependencyManager.ecoEnchantCompatibility != null) { val result = EcoItemDependencyUtil.ecoItemMaterialFromKey(key) if(result != null) return result } + val itemAdder = DependencyManager.itemsAdderCompatibility + if(itemAdder != null) { + val result = itemAdder.fromKey(key) + if (result != null) return result.type + } + return bukkitMaterialFromKey(key) } fun itemFromKey(key: NamespacedKey): ItemStack { - if(HasEcoItem) { + if(DependencyManager.ecoEnchantCompatibility != null) { val result = EcoItemDependencyUtil.newEcoItemstack(key) if(result != null) return result } + val itemAdder = DependencyManager.itemsAdderCompatibility + if(itemAdder != null) { + val result = itemAdder.fromKey(key) + if (result != null) return result + } + return ItemStack(bukkitMaterialFromKey(key)!!) } @@ -57,5 +74,32 @@ object MaterialUtil { return getMatFromKey(key) != null } + fun getMaterialCount(): Int { + var count = Material.entries.size + if(DependencyManager.ecoEnchantCompatibility != null) { + count += EcoItemDependencyUtil.getItems().size + } + + val itemAdder = DependencyManager.itemsAdderCompatibility + if(itemAdder != null) { + count += itemAdder.idsCount().size + } + + return count + } + + fun getMaterials(): MutableList { + val all = ArrayList(Material.entries.map { it.key }) + if(DependencyManager.ecoEnchantCompatibility != null) { + all.addAll(EcoItemDependencyUtil.getItems()) + } + + val itemAdder = DependencyManager.itemsAdderCompatibility + if(itemAdder != null) { + all.addAll(itemAdder.idsCount().map { NamespacedKey.fromString(it) }) + } + + return all + } } \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/NegativeSet.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/NegativeSet.kt similarity index 81% rename from src/main/kotlin/xyz/alexcrea/cuanvil/group/NegativeSet.kt rename to src/main/kotlin/xyz/alexcrea/cuanvil/util/NegativeSet.kt index 386ba5f..a94175b 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/NegativeSet.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/NegativeSet.kt @@ -1,6 +1,6 @@ -package xyz.alexcrea.cuanvil.group +package xyz.alexcrea.cuanvil.util -class NegativeSet(val negate: MutableSet) : MutableSet { +open class NegativeSet(val negate: MutableSet = HashSet()) : MutableSet { override fun iterator(): MutableIterator { TODO("Not yet implemented") // can't be implemented I guess @@ -15,7 +15,7 @@ class NegativeSet(val negate: MutableSet) : MutableSet { } override fun addAll(elements: Collection): Boolean { - return negate.removeAll(elements) + return negate.removeAll(elements.toSet()) } override fun removeAll(elements: Collection): Boolean { @@ -34,7 +34,7 @@ class NegativeSet(val negate: MutableSet) : MutableSet { TODO("Not yet implemented") } - override val size get() = TODO("Not yet implemented") + override val size: Int get() = TODO("Not yet implemented") override fun contains(element: T): Boolean { return !negate.contains(element)