add anvil simulation test for diag

This commit is contained in:
alexcrea 2026-03-02 19:03:33 +01:00
parent 6e981af017
commit 1ddedc6838
Signed by: alexcrea
GPG key ID: E346CD16413450E3
4 changed files with 142 additions and 34 deletions

View file

@ -7,7 +7,6 @@ import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender
import org.bukkit.command.TabCompleter
import java.util.ArrayList
import java.util.Arrays
class CustomAnvilCmd(plugin: CustomAnvil) : CommandExecutor, TabCompleter {
@ -61,12 +60,12 @@ class CustomAnvilCmd(plugin: CustomAnvil) : CommandExecutor, TabCompleter {
args: Array<out String>
): MutableList<String> {
val result = ArrayList<String>()
if(args.size < 3) {
for (cmd in commands) {
if(args.size < 2) {
for (cmd in commands) {
result.add(cmd.key)
}
} else {
val subcmd = commands[args[1].lowercase()]
val subcmd = commands[args[0].lowercase()]
if(subcmd != null) {
val newArgs = args.copyOfRange(1, args.size)

View file

@ -1,5 +1,6 @@
package xyz.alexcrea.cuanvil.command
import com.github.stefvanschie.inventoryframework.inventoryview.interface_.InventoryViewUtil
import io.delilaheve.CustomAnvil
import net.md_5.bungee.api.chat.ClickEvent
import net.md_5.bungee.api.chat.HoverEvent
@ -7,16 +8,27 @@ import net.md_5.bungee.api.chat.TextComponent
import net.md_5.bungee.api.chat.hover.content.Text
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.HumanEntity
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryType
import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.AnvilInventory
import org.bukkit.inventory.InventoryView
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Damageable
import org.bukkit.inventory.meta.EnchantmentStorageMeta
import org.bukkit.plugin.Plugin
import org.bukkit.plugin.PluginManager
import org.bukkit.plugin.RegisteredListener
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dependency.packet.NoPacketManager
import xyz.alexcrea.cuanvil.dependency.packet.ProtocoLibWrapper
import xyz.alexcrea.cuanvil.dependency.packet.versions.PaperPacketManager
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
import java.util.*
import java.util.stream.Collectors
@ -30,7 +42,8 @@ class DiagnosticExecutor: CASubCommand() {
enum class DiagParams(val value: String) {
OS_PRIVACY("os_privacy"),
PLUGIN_PRIVACY("plugin_privacy"),
//NO_TEST("no_anvil_test"),
NO_MERGE_TEST("no_merge_test");
// TODO enchant list
}
private fun fetchParameters(args: Array<out String>): EnumSet<DiagParams> {
@ -76,17 +89,22 @@ class DiagnosticExecutor: CASubCommand() {
val stb = StringBuilder("```\n")
val params = fetchParameters(args)
var hasError = false
try {
diagnostic(stb, params)
} catch(e: Exception){
diagnostic(sender, stb, params)
} catch(e: Throwable){
stb.append("\n\nError happened trying to get diagnostic data:\n")
.append(e.message).append("\n")
.append(e.stackTrace.joinToString("\n"))
hasError = true
e.printStackTrace()
}
stb.append("\n```")
if (sender is HumanEntity) {
if(hasError)
sender.spigot().sendMessage(TextComponent(ChatColor.RED.toString() + "There was an error running the diagnostic"))
val message = TextComponent(ChatColor.GREEN.toString() + "Click to copy diagnostic data")
message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString())
@ -104,42 +122,71 @@ class DiagnosticExecutor: CASubCommand() {
return sender.hasPermission(CustomAnvil.diagnosticPermission)
}
fun diagnostic(stb: StringBuilder, params: Set<DiagParams>){
fun diagnostic(sender: CommandSender, stb: StringBuilder, params: Set<DiagParams>){
stb.append("Server Info\n")
stb.append("Plugin Version: ").append(CustomAnvil.instance.description.version).append("\n")
stb.append("Latest Update: ").append(CustomAnvil.latestVer).append('\n')
stb.append("Server Version: ").append(Bukkit.getVersion()).append(" (").append(Bukkit.getName()).append(')').append("\n")
stb.append("Plugin Enabled: ").append(if(CustomAnvil.instance.isEnabled) "Yes" else "No").append("\n")
stb.append("NMS type: ").append(fetchNMSType())
stb.append("\nPlugin Version: ").append(CustomAnvil.instance.description.version)
stb.append("\nLatest Update: ").append(CustomAnvil.latestVer)
stb.append("\nServer Version: ").append(Bukkit.getVersion()).append(" (").append(Bukkit.getName()).append(')')
stb.append("\nPlugin Enabled: ").append(if(CustomAnvil.instance.isEnabled) "Yes" else "No")
stb.append("\nNMS type: ").append(fetchNMSType())
if(!params.contains(DiagParams.OS_PRIVACY)) {
stb.append("Java Version: ").append(System.getProperty("java.version")).append("\n")
stb.append("OS: ").append(System.getProperty("os.name")).append(" ")
stb.append("\nJava Version: ").append(System.getProperty("java.version"))
stb.append("\nOS: ").append(System.getProperty("os.name")).append(" ")
.append(System.getProperty("os.version"))
.append(System.getProperty("os.arch"))
.append("\n\n")
}
if(!params.contains(DiagParams.PLUGIN_PRIVACY)) {
pluginListDiag(stb)
pluginListDiag(sender, stb)
}
prepareAnvilListeners(stb)
stb.append("\n\n")
if(!params.contains(DiagParams.NO_MERGE_TEST)){
if(sender is Player) {
testMerge(sender, stb)
}
}
}
private fun testMerge(player: Player, stb: StringBuilder) {
val sword = ItemStack(Material.DIAMOND_SWORD)
val damagedSword = sword.clone()
val enchantedSword = sword.clone()
val enchantedBook = ItemStack(Material.ENCHANTED_BOOK)
val unitForRepair = ItemStack(Material.DIAMOND)
var meta = damagedSword.itemMeta
(meta as Damageable).damage = 5
damagedSword.itemMeta = meta
meta = enchantedSword.itemMeta
meta!!.addEnchant(Enchantment.DAMAGE_ALL, 1, true)
enchantedSword.itemMeta = meta
meta = enchantedBook.itemMeta
(meta as EnchantmentStorageMeta).addStoredEnchant(Enchantment.DAMAGE_ALL, 1, true)
enchantedBook.itemMeta = meta
stb.append("\n\nItem to Item repair:")
simulateAnvil(player, stb, damagedSword, damagedSword, sword)
stb.append("\n\nUnit repair:")
simulateAnvil(player, stb, damagedSword, unitForRepair, sword)
stb.append("\n\nEnchanting an item:")
simulateAnvil(player, stb, sword, enchantedBook, enchantedSword)
}
private fun fetchNMSType(): String {
val packetManager = DependencyManager.packetManager
val packetManagerClass = packetManager.javaClass
val result: String
if(packetManagerClass == PaperPacketManager::class.java) {
result = "Paper NMS"
} else if(packetManagerClass == ProtocoLibWrapper::class.java) {
result = "Protocolib"
} else if(packetManagerClass == NoPacketManager::class.java) {
result = "None"
} else {
result = "Version Specific"
val result = when (packetManagerClass) {
PaperPacketManager::class.java -> "Paper NMS"
ProtocoLibWrapper::class.java -> "Protocolib"
NoPacketManager::class.java -> "None"
else -> "Version Specific"
}
return "$result ${if(packetManager.canSetInstantBuild) '✅' else '❌'}"
@ -150,7 +197,7 @@ class DiagnosticExecutor: CASubCommand() {
return this.name + " v" + this.description.version
}
private fun pluginListDiag(stb: StringBuilder) {
private fun pluginListDiag(sender: CommandSender, stb: StringBuilder) {
val enabledPlugins: MutableList<Plugin?> = ArrayList<Plugin?>()
val disabledPlugins: MutableList<Plugin?> = ArrayList<Plugin?>()
for (plugin in Bukkit.getPluginManager().plugins) {
@ -161,17 +208,17 @@ class DiagnosticExecutor: CASubCommand() {
}
}
stb.append("Enabled Plugins: ").append(
stb.append("\nEnabled Plugins: ").append(
enabledPlugins.stream()
.map { plugin -> plugin!!.pluginNameDisplay }
.reduce { a: String?, b: String? -> "$a, $b" }.orElse("None")
).append("\n")
)
stb.append("Disabled Plugins: ").append(
stb.append("\nDisabled Plugins: ").append(
disabledPlugins.stream()
.map { plugin -> plugin!!.pluginNameDisplay }
.reduce { a: String?, b: String? -> "$a, $b" }.orElse("None")
).append("\n")
)
}
fun prepareAnvilListeners(stb: StringBuilder) {
@ -185,11 +232,63 @@ class DiagnosticExecutor: CASubCommand() {
.collect(Collectors.toSet())
eventListeners.remove(CustomAnvil.instance)
stb.append("Prepare Anvil Listeners: ").append(
stb.append("\nPrepare Anvil Listeners: ").append(
if (eventListeners.isEmpty()) "None" else eventListeners.stream()
.map { plugin -> plugin!!.pluginNameDisplay }
.reduce { a: String?, b: String? -> "$a, $b" }.orElse("None")
).append("\n\n")
)
}
fun simulateAnvil(player: Player, stb: StringBuilder, left: ItemStack?, right: ItemStack?, result: ItemStack?) {
var invView: InventoryView
var event: PrepareAnvilEvent
try {
val fakeInv = Bukkit.createInventory(player, InventoryType.ANVIL)
invView = player.openInventory(fakeInv)!!
event = PrepareAnvilEvent(invView, result)
} catch (e: Throwable) {
// Help
val menuTypeClazz = Class.forName("org.bukkit.inventory.MenuType")
val anvilTypeField = menuTypeClazz.getField("ANVIL")
val anvilType = anvilTypeField.get(null)
val createMethod = anvilType.javaClass.getMethod("create", HumanEntity::class.java)
invView = createMethod.invoke(anvilType, player) as InventoryView
player.openInventory(invView)
val anvilViewClass = Class.forName("org.bukkit.inventory.view.AnvilView")
val constructor = PrepareAnvilEvent::class.java.getConstructor(anvilViewClass, ItemStack::class.java)
event = constructor.newInstance(invView, result)
}
val fakeInv = InventoryViewUtil.getInstance().getTopInventory(invView) as AnvilInventory
fakeInv.setItem(0, left)
fakeInv.setItem(1, right)
val xp = fakeInv.repairCost
val maxXp = fakeInv.maximumRepairCost
val mergeResult = fakeInv.getItem(2)
stb.append("\n${if(result == mergeResult) "E" else "Une"}xpected Result")
PrepareAnvilListener().anvilCombineCheck(event)
// Now we check if item and xp same
stb.append("\nXP/Max XP: ")
.append(if(fakeInv.repairCost == xp) "Correct" else "Incorrect")
.append("/")
.append(if(fakeInv.maximumRepairCost == maxXp) "Correct" else "Incorrect")
.append(" (${fakeInv.repairCost} $xp|${fakeInv.maximumRepairCost} $maxXp)")
.append("\nMerge result: ")
.append(if(fakeInv.getItem(2) == mergeResult) "Correct" else "Incorrect")
PrepareAnvilListener.IS_EMPTY_TEST = true
Bukkit.getPluginManager().callEvent(event)
stb.append("\nNull result test: ")
.append(if(event.result == null) "Correct" else "Incorrect")
fakeInv.setItem(0, null)
fakeInv.setItem(1, null)
fakeInv.setItem(2, null)
player.closeInventory()
}
}

View file

@ -38,6 +38,8 @@ class PrepareAnvilListener : Listener {
const val ANVIL_INPUT_LEFT = 0
const val ANVIL_INPUT_RIGHT = 1
const val ANVIL_OUTPUT_SLOT = 2
var IS_EMPTY_TEST = false
}
private fun ItemStack?.isAir(): Boolean {
@ -63,6 +65,12 @@ class PrepareAnvilListener : Listener {
val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
val second = inventory.getItem(ANVIL_INPUT_RIGHT)
if(IS_EMPTY_TEST) {
event.result = null
IS_EMPTY_TEST = false
return
}
if (isImmutable(first) || isImmutable(second)) {
CustomAnvil.verboseLog("Skipping anvil process as one of the two item is immutable")

View file

@ -12,6 +12,8 @@ libraries: [${libraries}]
commands:
customanvil:
description: Generic command for custom anvil
aliases:
- ca
anvilconfigreload:
description: Reload every config of this plugin
permission: ca.command.reload