Compare commits

..

2 commits

Author SHA1 Message Date
1e2acb6f48
expose more enchantment function to API & use them
Some checks are pending
Java CI with Gradle / build (push) Waiting to run
2026-06-30 07:47:41 +02:00
72a7860d93
mark superenchant as bulk and clear optimized 2026-06-30 03:44:37 +02:00
8 changed files with 122 additions and 73 deletions

View file

@ -5,6 +5,7 @@ import io.delilaheve.util.ConfigOptions;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
@ -156,6 +157,7 @@ public class EnchantmentApi {
/** /**
* Get every registered custom anvil enchantments. * Get every registered custom anvil enchantments.
*
* @return An immutable map of enchantment key as map key and custom anvil enchantment as value. * @return An immutable map of enchantment key as map key and custom anvil enchantment as value.
*/ */
@NotNull @NotNull
@ -165,6 +167,7 @@ public class EnchantmentApi {
/** /**
* Write the default level and rarity configuration of the enchantment. * Write the default level and rarity configuration of the enchantment.
*
* @param enchantment The enchantment to write default configuration * @param enchantment The enchantment to write default configuration
* @param override If it should override old configuration * @param override If it should override old configuration
* @return Return false if override is false and a configuration exist. true otherwise. * @return Return false if override is false and a configuration exist. true otherwise.
@ -217,7 +220,10 @@ public class EnchantmentApi {
} }
/** /**
* Add a bulk get operator. * Add a bulk get operator. (not needed for proper "bukkit" enchantments)
* <p>
* Do not forget to mark your enchantments as {@link CAEnchantment#isGetOptimised() Get Optimized}
*
* @param operation An optimised get enchantments operation * @param operation An optimised get enchantments operation
*/ */
public static void addBulkGet(@NotNull BulkGetEnchantOperation operation) { public static void addBulkGet(@NotNull BulkGetEnchantOperation operation) {
@ -226,10 +232,60 @@ public class EnchantmentApi {
/** /**
* Add a bulk clean operator. * Add a bulk clean operator.
* @param operation An optimised clean enchantments operation *
* @param operation An optimised clean enchantments operation (not needed for proper "bukkit" enchantments)
* <p>
* Do not forget to mark your enchantments as {@link CAEnchantment#isCleanOptimised() Clean Optimized}
*/ */
public static void addBulkClean(@NotNull BulkCleanEnchantOperation operation) { public static void addBulkClean(@NotNull BulkCleanEnchantOperation operation) {
CAEnchantmentRegistry.getInstance().getOptimisedCleanOperators().add(operation); CAEnchantmentRegistry.getInstance().getOptimisedCleanOperators().add(operation);
} }
/**
* Get all the enchantments of an item
*
* @param item The item to get the enchantment from
* @return A map of key of enchantment, value the level of all the enchantments of the item
* @since 1.17.6
*/
public static Map<CAEnchantment, Integer> getEnchantments(@NotNull ItemStack item) {
return CAEnchantment.getEnchants(item);
}
/**
* Set all the enchantments to an item. Clearing previous enchantments
*
* @param item The item to get the enchantment from
* @param enchants A map of key of enchantment, value the level of all the enchantments
* @since 1.17.6
*/
public static void setEnchantments(@NotNull ItemStack item, @NotNull Map<CAEnchantment, Integer> enchants) {
clearEnchantments(item);
addEnchantments(item, enchants);
}
/**
* Add enchantment with there respective level.
* If the enchantment is already present it will be overridden to the new level
*
* @param item The item to get the enchantment from
* @param enchants A map of key of enchantment, value the level of the new enchantments
* @since 1.17.6
*/
public static void addEnchantments(@NotNull ItemStack item, @NotNull Map<CAEnchantment, Integer> enchants) {
enchants.forEach((enchantment, level) ->
enchantment.addEnchantmentUnsafe(item, level)
);
}
/**
* Clear all the enchantments
*
* @param item The item to clear the enchantments from
* @since 1.17.6
*/
public static void clearEnchantments(@NotNull ItemStack item) {
CAEnchantment.clearEnchants(item);
}
} }

View file

@ -41,7 +41,7 @@ public class SuperEnchantBulkOperation implements BulkGetEnchantOperation, BulkC
@Override @Override
public void bulkClear(@NotNull ItemStack item, @NotNull ItemMeta meta) { public void bulkClear(@NotNull ItemStack item, @NotNull ItemMeta meta) {
// item meta is not preferred for enchantment squared clear // item meta is not preferred for super enchant
} }
} }

View file

@ -73,4 +73,14 @@ public class CASuperEnchantEnchantment extends CAEnchantmentBase implements Addi
return !enchant.canApplyTo(item.getType()); return !enchant.canApplyTo(item.getType());
} }
@Override
public boolean isCleanOptimised() {
return true;
}
@Override
public boolean isGetOptimised() {
return true;
}
} }

