Compare commits

..

17 commits

Author SHA1 Message Date
036f480113
update from v1.18.0 2026-07-10 15:50:50 +02:00
13892f73b8
update from v1.x.x 2026-07-10 15:42:18 +02:00
5a6962b1c4
remove legacy command 2026-07-10 15:41:32 +02:00
0e65575c2b
rebase on news update 2026-07-10 15:41:31 +02:00
04ed7ea0b5
prepare for v2 2026-07-10 15:41:30 +02:00
63a9b5b1c6
rebase on new update 2026-07-10 15:41:09 +02:00
e2bbd66abf
1.21 cleanup and fix
also random cleanup
2026-07-10 15:40:55 +02:00
109ef0c5df
fix from rebase 2026-07-10 15:40:41 +02:00
38cf25ef1a
progress on 1.21 transition 2026-07-10 15:38:21 +02:00
5ba1bb98cc
initial 1.21 transition 2026-07-10 15:37:45 +02:00
862f9914fa
update faststat
Some checks failed
Java CI with Gradle / build (push) Has been cancelled
2026-07-10 15:25:13 +02:00
497a3e84bc
fix /ca enchant
Some checks failed
Java CI with Gradle / build (push) Has been cancelled
2026-07-08 17:36:47 +02:00
d469171e4d
fix support for enchantedbook
Some checks are pending
Java CI with Gradle / build (push) Waiting to run
2026-07-08 14:44:20 +02:00
b9ff4bdc40
add support for enchantedbook 2026-07-08 14:04:26 +02:00
16e4f0a923
fix using durability for max damage
Some checks are pending
Java CI with Gradle / build (push) Waiting to run
2026-07-08 04:26:13 +02:00
403c990083
migrate configanvil to ca config 2026-07-08 04:26:13 +02:00
e61baba175
remove use of useInFuture 2026-07-08 04:26:12 +02:00
35 changed files with 186 additions and 95 deletions

View file

