From 3571f618407ec19eb20b84260cf886317177785f Mon Sep 17 00:00:00 2001 From: Johny Muffin Date: Sun, 3 Mar 2024 14:15:41 +1000 Subject: [PATCH] Add TPS API and command --- .../legacyminecraft/poseidon/Poseidon.java | 21 ++++++ .../poseidon/PoseidonConfig.java | 5 ++ .../poseidon/commands/TPSCommand.java | 75 +++++++++++++++++++ .../net/minecraft/server/MinecraftServer.java | 30 ++++++++ .../org/bukkit/command/SimpleCommandMap.java | 8 +- 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/legacyminecraft/poseidon/Poseidon.java create mode 100644 src/main/java/com/legacyminecraft/poseidon/commands/TPSCommand.java diff --git a/src/main/java/com/legacyminecraft/poseidon/Poseidon.java b/src/main/java/com/legacyminecraft/poseidon/Poseidon.java new file mode 100644 index 00000000..2b116dd6 --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/Poseidon.java @@ -0,0 +1,21 @@ +package com.legacyminecraft.poseidon; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; + +import java.util.LinkedList; + +public class Poseidon { + + /** + * Returns a list of the server's TPS (Ticks Per Second) records for performance monitoring. + * The list contains Double values indicating the TPS at each second, ordered from most recent to oldest. + * + * @return LinkedList of TPS records. + */ + public static LinkedList getTpsRecords() { + return ((CraftServer) Bukkit.getServer()).getServer().getTpsRecords(); + } + + +} diff --git a/src/main/java/com/legacyminecraft/poseidon/PoseidonConfig.java b/src/main/java/com/legacyminecraft/poseidon/PoseidonConfig.java index 3dd9c613..f422fa5a 100644 --- a/src/main/java/com/legacyminecraft/poseidon/PoseidonConfig.java +++ b/src/main/java/com/legacyminecraft/poseidon/PoseidonConfig.java @@ -139,6 +139,11 @@ private void write() { generateConfigOption("message.player.join", "\u00A7e%player% joined the game."); generateConfigOption("message.player.leave", "\u00A7e%player% left the game."); + //Optional Poseidon Commands + generateConfigOption("command.info", "This section allows you to enable or disable optional Poseidon commands. This is useful if you have a plugin that conflicts with a Poseidon command."); + generateConfigOption("command.tps.info", "Enables the /tps command to show the server's TPS for various intervals."); + generateConfigOption("command.tps.enabled", true); + //Tree Leave Destroy Blacklist if (Boolean.valueOf(String.valueOf(getConfigOption("world.settings.block-tree-growth.enabled", true)))) { if (String.valueOf(this.getConfigOption("world.settings.block-tree-growth.list", "")).trim().isEmpty()) { diff --git a/src/main/java/com/legacyminecraft/poseidon/commands/TPSCommand.java b/src/main/java/com/legacyminecraft/poseidon/commands/TPSCommand.java new file mode 100644 index 00000000..a085f06f --- /dev/null +++ b/src/main/java/com/legacyminecraft/poseidon/commands/TPSCommand.java @@ -0,0 +1,75 @@ +package com.legacyminecraft.poseidon.commands; + +import com.legacyminecraft.poseidon.Poseidon; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.defaults.VanillaCommand; + +import java.util.LinkedList; +import java.util.LinkedHashMap; +import java.util.Map; + +public class TPSCommand extends Command { + + private final LinkedHashMap intervals = new LinkedHashMap<>(); + + public TPSCommand(String name) { + super(name); + this.description = "Shows the server's TPS for various intervals"; + this.usageMessage = "/tps"; + this.setPermission("poseidon.command.tps"); + + // Define the intervals for TPS calculation + intervals.put("5s", 5); + intervals.put("30s", 30); + intervals.put("1m", 60); + intervals.put("5m", 300); + intervals.put("10m", 600); + intervals.put("15m", 900); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + + LinkedList tpsRecords = Poseidon.getTpsRecords(); + StringBuilder message = new StringBuilder("§bServer TPS: "); + + // Calculate and format TPS for each interval dynamically + for (Map.Entry entry : intervals.entrySet()) { + double averageTps = calculateAverage(tpsRecords, entry.getValue()); + message.append(formatTps(averageTps)).append(" (").append(entry.getKey()).append("), "); + } + + // Remove the trailing comma and space + if (message.length() > 0) { + message.setLength(message.length() - 2); + } + + sender.sendMessage(message.toString()); + return true; + } + + private double calculateAverage(LinkedList records, int seconds) { + int size = Math.min(records.size(), seconds); + if (size == 0) return 20.0; + + double total = 0; + for (int i = 0; i < size; i++) { + total += records.get(i); + } + return total / size; + } + + private String formatTps(double tps) { + String colorCode; + if (tps >= 19) { + colorCode = "§a"; + } else if (tps >= 15) { + colorCode = "§e"; + } else { + colorCode = "§c"; + } + return colorCode + String.format("%.2f", tps); + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 871d6cd8..dff247ce 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -467,6 +467,16 @@ public void run() { } } + //Project Poseidon Start - Tick Update + private final LinkedList tpsRecords = new LinkedList<>(); + private long lastTick = System.currentTimeMillis(); + private int tickCount = 0; + + public LinkedList getTpsRecords() { + return tpsRecords; + } + //Project Poseidon End - Tick Update + private void h() { ArrayList arraylist = new ArrayList(); Iterator iterator = trackerList.keySet().iterator(); @@ -494,6 +504,26 @@ private void h() { ((CraftScheduler) this.server.getScheduler()).mainThreadHeartbeat(this.ticks); // CraftBukkit + //Project Poseidon Start - Tick Update + long currentTime = System.currentTimeMillis(); + tickCount++; + + //Check if a second has passed + if (currentTime - lastTick >= 1000) { + double tps = tickCount / ((currentTime - lastTick) / 1000.0); + tpsRecords.addFirst(tps); + if(tpsRecords.size() > 900) { //Don't keep more than 15 minutes of data + tpsRecords.removeLast(); + } + + tickCount = 0; + lastTick = currentTime; + } + + //Project Poseidon End - Tick Update + + + for (j = 0; j < this.worlds.size(); ++j) { // CraftBukkit // if (j == 0 || this.propertyManager.getBoolean("allow-nether", true)) { // CraftBukkit WorldServer worldserver = this.worlds.get(j); // CraftBukkit diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java index cca4d71a..3736fe30 100644 --- a/src/main/java/org/bukkit/command/SimpleCommandMap.java +++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java @@ -1,5 +1,7 @@ package org.bukkit.command; +import com.legacyminecraft.poseidon.PoseidonConfig; +import com.legacyminecraft.poseidon.commands.TPSCommand; import org.bukkit.Server; import org.bukkit.command.defaults.*; @@ -43,10 +45,14 @@ public SimpleCommandMap(final Server server) { } private void setDefaultCommands(final Server server) { - register("poseidon", new PoseidonCommand("poseidon")); register("bukkit", new VersionCommand("version")); register("bukkit", new ReloadCommand("reload")); register("bukkit", new PluginsCommand("plugins")); + + //Poseidon Command + register("poseidon", new PoseidonCommand("poseidon")); + if (PoseidonConfig.getInstance().getConfigBoolean("command.tps.enabled")) + register("poseidon", new TPSCommand("tps")); } /**