diff --git a/build.gradle.kts b/build.gradle.kts index a5dc7c34..4436e29e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,7 +22,7 @@ plugins { } group = "xyz.alexcrea" -version = "1.17.5" +version = "1.17.6" val isDevBuild = System.getenv("SMALL_COMMIT_HASH") != null val isPreRelease = System.getenv("IS_GITHUB_PRERELEASE") == "true" diff --git a/src/main/kotlin/io/delilaheve/CustomAnvil.kt b/src/main/kotlin/io/delilaheve/CustomAnvil.kt index 4d99faf5..e12ba4d6 100644 --- a/src/main/kotlin/io/delilaheve/CustomAnvil.kt +++ b/src/main/kotlin/io/delilaheve/CustomAnvil.kt @@ -71,21 +71,35 @@ open class CustomAnvil : JavaPlugin() { var latestVer: String? = null + // Debug + val debugStorageQueue = ArrayDeque() + + private fun addToLogQueue(message: String) { + if(debugStorageQueue.size >= 200) { + // Let not store infinite debug logs lol + debugStorageQueue.removeFirst() + } + + debugStorageQueue.addLast(message) + } + /** * Logging handler */ @JvmStatic fun log(message: String) { if (ConfigOptions.debugLog) { instance.logger.info(message) + addToLogQueue(message) } } /** * Vebose Logging handler */ - fun verboseLog(message: String) { + @JvmStatic fun verboseLog(message: String) { if (ConfigOptions.verboseDebugLog) { instance.logger.info(message) + addToLogQueue(message) } } diff --git a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt index 9dc85f97..86b531ec 100644 --- a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt +++ b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt @@ -128,6 +128,9 @@ object ConfigOptions { private const val DEFAULT_DEBUG_LOG = false private const val DEFAULT_VERBOSE_DEBUG_LOG = false + var OVERRIDE_DEBUG_LOG: Boolean? = null + var OVERRIDE_VERBOSE_DEBUG_LOG: Boolean? = null + // Dialog menu rename const val DEFAULT_DIALOG_RENAME_ENABLED = false const val DEFAULT_DIALOG_MAX_SIZE = 256 @@ -436,6 +439,9 @@ object ConfigOptions { */ val debugLog: Boolean get() { + val overrider = OVERRIDE_DEBUG_LOG + if(overrider != null) return overrider + return ConfigHolder.DEFAULT_CONFIG .config .getBoolean(DEBUG_LOGGING, DEFAULT_DEBUG_LOG) @@ -446,6 +452,9 @@ object ConfigOptions { */ val verboseDebugLog: Boolean get() { + val overrider = OVERRIDE_VERBOSE_DEBUG_LOG + if(overrider != null) return overrider + return ConfigHolder.DEFAULT_CONFIG .config .getBoolean(VERBOSE_DEBUG_LOGGING, DEFAULT_VERBOSE_DEBUG_LOG) diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/CustomAnvilCommand.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/CustomAnvilCommand.kt index e5e689e2..8bd1d827 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/command/CustomAnvilCommand.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/command/CustomAnvilCommand.kt @@ -22,6 +22,7 @@ class CustomAnvilCommand(plugin: CustomAnvil) : CommandExecutor, TabCompleter { "gui", editConfigCommand, "reload", ReloadExecutor(), "diagnostic", DiagnosticExecutor(), + "debug", DebugToggleExecutor(), "help", helpCommand, ) diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/DebugToggleExecutor.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/DebugToggleExecutor.kt new file mode 100644 index 00000000..9959d269 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/command/DebugToggleExecutor.kt @@ -0,0 +1,114 @@ +package xyz.alexcrea.cuanvil.command + +import io.delilaheve.CustomAnvil +import io.delilaheve.util.ConfigOptions +import net.md_5.bungee.api.chat.ClickEvent +import net.md_5.bungee.api.chat.HoverEvent +import net.md_5.bungee.api.chat.TextComponent +import net.md_5.bungee.api.chat.hover.content.Text +import org.bukkit.ChatColor +import org.bukkit.command.Command +import org.bukkit.command.CommandSender +import xyz.alexcrea.cuanvil.command.DiagnosticExecutor.Companion.NO_DIAG_PERM + +class DebugToggleExecutor : CASubCommand() { + + override fun description(): String { + return "Used to toggle debug logs and retrieve it" + } + + override fun allowed(sender: CommandSender): Boolean { + return sender.hasPermission(CustomAnvil.diagnosticPermission) + } + + override fun executeCommand( + sender: CommandSender, + cmd: Command, + cmdstr: String, + args: Array + ): Boolean { + if (!allowed(sender)) { + sender.sendMessage(NO_DIAG_PERM) + return false + } + + if (args.isEmpty()) { + sender.sendMessage("Need to specify a subcommand: \"toggle\" or \"get\"") + return true + } + when (args[0].lowercase()) { + "toggle" -> executeToggle(sender, args) + "get" -> executeGet(sender) + "get-and-clear" -> { + executeGet(sender) + CustomAnvil.debugStorageQueue.clear() + } + + "clear" -> { + CustomAnvil.debugStorageQueue.clear() + sender.sendMessage("Log Cleared") + } + + else -> return false + } + return true + } + + private fun executeToggle(sender: CommandSender, args: Array) { + if (args.size < 2) { + sender.sendMessage("Need to specify which type of debug to toggle: \"default\" or \"verbose\"") + return + } + when (args[1].lowercase()) { + "default" -> { + ConfigOptions.OVERRIDE_DEBUG_LOG = !ConfigOptions.debugLog + sender.sendMessage("Debug toggle to: ${ConfigOptions.debugLog}") + } + + "verbose" -> { + ConfigOptions.OVERRIDE_VERBOSE_DEBUG_LOG = !ConfigOptions.verboseDebugLog + sender.sendMessage("Debug toggle to: ${ConfigOptions.verboseDebugLog}") + } + + else -> sender.sendMessage("Invalid debug type: ${args[1]}") + } + + } + + private fun executeGet(sender: CommandSender) { + val stb = StringBuilder("Debug Log data:") + if (CustomAnvil.debugStorageQueue.isEmpty()) { + sender.sendMessage("No log to show ? make sure you tried with debug log toggled (/ca debug toggle)") + return + } + + stb.append("\nFound ${CustomAnvil.debugStorageQueue.size} lines\n") + for (log in CustomAnvil.debugStorageQueue) { + stb.append('\n').append(log) + } + + val message = TextComponent(ChatColor.GREEN.toString() + "Click to copy log data") + + message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString()) + message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("ยง7Click to copy")) + + sender.spigot().sendMessage(message); + } + + override fun tabCompleter(sender: CommandSender, args: Array, list: MutableList) { + if (!allowed(sender)) return + + list.addAll( + when (args.size) { + 1 -> listOf("toggle", "get", "get-and-clear", "clear") + 2 -> when (args[0].lowercase()) { + "toggle" -> listOf("default", "verbose") + else -> listOf() + } + + else -> listOf() + } + ) + } + +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/DiagnosticExecutor.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/DiagnosticExecutor.kt index 053a3fc1..b095e14c 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/command/DiagnosticExecutor.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/command/DiagnosticExecutor.kt @@ -36,7 +36,7 @@ import java.util.stream.Collectors class DiagnosticExecutor: CASubCommand() { companion object{ - private const val NO_DIAG_PERM = "You do not have permission to diagnostic this server" + const val NO_DIAG_PERM = "You do not have permission to diagnostic this server" fun fetchNMSType(): String { val packetManager = DependencyManager.packetManager diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt index e393dbd9..e9290ac9 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/AnvilResultListener.kt @@ -107,12 +107,17 @@ class AnvilResultListener : Listener { if (canMerge) { val result = AnvilMergeLogic.doMerge(view, inventory, player, leftItem, rightItem) - extractAnvilResult( + val worked = extractAnvilResult( event, player, inventory, null, 0, null, 0, result ) + if(!worked) { + CustomAnvil.verboseLog("Merge extract failed. reset the displayed price") + // Reset the price + AnvilXpUtil.setAnvilResult(inventory, view, player, result) + } return } @@ -276,11 +281,20 @@ class AnvilResultListener : Listener { val cost = result.cost if (cost.isMonetary) { val result = EconomyManager.economy!!.remove(player, cost.asMonetaryCost()) - if (!result) return false + if (!result) { + CustomAnvil.verboseLog("Could not remove monetary cost ${cost.asMonetaryCost()}") + return false + } } else { val xpCost = cost.filteredXpCost() - if (xpCost > AnvilXpUtil.maximumXpCost(result.ignoreXpRules)) return false - if (player.level < xpCost) return false + if (xpCost > AnvilXpUtil.maximumXpCost(result.ignoreXpRules)) { + CustomAnvil.verboseLog("Cost above maximum $xpCost > ${AnvilXpUtil.maximumXpCost(result.ignoreXpRules)}") + return false + } + if (player.level < xpCost) { + CustomAnvil.verboseLog("Player do not have enough xp ${player.level} < $xpCost") + return false + } player.level -= xpCost } @@ -298,7 +312,10 @@ class AnvilResultListener : Listener { rightRemoveCount: Int, result: AnvilResult ): Boolean { - if (result.isEmpty()) return false + if (result.isEmpty()) { + CustomAnvil.verboseLog("Merge result is empty") + return false + } // To avoid vanilla, we cancel the event event.result = Event.Result.DENY @@ -306,7 +323,10 @@ class AnvilResultListener : Listener { val cost = result.cost processCost(inventory, player, cost) - if (!cost.valid && player.gameMode != GameMode.CREATIVE) return false + if (!cost.valid && player.gameMode != GameMode.CREATIVE) { + CustomAnvil.verboseLog("Player cannot afford the cost") + return false + } // Where should we get the item val slotDestination = getActionSlot(event, player) diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt index 02179832..c0fe939b 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/listener/PrepareAnvilListener.kt @@ -171,11 +171,7 @@ class PrepareAnvilListener : Listener { private fun applyResult(event: PrepareAnvilEvent, player: Player, result: AnvilResult) { event.result = result.item - if(result.item == null) { - AnvilXpUtil.onNoResult(player, event.view) - return - } - AnvilXpUtil.setAnvilInvCost(event.inventory, event.view, player, result.cost, result.ignoreXpRules) + AnvilXpUtil.setAnvilResult(event.inventory, event.view, player, result) } } \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/anvil/AnvilXpUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/anvil/AnvilXpUtil.kt index 4846f319..01c4be90 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/util/anvil/AnvilXpUtil.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/anvil/AnvilXpUtil.kt @@ -15,6 +15,7 @@ import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.Repairable 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.config.ConfigHolder import xyz.alexcrea.cuanvil.dependency.DependencyManager @@ -28,7 +29,23 @@ object AnvilXpUtil { const val EXCLUSIVE_PENALTY_PREFIX = "repair_cost" /** - * Display the required cost (either as xp or as ) + * Display the required cost (either as xp or as money) or reset anvil price depending on result + */ + fun setAnvilResult( + inventory: AnvilInventory, + view: InventoryView, + player: Player, + result: AnvilResult) { + if(result.item == null) { + onNoResult(player, view) + return + } + + setAnvilInvCost(inventory, view, player, result.cost, result.ignoreXpRules) + } + + /** + * Display the required cost (either as xp or as money) */ fun setAnvilInvCost( inventory: AnvilInventory,