initial
This commit is contained in:
187
src/main/kotlin/org/server_info/server_info/Server_info.kt
Normal file
187
src/main/kotlin/org/server_info/server_info/Server_info.kt
Normal file
@@ -0,0 +1,187 @@
|
||||
package org.server_info.server_info
|
||||
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class Server_info : JavaPlugin() {
|
||||
|
||||
private var lastTickTime = System.currentTimeMillis()
|
||||
private var tickCount = 0
|
||||
private val tickTimeList = ArrayList<Long>()
|
||||
private var tps = 20.0
|
||||
private val df = DecimalFormat("#.##")
|
||||
|
||||
override fun onEnable() {
|
||||
// Register command
|
||||
getCommand("serverinfo")?.setExecutor(ServerInfoCommand(this))
|
||||
|
||||
// Start server info collectors
|
||||
startTPSCalculation()
|
||||
startTabListUpdater()
|
||||
|
||||
logger.info("ServerInfo plugin has been enabled!")
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
logger.info("ServerInfo plugin has been disabled!")
|
||||
}
|
||||
|
||||
private fun startTPSCalculation() {
|
||||
// Better TPS calculation method with moving average
|
||||
object : BukkitRunnable() {
|
||||
override fun run() {
|
||||
tickCount++
|
||||
|
||||
val now = System.currentTimeMillis()
|
||||
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
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(this, 1L, 1L) // Run every tick
|
||||
}
|
||||
|
||||
private fun startTabListUpdater() {
|
||||
object : BukkitRunnable() {
|
||||
override fun run() {
|
||||
updateTabList()
|
||||
}
|
||||
}.runTaskTimer(this, 20L, 20L) // Update every second
|
||||
}
|
||||
|
||||
private fun updateTabList() {
|
||||
val header = getTabListHeader()
|
||||
val footer = getTabListFooter()
|
||||
|
||||
for (player in Bukkit.getOnlinePlayers()) {
|
||||
player.sendPlayerListHeaderAndFooter(header, footer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTabListHeader(): Component {
|
||||
val serverName = server.name
|
||||
return Component.text("§6§l$serverName\n§r§7Online players: §f${server.onlinePlayers.size}/${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
|
||||
}
|
||||
|
||||
return Component.text(
|
||||
"\n§7RAM: §f${usedMemory}MB / ${maxMemory}MB" +
|
||||
"\n§7CPU: §f${df.format(cpuLoad)}%" +
|
||||
"\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
|
||||
}
|
||||
|
||||
// Format server info using string templates
|
||||
info.append("§6===== SERVER INFO =====\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") // Added % sign
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
} catch (e: Exception) {
|
||||
logger.warning("Failed to get ping for player: ${e.message}")
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
// Command executor inner class
|
||||
private inner class ServerInfoCommand(private val plugin: Server_info) : CommandExecutor {
|
||||
|
||||
override fun onCommand(sender: CommandSender, cmd: Command, label: String, args: Array<out String>): Boolean {
|
||||
if (cmd.name.equals("serverinfo", ignoreCase = true)) {
|
||||
// Send 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")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/main/resources/plugin.yml
Normal file
15
src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
name: ServerInfo
|
||||
version: 1.0-SNAPSHOT
|
||||
main: org.server_info.server_info.Server_info
|
||||
api-version: 1.19
|
||||
description: Displays server performance metrics
|
||||
commands:
|
||||
serverinfo:
|
||||
description: Shows server performance metrics
|
||||
usage: /<command>
|
||||
aliases: [sinfo, si]
|
||||
permission: serverinfo.use
|
||||
permissions:
|
||||
serverinfo.use:
|
||||
description: Allows using the serverinfo command
|
||||
default: true
|
||||
Reference in New Issue
Block a user