diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index d8e79b5..828e9fd 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -34,6 +34,9 @@ class AnvilEventListener : Listener { // Permission node required for the plugin to take over enchantment combination private val requirePermission: Permission get() = Permission(UnsafeEnchants.unsafePermission) + // Permission node to bypass illegal group check + private val bypassPermission: Permission + get() = Permission(UnsafeEnchants.unsafeBypassPermission) /** * Event handler logic for when an anvil contains items to be combined @@ -85,7 +88,10 @@ class AnvilEventListener : Listener { val player = event.whoClicked as? Player ?: return val inventory = event.inventory as? AnvilInventory ?: return val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return - if (output.findEnchantments().hasConflicts() && !player.hasPermission(requirePermission)) { return } + if(!player.hasPermission(bypassPermission)){ + if (output.findEnchantments().hasConflicts() && !player.hasPermission(requirePermission)) { return } + + } if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return } event.result = Event.Result.ALLOW } diff --git a/src/main/kotlin/io/delilaheve/UnsafeEnchants.kt b/src/main/kotlin/io/delilaheve/UnsafeEnchants.kt index 9fd73b4..9c0fb02 100644 --- a/src/main/kotlin/io/delilaheve/UnsafeEnchants.kt +++ b/src/main/kotlin/io/delilaheve/UnsafeEnchants.kt @@ -1,7 +1,9 @@ package io.delilaheve import io.delilaheve.util.ConfigOptions +import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.plugin.java.JavaPlugin +import xyz.alexcrea.group.ItemGroupManager /** * Bukkit/Spigot/Paper plugin to alter enchantment max @@ -12,8 +14,15 @@ class UnsafeEnchants : JavaPlugin() { companion object { // Permission string required to use the plugin's features const val unsafePermission = "ue.unsafe" + // Permission string required to bypass illegal enchantment group + const val unsafeBypassPermission = "ue.unsafe_all" + // Item Grouping Configuration file name + const val itemGroupingConfigName = "item_groups.yml" + // Current plugin instance lateinit var instance: UnsafeEnchants + // Current item grouping configuration instance + lateinit var itemGroups: ItemGroupManager /** * Logging handler @@ -31,6 +40,21 @@ class UnsafeEnchants : JavaPlugin() { override fun onEnable() { 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) + } + // Read material groups from config + itemGroups = ItemGroupManager() + itemGroups.prepareGroups(itemGroupConfig) + server.pluginManager.registerEvents( AnvilEventListener(), this diff --git a/src/main/kotlin/xyz/alexcrea/group/ExcludeGroup.kt b/src/main/kotlin/xyz/alexcrea/group/ExcludeGroup.kt new file mode 100644 index 0000000..d12378e8 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/group/ExcludeGroup.kt @@ -0,0 +1,12 @@ +package xyz.alexcrea.group + +import org.bukkit.Material + +class ExcludeGroup(name: String): IncludeGroup(name) { + + override fun contain(mat: Material): Boolean { + Material.POLISHED_DIORITE + return !super.contain(mat) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/group/IncludeGroup.kt b/src/main/kotlin/xyz/alexcrea/group/IncludeGroup.kt new file mode 100644 index 0000000..2b574d6 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/group/IncludeGroup.kt @@ -0,0 +1,42 @@ +package xyz.alexcrea.group + +import org.bukkit.Material + +open class IncludeGroup(private val name: String): MaterialGroup{ + private val includedMaterial = HashSet() + private val includedGroup = HashSet() + + override fun contain(mat: Material): Boolean { + if(mat in includedMaterial){ + return true + } + for (materialGroup in includedGroup.iterator()) { + if(materialGroup.contain(mat)){ + return true + } + } + return false + } + + override fun isReferencing(other: MaterialGroup): Boolean { + for (materialGroup in includedGroup.iterator()) { + if((materialGroup == other) || (materialGroup.isReferencing(other))){ + return true + } + } + return false + } + + override fun addToPolicy(mat: Material) { + includedMaterial.add(mat) + } + + override fun addToPolicy(other: MaterialGroup) { + includedGroup.add(other) + } + + override fun getName(): String { + return name + } + +} \ 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 new file mode 100644 index 0000000..5a6a3e6 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/group/ItemGroupManager.kt @@ -0,0 +1,118 @@ +package xyz.alexcrea.group + +import io.delilaheve.UnsafeEnchants +import org.bukkit.Material +import org.bukkit.configuration.ConfigurationSection +import org.bukkit.configuration.file.YamlConfiguration +import java.util.* +import kotlin.collections.HashMap + +class ItemGroupManager { + + companion object { + // Path for group type + private const val GROUP_TYPE_PATH = "type" + private const val MATERIAL_LIST_PATH = "items" + private const val GROUP_LIST_PATH = "groups" + } + + private lateinit var groupMap : HashMap + + // Read and create material groups + fun prepareGroups(config: YamlConfiguration){ + groupMap = HashMap() + + val keys = config.getKeys(false) + for (key in keys) { + if(groupMap.containsKey(key)) + continue + createGroup(config, keys, key) + } + } + + // Create group by key + private fun createGroup(config: YamlConfiguration, + keys: Set, + key: String): MaterialGroup{ + val groupSection = config.getConfigurationSection(key)!! + val groupType = groupSection.getString(GROUP_TYPE_PATH,null) + + // Create Material group according to the group type + val group: MaterialGroup + if(GroupType.EXCLUDE.equal(groupType)){ + group = ExcludeGroup(key) + }else { + group = IncludeGroup(key) + if(!GroupType.INCLUDE.equal(groupType)){ + UnsafeEnchants.instance.logger.warning("Group $key have an invalid group type. default to Include.") + } + } + + groupMap[key] = group + readGroup(group, groupSection, config, keys) + return group + } + + // Read Group elements + private fun readGroup(group: MaterialGroup, + groupSection: ConfigurationSection, + config: YamlConfiguration, + keys: Set){ + // Read material to include in this group policy + val materialList = groupSection.getStringList(MATERIAL_LIST_PATH) + for (materialTemp in materialList) { + val materialName = materialTemp.uppercase(Locale.getDefault()) + val material = Material.getMaterial(materialName) + if(material == null){ + UnsafeEnchants.instance.logger.warning( + "Unknown material $materialTemp on group ${group.getName()}") + continue + } + group.addToPolicy(material) + } + + // Read group to include in this group policy. + // please note the group name is case-sensitive. + val groupList = groupSection.getStringList(GROUP_LIST_PATH) + for (groupName in groupList) { + if(groupName !in keys){ + UnsafeEnchants.instance.logger.warning( + "Group $groupName do not exist but is included in group ${group.getName()}") + continue + } + // Get other group or create it if not yet created + val otherGroup = if(!groupMap.containsKey(groupName)){ + createGroup(config,keys,groupName) + }else{ + groupMap[groupName]!! + } + // Avoid self reference or it will create an infinite loop + if(otherGroup.isReferencing(group)){ + UnsafeEnchants.instance.logger.warning( + "Group $groupName is on a reference loop with group ${group.getName()} !") + UnsafeEnchants.instance.logger.warning( + "Please fix it in your item_groups config or the plugin will probably not work as expected.") + continue + } + + group.addToPolicy(otherGroup) + } + + } + +} + +enum class GroupType(private val groupID: String) { + + INCLUDE("include"), + EXCLUDE("exclude") + ; + + // Test if string is equal to the groupID of this enum + fun equal(toTest: String?): Boolean{ + if(toTest == null) + return false + return groupID.contentEquals(toTest.lowercase(Locale.getDefault())) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/group/MaterialGroup.kt b/src/main/kotlin/xyz/alexcrea/group/MaterialGroup.kt new file mode 100644 index 0000000..180544b --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/group/MaterialGroup.kt @@ -0,0 +1,22 @@ +package xyz.alexcrea.group + +import org.bukkit.Material + +interface MaterialGroup { + + // Get if a material is allowed following the group policy + fun contain(mat : Material): Boolean + + // Get if a group is referenced by this + fun isReferencing(other : MaterialGroup): Boolean + + // Push a material to this group to follow this group policy + fun addToPolicy(mat : Material) + + // Push a group to this group to follow this group policy + fun addToPolicy(other : MaterialGroup) + + // Get the group name in case something is wrong + fun getName(): String + +} \ No newline at end of file diff --git a/src/main/resources/item_groups.yml b/src/main/resources/item_groups.yml new file mode 100644 index 0000000..095dd2c --- /dev/null +++ b/src/main/resources/item_groups.yml @@ -0,0 +1,27 @@ +# Please note this config use spigot material names. +# It should match minecraft name in most case, maybe every case, but I can't be sure +# In case there an issue with material name, you can found them here: +# https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html + +# An empty Exclude group exclude nothing, so it contain everything +everything: + type: exclude + +# An empty include group will include nothing +nothing: + type: include + +# This group is an example of a group including only stone and polished granite +example_include: + type: include + items: + - stone + - polished_granite + +# This group contain everything except polished granite and elements of example_include +example_exclude: + type: exclude + items: + - polished_granite + groups: + - example_include diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index fad8c4a..b1be71d 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -8,4 +8,7 @@ author: DelilahEve permissions: ue.unsafe: default: true - description: Allow player to combine "unsafe" enchants + description: Allow player to combine allowed "unsafe" enchants + ue.unsafe_all: + default: false + description: Allow player to combine every "unsafe" enchants \ No newline at end of file