fixed stuff (added some more info) check commit diff
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
package org.server_info.server_info
|
package org.server_info.server_info
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component
|
import net.kyori.adventure.text.Component
|
||||||
import net.kyori.adventure.text.format.NamedTextColor
|
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.command.Command
|
import org.bukkit.command.Command
|
||||||
import org.bukkit.command.CommandExecutor
|
import org.bukkit.command.CommandExecutor
|
||||||
@@ -12,6 +11,7 @@ import org.bukkit.plugin.java.JavaPlugin
|
|||||||
import org.bukkit.scheduler.BukkitRunnable
|
import org.bukkit.scheduler.BukkitRunnable
|
||||||
import java.lang.management.ManagementFactory
|
import java.lang.management.ManagementFactory
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
|
import com.sun.management.OperatingSystemMXBean
|
||||||
|
|
||||||
class Server_info : JavaPlugin() {
|
class Server_info : JavaPlugin() {
|
||||||
|
|
||||||
@@ -21,25 +21,23 @@ class Server_info : JavaPlugin() {
|
|||||||
private var tps = 20.0
|
private var tps = 20.0
|
||||||
private val df = DecimalFormat("#.##")
|
private val df = DecimalFormat("#.##")
|
||||||
|
|
||||||
// Server title that appears at the top
|
|
||||||
private var serverTitle = "Paper"
|
private var serverTitle = "Paper"
|
||||||
|
private var cpuUsage = 0.0
|
||||||
|
private var lastCpuTime = 0L
|
||||||
|
private var lastSampleTime = 0L
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
// Save default config if it doesn't exist
|
|
||||||
saveDefaultConfig()
|
saveDefaultConfig()
|
||||||
|
|
||||||
// Load configuration
|
|
||||||
loadConfiguration()
|
loadConfiguration()
|
||||||
|
|
||||||
// Register command
|
|
||||||
getCommand("serverinfo")?.let { command ->
|
getCommand("serverinfo")?.let { command ->
|
||||||
val commandExecutor = ServerInfoCommand(this)
|
val commandExecutor = ServerInfoCommand(this)
|
||||||
command.setExecutor(commandExecutor)
|
command.setExecutor(commandExecutor)
|
||||||
command.tabCompleter = commandExecutor
|
command.tabCompleter = commandExecutor
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start server info collectors
|
|
||||||
startTPSCalculation()
|
startTPSCalculation()
|
||||||
|
startCPUMonitor()
|
||||||
startTabListUpdater()
|
startTabListUpdater()
|
||||||
|
|
||||||
logger.info("ServerInfo plugin has been enabled!")
|
logger.info("ServerInfo plugin has been enabled!")
|
||||||
@@ -47,15 +45,11 @@ class Server_info : JavaPlugin() {
|
|||||||
|
|
||||||
override fun onDisable() {
|
override fun onDisable() {
|
||||||
logger.info("ServerInfo plugin has been disabled!")
|
logger.info("ServerInfo plugin has been disabled!")
|
||||||
// Save configuration
|
|
||||||
saveConfig()
|
saveConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadConfiguration() {
|
private fun loadConfiguration() {
|
||||||
// Load server title from config, default to "Paper" if not set
|
|
||||||
serverTitle = config.getString("server-title") ?: "Paper"
|
serverTitle = config.getString("server-title") ?: "Paper"
|
||||||
|
|
||||||
// Create config options if they don't exist
|
|
||||||
if (!config.contains("server-title")) {
|
if (!config.contains("server-title")) {
|
||||||
config.set("server-title", serverTitle)
|
config.set("server-title", serverTitle)
|
||||||
saveConfig()
|
saveConfig()
|
||||||
@@ -66,12 +60,10 @@ class Server_info : JavaPlugin() {
|
|||||||
serverTitle = title
|
serverTitle = title
|
||||||
config.set("server-title", title)
|
config.set("server-title", title)
|
||||||
saveConfig()
|
saveConfig()
|
||||||
// Update tablist immediately to reflect the change
|
|
||||||
updateTabList()
|
updateTabList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startTPSCalculation() {
|
private fun startTPSCalculation() {
|
||||||
// Better TPS calculation method with moving average
|
|
||||||
object : BukkitRunnable() {
|
object : BukkitRunnable() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
tickCount++
|
tickCount++
|
||||||
@@ -80,28 +72,79 @@ class Server_info : JavaPlugin() {
|
|||||||
val elapsed = now - lastTickTime
|
val elapsed = now - lastTickTime
|
||||||
lastTickTime = now
|
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) {
|
if (tickCount > 1) {
|
||||||
tickTimeList.add(elapsed)
|
tickTimeList.add(elapsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep only the last 600 data points (30 seconds at 20 TPS)
|
|
||||||
while (tickTimeList.size > 600) {
|
while (tickTimeList.size > 600) {
|
||||||
tickTimeList.removeAt(0)
|
tickTimeList.removeAt(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate average tick time and TPS if we have data
|
|
||||||
if (tickTimeList.isNotEmpty()) {
|
if (tickTimeList.isNotEmpty()) {
|
||||||
val avgTickTime = tickTimeList.average()
|
val avgTickTime = tickTimeList.average()
|
||||||
tps = 1000.0 / avgTickTime
|
tps = 1000.0 / avgTickTime
|
||||||
|
tps = tps.coerceIn(0.0, 20.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimer(this, 1L, 1L)
|
||||||
|
}
|
||||||
|
|
||||||
// Clamp TPS between 0 and 20
|
private fun startCPUMonitor() {
|
||||||
if (tps > 20.0) tps = 20.0
|
object : BukkitRunnable() {
|
||||||
if (tps < 0.0) tps = 0.0
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.runTaskTimer(this, 1L, 1L) // Run every tick
|
|
||||||
|
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() {
|
private fun startTabListUpdater() {
|
||||||
@@ -109,7 +152,7 @@ class Server_info : JavaPlugin() {
|
|||||||
override fun run() {
|
override fun run() {
|
||||||
updateTabList()
|
updateTabList()
|
||||||
}
|
}
|
||||||
}.runTaskTimer(this, 20L, 20L) // Update every second
|
}.runTaskTimer(this, 20L, 20L)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTabList() {
|
private fun updateTabList() {
|
||||||
@@ -122,76 +165,73 @@ class Server_info : JavaPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getTabListHeader(): Component {
|
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 {
|
private fun getTabListFooter(): Component {
|
||||||
// Memory information
|
|
||||||
val runtime = Runtime.getRuntime()
|
val runtime = Runtime.getRuntime()
|
||||||
val maxMemory = runtime.maxMemory() / (1024 * 1024)
|
val maxMemory = runtime.maxMemory() / (1024 * 1024)
|
||||||
val allocatedMemory = runtime.totalMemory() / (1024 * 1024)
|
val allocatedMemory = runtime.totalMemory() / (1024 * 1024)
|
||||||
val freeMemory = runtime.freeMemory() / (1024 * 1024)
|
val freeMemory = runtime.freeMemory() / (1024 * 1024)
|
||||||
val usedMemory = allocatedMemory - freeMemory
|
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 {
|
val tpsColor = when {
|
||||||
tps >= 18.0 -> "§2" // Dark green
|
tps >= 18.0 -> "§2"
|
||||||
tps >= 15.0 -> "§e" // Yellow
|
tps >= 15.0 -> "§e"
|
||||||
else -> "§c" // Red
|
else -> "§c"
|
||||||
}
|
}
|
||||||
|
|
||||||
return Component.text(
|
return Component.text(
|
||||||
"\n§7RAM: §f${usedMemory}MB / ${maxMemory}MB" +
|
"\n§7RAM: §f${formatMemory(usedMemory)} / ${formatMemory(maxMemory)}" +
|
||||||
"\n§7CPU: §f${df.format(cpuLoad)}%" +
|
"\n§7CPU: ${formatCPU(cpuUsage)}%" +
|
||||||
"\n§7TPS: $tpsColor${df.format(tps)}"
|
"\n§7TPS: $tpsColor${df.format(tps)}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getServerInfo(): String {
|
fun getServerInfo(): String {
|
||||||
val info = StringBuilder()
|
|
||||||
|
|
||||||
// Memory information
|
|
||||||
val runtime = Runtime.getRuntime()
|
val runtime = Runtime.getRuntime()
|
||||||
val maxMemory = runtime.maxMemory() / (1024 * 1024)
|
val maxMemory = runtime.maxMemory() / (1024 * 1024)
|
||||||
val allocatedMemory = runtime.totalMemory() / (1024 * 1024)
|
val allocatedMemory = runtime.totalMemory() / (1024 * 1024)
|
||||||
val freeMemory = runtime.freeMemory() / (1024 * 1024)
|
val freeMemory = runtime.freeMemory() / (1024 * 1024)
|
||||||
val usedMemory = allocatedMemory - freeMemory
|
val usedMemory = allocatedMemory - freeMemory
|
||||||
|
|
||||||
// CPU usage
|
return buildString {
|
||||||
val osBean = ManagementFactory.getOperatingSystemMXBean()
|
append("§6--- ServerInfo ---\n")
|
||||||
var cpuLoad = osBean.systemLoadAverage
|
append("§6Title: §f$serverTitle\n")
|
||||||
if (cpuLoad < 0) {
|
append("§aRAM Usage: §f${formatMemory(usedMemory)} / ${formatMemory(allocatedMemory)}\n")
|
||||||
cpuLoad = osBean.availableProcessors * ManagementFactory.getThreadMXBean().threadCount / 100.0
|
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 {
|
private fun formatTPS(tps: Double): String {
|
||||||
return when {
|
return when {
|
||||||
tps >= 18.0 -> "§2${df.format(tps)}" // Dark green
|
tps >= 18.0 -> "§2${df.format(tps)}"
|
||||||
tps >= 15.0 -> "§e${df.format(tps)}" // Yellow
|
tps >= 15.0 -> "§e${df.format(tps)}"
|
||||||
else -> "§c${df.format(tps)}" // Red
|
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 {
|
fun getPingForPlayer(player: Player): Int {
|
||||||
return try {
|
return try {
|
||||||
// Get player ping using reflection
|
|
||||||
val entityPlayer = player.javaClass.getMethod("getHandle").invoke(player)
|
val entityPlayer = player.javaClass.getMethod("getHandle").invoke(player)
|
||||||
val pingField = entityPlayer.javaClass.getField("ping")
|
val pingField = entityPlayer.javaClass.getField("ping")
|
||||||
pingField.getInt(entityPlayer)
|
pingField.getInt(entityPlayer)
|
||||||
@@ -200,17 +240,14 @@ class Server_info : JavaPlugin() {
|
|||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Create CommandClass that stores the Commands that can be used
|
||||||
// Command executor inner class with tab completion
|
|
||||||
private inner class ServerInfoCommand(private val plugin: Server_info) : CommandExecutor, TabCompleter {
|
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 {
|
override fun onCommand(sender: CommandSender, cmd: Command, label: String, args: Array<out String>): Boolean {
|
||||||
if (cmd.name.equals("serverinfo", ignoreCase = true)) {
|
if (cmd.name.equals("serverinfo", ignoreCase = true)) {
|
||||||
// If there are arguments, handle them
|
|
||||||
if (args.isNotEmpty()) {
|
if (args.isNotEmpty()) {
|
||||||
when (args[0].lowercase()) {
|
when (args[0].lowercase()) {
|
||||||
"title", "settitle" -> {
|
"title", "settitle" -> {
|
||||||
// Check permission
|
|
||||||
if (!sender.hasPermission("serverinfo.admin")) {
|
if (!sender.hasPermission("serverinfo.admin")) {
|
||||||
sender.sendMessage("§cYou don't have permission to change the server title.")
|
sender.sendMessage("§cYou don't have permission to change the server title.")
|
||||||
return true
|
return true
|
||||||
@@ -221,14 +258,12 @@ class Server_info : JavaPlugin() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join remaining args as the title
|
|
||||||
val newTitle = args.copyOfRange(1, args.size).joinToString(" ")
|
val newTitle = args.copyOfRange(1, args.size).joinToString(" ")
|
||||||
plugin.setServerTitle(newTitle)
|
plugin.setServerTitle(newTitle)
|
||||||
sender.sendMessage("§aServer title changed to: §f$newTitle")
|
sender.sendMessage("§aServer title changed to: §f$newTitle")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
"reload" -> {
|
"reload" -> {
|
||||||
// Check permission
|
|
||||||
if (!sender.hasPermission("serverinfo.admin")) {
|
if (!sender.hasPermission("serverinfo.admin")) {
|
||||||
sender.sendMessage("§cYou don't have permission to reload the plugin.")
|
sender.sendMessage("§cYou don't have permission to reload the plugin.")
|
||||||
return true
|
return true
|
||||||
@@ -242,13 +277,12 @@ class Server_info : JavaPlugin() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default behavior - show server info
|
|
||||||
sender.sendMessage(plugin.getServerInfo())
|
sender.sendMessage(plugin.getServerInfo())
|
||||||
|
|
||||||
// If the sender is a player, show their ping
|
|
||||||
if (sender is Player) {
|
if (sender is Player) {
|
||||||
val ping = plugin.getPingForPlayer(sender)
|
val ping = plugin.getPingForPlayer(sender)
|
||||||
sender.sendMessage("§aYour Ping: §f${ping}ms")
|
sender.sendMessage("§aYour Ping: §f${ping}ms")
|
||||||
|
sender.sendMessage("§6-- Powered by Kotlin --")
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -256,12 +290,7 @@ class Server_info : JavaPlugin() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTabComplete(
|
override fun onTabComplete(sender: CommandSender, command: Command, alias: String, args: Array<out String>): List<String>? {
|
||||||
sender: CommandSender,
|
|
||||||
command: Command,
|
|
||||||
alias: String,
|
|
||||||
args: Array<out String>
|
|
||||||
): List<String>? {
|
|
||||||
if (command.name.equals("serverinfo", ignoreCase = true)) {
|
if (command.name.equals("serverinfo", ignoreCase = true)) {
|
||||||
if (args.size == 1) {
|
if (args.size == 1) {
|
||||||
val completions = mutableListOf<String>()
|
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