diff --git a/src/main/java/eu/mhsl/craftattack/spawn/appliances/tablist/Tablist.java b/src/main/java/eu/mhsl/craftattack/spawn/appliances/tablist/Tablist.java index 90a02da..6497dca 100644 --- a/src/main/java/eu/mhsl/craftattack/spawn/appliances/tablist/Tablist.java +++ b/src/main/java/eu/mhsl/craftattack/spawn/appliances/tablist/Tablist.java @@ -16,6 +16,8 @@ import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; import java.time.Duration; import java.util.List; @@ -23,6 +25,7 @@ import java.util.List; public class Tablist extends Appliance { private final RainbowComponent serverName = new RainbowComponent(" CraftAttack 7 ", 7, 3); private NetworkMonitor networkMonitor; + private OperatingSystemMXBean systemMonitor; public Tablist() { super("tablist"); @@ -32,6 +35,8 @@ public class Tablist extends Appliance { public void onEnable() { int tabRefreshRate = 3; this.networkMonitor = new NetworkMonitor(localConfig().getString("interface"), Duration.ofSeconds(1)); + this.systemMonitor = ManagementFactory.getOperatingSystemMXBean(); + Bukkit.getScheduler().runTaskTimerAsynchronously( Main.instance(), () -> IteratorUtil.onlinePlayers(this::updateHeader), @@ -63,8 +68,9 @@ public class Tablist extends Appliance { .append(ComponentUtil.getFormattedPing(player)).appendNewline() .append(ComponentUtil.getFormattedNetworkStats( this.networkMonitor.getTraffic(), - this.networkMonitor.getPackets()) - ).appendNewline(); + this.networkMonitor.getPackets() + )).appendNewline() + .append(ComponentUtil.getFormattedSystemStats(this.systemMonitor)).appendNewline(); } player.sendPlayerListHeader(header); diff --git a/src/main/java/eu/mhsl/craftattack/spawn/util/text/ComponentUtil.java b/src/main/java/eu/mhsl/craftattack/spawn/util/text/ComponentUtil.java index f4a5ee0..cdf6821 100644 --- a/src/main/java/eu/mhsl/craftattack/spawn/util/text/ComponentUtil.java +++ b/src/main/java/eu/mhsl/craftattack/spawn/util/text/ComponentUtil.java @@ -10,6 +10,7 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.awt.*; +import java.lang.management.OperatingSystemMXBean; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -46,34 +47,6 @@ public class ComponentUtil { return lines.collect(Collectors.joining("\n")); } - public static Component getFormattedTPS() { - double[] tpsValues = Bukkit.getTPS(); - - double min1 = Math.min(1.0, Math.max(0.0, tpsValues[0] / 20.0)); - double min2 = Math.min(1.0, Math.max(0.0, tpsValues[1] / 20.0)); - double min3 = Math.min(1.0, Math.max(0.0, tpsValues[2] / 20.0)); - - int red1 = (int) (255 * (1.0 - min1)); - int green1 = (int) (255 * min1); - int red2 = (int) (255 * (1.0 - min2)); - int green2 = (int) (255 * min2); - int red3 = (int) (255 * (1.0 - min3)); - int green3 = (int) (255 * min3); - - TextColor tpsColor1 = TextColor.color(red1, green1, 0); - TextColor tpsColor2 = TextColor.color(red2, green2, 0); - TextColor tpsColor3 = TextColor.color(red3, green3, 0); - - return Component.text() - .append(Component.text("TPS 1, 5, 15m: ", NamedTextColor.GRAY)) - .append(Component.text(String.format("%.2f", tpsValues[0]), tpsColor1)) - .append(Component.text(", ")) - .append(Component.text(String.format("%.2f", tpsValues[1]), tpsColor2)) - .append(Component.text(", ")) - .append(Component.text(String.format("%.2f", tpsValues[2]), tpsColor3)) - .build(); - } - public static Component getFormattedTickTimes(boolean detailed) { long[] times = Bukkit.getServer().getTickTimes(); float mspt = ((float) Arrays.stream(times).sum() / times.length) * 1.0E-6f; @@ -132,14 +105,68 @@ public class ComponentUtil { public static Component getFormattedNetworkStats(NetworkMonitor.Traffic traffic, NetworkMonitor.Packets packets) { return Component.text() .append(Component.text( - DataSizeConverter.convertBytesToHumanReadable(traffic.rxBytes()) + " ↓ " + NumberAbbreviation.abbreviateNumber(packets.rxCount()) + "pps", + DataSizeConverter.convertBytesPerSecond(traffic.rxBytes()) + " ↓ " + NumberAbbreviation.abbreviateNumber(packets.rxCount()) + "pps", NamedTextColor.GREEN )) .append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text( - DataSizeConverter.convertBytesToHumanReadable(traffic.txBytes()) + " ↑ " + NumberAbbreviation.abbreviateNumber(packets.rxCount()) + "pps", + DataSizeConverter.convertBytesPerSecond(traffic.txBytes()) + " ↑ " + NumberAbbreviation.abbreviateNumber(packets.rxCount()) + "pps", NamedTextColor.RED )) .build(); } + + public static Component getFormattedSystemStats(OperatingSystemMXBean systemMonitor) { + if(!(systemMonitor instanceof com.sun.management.OperatingSystemMXBean monitor)) + return Component.text("Could not get System information", NamedTextColor.DARK_GRAY); + + return Component.text() + .append(Component.text("proc: ", NamedTextColor.GRAY)) + .append(Component.text( + String.format("%.0f%%cpu", monitor.getProcessCpuLoad() * 100), + NamedTextColor.GOLD + )) + .append(Component.text(" | ", NamedTextColor.GRAY)) + .append(Component.text( + String.format("%s time", DataSizeConverter.formatCpuTimeToHumanReadable(monitor.getProcessCpuTime())), + NamedTextColor.LIGHT_PURPLE + )) + .append(Component.text(" | ", NamedTextColor.GRAY)) + .append(Component.text( + String.format( + "%s free, %s committed RAM", + DataSizeConverter.formatBytesToHumanReadable(monitor.getFreeMemorySize()), + DataSizeConverter.formatBytesToHumanReadable(monitor.getCommittedVirtualMemorySize()) + ), + NamedTextColor.DARK_AQUA + )) + .appendNewline() + .append(Component.text("sys: ", NamedTextColor.GRAY)) + .append(Component.text( + String.format("%.0f%%cpu", monitor.getCpuLoad() * 100), + NamedTextColor.GOLD + )) + .append(Component.text(" | ", NamedTextColor.GRAY)) + .append(Component.text( + String.format("%.2f load avg", monitor.getSystemLoadAverage()), + NamedTextColor.LIGHT_PURPLE + )) + .append(Component.text(" | ", NamedTextColor.GRAY)) + .append(Component.text( + String.format("%s total RAM", DataSizeConverter.formatBytesToHumanReadable(monitor.getTotalMemorySize())), + NamedTextColor.DARK_AQUA + )) + .appendNewline() + .append(Component.text( + String.format( + "%s(%s) \uD83D\uDE80 on %s with %s cpu(s)", + monitor.getName(), + monitor.getVersion(), + monitor.getArch(), + monitor.getAvailableProcessors() + ), + NamedTextColor.GRAY + )) + .build(); + } } diff --git a/src/main/java/eu/mhsl/craftattack/spawn/util/text/DataSizeConverter.java b/src/main/java/eu/mhsl/craftattack/spawn/util/text/DataSizeConverter.java index c736b96..8412326 100644 --- a/src/main/java/eu/mhsl/craftattack/spawn/util/text/DataSizeConverter.java +++ b/src/main/java/eu/mhsl/craftattack/spawn/util/text/DataSizeConverter.java @@ -1,7 +1,7 @@ package eu.mhsl.craftattack.spawn.util.text; public class DataSizeConverter { - public static String convertBytesToHumanReadable(long bytes) { + public static String convertBytesPerSecond(long bytes) { double kbits = bytes * 8.0 / 1000.0; double mbits = kbits / 1000.0; @@ -11,4 +11,29 @@ public class DataSizeConverter { return String.format("%.2f Kbit", kbits); } } + + public static String formatBytesToHumanReadable(long bytes) { + String[] units = {"B", "KB", "MB", "GB", "TB", "PB", "EB"}; + int unitIndex = 0; + double readableSize = bytes; + + while (readableSize >= 1024 && unitIndex < units.length - 1) { + readableSize /= 1024; + unitIndex++; + } + + return String.format("%.2f%s", readableSize, units[unitIndex]); + } + + public static String formatCpuTimeToHumanReadable(long nanoseconds) { + if (nanoseconds < 0) return "unsupported"; + + long seconds = nanoseconds / 1_000_000_000; + long minutes = seconds / 60; + long hours = minutes / 60; + + seconds %= 60; + minutes %= 60; + return String.format("%dh%dm%ds", hours, minutes, seconds); + } } \ No newline at end of file