mirror of
https://github.com/alexcrea/CustomAnvil.git
synced 2026-08-28 08:25:56 +02:00
344 lines
No EOL
12 KiB
Kotlin
344 lines
No EOL
12 KiB
Kotlin
package xyz.alexcrea.cuanvil.command
|
|
|
|
import io.delilaheve.CustomAnvil
|
|
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.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.ItemStack
|
|
import org.bukkit.inventory.meta.Damageable
|
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta
|
|
import org.bukkit.inventory.view.AnvilView
|
|
import org.bukkit.plugin.Plugin
|
|
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.enchant.CAEnchantmentRegistry
|
|
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
|
|
import xyz.alexcrea.cuanvil.util.MetricsUtil
|
|
import java.util.*
|
|
import java.util.stream.Collectors
|
|
|
|
class DiagnosticExecutor : CASubCommand {
|
|
|
|
companion object {
|
|
const val NO_DIAG_PERM = "You do not have permission to diagnostic this server"
|
|
|
|
fun fetchNMSType(): String {
|
|
val packetManager = DependencyManager.packetManager
|
|
val packetManagerClass = packetManager.javaClass
|
|
|
|
val className = packetManagerClass.name
|
|
val result = if (className.contains("PaperPacket")) {
|
|
"Paper"
|
|
} else {
|
|
when (packetManagerClass) {
|
|
ProtocoLibWrapper::class.java -> "Protocolib"
|
|
NoPacketManager::class.java -> "None"
|
|
else -> "Version Specific"
|
|
}
|
|
}
|
|
|
|
|
|
return "$result ${if (packetManager.canSetInstantBuild) '✅' else '❌'}"
|
|
}
|
|
}
|
|
|
|
enum class DiagParams(val value: String) {
|
|
OS_PRIVACY("os_privacy"),
|
|
PLUGIN_PRIVACY("plugin_privacy"),
|
|
NO_MERGE_TEST("no_merge_test"),
|
|
FULL_ENCHANTMENT_DATA("full_enchantment_data"),
|
|
INCLUDE_LAST_ERROR("include_last_error"),
|
|
}
|
|
|
|
private fun fetchParameters(args: Array<out String>): EnumSet<DiagParams> {
|
|
val result = EnumSet.noneOf(DiagParams::class.java)
|
|
val argSet = HashSet<String>()
|
|
|
|
for (string in args) {
|
|
argSet.add(string.lowercase())
|
|
}
|
|
|
|
for (param in DiagParams.entries) {
|
|
if (argSet.contains(param.value))
|
|
result.add(param)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
override fun tabCompleter(
|
|
sender: CommandSender,
|
|
args: Array<out String>,
|
|
list: MutableList<String>
|
|
) {
|
|
if (!allowed(sender)) return
|
|
|
|
val map = fetchParameters(args)
|
|
for (param in DiagParams.entries) {
|
|
if (!map.contains(param))
|
|
list.add(param.value)
|
|
}
|
|
|
|
}
|
|
|
|
override fun executeCommand(
|
|
sender: CommandSender,
|
|
cmd: Command,
|
|
cmdstr: String,
|
|
args: Array<out String>
|
|
): Boolean {
|
|
if (!allowed(sender)) {
|
|
sender.sendMessage(NO_DIAG_PERM)
|
|
return false
|
|
}
|
|
|
|
val stb = StringBuilder("```\n")
|
|
val params = fetchParameters(args)
|
|
var hasError = false
|
|
try {
|
|
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.sendMessage(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())
|
|
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("§7Click to copy"))
|
|
|
|
sender.spigot().sendMessage(message)
|
|
} else {
|
|
sender.sendMessage(stb.toString())
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
override fun allowed(sender: CommandSender): Boolean {
|
|
return sender.hasPermission(CustomAnvil.diagnosticPermission)
|
|
}
|
|
|
|
fun diagnostic(sender: CommandSender, stb: StringBuilder, params: Set<DiagParams>) {
|
|
stb.append("Server Info\n")
|
|
val version = CustomAnvil.instance.description.version
|
|
stb.append("\nPlugin Version: ").append(version)
|
|
if (version.contains("dev")) stb.append(" (alpha)")
|
|
|
|
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("\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"))
|
|
}
|
|
|
|
stb.append("\nHad detect error: ").append(if (MetricsUtil.lastError != null) "Yes" else "No")
|
|
|
|
if (!params.contains(DiagParams.PLUGIN_PRIVACY)) {
|
|
pluginListDiag(sender, stb)
|
|
}
|
|
prepareAnvilListeners(stb)
|
|
|
|
if (!params.contains(DiagParams.NO_MERGE_TEST)) {
|
|
if (sender is Player) testMerge(sender, stb)
|
|
}
|
|
|
|
stb.append("\n\nEnchantments data:")
|
|
partialEnchantmentData(stb)
|
|
if (params.contains(DiagParams.FULL_ENCHANTMENT_DATA)) {
|
|
fullEnchantmentData(stb)
|
|
}
|
|
|
|
if (params.contains(DiagParams.INCLUDE_LAST_ERROR)) {
|
|
includeLastError(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.SHARPNESS, 1, true)
|
|
enchantedSword.itemMeta = meta
|
|
|
|
meta = enchantedBook.itemMeta
|
|
(meta as EnchantmentStorageMeta).addStoredEnchant(Enchantment.SHARPNESS, 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 val Plugin.pluginNameDisplay: String
|
|
get() {
|
|
return this.name + " v" + this.description.version
|
|
}
|
|
|
|
override fun description(): String {
|
|
return "Basic diagnostic of this plugin"
|
|
}
|
|
|
|
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) {
|
|
if (plugin.isEnabled) {
|
|
enabledPlugins.add(plugin)
|
|
} else {
|
|
disabledPlugins.add(plugin)
|
|
}
|
|
}
|
|
|
|
stb.append("\nEnabled Plugins: ").append(
|
|
enabledPlugins.stream()
|
|
.map { plugin -> plugin!!.pluginNameDisplay }
|
|
.reduce { a: String?, b: String? -> "$a, $b" }.orElse("None")
|
|
)
|
|
|
|
stb.append("\nDisabled Plugins: ").append(
|
|
disabledPlugins.stream()
|
|
.map { plugin -> plugin!!.pluginNameDisplay }
|
|
.reduce { a: String?, b: String? -> "$a, $b" }.orElse("None")
|
|
)
|
|
}
|
|
|
|
fun prepareAnvilListeners(stb: StringBuilder) {
|
|
val eventListeners: MutableSet<Plugin?> = Arrays
|
|
.stream(
|
|
PrepareAnvilEvent
|
|
.getHandlerList()
|
|
.getRegisteredListeners()
|
|
)
|
|
.map { obj: RegisteredListener? -> obj!!.plugin }
|
|
.collect(Collectors.toSet())
|
|
|
|
eventListeners.remove(CustomAnvil.instance)
|
|
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")
|
|
)
|
|
}
|
|
|
|
fun simulateAnvil(player: Player, stb: StringBuilder, left: ItemStack?, right: ItemStack?, result: ItemStack?) {
|
|
var invView: AnvilView
|
|
var event: PrepareAnvilEvent
|
|
try {
|
|
val fakeInv = Bukkit.createInventory(player, InventoryType.ANVIL)
|
|
invView = player.openInventory(fakeInv)!! as AnvilView
|
|
event = DependencyManager.createFakeEvent(invView, result)
|
|
} catch (_: 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 AnvilView
|
|
|
|
player.openInventory(invView)
|
|
|
|
val constructor = PrepareAnvilEvent::class.java.getConstructor(AnvilView::class.java, ItemStack::class.java)
|
|
event = constructor.newInstance(invView, result)
|
|
}
|
|
|
|
invView.setItem(0, left)
|
|
invView.setItem(1, right)
|
|
|
|
val xp = invView.repairCost
|
|
val maxXp = invView.maximumRepairCost
|
|
val mergeResult = invView.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 (invView.repairCost == xp) "Correct" else "Incorrect")
|
|
.append("/")
|
|
.append(if (invView.maximumRepairCost == maxXp) "Correct" else "Incorrect")
|
|
.append(" (${invView.repairCost} $xp|${invView.maximumRepairCost} $maxXp)")
|
|
.append("\nMerge result: ")
|
|
.append(if (invView.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")
|
|
|
|
invView.setItem(0, null)
|
|
invView.setItem(1, null)
|
|
invView.setItem(2, null)
|
|
player.closeInventory()
|
|
}
|
|
|
|
private fun fullEnchantmentData(stb: StringBuilder) {
|
|
for (enchantment in CAEnchantmentRegistry.getInstance().values()) {
|
|
stb.append("\n- ").append(enchantment.key.toString())
|
|
.append(" ").append(enchantment.name)
|
|
.append(" ").append(enchantment.defaultMaxLevel())
|
|
}
|
|
}
|
|
|
|
private fun partialEnchantmentData(stb: StringBuilder) {
|
|
val map = HashMap<String, Int>()
|
|
for (enchant in CAEnchantmentRegistry.getInstance().values()) {
|
|
map[enchant.key.namespace] = map.getOrDefault(enchant.key.namespace, 0) + 1
|
|
}
|
|
|
|
stb.append(
|
|
"\nNamespaces: ${
|
|
map.entries.stream()
|
|
.map { (key, value) -> "$key ($value)" }
|
|
.reduce { a, b -> "$a, $b" }.get()
|
|
}"
|
|
)
|
|
|
|
}
|
|
|
|
private fun includeLastError(stb: StringBuilder) {
|
|
val e = MetricsUtil.lastError ?: return
|
|
|
|
stb.append("\n\nLast stack trace: ${e.stackTraceToString()}")
|
|
|
|
|
|
}
|
|
|
|
} |