package com.github.games647.lagmonitor.command.minecraft; import com.github.games647.lagmonitor.LagMonitor; import com.github.games647.lagmonitor.command.LagCommand; import com.github.games647.lagmonitor.traffic.TrafficReader; import com.github.games647.lagmonitor.util.LagUtils; import com.google.common.base.StandardSystemProperty; import java.io.File; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.management.ThreadMXBean; import java.time.Duration; import java.util.List; import java.util.Optional; import java.util.stream.Stream; import oshi.software.os.OSProcess; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.plugin.Plugin; import static com.github.games647.lagmonitor.util.LagUtils.readableBytes; public class SystemCommand extends LagCommand { public SystemCommand(LagMonitor plugin) { super(plugin); } @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (!canExecute(sender, command)) { return true; } displayRuntimeInfo(sender, ManagementFactory.getRuntimeMXBean()); displayThreadInfo(sender, ManagementFactory.getThreadMXBean()); displayProcessInfo(sender); displayUserInfo(sender); displayMinecraftInfo(sender); return true; } private void displayUserInfo(CommandSender sender) { sender.sendMessage(PRIMARY_COLOR + "User"); sendMessage(sender, " Timezone", System.getProperty("user.timezone", "Unknown")); sendMessage(sender, " Country", System.getProperty("user.country", "Unknown")); sendMessage(sender, " Language", System.getProperty("user.language", "Unknown")); sendMessage(sender, " Home", StandardSystemProperty.USER_HOME.value()); sendMessage(sender, " Name", StandardSystemProperty.USER_NAME.value()); } private void displayProcessInfo(CommandSender sender) { sender.sendMessage(PRIMARY_COLOR + "Process:"); Optional<OSProcess> optProcess = plugin.getNativeData().getProcess(); if (optProcess.isPresent()) { OSProcess process = optProcess.get(); sendMessage(sender, " PID", String.valueOf(process.getProcessID())); sendMessage(sender, " Name", process.getName()); sendMessage(sender, " Path", process.getPath()); sendMessage(sender, " Working directory", process.getCurrentWorkingDirectory()); sendMessage(sender, " User", process.getUser()); sendMessage(sender, " Group", process.getGroup()); } else { sendError(sender, NATIVE_NOT_FOUND); } } private void displayRuntimeInfo(CommandSender sender, RuntimeMXBean runtimeBean) { long uptime = runtimeBean.getUptime(); String uptimeFormat = LagMonitor.formatDuration(Duration.ofMillis(uptime)); displayMemoryInfo(sender, Runtime.getRuntime()); // runtime specific sendMessage(sender, "Uptime", uptimeFormat); sendMessage(sender, "Arguments", runtimeBean.getInputArguments().toString()); sendMessage(sender, "Classpath", runtimeBean.getClassPath()); sendMessage(sender, "Library path", runtimeBean.getLibraryPath()); } private void displayThreadInfo(CommandSender sender, ThreadMXBean threadBean) { sendMessage(sender, "Threads", String.valueOf(threadBean.getThreadCount())); sendMessage(sender, "Peak threads", String.valueOf(threadBean.getPeakThreadCount())); sendMessage(sender, "Daemon threads", String.valueOf(threadBean.getDaemonThreadCount())); sendMessage(sender, "Total started threads", String.valueOf(threadBean.getTotalStartedThreadCount())); } private void displayMemoryInfo(CommandSender sender, Runtime runtime) { long maxMemory = runtime.maxMemory(); long freeMemory = runtime.freeMemory(); long totalMemory = runtime.totalMemory(); sendMessage(sender, "Reserved used RAM", readableBytes(totalMemory - freeMemory)); sendMessage(sender, "Reserved free RAM", readableBytes(freeMemory)); sendMessage(sender, "Reserved RAM", readableBytes(totalMemory)); sendMessage(sender, "Max RAM", readableBytes(maxMemory)); } private void displayMinecraftInfo(CommandSender sender) { //Minecraft specific sendMessage(sender, "TPS", String.valueOf(plugin.getTpsHistoryTask().getLastSample())); TrafficReader trafficReader = plugin.getTrafficReader(); if (trafficReader != null) { String formattedIncoming = readableBytes(trafficReader.getIncomingBytes().longValue()); String formattedOutgoing = readableBytes(trafficReader.getOutgoingBytes().longValue()); sendMessage(sender, "Incoming Traffic", formattedIncoming); sendMessage(sender, "Outgoing Traffic", formattedOutgoing); } Plugin[] plugins = Bukkit.getPluginManager().getPlugins(); sendMessage(sender, "Loaded Plugins", String.format("%d/%d", getEnabledPlugins(plugins), plugins.length)); int onlinePlayers = Bukkit.getOnlinePlayers().size(); int maxPlayers = Bukkit.getMaxPlayers(); sendMessage(sender, "Players", String.format("%d/%d", onlinePlayers, maxPlayers)); displayWorldInfo(sender); sendMessage(sender, "Server version", Bukkit.getVersion()); } private void displayWorldInfo(CommandSender sender) { int entities = 0; int chunks = 0; int livingEntities = 0; int tileEntities = 0; long usedWorldSize = 0; List<World> worlds = Bukkit.getWorlds(); for (World world : worlds) { for (Chunk loadedChunk : world.getLoadedChunks()) { tileEntities += loadedChunk.getTileEntities().length; } livingEntities += world.getLivingEntities().size(); entities += world.getEntities().size(); chunks += world.getLoadedChunks().length; File worldFolder = Bukkit.getWorld(world.getUID()).getWorldFolder(); usedWorldSize += LagUtils.getFolderSize(plugin.getLogger(), worldFolder.toPath()); } sendMessage(sender, "Entities", String.format("%d/%d", livingEntities, entities)); sendMessage(sender, "Tile Entities", String.valueOf(tileEntities)); sendMessage(sender, "Loaded Chunks", String.valueOf(chunks)); sendMessage(sender, "Worlds", String.valueOf(worlds.size())); sendMessage(sender, "World Size", readableBytes(usedWorldSize)); } private int getEnabledPlugins(Plugin[] plugins) { return (int) Stream.of(plugins).filter(Plugin::isEnabled).count(); } }