View file

@ -21,23 +21,6 @@ object ItemUtil {
*/ */
fun ItemStack.isEnchantedBook() = type == ENCHANTED_BOOK fun ItemStack.isEnchantedBook() = type == ENCHANTED_BOOK
/**
* Find the enchantment map for this [ItemStack] and return it as a [MutableMap]
*/
fun ItemStack.findEnchantments(): MutableMap<CAEnchantment, Int> = CAEnchantment.getEnchants(this)
/**
* Apply an [enchantments] map to this [ItemStack]
*/
fun ItemStack.setEnchantmentsUnsafe(enchantments: Map<CAEnchantment, Int>) {
CAEnchantment.clearEnchants(this)
enchantments.forEach { (enchantment, level) ->
enchantment.addEnchantmentUnsafe(this, level)
}
}
private fun maxDamage(damageable: Damageable): Int { private fun maxDamage(damageable: Damageable): Int {
val ver = UpdateUtils.currentMinecraftVersion() val ver = UpdateUtils.currentMinecraftVersion()
if(ver.major <= 1 && ver.minor <= 20 && ver.patch < 5) return Integer.MAX_VALUE if(ver.major <= 1 && ver.minor <= 20 && ver.patch < 5) return Integer.MAX_VALUE

View file

@ -3,10 +3,8 @@ package xyz.alexcrea.cuanvil.anvil
import io.delilaheve.CustomAnvil import io.delilaheve.CustomAnvil
import io.delilaheve.util.ConfigOptions import io.delilaheve.util.ConfigOptions
import io.delilaheve.util.EnchantmentUtil.combineWith import io.delilaheve.util.EnchantmentUtil.combineWith
import io.delilaheve.util.ItemUtil.findEnchantments
import io.delilaheve.util.ItemUtil.isEnchantedBook import io.delilaheve.util.ItemUtil.isEnchantedBook
import io.delilaheve.util.ItemUtil.repairFrom import io.delilaheve.util.ItemUtil.repairFrom
import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe
import io.delilaheve.util.ItemUtil.unitRepair import io.delilaheve.util.ItemUtil.unitRepair
import org.bukkit.ChatColor import org.bukkit.ChatColor
import org.bukkit.Material import org.bukkit.Material
@ -17,6 +15,7 @@ import org.bukkit.inventory.InventoryView
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta import org.bukkit.inventory.meta.ItemMeta
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
import xyz.alexcrea.cuanvil.enchant.CAEnchantment import xyz.alexcrea.cuanvil.enchant.CAEnchantment
@ -189,14 +188,19 @@ object AnvilMergeLogic {
player: Player, player: Player,
first: ItemStack, second: ItemStack first: ItemStack, second: ItemStack
): AnvilResult { ): AnvilResult {
val newEnchants = first.findEnchantments() val firstEnchants = EnchantmentApi.getEnchantments(first)
.combineWith(second.findEnchantments(), first, player) val secondEnchants = EnchantmentApi.getEnchantments(second)
var hasChanged = !isIdentical(first.findEnchantments(), newEnchants)
// newEnchants will be mutated by combineWith
val newEnchants = HashMap(firstEnchants)
newEnchants.combineWith(secondEnchants, first, player)
var hasChanged = !isIdentical(firstEnchants, newEnchants)
val resultItem = DependencyManager.cloneItem(player, first) val resultItem = DependencyManager.cloneItem(player, first)
val cost = AnvilCost() val cost = AnvilCost()
if (hasChanged) { if (hasChanged) {
resultItem.setEnchantmentsUnsafe(newEnchants) EnchantmentApi.setEnchantments(resultItem, newEnchants)
// Calculate enchantment cost // Calculate enchantment cost
AnvilXpUtil.getRightValues(first, second, resultItem, cost) AnvilXpUtil.getRightValues(first, second, resultItem, cost)
} }

View file

@ -5,6 +5,7 @@ import org.bukkit.NamespacedKey
import org.bukkit.configuration.ConfigurationSection import org.bukkit.configuration.ConfigurationSection
import org.bukkit.enchantments.Enchantment import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantment import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
@ -140,7 +141,11 @@ class EnchantConflictManager {
return conflict return conflict
} }
private fun fetchConditionalRestriction(restrictions: MutableMap<CAEnchantment, Int>, section: ConfigurationSection?, conflictName: String) { private fun fetchConditionalRestriction(
restrictions: MutableMap<CAEnchantment, Int>,
section: ConfigurationSection?,
conflictName: String
) {
if (section == null) return if (section == null) return
for (enchantName in section.getKeys(false)) { for (enchantName in section.getKeys(false)) {
val enchants = getEnchantByIdentifier(enchantName) val enchants = getEnchantByIdentifier(enchantName)
@ -259,7 +264,8 @@ class EnchantConflictManager {
} }
if ((result != ConflictType.ITEM_CONFLICT) && (newEnchant is AdditionalTestEnchantment)) { if ((result != ConflictType.ITEM_CONFLICT) && (newEnchant is AdditionalTestEnchantment)) {
val partialItem = createPartialResult(item, immutableEnchants) val partialItem = item.clone()
EnchantmentApi.setEnchantments(partialItem, immutableEnchants)
if (newEnchant.isItemConflict(immutableEnchants, type, partialItem)) { if (newEnchant.isItemConflict(immutableEnchants, type, partialItem)) {
return ConflictType.ITEM_CONFLICT return ConflictType.ITEM_CONFLICT
@ -270,17 +276,6 @@ class EnchantConflictManager {
return result return result
} }
private fun createPartialResult(item: ItemStack, enchantments: Map<CAEnchantment, Int>): ItemStack {
val newItem = item.clone()
CAEnchantment.clearEnchants(newItem)
enchantments.forEach { enchantment ->
enchantment.key.addEnchantmentUnsafe(newItem, enchantment.value)
}
return newItem
}
} }
/** /**

View file

@ -3,7 +3,6 @@ package xyz.alexcrea.cuanvil.util.anvil
import io.delilaheve.CustomAnvil import io.delilaheve.CustomAnvil
import io.delilaheve.util.ConfigOptions import io.delilaheve.util.ConfigOptions
import io.delilaheve.util.EnchantmentUtil.enchantmentName import io.delilaheve.util.EnchantmentUtil.enchantmentName
import io.delilaheve.util.ItemUtil.findEnchantments
import io.delilaheve.util.ItemUtil.isEnchantedBook import io.delilaheve.util.ItemUtil.isEnchantedBook
import org.bukkit.GameMode import org.bukkit.GameMode
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
@ -17,6 +16,7 @@ import org.bukkit.persistence.PersistentDataType
import xyz.alexcrea.cuanvil.anvil.AnvilCost import xyz.alexcrea.cuanvil.anvil.AnvilCost
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.AnvilResult import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.AnvilResult
import xyz.alexcrea.cuanvil.anvil.AnvilUseType import xyz.alexcrea.cuanvil.anvil.AnvilUseType
import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager
@ -247,8 +247,8 @@ object AnvilXpUtil {
// Calculate right value and illegal enchant penalty // Calculate right value and illegal enchant penalty
val rightIsFormBook = right.isEnchantedBook() val rightIsFormBook = right.isEnchantedBook()
val rightEnchs = right.findEnchantments() val rightEnchs = EnchantmentApi.getEnchantments(right)
val resultEnchs = result.findEnchantments() val resultEnchs = EnchantmentApi.getEnchantments(result)
val resultEnchsKeys = HashMap(resultEnchs) val resultEnchsKeys = HashMap(resultEnchs)
var rightValue = 0 var rightValue = 0
@ -282,7 +282,7 @@ object AnvilXpUtil {
} }
if(ConfigOptions.includeLeftEnchantmentForCost) { if(ConfigOptions.includeLeftEnchantmentForCost) {
val leftIsFormBook = left.isEnchantedBook() val leftIsFormBook = left.isEnchantedBook()
val leftEnchs = left.findEnchantments() val leftEnchs = EnchantmentApi.getEnchantments(left)
for (enchantment in leftEnchs) { for (enchantment in leftEnchs) {
// Do not process enchantment that are present on the sacrifice // Do not process enchantment that are present on the sacrifice
if(rightEnchs.contains(enchantment.key)) continue if(rightEnchs.contains(enchantment.key)) continue

View file

@ -13,6 +13,7 @@ import org.bukkit.inventory.meta.Repairable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import xyz.alexcrea.cuanvil.api.EnchantmentApi;
import xyz.alexcrea.cuanvil.data.AnvilClickTestData; import xyz.alexcrea.cuanvil.data.AnvilClickTestData;
import xyz.alexcrea.cuanvil.data.AnvilFuseTestData; import xyz.alexcrea.cuanvil.data.AnvilFuseTestData;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
@ -47,7 +48,7 @@ public class AnvilFuseTestUtil {
} }
ItemStack item = new ItemStack(material); ItemStack item = new ItemStack(material);
ItemUtil.INSTANCE.setEnchantmentsUnsafe(item, enchantmentMap); EnchantmentApi.setEnchantments(item, enchantmentMap);
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
((Repairable) meta).setRepairCost(repairCost); ((Repairable) meta).setRepairCost(repairCost);