From 9f35c1a98d1d639e4c01ab5ff44e49c9e0a41b98 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:38:49 +0100 Subject: [PATCH] custom conflict now work. --- .../io/delilaheve/AnvilEventListener.kt | 41 +++++-- .../kotlin/io/delilaheve/UnsafeEnchants.kt | 56 +++++++-- .../io/delilaheve/util/EnchantmentUtil.kt | 2 +- .../alexcrea/group/EnchantConflictGroup.kt | 10 +- .../alexcrea/group/EnchantConflictManager.kt | 113 ++++++++++++++++++ .../xyz/alexcrea/group/ItemGroupManager.kt | 5 + 6 files changed, 201 insertions(+), 26 deletions(-) create mode 100644 src/main/kotlin/xyz/alexcrea/group/EnchantConflictManager.kt diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index c8a8028..d2ad72c 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -9,6 +9,7 @@ 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 org.bukkit.entity.HumanEntity import org.bukkit.entity.Player import org.bukkit.event.Event import org.bukkit.event.EventHandler @@ -18,6 +19,7 @@ import org.bukkit.event.inventory.InventoryClickEvent 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.permissions.Permission import kotlin.math.min @@ -63,7 +65,17 @@ class AnvilEventListener : Listener { if (ConfigOptions.limitRepairCost) { repairCost = min(repairCost, ConfigOptions.limitRepairValue) } - event.result = resultItem + + // Try to find player + val player = event.view.player + // Set object only if allowed + if(itemAllowed(resultItem,player)){ + event.result = resultItem + } else{ + event.result = null + return + } + /* 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. */ @@ -87,16 +99,27 @@ class AnvilEventListener : Listener { fun anvilExtractionCheck(event: InventoryClickEvent) { val player = event.whoClicked as? Player ?: return val inventory = event.inventory as? AnvilInventory ?: return - val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return - if(!player.hasPermission(bypassPermission)){ - if (output.findEnchantments().hasConflicts() && !player.hasPermission(requirePermission)) { - - - return - } - } if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return } + val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return + // Should be true most of the time + // But if permissions change in the anvil it can be false + if(!itemAllowed(output,player)){ + event.result = Event.Result.DENY + return + } event.result = Event.Result.ALLOW } + + private fun itemAllowed(item: ItemStack, player: HumanEntity): Boolean{ + if(!player.hasPermission(bypassPermission)){ + if(player.hasPermission(requirePermission)){ + if(UnsafeEnchants.conflictManager.isConflicting(item)) + return false + + } else if(item.findEnchantments().hasConflicts()) + return false + } + return true + } } diff --git a/src/main/kotlin/io/delilaheve/UnsafeEnchants.kt b/src/main/kotlin/io/delilaheve/UnsafeEnchants.kt index 9c0fb02..957cbde 100644 --- a/src/main/kotlin/io/delilaheve/UnsafeEnchants.kt +++ b/src/main/kotlin/io/delilaheve/UnsafeEnchants.kt @@ -1,9 +1,13 @@ package io.delilaheve import io.delilaheve.util.ConfigOptions +import org.bukkit.Bukkit import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.plugin.java.JavaPlugin +import xyz.alexcrea.group.EnchantConflictManager import xyz.alexcrea.group.ItemGroupManager +import java.io.File +import java.io.FileReader /** * Bukkit/Spigot/Paper plugin to alter enchantment max @@ -18,11 +22,13 @@ class UnsafeEnchants : JavaPlugin() { const val unsafeBypassPermission = "ue.unsafe_all" // Item Grouping Configuration file name const val itemGroupingConfigName = "item_groups.yml" + // Conflict Configuration file name + const val enchantConflicConfigName = "enchant_conflict.yml" // Current plugin instance lateinit var instance: UnsafeEnchants // Current item grouping configuration instance - lateinit var itemGroups: ItemGroupManager + lateinit var conflictManager: EnchantConflictManager /** * Logging handler @@ -41,24 +47,50 @@ class UnsafeEnchants : JavaPlugin() { instance = this saveDefaultConfig() - // Save default material grouping config - saveResource(itemGroupingConfigName,false) // Load material grouping config - val itemGroupConfig = YamlConfiguration() - val configReader = this.getTextResource(itemGroupingConfigName) - if(configReader == null){ - logger.severe("could no load item grouping configuration") - }else{ - itemGroupConfig.load(configReader) - } + val itemGroupConfig = reloadResource(itemGroupingConfigName) ?: return // Read material groups from config - itemGroups = ItemGroupManager() - itemGroups.prepareGroups(itemGroupConfig) + val itemGroupsManager = ItemGroupManager() + itemGroupsManager.prepareGroups(itemGroupConfig) + + // Load enchantment conflicts config + val conflictConfig = reloadResource(enchantConflicConfigName) ?: return + // Read conflicts from config and material group manager + conflictManager = EnchantConflictManager() + conflictManager.prepareConflicts(conflictConfig,itemGroupsManager) server.pluginManager.registerEvents( AnvilEventListener(), this ) + + } + + private fun reloadResource(resourceName: String, + hardFailSafe:Boolean = true): YamlConfiguration?{ + // Save default resource + val file = File(dataFolder,resourceName) + if(!file.exists()){ + saveResource(resourceName,false) + } + // Load resource + val yamlConfig = YamlConfiguration() + try { + val configReader = FileReader(file) + yamlConfig.load(configReader) + } catch (test: Exception){ + if(hardFailSafe){ + // This is important and may impact gameplay if it does not load. + // Failsafe is to stop the plugin + logger.severe("Resource $resourceName Could not be load or reload.") + logger.severe("Disabling plugin.") + Bukkit.getPluginManager().disablePlugin(this) + }else{ + logger.warning("Resource $resourceName Could not be load or reload.") + } + return null + } + return yamlConfig } } diff --git a/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt b/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt index 093e543..55c8c95 100644 --- a/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt +++ b/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt @@ -62,7 +62,7 @@ object EnchantmentUtil { enchantment2.conflictsWith(enchantment1) } if (hasConflict) { - return hasConflict + return true } } return false diff --git a/src/main/kotlin/xyz/alexcrea/group/EnchantConflictGroup.kt b/src/main/kotlin/xyz/alexcrea/group/EnchantConflictGroup.kt index 5405ee0..a05d028 100644 --- a/src/main/kotlin/xyz/alexcrea/group/EnchantConflictGroup.kt +++ b/src/main/kotlin/xyz/alexcrea/group/EnchantConflictGroup.kt @@ -13,15 +13,13 @@ class EnchantConflictGroup(val cantConflict: MaterialGroup, val minBeforeBlock: } fun allow(item: ItemStack) : Boolean{ - if(enchantments.size > minBeforeBlock){ + if(enchantments.size < minBeforeBlock){ return true } + if(cantConflict.contain(item.type)){ return true } - if(minBeforeBlock == 0){ - return false - } // Count the amount of enchantment that are in the list var enchantAmount = 0 @@ -36,5 +34,9 @@ class EnchantConflictGroup(val cantConflict: MaterialGroup, val minBeforeBlock: return true } + fun isEnchantEmpty(): Boolean { + return enchantments.size == 0 + } + } \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/group/EnchantConflictManager.kt b/src/main/kotlin/xyz/alexcrea/group/EnchantConflictManager.kt new file mode 100644 index 0000000..669ba0e --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/group/EnchantConflictManager.kt @@ -0,0 +1,113 @@ +package xyz.alexcrea.group + +import io.delilaheve.UnsafeEnchants +import org.bukkit.NamespacedKey +import org.bukkit.configuration.ConfigurationSection +import org.bukkit.configuration.file.YamlConfiguration +import org.bukkit.enchantments.Enchantment +import org.bukkit.inventory.ItemStack +import kotlin.collections.ArrayList + +class EnchantConflictManager { + + companion object { + // Path for the enchantments list + private const val ENCH_LIST_PATH = "enchantments" + // Path for group list related to the conflict + private const val CONFLICT_GROUP_PATH = "notAffectedGroups" + // Path for the maximum number of enchantment before validating the conflict + private const val ENCH_MAX_PATH = "maxEnchantmentBeforeConflict" + // Default name for an empty Material group + private val DEFAULT_EMPTY_GROUP = IncludeGroup("empty") + // Default name for a joining group + private const val DEFAULT_GROUP_NAME = "joinedGroup" + } + + private lateinit var conflictList: ArrayList + + // Read and prepare all conflict + fun prepareConflicts(config: YamlConfiguration, itemManager: ItemGroupManager){ + conflictList = ArrayList() + + val keys = config.getKeys(false) + for (key in keys) { + val section = config.getConfigurationSection(key)!! + val conflict = createConflict(section,itemManager,key) + + conflictList.add(conflict) + } + + } + + // create and read a conflict from a yaml section + private fun createConflict(section: ConfigurationSection, + itemManager: ItemGroupManager, + conflictName: String): EnchantConflictGroup { + + // Create conflict + val conflict = createConflictObject(section,itemManager,conflictName) + // Read and add enchantment to conflict + val enchantList = section.getStringList(ENCH_LIST_PATH) + for (enchantName in enchantList) { + val enchantKey = NamespacedKey.minecraft(enchantName) + val enchant = Enchantment.getByKey(enchantKey) + if(enchant == null){ + UnsafeEnchants.instance.logger.warning("Enchantment $enchantName do not exist but was asked for conflict $conflictName") + continue + } + conflict.addEnchantment(enchant) + } + if(conflict.isEnchantEmpty()){ + UnsafeEnchants.instance.logger.warning("Conflict $conflictName do not have valid enchantment, it will not work") + } + + return conflict + } + + private fun createConflictObject(section: ConfigurationSection, + itemManager: ItemGroupManager, + conflictName: String): EnchantConflictGroup { + // Get the maximum number of enchantment before validating the conflict + var minBeforeBlock = section.getInt(ENCH_MAX_PATH,0) + if(minBeforeBlock < 0){ + minBeforeBlock = 0 + UnsafeEnchants.instance.logger.warning("Conflict $conflictName have an invalid value of $ENCH_MAX_PATH") + UnsafeEnchants.instance.logger.warning("It should be more or equal to 0. default to 0") + } + // Find or create the selected group for the conflict + val groupList = section.getStringList(CONFLICT_GROUP_PATH) + val finalGroup: MaterialGroup + if(groupList.size < 1){ + finalGroup = DEFAULT_EMPTY_GROUP + }else if(groupList.size == 1){ + finalGroup = findGroup(groupList[0], itemManager, conflictName) + }else{ + finalGroup = IncludeGroup(DEFAULT_GROUP_NAME) + for (groupName in groupList) { + finalGroup.addToPolicy(findGroup(groupName, itemManager, conflictName)) + } + } + // Return conflict + return EnchantConflictGroup(finalGroup, minBeforeBlock) + } + + private fun findGroup(groupName: String,itemManager: ItemGroupManager, conflictName: String): MaterialGroup { + val group = itemManager.get(groupName) + if(group == null){ + UnsafeEnchants.instance.logger.warning("Group $groupName do not exist but is ask by conflict $conflictName") + return DEFAULT_EMPTY_GROUP + } + + return group + } + + fun isConflicting(item: ItemStack): Boolean{ + for (conflict in conflictList) { + if(!conflict.allow(item)) { + return true + } + } + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/group/ItemGroupManager.kt b/src/main/kotlin/xyz/alexcrea/group/ItemGroupManager.kt index e56f6d4..c901721 100644 --- a/src/main/kotlin/xyz/alexcrea/group/ItemGroupManager.kt +++ b/src/main/kotlin/xyz/alexcrea/group/ItemGroupManager.kt @@ -102,6 +102,11 @@ class ItemGroupManager { } + // Get the selected group or return null if it doesn't exist + fun get(groupName: String): MaterialGroup? { + return groupMap[groupName] + } + } enum class GroupType(private val groupID: String) {