Work with eco item (#106)

Use material key instead of material enum

This is made with the goal of making eco item work as independant item.
so item type key now depend on eco item's id 

Known issue: EcoEnchant target group still do not has the eco item id inside it and cannot be handled properly by custom anvil
This commit is contained in:
alexcrea 2026-04-21 15:18:37 +02:00 committed by GitHub
commit e30f09120d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 301 additions and 126 deletions

View file

@ -348,7 +348,7 @@ object ConfigOptions {
*
* @return the current enchantment limit. -1 if none
*/
fun getEnchantCountLimit(type: Material): Int? {
fun getEnchantCountLimit(type: NamespacedKey): Int? {
val limit = materialEnchantCountLimit(type)
if(limit != null) return limit
@ -362,8 +362,8 @@ object ConfigOptions {
*
* @return The current enchantment limit. -1 if none
*/
private fun materialEnchantCountLimit(type: Material): Int? {
val path = "$ENCHANT_COUNT_LIMIT_ITEMS.${type.key.key.lowercase()}"
private fun materialEnchantCountLimit(type: NamespacedKey): Int? {
val path = "$ENCHANT_COUNT_LIMIT_ITEMS.${type.key.lowercase()}"
if(!ConfigHolder.DEFAULT_CONFIG.config.isInt(path))
return null

View file

@ -6,6 +6,7 @@ import org.bukkit.inventory.ItemStack
import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.group.ConflictType
import xyz.alexcrea.cuanvil.util.MaterialUtil.customType
import kotlin.math.max
import kotlin.math.min
@ -34,7 +35,7 @@ object EnchantmentUtil {
val bypassFuse = player.hasPermission(CustomAnvil.bypassFusePermission)
val bypassLevel = player.hasPermission(CustomAnvil.bypassLevelPermission)
var maxEnchantCount = ConfigOptions.getEnchantCountLimit(item.type)
var maxEnchantCount = ConfigOptions.getEnchantCountLimit(item.customType)
if(maxEnchantCount == null || maxEnchantCount < 0) maxEnchantCount = Int.MAX_VALUE
val allowed = other.filter { (enchantment, _) -> enchantment.isAllowed(player) }

View file

@ -4,6 +4,7 @@ import org.bukkit.Material.ENCHANTED_BOOK
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Damageable
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.util.MaterialUtil.customType
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
@ -90,5 +91,5 @@ object ItemUtil {
*/
fun ItemStack.canMergeWith(
other: ItemStack?
) = (other != null) && (type == other.type || (other.isEnchantedBook()))
) = (other != null) && (customType == other.customType || (other.isEnchantedBook()))
}

View file

@ -145,7 +145,7 @@ object DataPackDependency {
CustomAnvil.instance.logger.warning("Could not find material $name for item group $groupName")
continue
}
group.addToPolicy(mat)
group.addToPolicy(mat.key)
}
for (name in section.getStringList("groups")) {
val otherGroup = MaterialGroupApi.getGroup(name)

View file

@ -0,0 +1,34 @@
package xyz.alexcrea.cuanvil.dependency.plugins
import com.willfp.ecoitems.items.EcoItem
import com.willfp.ecoitems.items.EcoItems
import com.willfp.ecoitems.items.ecoItem
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.inventory.ItemStack
object EcoItemDependencyUtil {
fun ecoItemNamespace(item: ItemStack): NamespacedKey? {
val ecoi = item.ecoItem ?: return null
return ecoi.id
}
fun ecoItemFromKey(key: NamespacedKey): EcoItem? {
return EcoItems.getByID(key.toString())
}
fun ecoItemMaterialFromKey(key: NamespacedKey): Material? {
val ecoi = ecoItemFromKey(key) ?: return null
return ecoi.itemStack.type
}
fun newEcoItemstack(key: NamespacedKey): ItemStack? {
val ecoi = ecoItemFromKey(key) ?: return null
return ecoi.itemStack
}
}

View file

@ -102,15 +102,15 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin)
private fun writeMissingGroups(){
// Write group that do not exist on custom anvil.
val shield = IncludeGroup("shield")
shield.addToPolicy(Material.SHIELD)
shield.addToPolicy(Material.SHIELD.key)
MaterialGroupApi.addMaterialGroup(shield)
val elytra = IncludeGroup("elytra")
elytra.addToPolicy(Material.ELYTRA)
elytra.addToPolicy(Material.ELYTRA.key)
MaterialGroupApi.addMaterialGroup(elytra)
val trinkets = IncludeGroup("trinkets")
trinkets.addToPolicy(Material.ROTTEN_FLESH)
trinkets.addToPolicy(Material.ROTTEN_FLESH.key)
MaterialGroupApi.addMaterialGroup(trinkets)
}

View file

@ -1,7 +1,8 @@
package xyz.alexcrea.cuanvil.group
import org.bukkit.Material
import java.util.*
import org.bukkit.NamespacedKey
import xyz.alexcrea.cuanvil.util.MaterialUtil
abstract class AbstractMaterialGroup(private val name: String) {
protected val includedMaterial by lazy { createDefaultSet() }
@ -9,12 +10,12 @@ abstract class AbstractMaterialGroup(private val name: String) {
/**
* Get the group default set
*/
protected abstract fun createDefaultSet(): EnumSet<Material>
protected abstract fun createDefaultSet(): MutableSet<NamespacedKey>
/**
* Get if a material is allowed following the group policy
*/
open fun contain(mat: Material): Boolean {
open fun contain(mat: NamespacedKey): Boolean {
return mat in getMaterials()
}
@ -27,13 +28,13 @@ abstract class AbstractMaterialGroup(private val name: String) {
* Push a material to this group to follow this group policy
* @return this instance.
*/
abstract fun addToPolicy(mat: Material): AbstractMaterialGroup
abstract fun addToPolicy(type: NamespacedKey): AbstractMaterialGroup
/**
* Push a list of material to this group to follow this group policy
* @return this instance.
*/
fun addAll(vararg materials: Material): AbstractMaterialGroup {
fun addAll(vararg materials: NamespacedKey): AbstractMaterialGroup {
for (material in materials) {
addToPolicy(material)
}
@ -60,19 +61,19 @@ abstract class AbstractMaterialGroup(private val name: String) {
/**
* Get the group contained material as a set
*/
abstract fun getMaterials(): EnumSet<Material>
abstract fun getMaterials(): Set<NamespacedKey>
/**
* Get the group non-inherited material as a set
*/
open fun getNonGroupInheritedMaterials(): EnumSet<Material> {
open fun getNonGroupInheritedMaterials(): Set<NamespacedKey> {
return includedMaterial
}
/**
* Get the group non-inherited material as a set
*/
open fun setNonGroupInheritedMaterials(materials: EnumSet<Material>) {
open fun setNonGroupInheritedMaterials(materials: Set<NamespacedKey>) {
this.includedMaterial.clear()
this.includedMaterial.addAll(materials)
}
@ -102,8 +103,9 @@ abstract class AbstractMaterialGroup(private val name: String) {
// Test inner material
val matIterator = includedMaterial.iterator()
while (matIterator.hasNext()) {
val material = matIterator.next()
if (material.isAir) continue
val key = matIterator.next()
val material = MaterialUtil.getMatFromKey(key)
if (material == null || material.isAir) continue
return material
}
// Test included group representative material

View file

@ -2,6 +2,7 @@ package xyz.alexcrea.cuanvil.group
import io.delilaheve.CustomAnvil
import org.bukkit.Material
import org.bukkit.NamespacedKey
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
class EnchantConflictGroup(
@ -53,7 +54,7 @@ class EnchantConflictGroup(
return canBypassByBeforeLevel(enchants) || canBypassByAfterLevel(enchants)
}
fun allowed(enchants: Map<CAEnchantment, Int>, mat: Material): Boolean {
fun allowed(enchants: Map<CAEnchantment, Int>, mat: NamespacedKey): Boolean {
if (enchantments.size < minBeforeBlock) {
CustomAnvil.verboseLog("Conflicting bc of to many enchantments")
return true

View file

@ -8,6 +8,7 @@ import org.bukkit.inventory.ItemStack
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
import xyz.alexcrea.cuanvil.util.MaterialUtil.customType
import java.util.*
import kotlin.collections.set
@ -220,8 +221,8 @@ class EnchantConflictManager {
item: ItemStack,
newEnchant: CAEnchantment
): ConflictType {
val mat = item.type
CustomAnvil.verboseLog("Testing conflict for ${newEnchant.key} on ${mat.key}")
val type = item.customType
CustomAnvil.verboseLog("Testing conflict for ${newEnchant.key} on ${type}")
val conflictList = newEnchant.conflicts
var result = ConflictType.NO_CONFLICT
@ -232,7 +233,7 @@ class EnchantConflictManager {
continue
}
val allowed = conflict.allowed(appliedEnchants, mat)
val allowed = conflict.allowed(appliedEnchants, type)
CustomAnvil.verboseLog("Was against $conflict and conflicting: ${!allowed} ")
if (!allowed) {
if (conflict.getEnchants().size <= 1) {
@ -248,7 +249,7 @@ class EnchantConflictManager {
val immutableEnchants = Collections.unmodifiableMap(appliedEnchants)
for (appliedEnchant in appliedEnchants.keys) {
if (appliedEnchant is AdditionalTestEnchantment) {
val doConflict = appliedEnchant.isEnchantConflict(immutableEnchants, mat)
val doConflict = appliedEnchant.isEnchantConflict(immutableEnchants, type)
if (doConflict) {
CustomAnvil.verboseLog("Big conflict by additional test, stopping")
return ConflictType.ENCHANTMENT_CONFLICT
@ -260,7 +261,7 @@ class EnchantConflictManager {
if ((result != ConflictType.ITEM_CONFLICT) && (newEnchant is AdditionalTestEnchantment)) {
val partialItem = createPartialResult(item, immutableEnchants)
if (newEnchant.isItemConflict(immutableEnchants, mat, partialItem)) {
if (newEnchant.isItemConflict(immutableEnchants, type, partialItem)) {
return ConflictType.ITEM_CONFLICT
}

View file

@ -1,11 +1,12 @@
package xyz.alexcrea.cuanvil.group
import org.bukkit.Material
import org.bukkit.NamespacedKey
import java.util.*
class ExcludeGroup(name: String) : AbstractMaterialGroup(name) {
override fun createDefaultSet(): EnumSet<Material> {
return EnumSet.allOf(Material::class.java)
override fun createDefaultSet(): MutableSet<NamespacedKey> {
return NegativeSet(HashSet())
}
private var includedGroup: MutableSet<AbstractMaterialGroup> = HashSet()
@ -20,9 +21,9 @@ class ExcludeGroup(name: String) : AbstractMaterialGroup(name) {
return false
}
override fun addToPolicy(mat: Material): ExcludeGroup {
includedMaterial.remove(mat)
groupItems.remove(mat)
override fun addToPolicy(type: NamespacedKey): ExcludeGroup {
includedMaterial.remove(type)
groupItems.remove(type)
return this
}
@ -60,7 +61,7 @@ class ExcludeGroup(name: String) : AbstractMaterialGroup(name) {
}
}
override fun getMaterials(): EnumSet<Material> {
override fun getMaterials(): MutableSet<NamespacedKey> {
return groupItems
}

View file

@ -1,11 +1,12 @@
package xyz.alexcrea.cuanvil.group
import org.bukkit.Material
import org.bukkit.NamespacedKey
import java.util.*
class IncludeGroup(name: String) : AbstractMaterialGroup(name) {
override fun createDefaultSet(): EnumSet<Material> {
return EnumSet.noneOf(Material::class.java)
override fun createDefaultSet(): MutableSet<NamespacedKey> {
return HashSet()
}
private var includedGroup: MutableSet<AbstractMaterialGroup> = HashSet()
@ -20,9 +21,9 @@ class IncludeGroup(name: String) : AbstractMaterialGroup(name) {
return false
}
override fun addToPolicy(mat: Material): IncludeGroup {
includedMaterial.add(mat)
groupItems.add(mat)
override fun addToPolicy(type: NamespacedKey): IncludeGroup {
includedMaterial.add(type)
groupItems.add(type)
return this
}
@ -47,7 +48,7 @@ class IncludeGroup(name: String) : AbstractMaterialGroup(name) {
}
}
override fun setNonGroupInheritedMaterials(materials: EnumSet<Material>) {
override fun setNonGroupInheritedMaterials(materials: Set<NamespacedKey>) {
super.setNonGroupInheritedMaterials(materials)
updateMaterials()
@ -66,7 +67,7 @@ class IncludeGroup(name: String) : AbstractMaterialGroup(name) {
}
}
override fun getMaterials(): EnumSet<Material> {
override fun getMaterials(): MutableSet<NamespacedKey> {
return groupItems
}

View file

@ -94,7 +94,7 @@ class ItemGroupManager {
}
continue
}
group.addToPolicy(material)
group.addToPolicy(material.key)
}
// Read group to include in this group policy.

View file

@ -0,0 +1,51 @@
package xyz.alexcrea.cuanvil.group
class NegativeSet<T>(val negate: MutableSet<T>) : MutableSet<T> {
override fun iterator(): MutableIterator<T> {
TODO("Not yet implemented") // can't be implemented I guess
}
override fun add(element: T): Boolean {
return negate.remove(element)
}
override fun remove(element: T): Boolean {
return negate.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
return negate.removeAll(elements)
}
override fun removeAll(elements: Collection<T>): Boolean {
return negate.addAll(elements)
}
override fun retainAll(elements: Collection<T>): Boolean {
TODO("Not yet implemented")
}
override fun clear() {
TODO("Not yet implemented")
}
override fun isEmpty(): Boolean {
TODO("Not yet implemented")
}
override val size get() = TODO("Not yet implemented")
override fun contains(element: T): Boolean {
return !negate.contains(element)
}
override fun containsAll(elements: Collection<T>): Boolean {
for (elm in elements) {
if(negate.contains(elm)) return false
}
return true
}
}

View file

@ -24,6 +24,7 @@ import org.bukkit.inventory.meta.ItemMeta
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.util.*
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
import java.util.concurrent.atomic.AtomicInteger
@ -42,10 +43,6 @@ class PrepareAnvilListener : Listener {
var IS_EMPTY_TEST = false
}
private fun ItemStack?.isAir(): Boolean {
return this == null || this.type.isAir || this.amount == 0
}
/**
* Event handler logic for when an anvil contains items to be combined
*/
@ -96,7 +93,7 @@ class PrepareAnvilListener : Listener {
if (testCustomRecipe(event, inventory, player, first, second)) return
// Test rename lonely item
val isAir = second.isAir()
val isAir = second.isAir
CustomAnvil.verboseLog("checking air in main logic: $isAir")
if (isAir) {
doRenaming(event, inventory, player, first)
@ -121,7 +118,7 @@ class PrepareAnvilListener : Listener {
}
private fun isImmutable(item: ItemStack?): Boolean {
if (item.isAir()) return false
if (item.isAir) return false
val meta = item!!.itemMeta
return meta != null &&
@ -172,7 +169,7 @@ class PrepareAnvilListener : Listener {
if (finalResult == null) return false
event.result = finalResult.result
if (finalResult.result.isAir()) return false
if (finalResult.result.isAir) return false
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost, true)
return true
@ -198,7 +195,7 @@ class PrepareAnvilListener : Listener {
if (finalResult == null) return
event.result = finalResult.result
if (finalResult.result.isAir()) return
if (finalResult.result.isAir) return
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost)
}
@ -286,7 +283,7 @@ class PrepareAnvilListener : Listener {
if (finalResult == null) return
event.result = finalResult.result
if (finalResult.result.isAir()) return
if (finalResult.result.isAir) return
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost)
}
@ -331,7 +328,7 @@ class PrepareAnvilListener : Listener {
if (finalResult == null) return false
event.result = finalResult.result
if (finalResult.result.isAir()) return false
if (finalResult.result.isAir) return false
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, finalResult.levelCost)
return true
@ -351,7 +348,7 @@ class PrepareAnvilListener : Listener {
result = AnvilLoreEditUtil.tryLoreEditByPaper(player, first, second, xpCost)
}
if (result.isAir() || first == result) {
if (result.isAir || first == result) {
CustomAnvil.log("lore edit, But input is same as output")
event.result = null
return false

View file

@ -7,6 +7,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant
import xyz.alexcrea.cuanvil.util.AnvilUseType
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
class AnvilCustomRecipe(
val name: String,
@ -80,11 +81,9 @@ class AnvilCustomRecipe(
}
fun validate(): Boolean {
return (leftItem != null) && !(leftItem!!.type.isAir) && (leftItem!!.amount > 0) &&
//(rightItem != null) && !(rightItem!!.type.isAir) && (rightItem!!.amount > 0) &&
((rightItem == null) || (!(rightItem!!.type.isAir) && (rightItem!!.amount > 0))) &&
(resultItem != null) && !(resultItem!!.type.isAir) && (resultItem!!.amount > 0)
return !leftItem.isAir &&
(rightItem == null || !resultItem.isAir) &&
!resultItem.isAir
}
fun saveToFile(writeFile: Boolean, doBackup: Boolean) {
@ -162,7 +161,7 @@ class AnvilCustomRecipe(
CustomAnvil.verboseLog("Testing $name $leftItem")
// We assume this function can be call only if leftItem != null
// Test is valid
// Test if valid
if (!validate()) return false
val leftSimilar = leftItem!!.isSimilar(item1)

View file

@ -0,0 +1,61 @@
package xyz.alexcrea.cuanvil.util
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.inventory.ItemStack
import xyz.alexcrea.cuanvil.dependency.plugins.EcoItemDependencyUtil
object MaterialUtil {
val ItemStack?.isAir: Boolean
get() {
return this == null || this.type.isAir || this.amount == 0
}
val NamespacedKey?.isAir: Boolean
get() {
return Material.AIR.key == this
}
private val HasEcoItem = Bukkit.getPluginManager().isPluginEnabled("EcoItems")
val ItemStack.customType: NamespacedKey
get() {
if(HasEcoItem) {
val result = EcoItemDependencyUtil.ecoItemNamespace(this)
if(result != null) return result
}
return this.type.key
}
private fun bukkitMaterialFromKey(key: NamespacedKey): Material? {
//TODO on paper only transition Registry.MATERIAL.get(key)
return Material.matchMaterial(key.toString())
}
fun getMatFromKey(key: NamespacedKey): Material? {
if(HasEcoItem) {
val result = EcoItemDependencyUtil.ecoItemMaterialFromKey(key)
if(result != null) return result
}
return bukkitMaterialFromKey(key)
}
fun itemFromKey(key: NamespacedKey): ItemStack {
if(HasEcoItem) {
val result = EcoItemDependencyUtil.newEcoItemstack(key)
if(result != null) return result
}
return ItemStack(bukkitMaterialFromKey(key)!!)
}
fun materialExist(key: NamespacedKey): Boolean {
return getMatFromKey(key) != null
}
}

View file

@ -3,6 +3,7 @@ package xyz.alexcrea.cuanvil.util
import org.bukkit.configuration.ConfigurationSection
import org.bukkit.inventory.ItemStack
import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.util.MaterialUtil.customType
object UnitRepairUtil {
@ -22,7 +23,7 @@ object UnitRepairUtil {
if (other == null) return null
val config = ConfigHolder.UNIT_REPAIR_HOLDER.config
// Get configuration section if exist
val otherName = other.type.name.lowercase()
val otherName = other.customType.key.lowercase()
var section = config.getConfigurationSection(otherName)
if (section == null) {
section = config.getConfigurationSection(otherName.uppercase())
@ -44,7 +45,7 @@ object UnitRepairUtil {
* If value is set to less than or equal to 0 then it will be set to default
*/
private fun getRepairAmount(item: ItemStack, section: ConfigurationSection, default: Double): Double? {
val itemName = item.type.name.lowercase()
val itemName = item.customType.key.lowercase()
val repairValue = if (section.isDouble(itemName)) {
section.getDouble(itemName)
} else if (section.isDouble(itemName.uppercase())) {