@ -40,6 +40,8 @@ Custom Items support is considered unstable. If you find issue please report it
- [Disenchantment](https://www.spigotmc.org/resources/disenchantment-1-21-1-1-20-6-new-book-splitting-mechanics.110741/) by H7KZ - [Disenchantment](https://www.spigotmc.org/resources/disenchantment-1-21-1-1-20-6-new-book-splitting-mechanics.110741/) by H7KZ
Partially use Custom Anvil maximum XP settings (>= 6.1.5) Partially use Custom Anvil maximum XP settings (>= 6.1.5)
- [EnchantedBook](https://modrinth.com/plugin/enchantedbook) by Minacle
- [HavenBags](https://www.spigotmc.org/resources/havenbags-shulker-like-player-bound-bags-1-17-1-21-4.110420/) by hyperdefined - [HavenBags](https://www.spigotmc.org/resources/havenbags-shulker-like-player-bound-bags-1-17-1-21-4.110420/) by hyperdefined
For bag upgrade and skin via anvil. (version >= 1.31.0) For bag upgrade and skin via anvil. (version >= 1.31.0)

View file

@ -58,7 +58,7 @@ dependencies {
compileOnly("org.spigotmc:spigot-api:1.21-R0.1-SNAPSHOT") compileOnly("org.spigotmc:spigot-api:1.21-R0.1-SNAPSHOT")
// fast stats // fast stats
implementation("dev.faststats.metrics:bukkit:0.27.0") implementation("dev.faststats.metrics:bukkit:0.27.2")
// minimessage // minimessage
implementation("net.kyori:adventure-text-minimessage:4.25.0") implementation("net.kyori:adventure-text-minimessage:4.25.0")

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #
@ -275,10 +275,7 @@ restriction_sweeping_edge:
- enchanted_book - enchanted_book
- swords - swords
# Do not exist in 1.18, that mean useInFuture will be set to true
# useInFuture set to true also mean it will not warn if there is an issue
restriction_swift_sneak: restriction_swift_sneak:
useInFuture: true
enchantments: enchantments:
- minecraft:swift_sneak - minecraft:swift_sneak
notAffectedGroups: notAffectedGroups:

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #
@ -272,10 +272,7 @@ restriction_sweeping_edge:
- enchanted_book - enchanted_book
- swords - swords
# Do not exist in 1.18, that mean useInFuture will be set to true
# useInFuture set to true also mean it will not warn if there is an issue
restriction_swift_sneak: restriction_swift_sneak:
useInFuture: true
enchantments: enchantments:
- minecraft:swift_sneak - minecraft:swift_sneak
notAffectedGroups: notAffectedGroups:

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -18,8 +18,8 @@ import org.bukkit.craftbukkit.inventory.CraftInventoryView
import org.bukkit.craftbukkit.inventory.view.CraftAnvilView import org.bukkit.craftbukkit.inventory.view.CraftAnvilView
import org.bukkit.entity.HumanEntity import org.bukkit.entity.HumanEntity
import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.InventoryView
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.view.AnvilView
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
import org.bukkit.plugin.Plugin import org.bukkit.plugin.Plugin
import java.util.* import java.util.*
@ -121,7 +121,7 @@ class AnvilRenameDialogImpl(
} }
} }
private fun setResult(player: HumanEntity, view: InventoryView, result: String?) { private fun setResult(player: HumanEntity, view: AnvilView, result: String?) {
val defaultName = itemDefaultName(view.getItem(0)) val defaultName = itemDefaultName(view.getItem(0))
if (defaultName == result) { if (defaultName == result) {
setName(player, view, "", null) setName(player, view, "", null)
@ -129,7 +129,7 @@ class AnvilRenameDialogImpl(
} else setName(player, view, result, result) } else setName(player, view, result, result)
} }
private fun setName(player: HumanEntity, view: InventoryView, name: String?, rename: String?) { private fun setName(player: HumanEntity, view: AnvilView, name: String?, rename: String?) {
val menu = (containerField.get(view) as AnvilMenu) val menu = (containerField.get(view) as AnvilMenu)
val isSameName = menu.itemName == name val isSameName = menu.itemName == name
menu.itemName = rename menu.itemName = rename

View file

@ -2,17 +2,18 @@ package xyz.alexcrea.cuanvil.util
import io.papermc.paper.threadedregions.scheduler.ScheduledTask import io.papermc.paper.threadedregions.scheduler.ScheduledTask
import org.bukkit.entity.HumanEntity import org.bukkit.entity.HumanEntity
import org.bukkit.inventory.InventoryView import org.bukkit.inventory.view.AnvilView
import org.bukkit.plugin.Plugin import org.bukkit.plugin.Plugin
import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
import java.util.HashMap import java.util.HashMap
import java.util.UUID import java.util.UUID
@Suppress("UnstableApiUsage")
object AnvilTitleUtil { object AnvilTitleUtil {
private val runTaskMap = HashMap<UUID, ScheduledTask>() private val runTaskMap = HashMap<UUID, ScheduledTask>()
private fun actualRename(view: InventoryView, name: String, player: HumanEntity, anvilDialog: AnvilRenameDialog) { private fun actualRename(view: AnvilView, name: String, player: HumanEntity, anvilDialog: AnvilRenameDialog) {
runTaskMap.remove(player.uniqueId) runTaskMap.remove(player.uniqueId)
if (view.title == name) return if (view.title == name) return
@ -24,7 +25,7 @@ object AnvilTitleUtil {
// We don't want to rename instantly it is causing issue with rename text // We don't want to rename instantly it is causing issue with rename text
// especially as it can "override" current ui when it is rename ui time but rename ui also need some delay // especially as it can "override" current ui when it is rename ui time but rename ui also need some delay
fun rename(view: InventoryView, name: String, player: HumanEntity, anvilDialog: AnvilRenameDialog, plugin: Plugin) { fun rename(view: AnvilView, name: String, player: HumanEntity, anvilDialog: AnvilRenameDialog, plugin: Plugin) {
runTaskMap.remove(player.uniqueId)?.cancel() runTaskMap.remove(player.uniqueId)?.cancel()
val task = player.scheduler.runDelayed( val task = player.scheduler.runDelayed(

View file

@ -128,7 +128,7 @@ public class EnchantmentApi {
* @return The custom anvil enchantment of this key. null if not found. * @return The custom anvil enchantment of this key. null if not found.
*/ */
@Nullable @Nullable
public static CAEnchantment getByKey(@NotNull NamespacedKey key) { public static CAEnchantment getByKey(@Nullable NamespacedKey key) {
return CAEnchantment.getByKey(key); return CAEnchantment.getByKey(key);
} }

View file

@ -230,7 +230,7 @@ public interface CAEnchantment {
* @param key The enchantment key * @param key The enchantment key
* @return Array of enchantment. * @return Array of enchantment.
*/ */
static @Nullable CAEnchantment getByKey(@NotNull NamespacedKey key){ static @Nullable CAEnchantment getByKey(@Nullable NamespacedKey key){
return CAEnchantmentRegistry.getInstance().getByKey(key); return CAEnchantmentRegistry.getInstance().getByKey(key);
} }

View file

@ -151,7 +151,7 @@ public class CAEnchantmentRegistry {
* @return Registered enchantment. null if absent. * @return Registered enchantment. null if absent.
*/ */
@Nullable @Nullable
public CAEnchantment getByKey(@NotNull NamespacedKey key) { public CAEnchantment getByKey(@Nullable NamespacedKey key) {
return byKeyMap.get(key); return byKeyMap.get(key);
} }

View file

@ -30,10 +30,11 @@ public class UpdateHandler {
new Version(1, 11, 0), PUpdate_1_11_0::handleUpdate, new Version(1, 11, 0), PUpdate_1_11_0::handleUpdate,
new Version(1, 15, 5), PUpdate_1_15_5::handleUpdate, new Version(1, 15, 5), PUpdate_1_15_5::handleUpdate,
new Version(1, 15, 6), PUpdate_1_15_6::handleUpdate, new Version(1, 15, 6), PUpdate_1_15_6::handleUpdate,
new Version(1, 17, 7), PUpdate_1_17_7::handleUpdate new Version(1, 18, 0), PUpdate_1_18::handleUpdate
); );
private static final List<MCUpdate> mcUpdateMap = List.of( private static final List<MCUpdate> mcUpdateMap = List.of(
new Update_1_19(),
new Update_1_20_5(), new Update_1_20_5(),
new Update_1_21(), new Update_1_21(),
new Update_1_21_9(), new Update_1_21_9(),

View file

@ -0,0 +1,40 @@
package xyz.alexcrea.cuanvil.update.minecraft;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.update.Version;
import java.util.HashSet;
import java.util.Set;
import static xyz.alexcrea.cuanvil.update.UpdateUtils.addAbsentToList;
public class Update_1_19 extends MCUpdate {
public Update_1_19() {
super(new Version(1, 19));
}
@Override
protected void doUpdate() {
var tosave = new HashSet<ConfigHolder>();
updateName(tosave);
for (ConfigHolder holder : tosave) {
holder.saveToDisk(true);
}
}
public static void updateName(@NotNull Set<ConfigHolder> tosave) {
var conflict = ConfigHolder.CONFLICT_HOLDER.getConfig();
addAbsentToList(conflict, "restriction_swift_sneak.enchantments", "minecraft:swift_sneak");
addAbsentToList(conflict, "restriction_swift_sneak.notAffectedGroups", "leggings", "enchanted_book");
ConfigHolder.ITEM_GROUP_HOLDER.reload();
tosave.add(ConfigHolder.DEFAULT_CONFIG);
tosave.add(ConfigHolder.CONFLICT_HOLDER);
}
}

View file

@ -3,19 +3,20 @@ package xyz.alexcrea.cuanvil.update.plugin;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.update.UpdateUtils; import xyz.alexcrea.cuanvil.update.UpdateUtils;
import xyz.alexcrea.cuanvil.update.Version; import xyz.alexcrea.cuanvil.update.Version;
import xyz.alexcrea.cuanvil.update.minecraft.Update_1_19;
import xyz.alexcrea.cuanvil.update.minecraft.Update_1_20_5; import xyz.alexcrea.cuanvil.update.minecraft.Update_1_20_5;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Set; import java.util.Set;
public class PUpdate_1_17_7 { public class PUpdate_1_18 {
public static void handleUpdate(@Nonnull Set<ConfigHolder> toSave) { public static void handleUpdate(@Nonnull Set<ConfigHolder> toSave) {
// fix only needed for 1.20.5 and above
Version current = UpdateUtils.currentMinecraftVersion(); Version current = UpdateUtils.currentMinecraftVersion();
if (new Version(1, 20, 5).greaterThan(current)) return; if (new Version(1, 19, 0).greaterThan(current)) return;
Update_1_19.updateName(toSave);
if (new Version(1, 20, 5).greaterThan(current)) return;
Update_1_20_5.updateName(toSave); Update_1_20_5.updateName(toSave);
} }
} }

View file

@ -1,9 +1,10 @@
package io.delilaheve.util package io.delilaheve.util
import org.bukkit.Material
import org.bukkit.Material.ENCHANTED_BOOK import org.bukkit.Material.ENCHANTED_BOOK
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Damageable import org.bukkit.inventory.meta.Damageable
import xyz.alexcrea.cuanvil.enchant.CAEnchantment import xyz.alexcrea.cuanvil.update.UpdateUtils
import xyz.alexcrea.cuanvil.util.MaterialUtil.customType import xyz.alexcrea.cuanvil.util.MaterialUtil.customType
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
@ -19,6 +20,13 @@ object ItemUtil {
*/ */
fun ItemStack.isEnchantedBook() = type == ENCHANTED_BOOK fun ItemStack.isEnchantedBook() = type == ENCHANTED_BOOK
private fun maxDamage(type: Material, damageable: Damageable): Int {
val ver = UpdateUtils.currentMinecraftVersion()
if(ver.major <= 1 && ver.minor <= 20 && ver.patch < 5) return type.maxDurability.toInt()
return if(damageable.hasMaxDamage()) damageable.maxDamage else type.maxDurability.toInt()
}
/** /**
* Set this [ItemStack]s durability from a combination of the * Set this [ItemStack]s durability from a combination of the
* [first] and [second] item's durability values * [first] and [second] item's durability values
@ -28,23 +36,22 @@ object ItemUtil {
first: ItemStack, first: ItemStack,
second: ItemStack second: ItemStack
): Boolean { ): Boolean {
(itemMeta as? Damageable)?.let { val meta = itemMeta
val durability = type.maxDurability.toInt() if(meta !is Damageable) return false
val firstDamage = (first.itemMeta as? Damageable)?.damage ?: 0
if (firstDamage == 0) return false
val firstDurability = durability - firstDamage val maxDamage = maxDamage(type, meta)
val secondDamage = (second.itemMeta as? Damageable)?.damage ?: 0 val damage = (first.itemMeta as? Damageable)?.damage ?: 0
val secondDurability = durability - secondDamage if (damage == 0) return false
val combinedDurability = firstDurability + secondDurability
val newDurability = min(combinedDurability, durability)
val maxDamage = if(it.hasMaxDamage()) it.maxDamage else Int.MAX_VALUE
it.damage = min(durability - newDurability, maxDamage) val firstDurability = maxDamage - damage
itemMeta = it val secondDamage = (second.itemMeta as? Damageable)?.damage ?: 0
return true val secondDurability = maxDamage - secondDamage
} val combinedDurability = firstDurability + secondDurability
return false val newDurability = min(combinedDurability, maxDamage)
meta.damage = min(maxDamage - newDurability, maxDamage)
this.itemMeta = meta
return true
} }
fun ItemStack.unitRepair( fun ItemStack.unitRepair(

View file

@ -129,9 +129,9 @@ class DiagnosticExecutor : CASubCommand {
message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString()) message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString())
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("§7Click to copy")) message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("§7Click to copy"))
sender.spigot().sendMessage(message); sender.spigot().sendMessage(message)
} else { } else {
sender.sendMessage(stb.toString()); sender.sendMessage(stb.toString())
} }
return true return true
@ -266,8 +266,8 @@ class DiagnosticExecutor : CASubCommand {
try { try {
val fakeInv = Bukkit.createInventory(player, InventoryType.ANVIL) val fakeInv = Bukkit.createInventory(player, InventoryType.ANVIL)
invView = player.openInventory(fakeInv)!! as AnvilView invView = player.openInventory(fakeInv)!! as AnvilView
event = PrepareAnvilEvent(invView, result) event = DependencyManager.createFakeEvent(invView, result)
} catch (e: Throwable) { } catch (_: Throwable) {
// Help // Help
val menuTypeClazz = Class.forName("org.bukkit.inventory.MenuType") val menuTypeClazz = Class.forName("org.bukkit.inventory.MenuType")
val anvilTypeField = menuTypeClazz.getField("ANVIL") val anvilTypeField = menuTypeClazz.getField("ANVIL")

View file

@ -2,10 +2,14 @@ package xyz.alexcrea.cuanvil.command
import io.delilaheve.CustomAnvil import io.delilaheve.CustomAnvil
import io.delilaheve.util.ConfigOptions import io.delilaheve.util.ConfigOptions
import io.delilaheve.util.ItemUtil.isEnchantedBook
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.command.Command import org.bukkit.command.Command
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
import org.bukkit.entity.HumanEntity import org.bukkit.entity.HumanEntity
import xyz.alexcrea.cuanvil.api.EnchantmentApi import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
class EnchantExecutor : CASubCommand { class EnchantExecutor : CASubCommand {
@ -37,22 +41,18 @@ class EnchantExecutor : CASubCommand {
sender.sendMessage("Missing enchantment parameter") sender.sendMessage("Missing enchantment parameter")
return true return true
} }
1 -> {
sender.sendMessage("Missing level parameter")
return true
}
} }
val enchants = EnchantmentApi.getByName(args[0].lowercase()) val enchant = firstEnchantment(args[0])
if (enchants.isEmpty()) { if (enchant == null) {
sender.sendMessage("Enchantment not found: ${args[0]}") sender.sendMessage("Enchantment not found: ${args[0]}")
return true return true
} }
val enchant = enchants.iterator().next() val level = if (args.size > 1)
args[1].toIntOrNull()?.coerceIn(0, ConfigOptions.ENCHANT_LIMIT)
else 1
val level = args[1].toIntOrNull()?.coerceIn(0, ConfigOptions.ENCHANT_LIMIT)
if (level == null) { if (level == null) {
sender.sendMessage("Invalid number: ${args[1]}") sender.sendMessage("Invalid number: ${args[1]}")
return true return true
@ -66,8 +66,15 @@ class EnchantExecutor : CASubCommand {
if (level == 0) { if (level == 0) {
enchant.removeFrom(inHand) enchant.removeFrom(inHand)
if (inHand.isEnchantedBook() && EnchantmentApi.getEnchantments(inHand).isEmpty())
inHand.type = Material.BOOK
sender.sendMessage("${enchant.prettyName} removed") sender.sendMessage("${enchant.prettyName} removed")
} else { } else {
if (Material.BOOK == inHand.type)
inHand.type = Material.ENCHANTED_BOOK
enchant.addEnchantmentUnsafe(inHand, level) enchant.addEnchantmentUnsafe(inHand, level)
sender.sendMessage("${enchant.prettyName} set to level $level") sender.sendMessage("${enchant.prettyName} set to level $level")
} }
@ -92,10 +99,8 @@ class EnchantExecutor : CASubCommand {
sender: HumanEntity, sender: HumanEntity,
name: String name: String
): Collection<String> { ): Collection<String> {
val enchants = EnchantmentApi.getByName(name.lowercase()) val enchant = firstEnchantment(name) ?: return listOf()
if (enchants.isEmpty()) return listOf()
val enchant = enchants.iterator().next()
val limit = ConfigOptions.enchantLimit(enchant) val limit = ConfigOptions.enchantLimit(enchant)
val result = mutableListOf<String>() val result = mutableListOf<String>()
@ -110,4 +115,12 @@ class EnchantExecutor : CASubCommand {
return result return result
} }
private fun firstEnchantment(name: String): CAEnchantment? {
val enchants = EnchantmentApi.getByName(name.lowercase())
if (!enchants.isEmpty())
return enchants.iterator().next()
return EnchantmentApi.getByKey(NamespacedKey.fromString(name))
}
} }

View file

@ -30,6 +30,7 @@ import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
import java.lang.reflect.Constructor
import java.util.logging.Level import java.util.logging.Level
@Suppress("UnstableApiUsage") @Suppress("UnstableApiUsage")
@ -120,6 +121,10 @@ object DependencyManager {
genericDependencies.add(compatibility) genericDependencies.add(compatibility)
} }
if (pluginManager.isPluginEnabled("EnchantedBook")) {
genericDependencies.add(EnchantedBookDependency(pluginManager.getPlugin("EnchantedBook")!!))
}
for (dependency in genericDependencies) for (dependency in genericDependencies)
dependency.redirectListeners() dependency.redirectListeners()
@ -325,4 +330,12 @@ object DependencyManager {
enchantmentSquaredCompatibility?.updateLore(item) enchantmentSquaredCompatibility?.updateLore(item)
} }
private val prepareAnvilConstructor =
PrepareAnvilEvent::class.java.constructors.first() as Constructor<PrepareAnvilEvent>
fun createFakeEvent(view: AnvilView, result: ItemStack?): PrepareAnvilEvent {
return prepareAnvilConstructor.newInstance(view, result)
}
} }

View file

@ -1,10 +1,11 @@
package xyz.alexcrea.cuanvil.dependency.gui package xyz.alexcrea.cuanvil.dependency.gui
import org.bukkit.inventory.InventoryView import org.bukkit.inventory.view.AnvilView
import xyz.alexcrea.cuanvil.dependency.MinecraftVersionUtil import xyz.alexcrea.cuanvil.dependency.MinecraftVersionUtil
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
import java.lang.reflect.Method import java.lang.reflect.Method
@Suppress("UnstableApiUsage")
class GenericExternGuiTester { class GenericExternGuiTester {
companion object { companion object {
@ -21,7 +22,7 @@ class GenericExternGuiTester {
var testedClass: String? = null var testedClass: String? = null
lateinit var getHandleMethod: Method lateinit var getHandleMethod: Method
private fun getContainerClass(view: InventoryView): Class<Any>? { private fun getContainerClass(view: AnvilView): Class<Any>? {
if(!testedClass.contentEquals(view.javaClass.name)) if(!testedClass.contentEquals(view.javaClass.name))
return null return null
@ -64,7 +65,7 @@ class GenericExternGuiTester {
} }
// Try if were in another plugin anvil inventory // Try if were in another plugin anvil inventory
fun testIfGui(view: InventoryView): Boolean { fun testIfGui(view: AnvilView): Boolean {
// In case we are in a test environment // In case we are in a test environment
if(isInTest()) return false if(isInTest()) return false

View file

@ -0,0 +1,34 @@
package xyz.alexcrea.cuanvil.dependency.plugins
import org.bukkit.event.Event
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.view.AnvilView
import org.bukkit.plugin.Plugin
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_LEFT
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
@Suppress("UnstableApiUsage")
class EnchantedBookDependency(plugin: Plugin) : GenericPluginDependency(plugin) {
override fun testAnvilResult(event: InventoryClickEvent): Boolean {
val view = event.view as? AnvilView ?: return false
val inv = event.inventory
//TODO use view here (v2)
val current = inv.getItem(ANVIL_OUTPUT_SLOT)
inv.setItem(ANVIL_OUTPUT_SLOT, null)
val fakeEvent = DependencyManager.createFakeEvent(view, null)
if (testPrepareAnvil(fakeEvent)) {
event.result = Event.Result.DEFAULT
inv.setItem(ANVIL_INPUT_LEFT, fakeEvent.result)
return true
}
inv.setItem(ANVIL_INPUT_LEFT, current)
return false
}
}

View file

@ -8,12 +8,12 @@ import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.plugin.RegisteredListener import org.bukkit.plugin.RegisteredListener
import xyz.alexcrea.cuanvil.api.EnchantmentApi import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResultEvent import xyz.alexcrea.cuanvil.api.event.listener.CATreatAnvilResultEvent
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEPreV5Enchantment import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEPreV5Enchantment
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5Enchantment import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5Enchantment
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5_4Enchantment import xyz.alexcrea.cuanvil.enchant.wrapped.CAEEV5_4Enchantment
import xyz.alexcrea.cuanvil.enchant.wrapped.CALegacyEEEnchantment import xyz.alexcrea.cuanvil.enchant.wrapped.CALegacyEEEnchantment
import java.lang.reflect.Constructor
import java.lang.reflect.Method import java.lang.reflect.Method
import su.nightexpress.excellentenchants.api.EnchantRegistry as V5EnchantRegistry import su.nightexpress.excellentenchants.api.EnchantRegistry as V5EnchantRegistry
import su.nightexpress.excellentenchants.enchantment.impl.universal.CurseOfFragilityEnchant as LegacyCurseOfFragilityEnchant import su.nightexpress.excellentenchants.enchantment.impl.universal.CurseOfFragilityEnchant as LegacyCurseOfFragilityEnchant
@ -47,7 +47,7 @@ class ExcellentEnchantsDependency {
listenerVersion = value listenerVersion = value
break break
} catch (ignored: ClassNotFoundException) { } catch (_: ClassNotFoundException) {
} }
} }
@ -60,7 +60,7 @@ class ExcellentEnchantsDependency {
var isModernCurseOfFragility = true var isModernCurseOfFragility = true
try { try {
Class.forName("su.nightexpress.excellentenchants.enchantment.universal.CurseOfFragilityEnchant") Class.forName("su.nightexpress.excellentenchants.enchantment.universal.CurseOfFragilityEnchant")
} catch (ignored: ClassNotFoundException) { } catch (_: ClassNotFoundException) {
isModernCurseOfFragility = false isModernCurseOfFragility = false
} }
@ -118,8 +118,6 @@ class ExcellentEnchantsDependency {
private lateinit var handleRechargeMethod: Method private lateinit var handleRechargeMethod: Method
private lateinit var handleCombineMethod: Method private lateinit var handleCombineMethod: Method
private val prepareAnvilConstructor = PrepareAnvilEvent::class.java.constructors.first() as Constructor<PrepareAnvilEvent>
fun redirectListeners() { fun redirectListeners() {
val toUnregister = ArrayList<RegisteredListener>() val toUnregister = ArrayList<RegisteredListener>()
// get required PrepareAnvilEvent listener // get required PrepareAnvilEvent listener
@ -227,7 +225,7 @@ class ExcellentEnchantsDependency {
val first: ItemStack = treatInput(event.leftItem) val first: ItemStack = treatInput(event.leftItem)
val second: ItemStack = treatInput(event.rightItem) val second: ItemStack = treatInput(event.rightItem)
val fakeEvent = prepareAnvilConstructor.newInstance(event.view, result) val fakeEvent = DependencyManager.createFakeEvent(event.view, result)
handleCombineMethod.invoke(this.usedAnvilListener, fakeEvent, first, second, result) handleCombineMethod.invoke(this.usedAnvilListener, fakeEvent, first, second, result)

View file

@ -3,7 +3,6 @@ package xyz.alexcrea.cuanvil.group
import io.delilaheve.CustomAnvil import io.delilaheve.CustomAnvil
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
import org.bukkit.configuration.ConfigurationSection import org.bukkit.configuration.ConfigurationSection
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.api.EnchantmentApi
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment
@ -32,10 +31,6 @@ class EnchantConflictManager {
// Path for the maximum number of enchantment before validating the conflict // Path for the maximum number of enchantment before validating the conflict
const val ENCH_MAX_PATH = "maxEnchantmentBeforeConflict" const val ENCH_MAX_PATH = "maxEnchantmentBeforeConflict"
// Path for a flag: if the enchantment will be used in the last supported version
// TODO maybe replace this system by a list of "future" enchantment.
private const val FUTURE_USE_PATH = "useInFuture"
// Default name for a joining group // Default name for a joining group
const val DEFAULT_GROUP_NAME = "joinedGroup" const val DEFAULT_GROUP_NAME = "joinedGroup"
} }
@ -100,8 +95,6 @@ class EnchantConflictManager {
itemManager: ItemGroupManager, itemManager: ItemGroupManager,
conflictName: String conflictName: String
): EnchantConflictGroup { ): EnchantConflictGroup {
// Is it planed for the future
val futureUse = section.getBoolean(FUTURE_USE_PATH, false)
// Create conflict // Create conflict
val conflict = createConflictObject(section, itemManager, conflictName) val conflict = createConflictObject(section, itemManager, conflictName)
// Read and add enchantment to conflict // Read and add enchantment to conflict
@ -109,17 +102,13 @@ class EnchantConflictManager {
for (enchantName in enchantList) { for (enchantName in enchantList) {
val enchants = getEnchantByIdentifier(enchantName) val enchants = getEnchantByIdentifier(enchantName)
if (enchants.isEmpty()) { if (enchants.isEmpty()) {
if (!futureUse) { //TODO future use will be deprecated once the new update system is finished CustomAnvil.instance.logger.warning("Enchantment $enchantName do not exist but was asked for conflict $conflictName")
CustomAnvil.instance.logger.warning("Enchantment $enchantName do not exist but was asked for conflict $conflictName")
}
continue continue
} }
conflict.addEnchantments(enchants) conflict.addEnchantments(enchants)
} }
if (conflict.getEnchants().isEmpty()) { if (conflict.getEnchants().isEmpty()) {
if (!futureUse) { //TODO future use will be deprecated once the new update system is finished CustomAnvil.instance.logger.warning("Conflict $conflictName do not have valid enchantment, it will not do anything")
CustomAnvil.instance.logger.warning("Conflict $conflictName do not have valid enchantment, it will not do anything")
}
} }
val conflictsAfterLevel = section.getConfigurationSection(CONFLICT_AFTER_LEVEL_LIST_PATH) val conflictsAfterLevel = section.getConfigurationSection(CONFLICT_AFTER_LEVEL_LIST_PATH)

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit most of these config. # It is recommended that you use /ca config to edit most of these config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #
@ -160,10 +160,6 @@ restriction_sweeping_edge:
enchantments: [ minecraft:sweeping, minecraft:sweeping_edge ] enchantments: [ minecraft:sweeping, minecraft:sweeping_edge ]
notAffectedGroups: [ enchanted_book, swords ] notAffectedGroups: [ enchanted_book, swords ]
restriction_swift_sneak:
enchantments: [ minecraft:swift_sneak ]
notAffectedGroups: [ enchanted_book, leggings ]
restriction_thorns: restriction_thorns:
enchantments: [ minecraft:thorns ] enchantments: [ minecraft:thorns ]
notAffectedGroups: [ enchanted_book, armors ] notAffectedGroups: [ enchanted_book, armors ]

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #

View file

@ -72,3 +72,4 @@ softdepend:
- ExcellentEnchants - ExcellentEnchants
- HavenBags - HavenBags
- SuperEnchants - SuperEnchants
- EnchantedBook

View file

@ -1,5 +1,5 @@
# #
# It is recommended that you use /configanvil to edit theses config. # It is recommended that you use /ca config to edit theses config.
# You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes ! # You can still manually edit here if you like to. but if you do, don't forget to /ca reload after you changes !
# #