fixed stuff (added some more info) check commit diff
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package org.server_info.server_info
|
||||
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.format.NamedTextColor
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
@@ -12,6 +11,7 @@ import org.bukkit.plugin.java.JavaPlugin
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.text.DecimalFormat
|
||||
import com.sun.management.OperatingSystemMXBean
|
||||
|
||||
class Server_info : JavaPlugin() {
|
||||
|
||||
@@ -21,25 +21,23 @@ class Server_info : JavaPlugin() {
|
||||
private var tps = 20.0
|
||||
private val df = DecimalFormat("#.##")
|
||||
|
||||
// Server title that appears at the top
|
||||
private var serverTitle = "Paper"
|
||||
private var cpuUsage = 0.0
|
||||
private var lastCpuTime = 0L
|
||||
private var lastSampleTime = 0L
|
||||
|
||||
override fun onEnable() {
|
||||
// Save default config if it doesn't exist
|
||||
saveDefaultConfig()
|
||||
|
||||
// Load configuration
|
||||
loadConfiguration()
|
||||
|
||||
// Register command
|
||||
getCommand("serverinfo")?.let { command ->
|
||||
val commandExecutor = ServerInfoCommand(this)
|
||||
command.setExecutor(commandExecutor)
|
||||
command.tabCompleter = commandExecutor
|
||||
}
|
||||
|
||||
// Start server info collectors
|
||||
startTPSCalculation()
|
||||
startCPUMonitor()
|
||||
startTabListUpdater()
|
||||
|
||||
logger.info("ServerInfo plugin has been enabled!")
|
||||
@@ -47,15 +45,11 @@ class Server_info : JavaPlugin() {
|
||||
|
||||
override fun onDisable() {
|
||||
logger.info("ServerInfo plugin has been disabled!")
|
||||
// Save configuration
|
||||
saveConfig()
|
||||
}
|
||||
|
||||
private fun loadConfiguration() {
|
||||
// Load server title from config, default to "Paper" if not set
|
||||
serverTitle = config.getString("server-title") ?: "Paper"
|
||||
|
||||
// Create config options if they don't exist
|
||||
if (!config.contains("server-title")) {
|
||||
config.set("server-title", serverTitle)
|
||||
saveConfig()
|
||||
@@ -66,12 +60,10 @@ class Server_info : JavaPlugin() {
|
||||
serverTitle = title
|
||||
config.set("server-title", title)
|
||||
saveConfig()
|
||||
// Update tablist immediately to reflect the change
|
||||
updateTabList()
|
||||
}
|
||||
|
||||
private fun startTPSCalculation() {
|
||||
// Better TPS calculation method with moving average
|
||||
object : BukkitRunnable() {
|
||||
override fun run() {
|
||||
tickCount++
|
||||
@@ -80,28 +72,79 @@ class Server_info : JavaPlugin() {
|
||||
val elapsed = now - lastTickTime
|
||||
lastTickTime = now
|
||||
|
||||
// Store data point - time per tick in ms
|
||||
// Only add if we've gone through at least one tick to avoid startup anomalies
|
||||
if (tickCount > 1) {
|
||||
tickTimeList.add(elapsed)
|
||||
}
|
||||
|
||||
// Keep only the last 600 data points (30 seconds at 20 TPS)
|
||||
while (tickTimeList.size > 600) {
|
||||
tickTimeList.removeAt(0)
|
||||
}
|
||||
|
||||
// Calculate average tick time and TPS if we have data
|
||||
if (tickTimeList.isNotEmpty()) {
|
||||
val avgTickTime = tickTimeList.average()
|
||||
tps = 1000.0 / avgTickTime
|
||||
|
||||
// Clamp TPS between 0 and 20
|
||||
if (tps > 20.0) tps = 20.0
|
||||
if (tps < 0.0) tps = 0.0
|
||||
tps = tps.coerceIn(0.0, 20.0)
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(this, 1L, 1L) // Run every tick
|
||||
}.runTaskTimer(this, 1L, 1L)
|
||||
}
|
||||
|
||||
private fun startCPUMonitor() {
|
||||
object : BukkitRunnable() {
|
||||
override fun run() {
|
||||
updateCPUUsage()
|
||||
}
|
||||
}.runTaskTimer(this, 20L, 20L) // Update every second
|
||||
}
|
||||
|
||||
private fun updateCPUUsage() {
|
||||
try {
|
||||
val osBean = ManagementFactory.getOperatingSystemMXBean()
|
||||
|
||||
if (osBean is com.sun.management.OperatingSystemMXBean) {
|
||||
// Modern JVM with com.sun.management API
|
||||
cpuUsage = osBean.processCpuLoad * 100
|
||||
} else {
|
||||
// Fallback to more basic metrics
|
||||
val runtime = Runtime.getRuntime()
|
||||
val processors = runtime.availableProcessors()
|
||||
|
||||
// Get JVM CPU time if available
|
||||
val bean = ManagementFactory.getThreadMXBean()
|
||||
if (bean.isThreadCpuTimeSupported && bean.isThreadCpuTimeEnabled) {
|
||||
var totalCpuTime = 0L
|
||||
for (threadId in bean.allThreadIds) {
|
||||
val cpuTime = bean.getThreadCpuTime(threadId)
|
||||
if (cpuTime >= 0) totalCpuTime += cpuTime
|
||||
}
|
||||
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
if (lastCpuTime > 0L && lastSampleTime > 0L) {
|
||||
val elapsedCpu = totalCpuTime - lastCpuTime
|
||||
val elapsedTime = (now - lastSampleTime) * 1000000 // Convert to nanoseconds
|
||||
|
||||
if (elapsedTime > 0) {
|
||||
// Calculate CPU usage as a percentage across all cores
|
||||
cpuUsage = (elapsedCpu * 100.0) / (elapsedTime * processors)
|
||||
cpuUsage = cpuUsage.coerceIn(0.0, 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
lastCpuTime = totalCpuTime
|
||||
lastSampleTime = now
|
||||
} else {
|
||||
// If CPU time not supported, use a basic estimate ( If this happens please check the server for issues! )
|
||||
val threadCount = ManagementFactory.getThreadMXBean().threadCount
|
||||
logger.warning(/* msg = */ "§4Accuarte CPU Monitoring isnt supported! Check Server for Issues!")
|
||||
cpuUsage = (threadCount * 100.0) / (processors * 20.0)
|
||||
cpuUsage = cpuUsage.coerceIn(0.0, 100.0)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.warning("Failed to calculate CPU usage: ${e.message}")
|
||||
cpuUsage = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
private fun startTabListUpdater() {
|
||||
@@ -109,7 +152,7 @@ class Server_info : JavaPlugin() {
|
||||
override fun run() {
|
||||
updateTabList()
|
||||
}
|
||||
}.runTaskTimer(this, 20L, 20L) // Update every second
|
||||
}.runTaskTimer(this, 20L, 20L)
|
||||
}
|
||||
|
||||
private fun updateTabList() {
|
||||
@@ -122,76 +165,73 @@ class Server_info : JavaPlugin() {
|
||||
}
|
||||
|
||||
private fun getTabListHeader(): Component {
|
||||
return Component.text("§6§l$serverTitle\n§r§7Online players: §f${server.onlinePlayers.size}/${server.maxPlayers}")
|
||||
return Component.text("§6§l$serverTitle\n§r§7Online players: §f${server.onlinePlayers.size} / §d${server.maxPlayers}")
|
||||
}
|
||||
|
||||
private fun getTabListFooter(): Component {
|
||||
// Memory information
|
||||
val runtime = Runtime.getRuntime()
|
||||
val maxMemory = runtime.maxMemory() / (1024 * 1024)
|
||||
val allocatedMemory = runtime.totalMemory() / (1024 * 1024)
|
||||
val freeMemory = runtime.freeMemory() / (1024 * 1024)
|
||||
val usedMemory = allocatedMemory - freeMemory
|
||||
|
||||
// CPU usage
|
||||
val osBean = ManagementFactory.getOperatingSystemMXBean()
|
||||
var cpuLoad = osBean.systemLoadAverage
|
||||
if (cpuLoad < 0) {
|
||||
cpuLoad = osBean.availableProcessors * ManagementFactory.getThreadMXBean().threadCount / 100.0
|
||||
}
|
||||
|
||||
val tpsColor = when {
|
||||
tps >= 18.0 -> "§2" // Dark green
|
||||
tps >= 15.0 -> "§e" // Yellow
|
||||
else -> "§c" // Red
|
||||
tps >= 18.0 -> "§2"
|
||||
tps >= 15.0 -> "§e"
|
||||
else -> "§c"
|
||||
}
|
||||
|
||||
return Component.text(
|
||||
"\n§7RAM: §f${usedMemory}MB / ${maxMemory}MB" +
|
||||
"\n§7CPU: §f${df.format(cpuLoad)}%" +
|
||||
"\n§7TPS: $tpsColor${df.format(tps)}"
|
||||
"\n§7RAM: §f${formatMemory(usedMemory)} / ${formatMemory(maxMemory)}" +
|
||||
"\n§7CPU: ${formatCPU(cpuUsage)}%" +
|
||||
"\n§7TPS: $tpsColor${df.format(tps)}"
|
||||
)
|
||||
}
|
||||
|
||||
fun getServerInfo(): String {
|
||||
val info = StringBuilder()
|
||||
|
||||
// Memory information
|
||||
val runtime = Runtime.getRuntime()
|
||||
val maxMemory = runtime.maxMemory() / (1024 * 1024)
|
||||
val allocatedMemory = runtime.totalMemory() / (1024 * 1024)
|
||||
val freeMemory = runtime.freeMemory() / (1024 * 1024)
|
||||
val usedMemory = allocatedMemory - freeMemory
|
||||
|
||||
// CPU usage
|
||||
val osBean = ManagementFactory.getOperatingSystemMXBean()
|
||||
var cpuLoad = osBean.systemLoadAverage
|
||||
if (cpuLoad < 0) {
|
||||
cpuLoad = osBean.availableProcessors * ManagementFactory.getThreadMXBean().threadCount / 100.0
|
||||
return buildString {
|
||||
append("§6--- ServerInfo ---\n")
|
||||
append("§6Title: §f$serverTitle\n")
|
||||
append("§aRAM Usage: §f${formatMemory(usedMemory)} / ${formatMemory(allocatedMemory)}\n")
|
||||
append("§aMax RAM: §f${formatMemory(maxMemory)}\n")
|
||||
append("§aCPU Load: ${formatCPU(cpuUsage)}%\n")
|
||||
append("§aTPS: ${formatTPS(tps)}\n")
|
||||
}
|
||||
|
||||
// Format server info using string templates
|
||||
info.append("§6===== SERVER INFO =====\n")
|
||||
info.append("§6Title: §f$serverTitle\n")
|
||||
info.append("§aRAM Usage: §f${usedMemory}MB / ${allocatedMemory}MB\n")
|
||||
info.append("§aMax RAM: §f${maxMemory}MB\n")
|
||||
info.append("§aCPU Load: §f${df.format(cpuLoad)}%\n")
|
||||
info.append("§aTPS: ${formatTPS(tps)}\n")
|
||||
|
||||
return info.toString()
|
||||
}
|
||||
|
||||
private fun formatTPS(tps: Double): String {
|
||||
return when {
|
||||
tps >= 18.0 -> "§2${df.format(tps)}" // Dark green
|
||||
tps >= 15.0 -> "§e${df.format(tps)}" // Yellow
|
||||
else -> "§c${df.format(tps)}" // Red
|
||||
tps >= 18.0 -> "§2${df.format(tps)}"
|
||||
tps >= 15.0 -> "§e${df.format(tps)}"
|
||||
else -> "§c${df.format(tps)}"
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatMemory(valueInMB: Long): String {
|
||||
return if (valueInMB >= 1000) {
|
||||
val gb = valueInMB / 1024.0
|
||||
"${df.format(gb)} GB"
|
||||
} else {
|
||||
"$valueInMB MB"
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatCPU(cpu: Double): String {
|
||||
return when {
|
||||
cpu <= 30.0 -> "§2${df.format(cpu)}"
|
||||
cpu <= 70.0 -> "§e${df.format(cpu)}"
|
||||
else -> "§c${df.format(cpu)}"
|
||||
}
|
||||
}
|
||||
|
||||
fun getPingForPlayer(player: Player): Int {
|
||||
return try {
|
||||
// Get player ping using reflection
|
||||
val entityPlayer = player.javaClass.getMethod("getHandle").invoke(player)
|
||||
val pingField = entityPlayer.javaClass.getField("ping")
|
||||
pingField.getInt(entityPlayer)
|
||||
@@ -200,17 +240,14 @@ class Server_info : JavaPlugin() {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
// Command executor inner class with tab completion
|
||||
// Create CommandClass that stores the Commands that can be used
|
||||
private inner class ServerInfoCommand(private val plugin: Server_info) : CommandExecutor, TabCompleter {
|
||||
|
||||
override fun onCommand(sender: CommandSender, cmd: Command, label: String, args: Array<out String>): Boolean {
|
||||
if (cmd.name.equals("serverinfo", ignoreCase = true)) {
|
||||
// If there are arguments, handle them
|
||||
if (args.isNotEmpty()) {
|
||||
when (args[0].lowercase()) {
|
||||
"title", "settitle" -> {
|
||||
// Check permission
|
||||
if (!sender.hasPermission("serverinfo.admin")) {
|
||||
sender.sendMessage("§cYou don't have permission to change the server title.")
|
||||
return true
|
||||
@@ -221,14 +258,12 @@ class Server_info : JavaPlugin() {
|
||||
return true
|
||||
}
|
||||
|
||||
// Join remaining args as the title
|
||||
val newTitle = args.copyOfRange(1, args.size).joinToString(" ")
|
||||
plugin.setServerTitle(newTitle)
|
||||
sender.sendMessage("§aServer title changed to: §f$newTitle")
|
||||
return true
|
||||
}
|
||||
"reload" -> {
|
||||
// Check permission
|
||||
if (!sender.hasPermission("serverinfo.admin")) {
|
||||
sender.sendMessage("§cYou don't have permission to reload the plugin.")
|
||||
return true
|
||||
@@ -242,13 +277,12 @@ class Server_info : JavaPlugin() {
|
||||
}
|
||||
}
|
||||
|
||||
// Default behavior - show server info
|
||||
sender.sendMessage(plugin.getServerInfo())
|
||||
|
||||
// If the sender is a player, show their ping
|
||||
if (sender is Player) {
|
||||
val ping = plugin.getPingForPlayer(sender)
|
||||
sender.sendMessage("§aYour Ping: §f${ping}ms")
|
||||
sender.sendMessage("§6-- Powered by Kotlin --")
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -256,12 +290,7 @@ class Server_info : JavaPlugin() {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onTabComplete(
|
||||
sender: CommandSender,
|
||||
command: Command,
|
||||
alias: String,
|
||||
args: Array<out String>
|
||||
): List<String>? {
|
||||
override fun onTabComplete(sender: CommandSender, command: Command, alias: String, args: Array<out String>): List<String>? {
|
||||
if (command.name.equals("serverinfo", ignoreCase = true)) {
|
||||
if (args.size == 1) {
|
||||
val completions = mutableListOf<String>()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user