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.configuration.file.FileConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.config.ConfigHolder;
@ -38,14 +39,14 @@ public class EnchantmentApi {
* @param enchantment The enchantment to register
* @return True if successful.
*/
public static boolean registerEnchantment(@NotNull CAEnchantment enchantment){
if(!CAEnchantmentRegistry.getInstance().register(enchantment)) return false;
public static boolean registerEnchantment(@NotNull CAEnchantment enchantment) {
if (!CAEnchantmentRegistry.getInstance().register(enchantment)) return false;
// Add enchantment to gui.
if(EnchantCostConfigGui.getInstance() != null){
if (EnchantCostConfigGui.getInstance() != null) {
EnchantCostConfigGui.getInstance().updateValueForGeneric(enchantment, true);
}
if(EnchantLimitConfigGui.getInstance() != null){
if (EnchantLimitConfigGui.getInstance() != null) {
EnchantLimitConfigGui.getInstance().updateValueForGeneric(enchantment, true);
}
@ -62,8 +63,8 @@ public class EnchantmentApi {
* @param defaultRarity The default rarity of the provided enchantment
* @return True if successful.
*/
public static boolean registerEnchantment(@NotNull Enchantment enchantment, @Nullable EnchantmentRarity defaultRarity){
if(defaultRarity == null)
public static boolean registerEnchantment(@NotNull Enchantment enchantment, @Nullable EnchantmentRarity defaultRarity) {
if (defaultRarity == null)
return registerEnchantment(new CABukkitEnchantment(enchantment));
return registerEnchantment(new CABukkitEnchantment(enchantment, defaultRarity));
@ -77,7 +78,7 @@ public class EnchantmentApi {
* @param enchantment The enchantment to register
* @return True if successful.
*/
public static boolean registerEnchantment(@NotNull Enchantment enchantment){
public static boolean registerEnchantment(@NotNull Enchantment enchantment) {
return registerEnchantment(new CABukkitEnchantment(enchantment));
}
@ -87,12 +88,12 @@ public class EnchantmentApi {
* @param enchantment The enchantment to unregister
* @return True if successful.
*/
public static boolean unregisterEnchantment(@Nullable CAEnchantment enchantment){
public static boolean unregisterEnchantment(@Nullable CAEnchantment enchantment) {
// Remove from gui
if(EnchantCostConfigGui.getInstance() != null){
if (EnchantCostConfigGui.getInstance() != null) {
EnchantCostConfigGui.getInstance().removeGeneric(enchantment);
}
if(EnchantLimitConfigGui.getInstance() != null){
if (EnchantLimitConfigGui.getInstance() != null) {
EnchantLimitConfigGui.getInstance().removeGeneric(enchantment);
}
@ -105,7 +106,7 @@ public class EnchantmentApi {
* @param key The enchantment key to unregister
* @return True if successful.
*/
public static boolean unregisterEnchantment(@NotNull NamespacedKey key){
public static boolean unregisterEnchantment(@NotNull NamespacedKey key) {
CAEnchantment enchantment = CAEnchantment.getByKey(key);
return unregisterEnchantment(enchantment);
}
@ -116,7 +117,7 @@ public class EnchantmentApi {
* @param enchantment The enchantment to unregister
* @return True if successful.
*/
public static boolean unregisterEnchantment(@NotNull Enchantment enchantment){
public static boolean unregisterEnchantment(@NotNull Enchantment enchantment) {
return unregisterEnchantment(enchantment.getKey());
}
@ -127,7 +128,7 @@ public class EnchantmentApi {
* @return The custom anvil enchantment of this key. null if not found.
*/
@Nullable
public static CAEnchantment getByKey(@NotNull NamespacedKey key){
public static CAEnchantment getByKey(@NotNull NamespacedKey key) {
return CAEnchantment.getByKey(key);
}
@ -140,7 +141,7 @@ public class EnchantmentApi {
*/
@Deprecated(since = "1.6.3")
@Nullable
public static CAEnchantment getByName(@NotNull String name){
public static CAEnchantment getByName(@NotNull String name) {
return CAEnchantment.getByName(name);
}
@ -150,29 +151,31 @@ public class EnchantmentApi {
* @param name The name used to fetch
* @return List of custom anvil enchantments of this name. May be empty if not found.
*/
public static List<CAEnchantment> getListByName(@NotNull String name){
public static List<CAEnchantment> getListByName(@NotNull String name) {
return CAEnchantment.getListByName(name);
}
/**
* Get every registered custom anvil enchantments.
*
* @return An immutable map of enchantment key as map key and custom anvil enchantment as value.
*/
@NotNull
public static Map<NamespacedKey, CAEnchantment> getRegisteredEnchantments(){
public static Map<NamespacedKey, CAEnchantment> getRegisteredEnchantments() {
return Collections.unmodifiableMap(CAEnchantmentRegistry.getInstance().registeredEnchantments());
}
/**
* Write the default level and rarity configuration of the enchantment.
*
* @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.
*/
public static boolean writeDefaultConfig(CAEnchantment enchantment, boolean override){
public static boolean writeDefaultConfig(CAEnchantment enchantment, boolean override) {
FileConfiguration config = ConfigHolder.DEFAULT_CONFIG.getConfig();
if(tryWriteDefaultConfig(config, enchantment, override)){
if (tryWriteDefaultConfig(config, enchantment, override)) {
prepareSaveTask();
}
return true;
@ -182,7 +185,7 @@ public class EnchantmentApi {
boolean hasChange = false;
String levelPath = ConfigOptions.ENCHANT_LIMIT_ROOT + "." + enchantment.getKey();
if(override || !defaultConfig.isSet(levelPath)){
if (override || !defaultConfig.isSet(levelPath)) {
defaultConfig.set(levelPath, enchantment.defaultMaxLevel());
hasChange = true;
}
@ -192,11 +195,11 @@ public class EnchantmentApi {
String itemPath = basePath + ".item";
String bookPath = basePath + ".book";
if(override || !defaultConfig.isSet(itemPath)){
if (override || !defaultConfig.isSet(itemPath)) {
defaultConfig.set(itemPath, rarity.getItemValue());
hasChange = true;
}
if(override || !defaultConfig.isSet(bookPath)){
if (override || !defaultConfig.isSet(bookPath)) {
defaultConfig.set(bookPath, rarity.getBookValue());
hasChange = true;
}
@ -208,28 +211,81 @@ public class EnchantmentApi {
* Prepare a task to save custom recipe configuration.
*/
private static void prepareSaveTask() {
if(saveChangeTask != null) return;
if (saveChangeTask != null) return;
saveChangeTask = DependencyManager.scheduler.scheduleGlobally(CustomAnvil.instance, ()->{
saveChangeTask = DependencyManager.scheduler.scheduleGlobally(CustomAnvil.instance, () -> {
ConfigHolder.DEFAULT_CONFIG.saveToDisk(true);
saveChangeTask = null;
});
}
/**
* 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
*/
public static void addBulkGet(@NotNull BulkGetEnchantOperation operation){
public static void addBulkGet(@NotNull BulkGetEnchantOperation operation) {
CAEnchantmentRegistry.getInstance().getOptimisedGetOperators().add(operation);
}
/**
* 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);
}
/**
* 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
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());
}
@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
/**
* 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 {
val ver = UpdateUtils.currentMinecraftVersion()
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.util.ConfigOptions
import io.delilaheve.util.EnchantmentUtil.combineWith
import io.delilaheve.util.ItemUtil.findEnchantments
import io.delilaheve.util.ItemUtil.isEnchantedBook
import io.delilaheve.util.ItemUtil.repairFrom
import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe
import io.delilaheve.util.ItemUtil.unitRepair
import org.bukkit.ChatColor
import org.bukkit.Material
@ -17,6 +15,7 @@ import org.bukkit.inventory.InventoryView
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import org.bukkit.persistence.PersistentDataType
import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
@ -189,14 +188,19 @@ object AnvilMergeLogic {
player: Player,
first: ItemStack, second: ItemStack
): AnvilResult {
val newEnchants = first.findEnchantments()
.combineWith(second.findEnchantments(), first, player)
var hasChanged = !isIdentical(first.findEnchantments(), newEnchants)
val firstEnchants = EnchantmentApi.getEnchantments(first)
val secondEnchants = EnchantmentApi.getEnchantments(second)
// 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 cost = AnvilCost()
if (hasChanged) {
resultItem.setEnchantmentsUnsafe(newEnchants)
EnchantmentApi.setEnchantments(resultItem, newEnchants)
// Calculate enchantment 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.enchantments.Enchantment
import org.bukkit.inventory.ItemStack
import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
@ -66,7 +67,7 @@ class EnchantConflictManager {
val keys = config.getKeys(false)
for (key in keys) {
val section = config.getConfigurationSection(key)
if(section == null) {
if (section == null) {
warnBadKey(key)
continue
}
@ -140,8 +141,12 @@ class EnchantConflictManager {
return conflict
}
private fun fetchConditionalRestriction(restrictions: MutableMap<CAEnchantment, Int>, section: ConfigurationSection?, conflictName: String) {
if(section == null) return
private fun fetchConditionalRestriction(
restrictions: MutableMap<CAEnchantment, Int>,
section: ConfigurationSection?,
conflictName: String
) {
if (section == null) return
for (enchantName in section.getKeys(false)) {
val enchants = getEnchantByIdentifier(enchantName)
if (enchants.isEmpty()) {
@ -150,7 +155,7 @@ class EnchantConflictManager {
}
val value = section.getInt(enchantName, -1)
if(value < 0) continue
if (value < 0) continue
for (enchant in enchants) {
val previous = restrictions.getOrDefault(enchant, value)
@ -259,7 +264,8 @@ class EnchantConflictManager {
}
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)) {
return ConflictType.ITEM_CONFLICT
@ -270,17 +276,6 @@ class EnchantConflictManager {
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.util.ConfigOptions
import io.delilaheve.util.EnchantmentUtil.enchantmentName
import io.delilaheve.util.ItemUtil.findEnchantments
import io.delilaheve.util.ItemUtil.isEnchantedBook
import org.bukkit.GameMode
import org.bukkit.NamespacedKey
@ -17,6 +16,7 @@ import org.bukkit.persistence.PersistentDataType
import xyz.alexcrea.cuanvil.anvil.AnvilCost
import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.AnvilResult
import xyz.alexcrea.cuanvil.anvil.AnvilUseType
import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dependency.economy.EconomyManager
@ -247,8 +247,8 @@ object AnvilXpUtil {
// Calculate right value and illegal enchant penalty
val rightIsFormBook = right.isEnchantedBook()
val rightEnchs = right.findEnchantments()
val resultEnchs = result.findEnchantments()
val rightEnchs = EnchantmentApi.getEnchantments(right)
val resultEnchs = EnchantmentApi.getEnchantments(result)
val resultEnchsKeys = HashMap(resultEnchs)
var rightValue = 0
@ -282,7 +282,7 @@ object AnvilXpUtil {
}
if(ConfigOptions.includeLeftEnchantmentForCost) {
val leftIsFormBook = left.isEnchantedBook()
val leftEnchs = left.findEnchantments()
val leftEnchs = EnchantmentApi.getEnchantments(left)
for (enchantment in leftEnchs) {
// Do not process enchantment that are present on the sacrifice
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.Nullable;
import org.junit.jupiter.api.Assertions;
import xyz.alexcrea.cuanvil.api.EnchantmentApi;
import xyz.alexcrea.cuanvil.data.AnvilClickTestData;
import xyz.alexcrea.cuanvil.data.AnvilFuseTestData;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
@ -47,7 +48,7 @@ public class AnvilFuseTestUtil {
}
ItemStack item = new ItemStack(material);
ItemUtil.INSTANCE.setEnchantmentsUnsafe(item, enchantmentMap);
EnchantmentApi.setEnchantments(item, enchantmentMap);
ItemMeta meta = item.getItemMeta();
((Repairable) meta).setRepairCost(repairCost);