aboutsummaryrefslogtreecommitdiff
path: root/spark-common/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'spark-common/src/main/java')
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java36
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java5
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java33
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java233
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java116
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java53
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java9
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java70
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java32
9 files changed, 390 insertions, 197 deletions
diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
index 7a33c39..6b3eb21 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java
@@ -33,6 +33,10 @@ import me.lucko.spark.common.command.tabcomplete.TabCompleter;
import me.lucko.spark.common.monitor.tick.TpsCalculator;
import me.lucko.spark.common.sampler.TickCounter;
import me.lucko.spark.common.util.BytebinClient;
+import net.kyori.text.Component;
+import net.kyori.text.TextComponent;
+import net.kyori.text.format.TextColor;
+import net.kyori.text.format.TextDecoration;
import okhttp3.OkHttpClient;
import java.util.ArrayList;
@@ -116,7 +120,7 @@ public class SparkPlatform<S> {
command.executor().execute(this, sender, resp, new Arguments(rawArgs));
} catch (IllegalArgumentException e) {
e.printStackTrace();
- resp.replyPrefixed("&c" + e.getMessage());
+ resp.replyPrefixed(TextComponent.of(e.getMessage(), TextColor.RED));
}
return;
}
@@ -146,14 +150,36 @@ public class SparkPlatform<S> {
}
private void sendUsage(CommandResponseHandler<S> sender) {
- sender.replyPrefixed("&fspark &7v" + getPlugin().getVersion());
+ sender.replyPrefixed(TextComponent.builder()
+ .append(TextComponent.of("spark", TextColor.WHITE))
+ .append(Component.space())
+ .append(TextComponent.of("v" + getPlugin().getVersion(), TextColor.GRAY))
+ .build()
+ );
for (Command<S> command : this.commands) {
- sender.reply("&6&l> &7/" + getPlugin().getLabel() + " " + command.aliases().get(0));
+ sender.reply(TextComponent.builder()
+ .append(TextComponent.builder(">").color(TextColor.GOLD).decoration(TextDecoration.BOLD, true).build())
+ .append(Component.space())
+ .append(TextComponent.of("/" + getPlugin().getLabel() + " " + command.aliases().get(0), TextColor.GRAY))
+ .build()
+ );
for (Command.ArgumentInfo arg : command.arguments()) {
if (arg.requiresParameter()) {
- sender.reply(" &8[&7--" + arg.argumentName() + "&8 <" + arg.parameterDescription() + ">]");
+ sender.reply(TextComponent.builder(" ")
+ .append(TextComponent.of("[", TextColor.DARK_GRAY))
+ .append(TextComponent.of("--" + arg.argumentName(), TextColor.GRAY))
+ .append(Component.space())
+ .append(TextComponent.of("<" + arg.parameterDescription() + ">", TextColor.DARK_GRAY))
+ .append(TextComponent.of("]", TextColor.DARK_GRAY))
+ .build()
+ );
} else {
- sender.reply(" &8[&7--" + arg.argumentName() + "]");
+ sender.reply(TextComponent.builder(" ")
+ .append(TextComponent.of("[", TextColor.DARK_GRAY))
+ .append(TextComponent.of("--" + arg.argumentName(), TextColor.GRAY))
+ .append(TextComponent.of("]", TextColor.DARK_GRAY))
+ .build()
+ );
}
}
}
diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java
index 481a615..19eb3d3 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java
@@ -22,6 +22,7 @@ package me.lucko.spark.common;
import me.lucko.spark.common.sampler.ThreadDumper;
import me.lucko.spark.common.sampler.TickCounter;
+import net.kyori.text.Component;
import java.nio.file.Path;
import java.util.Set;
@@ -36,9 +37,7 @@ public interface SparkPlugin<S> {
Set<S> getSendersWithPermission(String permission);
- void sendMessage(S sender, String message);
-
- void sendLink(S sender, String url);
+ void sendMessage(S sender, Component message);
void runAsync(Runnable r);
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java b/spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java
index 9d604bd..94e1946 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/CommandResponseHandler.java
@@ -21,14 +21,24 @@
package me.lucko.spark.common.command;
import me.lucko.spark.common.SparkPlatform;
+import net.kyori.text.Component;
+import net.kyori.text.TextComponent;
+import net.kyori.text.event.ClickEvent;
+import net.kyori.text.format.TextColor;
+import net.kyori.text.format.TextDecoration;
import java.util.Set;
import java.util.function.Consumer;
public class CommandResponseHandler<S> {
- /** The prefix used in all messages */
- private static final String PREFIX = "&8[&e&l⚡&8] &7";
+ /** The prefix used in all messages "&8[&e&l⚡&8] &7" */
+ private static final TextComponent PREFIX = TextComponent.builder().color(TextColor.GRAY)
+ .append(TextComponent.of("[", TextColor.DARK_GRAY))
+ .append(TextComponent.builder("⚡").color(TextColor.YELLOW).decoration(TextDecoration.BOLD, TextDecoration.State.TRUE).build())
+ .append(TextComponent.of("]", TextColor.DARK_GRAY))
+ .append(TextComponent.of(" "))
+ .build();
private final SparkPlatform<S> platform;
private final S sender;
@@ -48,28 +58,21 @@ public class CommandResponseHandler<S> {
senders.forEach(action);
}
- public void reply(String message) {
+ public void reply(Component message) {
this.platform.getPlugin().sendMessage(this.sender, message);
}
- public void broadcast(String message) {
+ public void broadcast(Component message) {
allSenders(sender -> this.platform.getPlugin().sendMessage(sender, message));
}
- public void replyPrefixed(String message) {
- this.platform.getPlugin().sendMessage(this.sender, PREFIX + message);
+ public void replyPrefixed(Component message) {
+ reply(PREFIX.append(message));
}
- public void broadcastPrefixed(String message) {
- allSenders(sender -> this.platform.getPlugin().sendMessage(sender, PREFIX + message));
+ public void broadcastPrefixed(Component message) {
+ broadcast(PREFIX.append(message));
}
- public void replyLink(String link) {
- this.platform.getPlugin().sendLink(this.sender, link);
- }
-
- public void broadcastLink(String link) {
- allSenders(sender -> this.platform.getPlugin().sendLink(sender, link));
- }
}
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java
index 66cee54..097d264 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/HealthModule.java
@@ -26,6 +26,10 @@ import me.lucko.spark.common.command.CommandModule;
import me.lucko.spark.common.command.tabcomplete.TabCompleter;
import me.lucko.spark.common.monitor.cpu.CpuMonitor;
import me.lucko.spark.common.monitor.tick.TpsCalculator;
+import net.kyori.text.Component;
+import net.kyori.text.TextComponent;
+import net.kyori.text.format.TextColor;
+import net.kyori.text.format.TextDecoration;
import java.io.IOException;
import java.lang.management.ManagementFactory;
@@ -45,50 +49,77 @@ public class HealthModule<S> implements CommandModule<S> {
@Override
public void registerCommands(Consumer<Command<S>> consumer) {
consumer.accept(Command.<S>builder()
- .aliases("tps")
- .executor((platform, sender, resp, arguments) -> {
- TpsCalculator tpsCalculator = platform.getTpsCalculator();
- if (tpsCalculator != null) {
- resp.replyPrefixed("TPS from last 5s, 10s, 1m, 5m, 15m:");
- resp.replyPrefixed(" " + tpsCalculator.toFormattedString());
- } else {
- resp.replyPrefixed("Not supported!");
- }
- })
- .tabCompleter(Command.TabCompleter.empty())
- .build()
+ .aliases("tps")
+ .executor((platform, sender, resp, arguments) -> {
+ TpsCalculator tpsCalculator = platform.getTpsCalculator();
+ if (tpsCalculator != null) {
+ resp.replyPrefixed(TextComponent.of("TPS from last 5s, 10s, 1m, 5m, 15m:"));
+ resp.replyPrefixed(TextComponent.builder(" ").append(tpsCalculator.toFormattedComponent()).build());
+ } else {
+ resp.replyPrefixed(TextComponent.of("Not supported!"));
+ }
+ })
+ .tabCompleter(Command.TabCompleter.empty())
+ .build()
);
consumer.accept(Command.<S>builder()
.aliases("healthreport", "health", "ht")
.argumentUsage("memory", null)
.executor((platform, sender, resp, arguments) -> {
- resp.replyPrefixed("&7Generating server health report...");
+ resp.replyPrefixed(TextComponent.of("Generating server health report..."));
platform.getPlugin().runAsync(() -> {
- List<String> report = new ArrayList<>(15);
- report.add("");
+ List<Component> report = new ArrayList<>(15);
+ report.add(Component.empty());
TpsCalculator tpsCalculator = platform.getTpsCalculator();
if (tpsCalculator != null) {
- report.add("&8&l>&6 TPS from last 5s, 10s, 1m, 5m, 15m:");
- report.add(" " + tpsCalculator.toFormattedString());
- report.add("");
+ report.add(TextComponent.builder()
+ .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build())
+ .append(Component.space())
+ .append(TextComponent.of("TPS from last 5s, 10s, 1m, 5m, 15m:", TextColor.GOLD))
+ .build()
+ );
+ report.add(TextComponent.builder(" ").append(tpsCalculator.toFormattedComponent()).build());
+ report.add(Component.empty());
}
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
-
MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();
- report.add("&8&l>&6 Memory usage: ");
- report.add(" &f" + formatBytes(heapUsage.getUsed()) + " &7/ &f" + formatBytes(heapUsage.getMax()) +
- " &7(&a" + percent(heapUsage.getUsed(), heapUsage.getMax()) + "&7)");
- report.add(" " + generateMemoryUsageDiagram(heapUsage, 40));
- report.add("");
+ report.add(TextComponent.builder()
+ .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build())
+ .append(Component.space())
+ .append(TextComponent.of("Memory usage:", TextColor.GOLD))
+ .build()
+ );
+ report.add(TextComponent.builder(" ")
+ .append(TextComponent.of(formatBytes(heapUsage.getUsed()), TextColor.WHITE))
+ .append(Component.space())
+ .append(TextComponent.of("/", TextColor.GRAY))
+ .append(Component.space())
+ .append(TextComponent.of(formatBytes(heapUsage.getMax()), TextColor.WHITE))
+ .append(TextComponent.of(" "))
+ .append(TextComponent.of("(", TextColor.GRAY))
+ .append(TextComponent.of(percent(heapUsage.getUsed(), heapUsage.getMax()), TextColor.GREEN))
+ .append(TextComponent.of(")", TextColor.GRAY))
+ .build()
+ );
+ report.add(TextComponent.builder(" ").append(generateMemoryUsageDiagram(heapUsage, 40)).build());
+ report.add(Component.empty());
if (arguments.boolFlag("memory")) {
MemoryUsage nonHeapUsage = memoryMXBean.getNonHeapMemoryUsage();
- report.add("&8&l>&6 Non-heap memory usage: ");
- report.add(" &f" + formatBytes(nonHeapUsage.getUsed()));
- report.add("");
+ report.add(TextComponent.builder()
+ .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build())
+ .append(Component.space())
+ .append(TextComponent.of("Non-heap memory usage:", TextColor.GOLD))
+ .build()
+ );
+ report.add(TextComponent.builder(" ")
+ .append(TextComponent.of(formatBytes(nonHeapUsage.getUsed()), TextColor.WHITE))
+ .build()
+ );
+ report.add(Component.empty());
List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean memoryPool : memoryPoolMXBeans) {
@@ -103,16 +134,37 @@ public class HealthModule<S> implements CommandModule<S> {
usage = new MemoryUsage(usage.getInit(), usage.getUsed(), usage.getCommitted(), usage.getCommitted());
}
- report.add("&8&l>&6 " + memoryPool.getName() + " pool usage: ");
- report.add(" &f" + formatBytes(usage.getUsed()) + " &7/ &f" + formatBytes(usage.getMax()) +
- " &7(&a" + percent(usage.getUsed(), usage.getMax()) + "&7)");
- report.add(" " + generateMemoryPoolDiagram(usage, collectionUsage,40));
-
+ report.add(TextComponent.builder()
+ .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build())
+ .append(Component.space())
+ .append(TextComponent.of(memoryPool.getName() + " pool usage:", TextColor.GOLD))
+ .build()
+ );
+ report.add(TextComponent.builder(" ")
+ .append(TextComponent.of(formatBytes(usage.getUsed()), TextColor.WHITE))
+ .append(Component.space())
+ .append(TextComponent.of("/", TextColor.GRAY))
+ .append(Component.space())
+ .append(TextComponent.of(formatBytes(usage.getMax()), TextColor.WHITE))
+ .append(TextComponent.of(" "))
+ .append(TextComponent.of("(", TextColor.GRAY))
+ .append(TextComponent.of(percent(usage.getUsed(), usage.getMax()), TextColor.GREEN))
+ .append(TextComponent.of(")", TextColor.GRAY))
+ .build()
+ );
+ report.add(TextComponent.builder(" ").append(generateMemoryPoolDiagram(usage, collectionUsage, 40)).build());
if (collectionUsage != null) {
- report.add(" &c- &7Usage at last GC: &f" + formatBytes(collectionUsage.getUsed()));
+ report.add(TextComponent.builder(" ")
+ .append(TextComponent.of("-", TextColor.RED))
+ .append(Component.space())
+ .append(TextComponent.of("Usage at last GC:", TextColor.GRAY))
+ .append(Component.space())
+ .append(TextComponent.of(formatBytes(collectionUsage.getUsed()), TextColor.WHITE))
+ .build()
+ );
}
- report.add("");
+ report.add(Component.empty());
}
}
@@ -120,17 +172,30 @@ public class HealthModule<S> implements CommandModule<S> {
double processCpuLoad = CpuMonitor.getProcessCpuLoad();
if (systemCpuLoad >= 0 || processCpuLoad >= 0) {
- report.add("&8&l>&6 CPU usage: ");
+ report.add(TextComponent.builder()
+ .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build())
+ .append(Component.space())
+ .append(TextComponent.of("CPU usage:", TextColor.GOLD))
+ .build()
+ );
if (systemCpuLoad >= 0) {
- report.add(" &7System: &a" + percent(systemCpuLoad, 1.0d));
- report.add(" " + generateCpuUsageDiagram(systemCpuLoad, 40));
- report.add("");
+ report.add(TextComponent.builder(" ")
+ .append(TextComponent.of("System: ", TextColor.GRAY))
+ .append(TextComponent.of(percent(systemCpuLoad, 1.0d), TextColor.GREEN))
+ .build()
+ );
+ report.add(TextComponent.builder(" ").append(generateCpuUsageDiagram(systemCpuLoad, 40)).build());
+ report.add(Component.empty());
}
if (processCpuLoad >= 0) {
- report.add(" &7Process: &a" + percent(processCpuLoad, 1.0d));
- report.add(" " + generateCpuUsageDiagram(processCpuLoad, 40));
- report.add("");
+ report.add(TextComponent.builder(" ")
+ .append(TextComponent.of("Process: ", TextColor.GRAY))
+ .append(TextComponent.of(percent(processCpuLoad, 1.0d), TextColor.GREEN))
+ .build()
+ );
+ report.add(TextComponent.builder(" ").append(generateCpuUsageDiagram(processCpuLoad, 40)).build());
+ report.add(Component.empty());
}
}
@@ -138,17 +203,33 @@ public class HealthModule<S> implements CommandModule<S> {
FileStore fileStore = Files.getFileStore(Paths.get("."));
long totalSpace = fileStore.getTotalSpace();
long usedSpace = totalSpace - fileStore.getUsableSpace();
-
- report.add("&8&l>&6 Disk usage: ");
- report.add(" &f" + formatBytes(usedSpace) + " &7/ &f" + formatBytes(totalSpace) +
- " &7(&a" + percent(usedSpace, totalSpace) + "&7)");
- report.add(" " + generateDiskUsageDiagram(usedSpace, totalSpace, 40));
- report.add("");
+ report.add(TextComponent.builder()
+ .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build())
+ .append(Component.space())
+ .append(TextComponent.of("Disk usage:", TextColor.GOLD))
+ .build()
+ );
+ report.add(TextComponent.builder(" ")
+ .append(TextComponent.of(formatBytes(usedSpace), TextColor.WHITE))
+ .append(Component.space())
+ .append(TextComponent.of("/", TextColor.GRAY))
+ .append(Component.space())
+ .append(TextComponent.of(formatBytes(totalSpace), TextColor.WHITE))
+ .append(TextComponent.of(" "))
+ .append(TextComponent.of("(", TextColor.GRAY))
+ .append(TextComponent.of(percent(usedSpace, totalSpace), TextColor.GREEN))
+ .append(TextComponent.of(")", TextColor.GRAY))
+ .build()
+ );
+ report.add(TextComponent.builder(" ").append(generateDiskUsageDiagram(usedSpace, totalSpace, 40)).build());
+ report.add(Component.empty());
} catch (IOException e) {
e.printStackTrace();
}
- report.forEach(resp::reply);
+ TextComponent.Builder builder = TextComponent.builder();
+ report.forEach(line -> builder.append(line).append(Component.newline()));
+ resp.reply(builder.build());
});
})
.tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--memory"))
@@ -161,7 +242,7 @@ public class HealthModule<S> implements CommandModule<S> {
return (int) percent + "%";
}
- private static String generateMemoryUsageDiagram(MemoryUsage usage, int length) {
+ private static TextComponent generateMemoryUsageDiagram(MemoryUsage usage, int length) {
double used = usage.getUsed();
double committed = usage.getCommitted();
double max = usage.getMax();
@@ -169,18 +250,23 @@ public class HealthModule<S> implements CommandModule<S> {
int usedChars = (int) ((used * length) / max);
int committedChars = (int) ((committed * length) / max);
- String line = "&7" + Strings.repeat("/", usedChars);
+ TextComponent.Builder line = TextComponent.builder(Strings.repeat("/", usedChars)).color(TextColor.GRAY);
if (committedChars > usedChars) {
- line += Strings.repeat(" ", (committedChars - usedChars) - 1) + "&e|";
+ line.append(TextComponent.of(Strings.repeat(" ", (committedChars - usedChars) - 1)));
+ line.append(TextComponent.of("|", TextColor.YELLOW));
}
if (length > committedChars) {
- line += Strings.repeat(" ", (length - committedChars));
+ line.append(TextComponent.of(Strings.repeat(" ", (length - committedChars))));
}
- return "&8[" + line + "&8]";
+ return TextComponent.builder()
+ .append(TextComponent.of("[", TextColor.DARK_GRAY))
+ .append(line.build())
+ .append(TextComponent.of("]", TextColor.DARK_GRAY))
+ .build();
}
- private static String generateMemoryPoolDiagram(MemoryUsage usage, MemoryUsage collectionUsage, int length) {
+ private static TextComponent generateMemoryPoolDiagram(MemoryUsage usage, MemoryUsage collectionUsage, int length) {
double used = usage.getUsed();
double collectionUsed = used;
if (collectionUsage != null) {
@@ -193,32 +279,45 @@ public class HealthModule<S> implements CommandModule<S> {
int collectionUsedChars = (int) ((collectionUsed * length) / max);
int committedChars = (int) ((committed * length) / max);
- String line = "&7" + Strings.repeat("/", collectionUsedChars);
+ TextComponent.Builder line = TextComponent.builder(Strings.repeat("/", collectionUsedChars)).color(TextColor.GRAY);
+
if (usedChars > collectionUsedChars) {
- line += "&c|&7" + Strings.repeat("/", (usedChars - collectionUsedChars) - 1);
+ line.append(TextComponent.of("|", TextColor.RED));
+ line.append(TextComponent.of(Strings.repeat("/", (usedChars - collectionUsedChars) - 1), TextColor.GRAY));
}
if (committedChars > usedChars) {
- line += Strings.repeat(" ", (committedChars - usedChars) - 1) + "&e|";
+ line.append(TextComponent.of(Strings.repeat(" ", (committedChars - usedChars) - 1)));
+ line.append(TextComponent.of("|", TextColor.YELLOW));
}
if (length > committedChars) {
- line += Strings.repeat(" ", (length - committedChars));
+ line.append(TextComponent.of(Strings.repeat(" ", (length - committedChars))));
}
- return "&8[" + line + "&8]";
+ return TextComponent.builder()
+ .append(TextComponent.of("[", TextColor.DARK_GRAY))
+ .append(line.build())
+ .append(TextComponent.of("]", TextColor.DARK_GRAY))
+ .build();
}
- private static String generateCpuUsageDiagram(double usage, int length) {
+ private static TextComponent generateCpuUsageDiagram(double usage, int length) {
int usedChars = (int) ((usage * length));
-
- String line = "&7" + Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars);
- return "&8[" + line + "&8]";
+ String line = Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars);
+ return TextComponent.builder()
+ .append(TextComponent.of("[", TextColor.DARK_GRAY))
+ .append(TextComponent.of(line, TextColor.GRAY))
+ .append(TextComponent.of("]", TextColor.DARK_GRAY))
+ .build();
}
- private static String generateDiskUsageDiagram(double used, double max, int length) {
+ private static TextComponent generateDiskUsageDiagram(double used, double max, int length) {
int usedChars = (int) ((used * length) / max);
-
- String line = "&7" + Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars);
- return "&8[" + line + "&8]";
+ String line = Strings.repeat("/", usedChars) + Strings.repeat(" ", length - usedChars);
+ return TextComponent.builder()
+ .append(TextComponent.of("[", TextColor.DARK_GRAY))
+ .append(TextComponent.of(line, TextColor.GRAY))
+ .append(TextComponent.of("]", TextColor.DARK_GRAY))
+ .build();
}
private static String formatBytes(long bytes) {
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java
index 583b1b6..e2d817d 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/MemoryModule.java
@@ -26,6 +26,9 @@ import me.lucko.spark.common.command.CommandModule;
import me.lucko.spark.common.command.tabcomplete.TabCompleter;
import me.lucko.spark.common.heapdump.HeapDump;
import me.lucko.spark.common.heapdump.HeapDumpSummary;
+import net.kyori.text.TextComponent;
+import net.kyori.text.event.ClickEvent;
+import net.kyori.text.format.TextColor;
import okhttp3.MediaType;
import java.io.IOException;
@@ -45,32 +48,38 @@ public class MemoryModule<S> implements CommandModule<S> {
.argumentUsage("run-gc-before", null)
.executor((platform, sender, resp, arguments) -> {
platform.getPlugin().runAsync(() -> {
- if (arguments.boolFlag("run-gc-before")) {
- resp.broadcastPrefixed("&7Running garbage collector...");
- System.gc();
- }
-
- resp.broadcastPrefixed("&7Creating a new heap dump summary, please wait...");
-
- HeapDumpSummary heapDump;
- try {
- heapDump = HeapDumpSummary.createNew();
- } catch (Exception e) {
- resp.broadcastPrefixed("&cAn error occurred whilst inspecting the heap.");
- e.printStackTrace();
- return;
- }
-
- byte[] output = heapDump.formCompressedDataPayload();
- try {
- String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, JSON_TYPE, false).key();
- resp.broadcastPrefixed("&6Heap dump summmary output:");
- resp.broadcastLink(SparkPlatform.VIEWER_URL + key);
- } catch (IOException e) {
- resp.broadcastPrefixed("&cAn error occurred whilst uploading the data.");
- e.printStackTrace();
- }
- });
+ if (arguments.boolFlag("run-gc-before")) {
+ resp.broadcastPrefixed(TextComponent.of("Running garbage collector..."));
+ System.gc();
+ }
+
+ resp.broadcastPrefixed(TextComponent.of("Creating a new heap dump summary, please wait..."));
+
+ HeapDumpSummary heapDump;
+ try {
+ heapDump = HeapDumpSummary.createNew();
+ } catch (Exception e) {
+ resp.broadcastPrefixed(TextComponent.of("An error occurred whilst inspecting the heap.", TextColor.RED));
+ e.printStackTrace();
+ return;
+ }
+
+ byte[] output = heapDump.formCompressedDataPayload();
+ try {
+ String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, JSON_TYPE, false).key();
+ String url = SparkPlatform.VIEWER_URL + key;
+
+ resp.broadcastPrefixed(TextComponent.of("Heap dump summmary output:", TextColor.GOLD));
+ resp.broadcast(TextComponent.builder(url)
+ .color(TextColor.GRAY)
+ .clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url))
+ .build()
+ );
+ } catch (IOException e) {
+ resp.broadcastPrefixed(TextComponent.of("An error occurred whilst uploading the data.", TextColor.RED));
+ e.printStackTrace();
+ }
+ });
})
.tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--run-gc-before"))
.build()
@@ -81,35 +90,34 @@ public class MemoryModule<S> implements CommandModule<S> {
.argumentUsage("run-gc-before", null)
.argumentUsage("include-non-live", null)
.executor((platform, sender, resp, arguments) -> {
- // ignore
platform.getPlugin().runAsync(() -> {
- Path pluginFolder = platform.getPlugin().getPluginFolder();
- try {
- Files.createDirectories(pluginFolder);
- } catch (IOException e) {
- // ignore
- }
-
- Path file = pluginFolder.resolve("heap-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + (HeapDump.isOpenJ9() ? ".phd" : ".hprof"));
- boolean liveOnly = !arguments.boolFlag("include-non-live");
-
- if (arguments.boolFlag("run-gc-before")) {
- resp.broadcastPrefixed("&7Running garbage collector...");
- System.gc();
- }
-
- resp.broadcastPrefixed("&7Creating a new heap dump, please wait...");
-
- try {
- HeapDump.dumpHeap(file, liveOnly);
- } catch (Exception e) {
- resp.broadcastPrefixed("&cAn error occurred whilst creating a heap dump.");
- e.printStackTrace();
- return;
- }
-
- resp.broadcastPrefixed("&6Heap dump written to: " + file.toString());
- });
+ Path pluginFolder = platform.getPlugin().getPluginFolder();
+ try {
+ Files.createDirectories(pluginFolder);
+ } catch (IOException e) {
+ // ignore
+ }
+
+ Path file = pluginFolder.resolve("heap-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + (HeapDump.isOpenJ9() ? ".phd" : ".hprof"));
+ boolean liveOnly = !arguments.boolFlag("include-non-live");
+
+ if (arguments.boolFlag("run-gc-before")) {
+ resp.broadcastPrefixed(TextComponent.of("Running garbage collector..."));
+ System.gc();
+ }
+
+ resp.broadcastPrefixed(TextComponent.of("Creating a new heap dump, please wait..."));
+
+ try {
+ HeapDump.dumpHeap(file, liveOnly);
+ } catch (Exception e) {
+ resp.broadcastPrefixed(TextComponent.of("An error occurred whilst creating a heap dump.", TextColor.RED));
+ e.printStackTrace();
+ return;
+ }
+
+ resp.broadcastPrefixed(TextComponent.of("Heap dump written to: " + file.toString(), TextColor.GOLD));
+ });
})
.tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--run-gc-before", "--include-non-live"))
.build()
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java
index 88430f9..e450b0b 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java
@@ -31,6 +31,9 @@ import me.lucko.spark.common.sampler.SamplerBuilder;
import me.lucko.spark.common.sampler.ThreadDumper;
import me.lucko.spark.common.sampler.ThreadGrouper;
import me.lucko.spark.common.sampler.TickCounter;
+import net.kyori.text.TextComponent;
+import net.kyori.text.event.ClickEvent;
+import net.kyori.text.format.TextColor;
import okhttp3.MediaType;
import java.io.IOException;
@@ -70,18 +73,18 @@ public class SamplerModule<S> implements CommandModule<S> {
if (arguments.boolFlag("info")) {
synchronized (this.activeSamplerMutex) {
if (this.activeSampler == null) {
- resp.replyPrefixed("&7There isn't an active sampling task running.");
+ resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running."));
} else {
long timeout = this.activeSampler.getEndTime();
if (timeout == -1) {
- resp.replyPrefixed("&7There is an active sampler currently running, with no defined timeout.");
+ resp.replyPrefixed(TextComponent.of("There is an active sampler currently running, with no defined timeout."));
} else {
long timeoutDiff = (timeout - System.currentTimeMillis()) / 1000L;
- resp.replyPrefixed("&7There is an active sampler currently running, due to timeout in " + timeoutDiff + " seconds.");
+ resp.replyPrefixed(TextComponent.of("There is an active sampler currently running, due to timeout in " + timeoutDiff + " seconds."));
}
long runningTime = (System.currentTimeMillis() - this.activeSampler.getStartTime()) / 1000L;
- resp.replyPrefixed("&7It has been sampling for " + runningTime + " seconds so far.");
+ resp.replyPrefixed(TextComponent.of("It has been sampling for " + runningTime + " seconds so far."));
}
}
return;
@@ -90,11 +93,11 @@ public class SamplerModule<S> implements CommandModule<S> {
if (arguments.boolFlag("cancel")) {
synchronized (this.activeSamplerMutex) {
if (this.activeSampler == null) {
- resp.replyPrefixed("&7There isn't an active sampling task running.");
+ resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running."));
} else {
this.activeSampler.cancel();
this.activeSampler = null;
- resp.broadcastPrefixed("&6The active sampling task has been cancelled.");
+ resp.broadcastPrefixed(TextComponent.of("The active sampling task has been cancelled.", TextColor.GOLD));
}
}
return;
@@ -103,10 +106,10 @@ public class SamplerModule<S> implements CommandModule<S> {
if (arguments.boolFlag("stop") || arguments.boolFlag("upload")) {
synchronized (this.activeSamplerMutex) {
if (this.activeSampler == null) {
- resp.replyPrefixed("&7There isn't an active sampling task running.");
+ resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running."));
} else {
this.activeSampler.cancel();
- resp.broadcastPrefixed("&7The active sampling operation has been stopped! Uploading results...");
+ resp.broadcastPrefixed(TextComponent.of("The active sampling operation has been stopped! Uploading results..."));
handleUpload(platform, resp, this.activeSampler);
this.activeSampler = null;
}
@@ -116,12 +119,14 @@ public class SamplerModule<S> implements CommandModule<S> {
int timeoutSeconds = arguments.intFlag("timeout");
if (timeoutSeconds != -1 && timeoutSeconds <= 10) {
- resp.replyPrefixed("&cThe specified timeout is not long enough for accurate results to be formed. Please choose a value greater than 10.");
+ resp.replyPrefixed(TextComponent.of("The specified timeout is not long enough for accurate results to be formed. " +
+ "Please choose a value greater than 10.", TextColor.RED));
return;
}
if (timeoutSeconds != -1 && timeoutSeconds < 30) {
- resp.replyPrefixed("&7The accuracy of the output will significantly improve when sampling is able to run for longer periods. Consider setting a timeout value over 30 seconds.");
+ resp.replyPrefixed(TextComponent.of("The accuracy of the output will significantly improve when sampling is able to run for longer periods. " +
+ "Consider setting a timeout value over 30 seconds."));
}
double intervalMillis = arguments.doubleFlag("interval");
@@ -161,7 +166,7 @@ public class SamplerModule<S> implements CommandModule<S> {
if (ticksOver != -1) {
tickCounter = platform.getTickCounter();
if (tickCounter == null) {
- resp.replyPrefixed("&cTick counting is not supported!");
+ resp.replyPrefixed(TextComponent.of("Tick counting is not supported!", TextColor.RED));
return;
}
}
@@ -169,11 +174,11 @@ public class SamplerModule<S> implements CommandModule<S> {
Sampler sampler;
synchronized (this.activeSamplerMutex) {
if (this.activeSampler != null) {
- resp.replyPrefixed("&7An active sampler is already running.");
+ resp.replyPrefixed(TextComponent.of("An active sampler is already running."));
return;
}
- resp.broadcastPrefixed("&7Initializing a new profiler, please wait...");
+ resp.broadcastPrefixed(TextComponent.of("Initializing a new profiler, please wait..."));
SamplerBuilder builder = new SamplerBuilder();
builder.threadDumper(threadDumper);
@@ -188,11 +193,11 @@ public class SamplerModule<S> implements CommandModule<S> {
}
sampler = this.activeSampler = builder.start();
- resp.broadcastPrefixed("&6Profiler now active!");
+ resp.broadcastPrefixed(TextComponent.of("Profiler now active!", TextColor.GOLD));
if (timeoutSeconds == -1) {
- resp.broadcastPrefixed("&7Use '/" + platform.getPlugin().getLabel() + " stop' to stop profiling and upload the results.");
+ resp.broadcastPrefixed(TextComponent.of("Use '/" + platform.getPlugin().getLabel() + " stop' to stop profiling and upload the results."));
} else {
- resp.broadcastPrefixed("&7The results will be automatically returned after the profiler has been running for " + timeoutSeconds + " seconds.");
+ resp.broadcastPrefixed(TextComponent.of("The results will be automatically returned after the profiler has been running for " + timeoutSeconds + " seconds."));
}
}
@@ -201,7 +206,7 @@ public class SamplerModule<S> implements CommandModule<S> {
// send message if profiling fails
future.whenCompleteAsync((s, throwable) -> {
if (throwable != null) {
- resp.broadcastPrefixed("&cSampling operation failed unexpectedly. Error: " + throwable.toString());
+ resp.broadcastPrefixed(TextComponent.of("Sampling operation failed unexpectedly. Error: " + throwable.toString(), TextColor.RED));
throwable.printStackTrace();
}
});
@@ -218,7 +223,7 @@ public class SamplerModule<S> implements CommandModule<S> {
// await the result
if (timeoutSeconds != -1) {
future.thenAcceptAsync(s -> {
- resp.broadcastPrefixed("&7The active sampling operation has completed! Uploading results...");
+ resp.broadcastPrefixed(TextComponent.of("The active sampling operation has completed! Uploading results..."));
handleUpload(platform, resp, s);
});
}
@@ -246,10 +251,16 @@ public class SamplerModule<S> implements CommandModule<S> {
byte[] output = sampler.formCompressedDataPayload();
try {
String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, JSON_TYPE, false).key();
- resp.broadcastPrefixed("&6Sampling results:");
- resp.broadcastLink(SparkPlatform.VIEWER_URL + key);
+ String url = SparkPlatform.VIEWER_URL + key;
+
+ resp.broadcastPrefixed(TextComponent.of("Sampling results:", TextColor.GOLD));
+ resp.broadcast(TextComponent.builder(url)
+ .color(TextColor.GRAY)
+ .clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url))
+ .build()
+ );
} catch (IOException e) {
- resp.broadcastPrefixed("&cAn error occurred whilst uploading the results.");
+ resp.broadcastPrefixed(TextComponent.of("An error occurred whilst uploading the results.", TextColor.RED));
e.printStackTrace();
}
});
diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java
index bea7a07..3b26018 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/TickMonitoringModule.java
@@ -26,6 +26,9 @@ import me.lucko.spark.common.command.CommandResponseHandler;
import me.lucko.spark.common.command.tabcomplete.TabCompleter;
import me.lucko.spark.common.monitor.tick.TickMonitor;
import me.lucko.spark.common.sampler.TickCounter;
+import net.kyori.text.Component;
+import net.kyori.text.TextComponent;
+import net.kyori.text.format.TextColor;
import java.util.function.Consumer;
@@ -43,7 +46,7 @@ public class TickMonitoringModule<S> implements CommandModule<S> {
.executor((platform, sender, resp, arguments) -> {
TickCounter tickCounter = platform.getTickCounter();
if (tickCounter == null) {
- resp.replyPrefixed("&cNot supported!");
+ resp.replyPrefixed(TextComponent.of("Not supported!", TextColor.RED));
return;
}
@@ -59,7 +62,7 @@ public class TickMonitoringModule<S> implements CommandModule<S> {
tickCounter.removeTickTask(this.activeTickMonitor);
this.activeTickMonitor.close();
this.activeTickMonitor = null;
- resp.broadcastPrefixed("&7Tick monitor disabled.");
+ resp.broadcastPrefixed(TextComponent.of("Tick monitor disabled."));
}
})
.tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--threshold", "--without-gc"))
@@ -76,7 +79,7 @@ public class TickMonitoringModule<S> implements CommandModule<S> {
}
@Override
- protected void sendMessage(String message) {
+ protected void sendMessage(Component message) {
this.resp.broadcastPrefixed(message);
}
}
diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java
index 5693df6..3d91368 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TickMonitor.java
@@ -21,9 +21,14 @@
package me.lucko.spark.common.monitor.tick;
import com.sun.management.GarbageCollectionNotificationInfo;
+import com.sun.org.apache.regexp.internal.RE;
import me.lucko.spark.common.monitor.memory.GarbageCollectionMonitor;
import me.lucko.spark.common.sampler.TickCounter;
+import net.kyori.text.Component;
+import net.kyori.text.TextComponent;
+import net.kyori.text.format.TextColor;
+import java.awt.*;
import java.text.DecimalFormat;
import java.util.DoubleSummaryStatistics;
@@ -52,7 +57,7 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec
}
}
- protected abstract void sendMessage(String message);
+ protected abstract void sendMessage(Component message);
@Override
public void close() {
@@ -69,8 +74,8 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec
if (this.state == null) {
this.state = State.SETUP;
this.lastTickTime = now;
- sendMessage("Tick monitor started. Before the monitor becomes fully active, the server's " +
- "average tick rate will be calculated over a period of 120 ticks (approx 6 seconds).");
+ sendMessage(TextComponent.of("Tick monitor started. Before the monitor becomes fully active, the server's " +
+ "average tick rate will be calculated over a period of 120 ticks (approx 6 seconds)."));
return;
}
@@ -90,13 +95,33 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec
// move onto the next state
if (this.averageTickTime.getCount() >= 120) {
-
- sendMessage("&6Analysis is now complete.");
- sendMessage("&f> &7Max: " + df.format(this.averageTickTime.getMax()) + "ms");
- sendMessage("&f> &7Min: " + df.format(this.averageTickTime.getMin()) + "ms");
- sendMessage("&f> &7Avg: " + df.format(this.averageTickTime.getAverage()) + "ms");
- sendMessage("Starting now, any ticks with >" + this.percentageChangeThreshold + "% increase in " +
- "duration compared to the average will be reported.");
+ sendMessage(TextComponent.of("Analysis is now complete.", TextColor.GOLD));
+ sendMessage(TextComponent.builder().color(TextColor.GRAY)
+ .append(TextComponent.of(">", TextColor.WHITE))
+ .append(Component.space())
+ .append(TextComponent.of("Max: "))
+ .append(TextComponent.of(df.format(this.averageTickTime.getMax())))
+ .append(TextComponent.of("ms"))
+ .build()
+ );
+ sendMessage(TextComponent.builder().color(TextColor.GRAY)
+ .append(TextComponent.of(">", TextColor.WHITE))
+ .append(Component.space())
+ .append(TextComponent.of("Min: "))
+ .append(TextComponent.of(df.format(this.averageTickTime.getMin())))
+ .append(TextComponent.of("ms"))
+ .build()
+ );
+ sendMessage(TextComponent.builder().color(TextColor.GRAY)
+ .append(TextComponent.of(">", TextColor.WHITE))
+ .append(Component.space())
+ .append(TextComponent.of("Avg: "))
+ .append(TextComponent.of(df.format(this.averageTickTime.getAverage())))
+ .append(TextComponent.of("ms"))
+ .build()
+ );
+ sendMessage(TextComponent.of("Starting now, any ticks with >" + this.percentageChangeThreshold + "% increase in " +
+ "duration compared to the average will be reported."));
this.avg = this.averageTickTime.getAverage();
this.state = State.MONITORING;
@@ -111,8 +136,17 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec
double percentageChange = (increase * 100d) / this.avg;
if (percentageChange > this.percentageChangeThreshold) {
- sendMessage("&7Tick &8#" + counter.getCurrentTick() + " &7lasted &6" + df.format(diff) +
- "&7 ms. (&6" + df.format(percentageChange) + "% &7increase from average)");
+ sendMessage(TextComponent.builder().color(TextColor.GRAY)
+ .append(TextComponent.of("Tick "))
+ .append(TextComponent.of("#" + counter.getCurrentTick(), TextColor.DARK_GRAY))
+ .append(TextComponent.of(" lasted "))
+ .append(TextComponent.of(df.format(diff), TextColor.GOLD))
+ .append(TextComponent.of(" ms. "))
+ .append(TextComponent.of("("))
+ .append(TextComponent.of(df.format(percentageChange) + "%", TextColor.GOLD))
+ .append(TextComponent.of("increase from avg)"))
+ .build()
+ );
}
}
}
@@ -132,8 +166,16 @@ public abstract class TickMonitor implements TickCounter.TickTask, GarbageCollec
gcType = "Old Gen GC";
}
- sendMessage("&7Tick &8#" + this.tickCounter.getCurrentTick() + " &7included &4GC &7lasting &6" +
- df.format(data.getGcInfo().getDuration()) + "&7 ms. (type = " + gcType + ")");
+ sendMessage(TextComponent.builder().color(TextColor.GRAY)
+ .append(TextComponent.of("Tick "))
+ .append(TextComponent.of("#" + this.tickCounter.getCurrentTick(), TextColor.DARK_GRAY))
+ .append(TextComponent.of(" included "))
+ .append(TextComponent.of("GC", TextColor.RED))
+ .append(TextComponent.of(" lasting "))
+ .append(TextComponent.of(df.format(data.getGcInfo().getDuration()), TextColor.GOLD))
+ .append(TextComponent.of(" ms. (type = " + gcType + ")"))
+ .build()
+ );
}
private enum State {
diff --git a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java
index 2f3af3e..90a7b78 100644
--- a/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java
+++ b/spark-common/src/main/java/me/lucko/spark/common/monitor/tick/TpsCalculator.java
@@ -21,6 +21,8 @@
package me.lucko.spark.common.monitor.tick;
import me.lucko.spark.common.sampler.TickCounter;
+import net.kyori.text.TextComponent;
+import net.kyori.text.format.TextColor;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -100,27 +102,27 @@ public class TpsCalculator implements TickCounter.TickTask {
return this.tps15M;
}
- public String toFormattedString() {
- return formatTps(this.tps5S.getAverage()) + ", " +
- formatTps(this.tps10S.getAverage()) + ", " +
- formatTps(this.tps1M.getAverage()) + ", " +
- formatTps(this.tps5M.getAverage()) + ", " +
- formatTps(this.tps15M.getAverage());
+ public TextComponent toFormattedComponent() {
+ return TextComponent.builder()
+ .append(format(this.tps5S.getAverage())).append(TextComponent.of(", "))
+ .append(format(this.tps10S.getAverage())).append(TextComponent.of(", "))
+ .append(format(this.tps1M.getAverage())).append(TextComponent.of(", "))
+ .append(format(this.tps5M.getAverage())).append(TextComponent.of(", "))
+ .append(format(this.tps15M.getAverage()))
+ .build();
}
- public static String formatTps(double tps) {
- StringBuilder sb = new StringBuilder();
+ private static TextComponent format(double tps) {
+ TextColor color;
if (tps > 18.0) {
- sb.append("&a");
+ color = TextColor.GREEN;
} else if (tps > 16.0) {
- sb.append("&e");
+ color = TextColor.YELLOW;
} else {
- sb.append("&c");
+ color = TextColor.RED;
}
- if (tps > 20.0) {
- sb.append('*');
- }
- return sb.append(Math.min(Math.round(tps * 100.0) / 100.0, 20.0)).toString();
+
+ return TextComponent.of( (tps > 20.0 ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0), color);
}
/**