From b25e3961c231e2d2830608e244b20746d8264343 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Sat, 8 Mar 2025 11:16:55 +0100 Subject: [PATCH] book edit kind of working --- .../cuanvil/listener/AnvilResultListener.kt | 219 +++++++++++++----- .../cuanvil/listener/PrepareAnvilListener.kt | 2 +- .../cuanvil/util/AnvilLoreEditUtil.kt | 41 ++-- 3 files changed, 180 insertions(+), 82 deletions(-) diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt index 5190c8c..9025de8 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt @@ -15,18 +15,21 @@ import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.InventoryView import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.BookMeta import xyz.alexcrea.cuanvil.dependency.DependencyManager import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_LEFT import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_RIGHT import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe +import xyz.alexcrea.cuanvil.util.AnvilLoreEditUtil import xyz.alexcrea.cuanvil.util.AnvilUseType import xyz.alexcrea.cuanvil.util.AnvilXpUtil import xyz.alexcrea.cuanvil.util.CustomRecipeUtil import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair +import java.util.* import kotlin.math.min -class AnvilResultListener: Listener { +class AnvilResultListener : Listener { companion object { // static slot container @@ -48,67 +51,80 @@ class AnvilResultListener: Listener { } // Test if the event should bypass custom anvil. - if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return + if (DependencyManager.tryClickAnvilResultBypass(event, inventory)) return val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) - if(GameMode.CREATIVE != player.gameMode && inventory.repairCost >= inventory.maximumRepairCost) { + if (GameMode.CREATIVE != player.gameMode && inventory.repairCost >= inventory.maximumRepairCost) { event.result = Event.Result.DENY return } // Test custom recipe val recipe = CustomRecipeUtil.getCustomRecipe(leftItem, rightItem) - if(recipe != null){ + if (recipe != null) { event.result = Event.Result.ALLOW onCustomCraft( event, recipe, player, - leftItem, rightItem, output, inventory) + leftItem, rightItem, output, inventory + ) return } - val canMerge = leftItem.canMergeWith(rightItem) - val unitRepairResult = leftItem.getRepair(rightItem) - val allowed = (rightItem == null) - || (canMerge) - || (unitRepairResult != null) - - // True if there was no change or not allowed - if ((output == inventory.getItem(ANVIL_INPUT_LEFT)) - || !allowed - ) { + // Do not continue if there was no change + if ((output == inventory.getItem(ANVIL_INPUT_LEFT))) { event.result = Event.Result.DENY return } + + // Rename if (rightItem == null) { event.result = Event.Result.ALLOW return } + + // Merge + val canMerge = leftItem.canMergeWith(rightItem) if (canMerge) { event.result = Event.Result.ALLOW - } else if (unitRepairResult != null) { + return + } + + // Unit repair + val unitRepairResult = leftItem.getRepair(rightItem) + if (unitRepairResult != null) { onUnitRepairExtract( leftItem, rightItem, output, unitRepairResult, event, player, inventory ) - return } + + // For lore edit + if (handleBookLoreEdit(event, inventory, player, leftItem, rightItem, output)) { + return + } else if (Material.PAPER == rightItem.type) { + //TODO + } + + // Else there was no working situation somehow so we deny + event.result = Event.Result.DENY } - private fun onCustomCraft(event: InventoryClickEvent, - recipe: AnvilCustomRecipe, - player: Player, - leftItem: ItemStack, - rightItem: ItemStack?, - output: ItemStack, - inventory: AnvilInventory + private fun onCustomCraft( + event: InventoryClickEvent, + recipe: AnvilCustomRecipe, + player: Player, + leftItem: ItemStack, + rightItem: ItemStack?, + output: ItemStack, + inventory: AnvilInventory ) { event.result = Event.Result.DENY - if(recipe.leftItem == null) return // in case it changed + if (recipe.leftItem == null) return // in case it changed val amount = CustomRecipeUtil.getCustomRecipeAmount(recipe, leftItem, rightItem) val xpCost = amount * recipe.xpCostPerCraft @@ -123,7 +139,8 @@ class AnvilResultListener: Listener { // Handle not creative middle click... if (event.click != ClickType.MIDDLE && - !handleCustomCraftClick(event, recipe, inventory, player, leftItem, rightItem, amount, xpCost)) return + !handleCustomCraftClick(event, recipe, inventory, player, leftItem, rightItem, amount, xpCost) + ) return // Finally, we add the item to the player if (slotDestination.type == SlotType.CURSOR) { @@ -133,13 +150,15 @@ class AnvilResultListener: Listener { } } - private fun handleCustomCraftClick(event: InventoryClickEvent, recipe: AnvilCustomRecipe, - inventory: AnvilInventory, player: Player, - leftItem: ItemStack, rightItem: ItemStack?, - amount: Int, xpCost: Int): Boolean { + private fun handleCustomCraftClick( + event: InventoryClickEvent, recipe: AnvilCustomRecipe, + inventory: AnvilInventory, player: Player, + leftItem: ItemStack, rightItem: ItemStack?, + amount: Int, xpCost: Int + ): Boolean { // We remove what should be removed - if(rightItem != null){ - if(recipe.rightItem == null) return false// in case it changed + if (rightItem != null) { + if (recipe.rightItem == null) return false// in case it changed rightItem.amount -= amount * recipe.rightItem!!.amount inventory.setItem(ANVIL_INPUT_RIGHT, rightItem) @@ -148,7 +167,7 @@ class AnvilResultListener: Listener { leftItem.amount -= amount * recipe.leftItem!!.amount inventory.setItem(ANVIL_INPUT_LEFT, leftItem) - if(player.gameMode != GameMode.CREATIVE){ + if (player.gameMode != GameMode.CREATIVE) { player.level -= xpCost } @@ -156,9 +175,9 @@ class AnvilResultListener: Listener { val newAmount = CustomRecipeUtil.getCustomRecipeAmount(recipe, leftItem, rightItem) CustomAnvil.verboseLog("new amount is $newAmount") - if(newAmount <= 0 || recipe.exactCount){ + if (newAmount <= 0 || recipe.exactCount) { inventory.setItem(ANVIL_OUTPUT_SLOT, null) - }else{ + } else { val resultItem: ItemStack = recipe.resultItem!!.clone() resultItem.amount *= newAmount @@ -174,6 +193,48 @@ class AnvilResultListener: Listener { return true } + private fun extractAnvilResult( + event: InventoryClickEvent, + player: Player, + inventory: AnvilInventory, + leftItem: ItemStack, + leftRemoveCount: Int, + rightItem: ItemStack, + rightRemoveCount: Int, + output: ItemStack, + repairCost: Int, + ): Boolean { + // Assumed if player do not have enough xp then it returned MIN_VALUE + if (repairCost == Int.MIN_VALUE) return false + + // Where should we get the item + val slotDestination = getActionSlot(event, player) + if (slotDestination.type == SlotType.NO_SLOT) return false + + // If not creative middle click... + if (event.click != ClickType.MIDDLE) { + // We remove what should be removed + leftItem.amount -= leftRemoveCount + inventory.setItem(ANVIL_INPUT_LEFT, leftItem) + + rightItem.amount -= rightRemoveCount + inventory.setItem(ANVIL_INPUT_RIGHT, rightItem) + + inventory.setItem(ANVIL_OUTPUT_SLOT, null) + player.level -= repairCost + } + + // Finally, we add the item to the player + if (SlotType.CURSOR == slotDestination.type) { + player.setItemOnCursor(output) + } else {// We assume SlotType == SlotType.INVENTORY + player.inventory.setItem(slotDestination.slot, output) + } + + // TODO probably anvil damage & sound here ?? + return true + } + private fun onUnitRepairExtract( leftItem: ItemStack, rightItem: ItemStack, @@ -191,36 +252,24 @@ class AnvilResultListener: Listener { // To avoid vanilla, we cancel the event for unit repair event.result = Event.Result.DENY event.isCancelled = true - // And we give the item manually - // But first we check if we should give the item - val slotDestination = getActionSlot(event, player) - if (slotDestination.type == SlotType.NO_SLOT) return - // Test repair cost + // Get repair cost val repairCost = getUnitRepairCost(inventory, player, leftItem, output, resultCopy, resultAmount) - if(repairCost == Int.MIN_VALUE) return - // If not creative middle click... - if (event.click != ClickType.MIDDLE) { - // We remove what should be removed - inventory.setItem(ANVIL_INPUT_LEFT, null) - rightItem.amount -= resultAmount - inventory.setItem(ANVIL_INPUT_RIGHT, rightItem) - inventory.setItem(ANVIL_OUTPUT_SLOT, null) - player.level -= repairCost - } - - // Finally, we add the item to the player - if (slotDestination.type == SlotType.CURSOR) { - player.setItemOnCursor(output) - } else {// We assume SlotType == SlotType.INVENTORY - player.inventory.setItem(slotDestination.slot, output) - } + // And then we give the item manually + extractAnvilResult( + event, player, inventory, + leftItem, 1, + rightItem, resultAmount, + output, repairCost + ) } - private fun getUnitRepairCost(inventory: AnvilInventory, player: Player, - leftItem: ItemStack, output: ItemStack, - resultCopy: ItemStack, resultAmount: Int): Int { + private fun getUnitRepairCost( + inventory: AnvilInventory, player: Player, + leftItem: ItemStack, output: ItemStack, + resultCopy: ItemStack, resultAmount: Int + ): Int { if (player.gameMode == GameMode.CREATIVE) return 0 var repairCost = 0 @@ -233,7 +282,7 @@ class AnvilResultListener: Listener { repairCost += ConfigOptions.itemRenameCost // Color cost - if(it.displayName.contains('§')){ + if (it.displayName.contains('§')) { repairCost += ConfigOptions.useOfColorCost } } @@ -257,6 +306,51 @@ class AnvilResultListener: Listener { return repairCost } + private fun handleBookLoreEdit( + event: InventoryClickEvent, + inventory: AnvilInventory, + player: Player, + leftItem: ItemStack, + rightItem: ItemStack, + output: ItemStack, + ): Boolean { + if (Material.WRITABLE_BOOK != rightItem.type) return false + val bookMeta = rightItem.itemMeta as BookMeta + + val editType = AnvilLoreEditUtil.bookLoreEditTypeAppend(leftItem, rightItem) ?: return false + + if (editType) { + if (output != AnvilLoreEditUtil.handleLoreAppendByBook(player, leftItem, bookMeta)) return false + + // Remove pages to + val bookCopy = rightItem.clone() + bookMeta.pages = Collections.emptyList() + bookCopy.itemMeta = bookMeta + + return extractAnvilResult( + event, player, inventory, + leftItem, 1, + bookCopy, 0, + output, 0 + ) //TODO DO REPAIR COST + } else { + if (output != AnvilLoreEditUtil.handleLoreRemoveByBook(player, leftItem, rightItem, bookMeta)) return false + + // remove lore + val leftCopy = leftItem.clone() + val leftMeta = leftCopy.itemMeta + leftMeta!!.lore = null + leftCopy.itemMeta = leftMeta + + return extractAnvilResult( + event, player, inventory, + leftCopy, 0, + rightItem, 1, + output, 0 + ) //TODO DO REPAIR COST + } + } + /** * Get the destination slot or "NO_SLOT" slot container if there is no slot available */ @@ -283,8 +377,7 @@ class AnvilResultListener: Listener { return NO_SLOT } return SlotContainer(SlotType.INVENTORY, slotIndex) - } - else if (player.itemOnCursor.type != Material.AIR) return NO_SLOT + } else if (player.itemOnCursor.type != Material.AIR) return NO_SLOT return CURSOR_SLOT } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt index 39f415f..95a6159 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt @@ -245,7 +245,7 @@ class PrepareAnvilListener : Listener { event.result = result // TODO forgot about xp config & logic - // AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, anvilCost) + AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, 1) return true } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilLoreEditUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilLoreEditUtil.kt index 342ba74..e3927c4 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilLoreEditUtil.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilLoreEditUtil.kt @@ -19,26 +19,27 @@ object AnvilLoreEditUtil { return ConfigOptions.PaperLoreEditNeedPermission && player.hasPermission(LORE_BY_PAPER) } - private fun handleLoreAppendByBook(player: Permissible, first: ItemStack, book: BookMeta): ItemStack? { - if(!hasLoreEditByBookPermission(player)) return null + fun handleLoreAppendByBook(player: Permissible, first: ItemStack, book: BookMeta): ItemStack? { + if (!hasLoreEditByBookPermission(player)) return null val result = first.clone() val meta = result.itemMeta + //TODO take into account previous lore meta?.lore = book.pages[0].split("\n") //TODO check color if color is enabled result.itemMeta = meta return result } - private fun handleLoreRemoveByBook(player: Permissible, first: ItemStack, second: ItemStack, book: BookMeta): ItemStack? { - if(!hasLoreEditByBookPermission(player)) return null + fun handleLoreRemoveByBook(player: Permissible, first: ItemStack, second: ItemStack, book: BookMeta): ItemStack? { + if (!hasLoreEditByBookPermission(player)) return null val meta = first.itemMeta - if(meta == null || !meta.hasLore()) return null + if (meta == null || !meta.hasLore()) return null val bookPage = StringBuilder() meta.lore!!.forEach { - if(bookPage.isNotEmpty()) bookPage.append('\n') + if (bookPage.isNotEmpty()) bookPage.append('\n') bookPage.append(it) } @@ -52,15 +53,16 @@ object AnvilLoreEditUtil { return result } - fun bookLoreEditType(second: ItemStack) : Boolean? { + // Return true if append, false if remove, null if neither + fun bookLoreEditTypeAppend(first: ItemStack, second: ItemStack): Boolean? { // Test if the book & quil contain content val meta = second.itemMeta as BookMeta var hasContent = false - if(meta.hasPages() && meta.pageCount >= 1){ + if (meta.hasPages() && meta.pageCount >= 1) { // Test if the pages is ok for (page in meta.pages) { - if(page.isNotEmpty()) { + if (page.isNotEmpty()) { hasContent = true break } @@ -68,23 +70,26 @@ object AnvilLoreEditUtil { } // We don't want to "add" the first page is there is content and the first page is empty - if(hasContent){ - if(meta.pages[0].isEmpty()) return null - if(ConfigOptions.appendLoreBookAndQuil) + if (hasContent) { + if (meta.pages[0].isEmpty()) return null + if (ConfigOptions.appendLoreBookAndQuil) return true - } - else if(ConfigOptions.removeLoreBookAndQuil) { - return false + } else if (ConfigOptions.removeLoreBookAndQuil) { + if (!first.hasItemMeta()) return null + + val leftMeta = first.itemMeta!! + return if (leftMeta.hasLore()) false + else null } return null } fun tryLoreEditByBook(player: HumanEntity, first: ItemStack, second: ItemStack): ItemStack? { - val bookType = bookLoreEditType(second) ?: return null + val bookType = bookLoreEditTypeAppend(first, second) ?: return null val meta = second.itemMeta as BookMeta - return if(bookType) handleLoreAppendByBook(player, first, meta) - else handleLoreRemoveByBook(player, first, second, meta) + return if (bookType) handleLoreAppendByBook(player, first, meta) + else handleLoreRemoveByBook(player, first, second, meta) } } \ No newline at end of file