diff options
author | Luck <git@lucko.me> | 2020-11-07 17:41:39 +0000 |
---|---|---|
committer | Luck <git@lucko.me> | 2020-11-07 17:41:39 +0000 |
commit | 8cc92ff83634dffacfe1f25a135bc9ac665ff68b (patch) | |
tree | 35efc9d9131c7ceb1db3822fbb6a0707535f7c18 /spark-common | |
parent | 70a468e114316a98f6d7f7e91afa8d50639762c9 (diff) | |
download | spark-8cc92ff83634dffacfe1f25a135bc9ac665ff68b.tar.gz spark-8cc92ff83634dffacfe1f25a135bc9ac665ff68b.tar.bz2 spark-8cc92ff83634dffacfe1f25a135bc9ac665ff68b.zip |
Update from text to adventure
Diffstat (limited to 'spark-common')
15 files changed, 1183 insertions, 396 deletions
diff --git a/spark-common/build.gradle b/spark-common/build.gradle index 3942bfd..8e526e6 100644 --- a/spark-common/build.gradle +++ b/spark-common/build.gradle @@ -8,18 +8,15 @@ dependencies { compile 'com.squareup.okhttp3:okhttp:3.14.1' compile 'com.squareup.okio:okio:1.17.3' compile 'org.tukaani:xz:1.8' - compile('net.kyori:text-api:3.0.4') { + compile('net.kyori:adventure-api:4.1.1') { exclude(module: 'checker-qual') } - compile('net.kyori:text-serializer-gson:3.0.4') { - exclude(module: 'text-api') + compile('net.kyori:adventure-text-serializer-gson:4.1.1') { + exclude(module: 'adventure-api') exclude(module: 'gson') } - compile('net.kyori:text-serializer-legacy:3.0.4') { - exclude(module: 'text-api') - } - compile('net.kyori:text-feature-pagination:3.0.4') { - exclude(module: 'text-api') + compile('net.kyori:adventure-text-serializer-legacy:4.1.1') { + exclude(module: 'adventure-api') } compileOnly 'com.google.code.gson:gson:2.7' compileOnly 'com.google.guava:guava:19.0' 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 da4f4d8..f03bab2 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 @@ -42,10 +42,7 @@ import me.lucko.spark.common.monitor.tick.TickStatistics; import me.lucko.spark.common.sampler.tick.TickHook; import me.lucko.spark.common.sampler.tick.TickReporter; import me.lucko.spark.common.util.BytebinClient; -import net.kyori.text.TextComponent; -import net.kyori.text.event.ClickEvent; -import net.kyori.text.format.TextColor; -import net.kyori.text.format.TextDecoration; +import net.kyori.adventure.text.event.ClickEvent; import okhttp3.OkHttpClient; import java.util.ArrayList; @@ -55,6 +52,10 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import static net.kyori.adventure.text.Component.*; +import static net.kyori.adventure.text.format.NamedTextColor.*; +import static net.kyori.adventure.text.format.TextDecoration.*; + /** * Abstract spark implementation used by all platforms. */ @@ -166,26 +167,28 @@ public class SparkPlatform { CommandResponseHandler resp = new CommandResponseHandler(this, sender); if (!sender.hasPermission("spark")) { - resp.replyPrefixed(TextComponent.of("You do not have permission to use this command.", TextColor.RED)); + resp.replyPrefixed(text("You do not have permission to use this command.", RED)); return; } if (args.length == 0) { - resp.replyPrefixed(TextComponent.builder("") - .append(TextComponent.of("spark", TextColor.WHITE)) - .append(TextComponent.space()) - .append(TextComponent.of("v" + getPlugin().getVersion(), TextColor.GRAY)) + resp.replyPrefixed(text() + .append(text("spark", WHITE)) + .append(space()) + .append(text("v" + getPlugin().getVersion(), GRAY)) .build() ); - resp.replyPrefixed(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of("Use ")) - .append(TextComponent.builder("/" + getPlugin().getCommandName() + " help") - .color(TextColor.WHITE) - .decoration(TextDecoration.UNDERLINED, true) + resp.replyPrefixed(text() + .color(GRAY) + .append(text("Use ")) + .append(text() + .content("/" + getPlugin().getCommandName() + " help") + .color(WHITE) + .decoration(UNDERLINED, true) .clickEvent(ClickEvent.runCommand("/" + getPlugin().getCommandName() + " help")) .build() ) - .append(TextComponent.of(" to view usage information.")) + .append(text(" to view usage information.")) .build() ); return; @@ -199,7 +202,7 @@ public class SparkPlatform { try { command.executor().execute(this, sender, resp, new Arguments(rawArgs)); } catch (IllegalArgumentException e) { - resp.replyPrefixed(TextComponent.of(e.getMessage(), TextColor.RED)); + resp.replyPrefixed(text(e.getMessage(), RED)); } return; } @@ -233,36 +236,38 @@ public class SparkPlatform { } private void sendUsage(CommandResponseHandler sender) { - sender.replyPrefixed(TextComponent.builder("") - .append(TextComponent.of("spark", TextColor.WHITE)) - .append(TextComponent.space()) - .append(TextComponent.of("v" + getPlugin().getVersion(), TextColor.GRAY)) + sender.replyPrefixed(text() + .append(text("spark", WHITE)) + .append(space()) + .append(text("v" + getPlugin().getVersion(), GRAY)) .build() ); for (Command command : this.commands) { String usage = "/" + getPlugin().getCommandName() + " " + command.aliases().get(0); ClickEvent clickEvent = ClickEvent.suggestCommand(usage); - sender.reply(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.GOLD).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.builder(usage).color(TextColor.GRAY).clickEvent(clickEvent).build()) + sender.reply(text() + .append(text(">", GOLD, BOLD)) + .append(space()) + .append(text().content(usage).color(GRAY).clickEvent(clickEvent).build()) .build() ); for (Command.ArgumentInfo arg : command.arguments()) { if (arg.requiresParameter()) { - sender.reply(TextComponent.builder(" ") - .append(TextComponent.of("[", TextColor.DARK_GRAY)) - .append(TextComponent.of("--" + arg.argumentName(), TextColor.GRAY)) - .append(TextComponent.space()) - .append(TextComponent.of("<" + arg.parameterDescription() + ">", TextColor.DARK_GRAY)) - .append(TextComponent.of("]", TextColor.DARK_GRAY)) + sender.reply(text() + .content(" ") + .append(text("[", DARK_GRAY)) + .append(text("--" + arg.argumentName(), GRAY)) + .append(space()) + .append(text("<" + arg.parameterDescription() + ">", DARK_GRAY)) + .append(text("]", DARK_GRAY)) .build() ); } else { - sender.reply(TextComponent.builder(" ") - .append(TextComponent.of("[", TextColor.DARK_GRAY)) - .append(TextComponent.of("--" + arg.argumentName(), TextColor.GRAY)) - .append(TextComponent.of("]", TextColor.DARK_GRAY)) + sender.reply(text() + .content(" ") + .append(text("[", DARK_GRAY)) + .append(text("--" + arg.argumentName(), GRAY)) + .append(text("]", DARK_GRAY)) .build() ); } 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 635e785..472ae4c 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 @@ -22,23 +22,26 @@ package me.lucko.spark.common.command; import me.lucko.spark.common.SparkPlatform; import me.lucko.spark.common.command.sender.CommandSender; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; -import net.kyori.text.format.TextDecoration; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; +import static net.kyori.adventure.text.Component.*; +import static net.kyori.adventure.text.format.NamedTextColor.*; +import static net.kyori.adventure.text.format.TextDecoration.*; + public class CommandResponseHandler { /** 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(" ")) + private static final TextComponent PREFIX = text() + .color(GRAY) + .append(text("[", DARK_GRAY)) + .append(text("⚡", YELLOW, BOLD)) + .append(text("]", DARK_GRAY)) + .append(text(" ")) .build(); private final SparkPlatform platform; diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java index c78e567..9b611fb 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/ActivityLogModule.java @@ -24,14 +24,12 @@ import me.lucko.spark.common.activitylog.ActivityLog.Activity; import me.lucko.spark.common.command.Command; import me.lucko.spark.common.command.CommandModule; import me.lucko.spark.common.command.tabcomplete.TabCompleter; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.event.ClickEvent; -import net.kyori.text.feature.pagination.Pagination; -import net.kyori.text.feature.pagination.Pagination.Renderer; -import net.kyori.text.feature.pagination.Pagination.Renderer.RowRenderer; -import net.kyori.text.format.TextColor; -import net.kyori.text.format.TextDecoration; +import me.lucko.spark.common.util.pagination.Pagination; +import me.lucko.spark.common.util.pagination.Pagination.Renderer; +import me.lucko.spark.common.util.pagination.Pagination.Renderer.RowRenderer; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.ClickEvent; import java.util.ArrayList; import java.util.Collection; @@ -39,6 +37,9 @@ import java.util.List; import java.util.function.Consumer; import static me.lucko.spark.common.command.CommandResponseHandler.*; +import static net.kyori.adventure.text.Component.*; +import static net.kyori.adventure.text.format.NamedTextColor.*; +import static net.kyori.adventure.text.format.TextDecoration.*; public class ActivityLogModule implements CommandModule, RowRenderer<Activity> { @@ -46,12 +47,12 @@ public class ActivityLogModule implements CommandModule, RowRenderer<Activity> { .renderer(new Renderer() { @Override public Component renderEmpty() { - return applyPrefix(TextComponent.of("There are no entries present in the log.")); + return applyPrefix(text("There are no entries present in the log.")); } @Override public Component renderUnknownPage(int page, int pages) { - return applyPrefix(TextComponent.of("Unknown page selected. " + pages + " total pages.")); + return applyPrefix(text("Unknown page selected. " + pages + " total pages.")); } }) .resultsPerPage(4); @@ -59,33 +60,35 @@ public class ActivityLogModule implements CommandModule, RowRenderer<Activity> { @Override public Collection<Component> renderRow(Activity activity, int index) { List<Component> reply = new ArrayList<>(5); - reply.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of("#" + (index + 1), TextColor.WHITE)) - .append(TextComponent.of(" - ", TextColor.DARK_GRAY)) - .append(TextComponent.of(activity.getType(), TextColor.YELLOW)) - .append(TextComponent.of(" - ", TextColor.DARK_GRAY)) - .append(TextComponent.of(formatDateDiff(activity.getTime()), TextColor.GRAY)) + reply.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text("#" + (index + 1), WHITE)) + .append(text(" - ", DARK_GRAY)) + .append(text(activity.getType(), YELLOW)) + .append(text(" - ", DARK_GRAY)) + .append(text(formatDateDiff(activity.getTime()), GRAY)) .build() ); - reply.add(TextComponent.builder(" ") - .append(TextComponent.of("Created by: ", TextColor.GRAY)) - .append(TextComponent.of(activity.getUser().getName(), TextColor.WHITE)) + reply.add(text() + .content(" ") + .append(text("Created by: ", GRAY)) + .append(text(activity.getUser().getName(), WHITE)) .build() ); - TextComponent.Builder valueComponent = TextComponent.builder(activity.getDataValue(), TextColor.WHITE); + TextComponent.Builder valueComponent = text().content(activity.getDataValue()).color(WHITE); if (activity.getDataType().equals("url")) { valueComponent.clickEvent(ClickEvent.openUrl(activity.getDataValue())); } - reply.add(TextComponent.builder(" ") - .append(TextComponent.of(Character.toUpperCase(activity.getDataType().charAt(0)) + activity.getDataType().substring(1) + ": ", TextColor.GRAY)) + reply.add(text() + .content(" ") + .append(text(Character.toUpperCase(activity.getDataType().charAt(0)) + activity.getDataType().substring(1) + ": ", GRAY)) .append(valueComponent) .build() ); - reply.add(TextComponent.space()); + reply.add(space()); return reply; } @@ -99,14 +102,14 @@ public class ActivityLogModule implements CommandModule, RowRenderer<Activity> { log.removeIf(Activity::shouldExpire); if (log.isEmpty()) { - resp.replyPrefixed(TextComponent.of("There are no entries present in the log.")); + resp.replyPrefixed(text("There are no entries present in the log.")); return; } int page = Math.max(1, arguments.intFlag("page")); Pagination<Activity> activityPagination = this.pagination.build( - TextComponent.of("Recent spark activity", TextColor.GOLD), + text("Recent spark activity", GOLD), this, value -> "/" + platform.getPlugin().getCommandName() + " activity --page " + value ); diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/GcMonitoringModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/GcMonitoringModule.java index ea1cc00..d66a181 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/GcMonitoringModule.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/GcMonitoringModule.java @@ -28,10 +28,7 @@ import me.lucko.spark.common.command.CommandResponseHandler; import me.lucko.spark.common.monitor.memory.GarbageCollectionMonitor; import me.lucko.spark.common.monitor.memory.GarbageCollectorStatistics; import me.lucko.spark.common.util.FormatUtil; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; -import net.kyori.text.format.TextDecoration; +import net.kyori.adventure.text.Component; import java.lang.management.MemoryUsage; import java.text.DecimalFormat; @@ -40,6 +37,10 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; +import static net.kyori.adventure.text.Component.*; +import static net.kyori.adventure.text.format.NamedTextColor.*; +import static net.kyori.adventure.text.format.TextDecoration.*; + public class GcMonitoringModule implements CommandModule { private static final DecimalFormat df = new DecimalFormat("#.##"); @@ -59,14 +60,14 @@ public class GcMonitoringModule implements CommandModule { consumer.accept(Command.builder() .aliases("gc") .executor((platform, sender, resp, arguments) -> { - resp.replyPrefixed(TextComponent.of("Calculating GC statistics...")); + resp.replyPrefixed(text("Calculating GC statistics...")); List<Component> report = new LinkedList<>(); - report.add(TextComponent.empty()); - report.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of("Garbage Collector statistics", TextColor.GOLD)) + report.add(empty()); + report.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text("Garbage Collector statistics", GOLD)) .build() ); @@ -78,16 +79,18 @@ public class GcMonitoringModule implements CommandModule { double collectionTime = collector.getValue().getCollectionTime(); long collectionCount = collector.getValue().getCollectionCount(); - report.add(TextComponent.empty()); + report.add(empty()); if (collectionCount == 0) { - report.add(TextComponent.builder(" ") - .append(TextComponent.of(collectorName + " collector:", TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(collectorName + " collector:", GRAY)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(0, TextColor.WHITE)) - .append(TextComponent.of(" collections", TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(0, WHITE)) + .append(text(" collections", GRAY)) .build() ); continue; @@ -96,27 +99,30 @@ public class GcMonitoringModule implements CommandModule { double averageCollectionTime = collectionTime / collectionCount; double averageFrequency = (serverUptime - collectionTime) / collectionCount; - report.add(TextComponent.builder(" ") - .append(TextComponent.of(collectorName + " collector:", TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(collectorName + " collector:", GRAY)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(df.format(averageCollectionTime), TextColor.GOLD)) - .append(TextComponent.of(" ms avg", TextColor.GRAY)) - .append(TextComponent.of(", ", TextColor.DARK_GRAY)) - .append(TextComponent.of(collectionCount, TextColor.WHITE)) - .append(TextComponent.of(" total collections", TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(df.format(averageCollectionTime), GOLD)) + .append(text(" ms avg", GRAY)) + .append(text(", ", DARK_GRAY)) + .append(text(collectionCount, WHITE)) + .append(text(" total collections", GRAY)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(formatTime((long) averageFrequency), TextColor.WHITE)) - .append(TextComponent.of(" avg frequency", TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(formatTime((long) averageFrequency), WHITE)) + .append(text(" avg frequency", GRAY)) .build() ); } if (report.size() == 1) { - resp.replyPrefixed(TextComponent.of("No garbage collectors are reporting data.")); + resp.replyPrefixed(text("No garbage collectors are reporting data.")); } else { report.forEach(resp::reply); } @@ -129,10 +135,10 @@ public class GcMonitoringModule implements CommandModule { .executor((platform, sender, resp, arguments) -> { if (this.activeGcMonitor == null) { this.activeGcMonitor = new ReportingGcMonitor(platform, resp); - resp.broadcastPrefixed(TextComponent.of("GC monitor enabled.")); + resp.broadcastPrefixed(text("GC monitor enabled.")); } else { close(); - resp.broadcastPrefixed(TextComponent.of("GC monitor disabled.")); + resp.broadcastPrefixed(text("GC monitor disabled.")); } }) .build() @@ -195,13 +201,15 @@ public class GcMonitoringModule implements CommandModule { this.platform.getPlugin().executeAsync(() -> { List<Component> report = new LinkedList<>(); - report.add(CommandResponseHandler.applyPrefix(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of(gcType + " ")) - .append(TextComponent.of("GC", TextColor.RED)) - .append(TextComponent.of(" lasting ")) - .append(TextComponent.of(df.format(data.getGcInfo().getDuration()), TextColor.GOLD)) - .append(TextComponent.of(" ms." + gcCause)) - .build() + report.add(CommandResponseHandler.applyPrefix( + text() + .color(GRAY) + .append(text(gcType + " ")) + .append(text("GC", RED)) + .append(text(" lasting ")) + .append(text(df.format(data.getGcInfo().getDuration()), GOLD)) + .append(text(" ms." + gcCause)) + .build() )); for (Map.Entry<String, MemoryUsage> entry : afterUsages.entrySet()) { @@ -219,33 +227,37 @@ public class GcMonitoringModule implements CommandModule { } if (diff > 0) { - report.add(TextComponent.builder(" ") - .append(TextComponent.of(FormatUtil.formatBytes(diff), TextColor.GOLD)) - .append(TextComponent.of(" freed from ", TextColor.DARK_GRAY)) - .append(TextComponent.of(type, TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(FormatUtil.formatBytes(diff), GOLD)) + .append(text(" freed from ", DARK_GRAY)) + .append(text(type, GRAY)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(FormatUtil.formatBytes(before.getUsed()), TextColor.GRAY)) - .append(TextComponent.of(" → ", TextColor.DARK_GRAY)) - .append(TextComponent.of(FormatUtil.formatBytes(after.getUsed()), TextColor.GRAY)) - .append(TextComponent.space()) - .append(TextComponent.of("(", TextColor.DARK_GRAY)) - .append(TextComponent.of(FormatUtil.percent(diff, before.getUsed()), TextColor.WHITE)) - .append(TextComponent.of(")", TextColor.DARK_GRAY)) + report.add(text() + .content(" ") + .append(text(FormatUtil.formatBytes(before.getUsed()), GRAY)) + .append(text(" → ", DARK_GRAY)) + .append(text(FormatUtil.formatBytes(after.getUsed()), GRAY)) + .append(space()) + .append(text("(", DARK_GRAY)) + .append(text(FormatUtil.percent(diff, before.getUsed()), WHITE)) + .append(text(")", DARK_GRAY)) .build() ); } else { - report.add(TextComponent.builder(" ") - .append(TextComponent.of(FormatUtil.formatBytes(-diff), TextColor.GOLD)) - .append(TextComponent.of(" moved to ", TextColor.DARK_GRAY)) - .append(TextComponent.of(type, TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(FormatUtil.formatBytes(-diff), GOLD)) + .append(text(" moved to ", DARK_GRAY)) + .append(text(type, GRAY)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(FormatUtil.formatBytes(before.getUsed()), TextColor.GRAY)) - .append(TextComponent.of(" → ", TextColor.DARK_GRAY)) - .append(TextComponent.of(FormatUtil.formatBytes(after.getUsed()), TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(FormatUtil.formatBytes(before.getUsed()), GRAY)) + .append(text(" → ", DARK_GRAY)) + .append(text(FormatUtil.formatBytes(after.getUsed()), GRAY)) .build() ); } 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 64c2fba..9bf3421 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 @@ -28,10 +28,9 @@ import me.lucko.spark.common.monitor.cpu.CpuMonitor; import me.lucko.spark.common.monitor.tick.TickStatistics; import me.lucko.spark.common.util.FormatUtil; import me.lucko.spark.common.util.RollingAverage; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; -import net.kyori.text.format.TextDecoration; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.TextColor; import java.io.IOException; import java.lang.management.ManagementFactory; @@ -46,6 +45,10 @@ import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; +import static net.kyori.adventure.text.Component.*; +import static net.kyori.adventure.text.format.NamedTextColor.*; +import static net.kyori.adventure.text.format.TextDecoration.*; + public class HealthModule implements CommandModule { private static final int MSPT_95_PERCENTILE = 95; @@ -57,41 +60,45 @@ public class HealthModule implements CommandModule { .executor((platform, sender, resp, arguments) -> { TickStatistics tickStatistics = platform.getTickStatistics(); if (tickStatistics != null) { - resp.replyPrefixed(TextComponent.of("TPS from last 5s, 10s, 1m, 5m, 15m:")); - resp.replyPrefixed(TextComponent.builder(" ") - .append(formatTps(tickStatistics.tps5Sec())).append(TextComponent.of(", ")) - .append(formatTps(tickStatistics.tps10Sec())).append(TextComponent.of(", ")) - .append(formatTps(tickStatistics.tps1Min())).append(TextComponent.of(", ")) - .append(formatTps(tickStatistics.tps5Min())).append(TextComponent.of(", ")) + resp.replyPrefixed(text("TPS from last 5s, 10s, 1m, 5m, 15m:")); + resp.replyPrefixed(text() + .content(" ") + .append(formatTps(tickStatistics.tps5Sec())).append(text(", ")) + .append(formatTps(tickStatistics.tps10Sec())).append(text(", ")) + .append(formatTps(tickStatistics.tps1Min())).append(text(", ")) + .append(formatTps(tickStatistics.tps5Min())).append(text(", ")) .append(formatTps(tickStatistics.tps15Min())) .build() ); - resp.replyPrefixed(TextComponent.empty()); + resp.replyPrefixed(empty()); if (tickStatistics.isDurationSupported()) { - resp.replyPrefixed(TextComponent.of("Tick durations (min/med/95%ile/max ms) from last 10s, 1m:")); - resp.replyPrefixed(TextComponent.builder(" ") - .append(formatTickDurations(tickStatistics.duration10Sec())).append(TextComponent.of("; ")) + resp.replyPrefixed(text("Tick durations (min/med/95%ile/max ms) from last 10s, 1m:")); + resp.replyPrefixed(text() + .content(" ") + .append(formatTickDurations(tickStatistics.duration10Sec())).append(text("; ")) .append(formatTickDurations(tickStatistics.duration1Min())) .build() ); - resp.replyPrefixed(TextComponent.empty()); + resp.replyPrefixed(empty()); } } - resp.replyPrefixed(TextComponent.of("CPU usage from last 10s, 1m, 15m:")); - resp.replyPrefixed(TextComponent.builder(" ") - .append(formatCpuUsage(CpuMonitor.systemLoad10SecAvg())).append(TextComponent.of(", ")) - .append(formatCpuUsage(CpuMonitor.systemLoad1MinAvg())).append(TextComponent.of(", ")) + resp.replyPrefixed(text("CPU usage from last 10s, 1m, 15m:")); + resp.replyPrefixed(text() + .content(" ") + .append(formatCpuUsage(CpuMonitor.systemLoad10SecAvg())).append(text(", ")) + .append(formatCpuUsage(CpuMonitor.systemLoad1MinAvg())).append(text(", ")) .append(formatCpuUsage(CpuMonitor.systemLoad15MinAvg())) - .append(TextComponent.of(" (system)", TextColor.DARK_GRAY)) + .append(text(" (system)", DARK_GRAY)) .build() ); - resp.replyPrefixed(TextComponent.builder(" ") - .append(formatCpuUsage(CpuMonitor.processLoad10SecAvg())).append(TextComponent.of(", ")) - .append(formatCpuUsage(CpuMonitor.processLoad1MinAvg())).append(TextComponent.of(", ")) + resp.replyPrefixed(text() + .content(" ") + .append(formatCpuUsage(CpuMonitor.processLoad10SecAvg())).append(text(", ")) + .append(formatCpuUsage(CpuMonitor.processLoad1MinAvg())).append(text(", ")) .append(formatCpuUsage(CpuMonitor.processLoad15MinAvg())) - .append(TextComponent.of(" (process)", TextColor.DARK_GRAY)) + .append(text(" (process)", DARK_GRAY)) .build() ); }) @@ -103,103 +110,109 @@ public class HealthModule implements CommandModule { .aliases("healthreport", "health", "ht") .argumentUsage("memory", null) .executor((platform, sender, resp, arguments) -> { - resp.replyPrefixed(TextComponent.of("Generating server health report...")); + resp.replyPrefixed(text("Generating server health report...")); platform.getPlugin().executeAsync(() -> { List<Component> report = new LinkedList<>(); - report.add(TextComponent.empty()); + report.add(empty()); TickStatistics tickStatistics = platform.getTickStatistics(); if (tickStatistics != null) { - report.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of("TPS from last 5s, 10s, 1m, 5m, 15m:", TextColor.GOLD)) + report.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text("TPS from last 5s, 10s, 1m, 5m, 15m:", GOLD)) .build() ); - report.add(TextComponent.builder(" ") - .append(formatTps(tickStatistics.tps5Sec())).append(TextComponent.of(", ")) - .append(formatTps(tickStatistics.tps10Sec())).append(TextComponent.of(", ")) - .append(formatTps(tickStatistics.tps1Min())).append(TextComponent.of(", ")) - .append(formatTps(tickStatistics.tps5Min())).append(TextComponent.of(", ")) + report.add(text() + .content(" ") + .append(formatTps(tickStatistics.tps5Sec())).append(text(", ")) + .append(formatTps(tickStatistics.tps10Sec())).append(text(", ")) + .append(formatTps(tickStatistics.tps1Min())).append(text(", ")) + .append(formatTps(tickStatistics.tps5Min())).append(text(", ")) .append(formatTps(tickStatistics.tps15Min())) .build() ); - report.add(TextComponent.empty()); + report.add(empty()); if (tickStatistics.isDurationSupported()) { - report.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of("Tick durations (min/med/95%ile/max ms) from last 10s, 1m:", TextColor.GOLD)) + report.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text("Tick durations (min/med/95%ile/max ms) from last 10s, 1m:", GOLD)) .build() ); - report.add(TextComponent.builder(" ") - .append(formatTickDurations(tickStatistics.duration10Sec())).append(TextComponent.of("; ")) + report.add(text() + .content(" ") + .append(formatTickDurations(tickStatistics.duration10Sec())).append(text("; ")) .append(formatTickDurations(tickStatistics.duration1Min())) .build() ); - report.add(TextComponent.empty()); + report.add(empty()); } } - report.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of("CPU usage from last 10s, 1m, 15m:", TextColor.GOLD)) + report.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text("CPU usage from last 10s, 1m, 15m:", GOLD)) .build() ); - report.add(TextComponent.builder(" ") - .append(formatCpuUsage(CpuMonitor.systemLoad10SecAvg())).append(TextComponent.of(", ")) - .append(formatCpuUsage(CpuMonitor.systemLoad1MinAvg())).append(TextComponent.of(", ")) + report.add(text() + .content(" ") + .append(formatCpuUsage(CpuMonitor.systemLoad10SecAvg())).append(text(", ")) + .append(formatCpuUsage(CpuMonitor.systemLoad1MinAvg())).append(text(", ")) .append(formatCpuUsage(CpuMonitor.systemLoad15MinAvg())) - .append(TextComponent.of(" (system)", TextColor.DARK_GRAY)) + .append(text(" (system)", DARK_GRAY)) .build() ); - report.add(TextComponent.builder(" ") - .append(formatCpuUsage(CpuMonitor.processLoad10SecAvg())).append(TextComponent.of(", ")) - .append(formatCpuUsage(CpuMonitor.processLoad1MinAvg())).append(TextComponent.of(", ")) + report.add(text() + .content(" ") + .append(formatCpuUsage(CpuMonitor.processLoad10SecAvg())).append(text(", ")) + .append(formatCpuUsage(CpuMonitor.processLoad1MinAvg())).append(text(", ")) .append(formatCpuUsage(CpuMonitor.processLoad15MinAvg())) - .append(TextComponent.of(" (process)", TextColor.DARK_GRAY)) + .append(text(" (process)", DARK_GRAY)) .build() ); - report.add(TextComponent.empty()); + report.add(empty()); MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage(); - report.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of("Memory usage:", TextColor.GOLD)) + report.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text("Memory usage:", GOLD)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(FormatUtil.formatBytes(heapUsage.getUsed()), TextColor.WHITE)) - .append(TextComponent.space()) - .append(TextComponent.of("/", TextColor.GRAY)) - .append(TextComponent.space()) - .append(TextComponent.of(FormatUtil.formatBytes(heapUsage.getMax()), TextColor.WHITE)) - .append(TextComponent.of(" ")) - .append(TextComponent.of("(", TextColor.GRAY)) - .append(TextComponent.of(FormatUtil.percent(heapUsage.getUsed(), heapUsage.getMax()), TextColor.GREEN)) - .append(TextComponent.of(")", TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(FormatUtil.formatBytes(heapUsage.getUsed()), WHITE)) + .append(space()) + .append(text("/", GRAY)) + .append(space()) + .append(text(FormatUtil.formatBytes(heapUsage.getMax()), WHITE)) + .append(text(" ")) + .append(text("(", GRAY)) + .append(text(FormatUtil.percent(heapUsage.getUsed(), heapUsage.getMax()), GREEN)) + .append(text(")", GRAY)) .build() ); - report.add(TextComponent.builder(" ").append(generateMemoryUsageDiagram(heapUsage, 40)).build()); - report.add(TextComponent.empty()); + report.add(text().content(" ").append(generateMemoryUsageDiagram(heapUsage, 40)).build()); + report.add(empty()); if (arguments.boolFlag("memory")) { MemoryUsage nonHeapUsage = memoryMXBean.getNonHeapMemoryUsage(); - report.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of("Non-heap memory usage:", TextColor.GOLD)) + report.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text("Non-heap memory usage:", GOLD)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(FormatUtil.formatBytes(nonHeapUsage.getUsed()), TextColor.WHITE)) + report.add(text() + .content(" ") + .append(text(FormatUtil.formatBytes(nonHeapUsage.getUsed()), WHITE)) .build() ); - report.add(TextComponent.empty()); + report.add(empty()); List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans(); for (MemoryPoolMXBean memoryPool : memoryPoolMXBeans) { @@ -214,37 +227,39 @@ public class HealthModule implements CommandModule { usage = new MemoryUsage(usage.getInit(), usage.getUsed(), usage.getCommitted(), usage.getCommitted()); } - report.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of(memoryPool.getName() + " pool usage:", TextColor.GOLD)) + report.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text(memoryPool.getName() + " pool usage:", GOLD)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(FormatUtil.formatBytes(usage.getUsed()), TextColor.WHITE)) - .append(TextComponent.space()) - .append(TextComponent.of("/", TextColor.GRAY)) - .append(TextComponent.space()) - .append(TextComponent.of(FormatUtil.formatBytes(usage.getMax()), TextColor.WHITE)) - .append(TextComponent.of(" ")) - .append(TextComponent.of("(", TextColor.GRAY)) - .append(TextComponent.of(FormatUtil.percent(usage.getUsed(), usage.getMax()), TextColor.GREEN)) - .append(TextComponent.of(")", TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(FormatUtil.formatBytes(usage.getUsed()), WHITE)) + .append(space()) + .append(text("/", GRAY)) + .append(space()) + .append(text(FormatUtil.formatBytes(usage.getMax()), WHITE)) + .append(text(" ")) + .append(text("(", GRAY)) + .append(text(FormatUtil.percent(usage.getUsed(), usage.getMax()), GREEN)) + .append(text(")", GRAY)) .build() ); - report.add(TextComponent.builder(" ").append(generateMemoryPoolDiagram(usage, collectionUsage, 40)).build()); + report.add(text().content(" ").append(generateMemoryPoolDiagram(usage, collectionUsage, 40)).build()); if (collectionUsage != null) { - report.add(TextComponent.builder(" ") - .append(TextComponent.of("-", TextColor.RED)) - .append(TextComponent.space()) - .append(TextComponent.of("Usage at last GC:", TextColor.GRAY)) - .append(TextComponent.space()) - .append(TextComponent.of(FormatUtil.formatBytes(collectionUsage.getUsed()), TextColor.WHITE)) + report.add(text() + .content(" ") + .append(text("-", RED)) + .append(space()) + .append(text("Usage at last GC:", GRAY)) + .append(space()) + .append(text(FormatUtil.formatBytes(collectionUsage.getUsed()), WHITE)) .build() ); } - report.add(TextComponent.empty()); + report.add(empty()); } } @@ -252,26 +267,27 @@ public class HealthModule implements CommandModule { FileStore fileStore = Files.getFileStore(Paths.get(".")); long totalSpace = fileStore.getTotalSpace(); long usedSpace = totalSpace - fileStore.getUsableSpace(); - report.add(TextComponent.builder("") - .append(TextComponent.builder(">").color(TextColor.DARK_GRAY).decoration(TextDecoration.BOLD, true).build()) - .append(TextComponent.space()) - .append(TextComponent.of("Disk usage:", TextColor.GOLD)) + report.add(text() + .append(text(">", DARK_GRAY, BOLD)) + .append(space()) + .append(text("Disk usage:", GOLD)) .build() ); - report.add(TextComponent.builder(" ") - .append(TextComponent.of(FormatUtil.formatBytes(usedSpace), TextColor.WHITE)) - .append(TextComponent.space()) - .append(TextComponent.of("/", TextColor.GRAY)) - .append(TextComponent.space()) - .append(TextComponent.of(FormatUtil.formatBytes(totalSpace), TextColor.WHITE)) - .append(TextComponent.of(" ")) - .append(TextComponent.of("(", TextColor.GRAY)) - .append(TextComponent.of(FormatUtil.percent(usedSpace, totalSpace), TextColor.GREEN)) - .append(TextComponent.of(")", TextColor.GRAY)) + report.add(text() + .content(" ") + .append(text(FormatUtil.formatBytes(usedSpace), WHITE)) + .append(space()) + .append(text("/", GRAY)) + .append(space()) + .append(text(FormatUtil.formatBytes(totalSpace), WHITE)) + .append(text(" ")) + .append(text("(", GRAY)) + .append(text(FormatUtil.percent(usedSpace, totalSpace), GREEN)) + .append(text(")", GRAY)) .build() ); - report.add(TextComponent.builder(" ").append(generateDiskUsageDiagram(usedSpace, totalSpace, 40)).build()); - report.add(TextComponent.empty()); + report.add(text().content(" ").append(generateDiskUsageDiagram(usedSpace, totalSpace, 40)).build()); + report.add(empty()); } catch (IOException e) { e.printStackTrace(); } @@ -287,24 +303,24 @@ public class HealthModule implements CommandModule { public static TextComponent formatTps(double tps) { TextColor color; if (tps > 18.0) { - color = TextColor.GREEN; + color = GREEN; } else if (tps > 16.0) { - color = TextColor.YELLOW; + color = YELLOW; } else { - color = TextColor.RED; + color = RED; } - return TextComponent.of( (tps > 20.0 ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0), color); + return text((tps > 20.0 ? "*" : "") + Math.min(Math.round(tps * 100.0) / 100.0, 20.0), color); } public static TextComponent formatTickDurations(RollingAverage average){ - return TextComponent.builder("") + return text() .append(formatTickDuration(average.getMin())) - .append(TextComponent.of('/', TextColor.GRAY)) + .append(text('/', GRAY)) .append(formatTickDuration(average.getMedian())) - .append(TextComponent.of('/', TextColor.GRAY)) + .append(text('/', GRAY)) .append(formatTickDuration(average.getPercentile(MSPT_95_PERCENTILE))) - .append(TextComponent.of('/', TextColor.GRAY)) + .append(text('/', GRAY)) .append(formatTickDuration(average.getMax())) .build(); } @@ -312,27 +328,27 @@ public class HealthModule implements CommandModule { public static TextComponent formatTickDuration(double duration){ TextColor color; if (duration >= 50d) { - color = TextColor.RED; + color = RED; } else if (duration >= 40d) { - color = TextColor.YELLOW; + color = YELLOW; } else { - color = TextColor.GREEN; + color = GREEN; } - return TextComponent.of(String.format("%.1f", duration), color); + return text(String.format("%.1f", duration), color); } public static TextComponent formatCpuUsage(double usage) { TextColor color; if (usage > 0.9) { - color = TextColor.RED; + color = RED; } else if (usage > 0.65) { - color = TextColor.YELLOW; + color = YELLOW; } else { - color = TextColor.GREEN; + color = GREEN; } - return TextComponent.of(FormatUtil.percent(usage, 1d), color); + return text(FormatUtil.percent(usage, 1d), color); } private static TextComponent generateMemoryUsageDiagram(MemoryUsage usage, int length) { @@ -343,19 +359,19 @@ public class HealthModule implements CommandModule { int usedChars = (int) ((used * length) / max); int committedChars = (int) ((committed * length) / max); - TextComponent.Builder line = TextComponent.builder(Strings.repeat("/", usedChars)).color(TextColor.GRAY); + TextComponent.Builder line = text().content(Strings.repeat("/", usedChars)).color(GRAY); if (committedChars > usedChars) { - line.append(TextComponent.of(Strings.repeat(" ", (committedChars - usedChars) - 1))); - line.append(TextComponent.of("|", TextColor.YELLOW)); + line.append(text(Strings.repeat(" ", (committedChars - usedChars) - 1))); + line.append(text("|", YELLOW)); } if (length > committedChars) { - line.append(TextComponent.of(Strings.repeat(" ", (length - committedChars)))); + line.append(text(Strings.repeat(" ", (length - committedChars)))); } - return TextComponent.builder("") - .append(TextComponent.of("[", TextColor.DARK_GRAY)) + return text() + .append(text("[", DARK_GRAY)) .append(line.build()) - .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .append(text("]", DARK_GRAY)) .build(); } @@ -372,34 +388,34 @@ public class HealthModule implements CommandModule { int collectionUsedChars = (int) ((collectionUsed * length) / max); int committedChars = (int) ((committed * length) / max); - TextComponent.Builder line = TextComponent.builder(Strings.repeat("/", collectionUsedChars)).color(TextColor.GRAY); + TextComponent.Builder line = text().content(Strings.repeat("/", collectionUsedChars)).color(GRAY); if (usedChars > collectionUsedChars) { - line.append(TextComponent.of("|", TextColor.RED)); - line.append(TextComponent.of(Strings.repeat("/", (usedChars - collectionUsedChars) - 1), TextColor.GRAY)); + line.append(text("|", RED)); + line.append(text(Strings.repeat("/", (usedChars - collectionUsedChars) - 1), GRAY)); } if (committedChars > usedChars) { - line.append(TextComponent.of(Strings.repeat(" ", (committedChars - usedChars) - 1))); - line.append(TextComponent.of("|", TextColor.YELLOW)); + line.append(text(Strings.repeat(" ", (committedChars - usedChars) - 1))); + line.append(text("|", YELLOW)); } if (length > committedChars) { - line.append(TextComponent.of(Strings.repeat(" ", (length - committedChars)))); + line.append(text(Strings.repeat(" ", (length - committedChars)))); } - return TextComponent.builder("") - .append(TextComponent.of("[", TextColor.DARK_GRAY)) + return text() + .append(text("[", DARK_GRAY)) .append(line.build()) - .append(TextComponent.of("]", TextColor.DARK_GRAY)) + .append(text("]", DARK_GRAY)) .build(); } private static TextComponent generateDiskUsageDiagram(double used, double max, int length) { int usedChars = (int) ((used * length) / max); 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)) + return text() + .append(text("[", DARK_GRAY)) + .append(text(line, GRAY)) + .append(text("]", DARK_GRAY)) .build(); } diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/HeapAnalysisModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/HeapAnalysisModule.java index 0b46afd..edbc9cb 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/HeapAnalysisModule.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/HeapAnalysisModule.java @@ -28,9 +28,7 @@ import me.lucko.spark.common.command.tabcomplete.TabCompleter; import me.lucko.spark.common.heapdump.HeapDump; import me.lucko.spark.common.heapdump.HeapDumpSummary; import me.lucko.spark.common.util.FormatUtil; -import net.kyori.text.TextComponent; -import net.kyori.text.event.ClickEvent; -import net.kyori.text.format.TextColor; +import net.kyori.adventure.text.event.ClickEvent; import okhttp3.MediaType; import org.tukaani.xz.LZMA2Options; import org.tukaani.xz.LZMAOutputStream; @@ -50,6 +48,9 @@ import java.util.function.Consumer; import java.util.function.LongConsumer; import java.util.zip.GZIPOutputStream; +import static net.kyori.adventure.text.Component.*; +import static net.kyori.adventure.text.format.NamedTextColor.*; + public class HeapAnalysisModule implements CommandModule { private static final MediaType SPARK_HEAP_MEDIA_TYPE = MediaType.parse("application/x-spark-heap"); @@ -61,17 +62,17 @@ public class HeapAnalysisModule implements CommandModule { .executor((platform, sender, resp, arguments) -> { platform.getPlugin().executeAsync(() -> { if (arguments.boolFlag("run-gc-before")) { - resp.broadcastPrefixed(TextComponent.of("Running garbage collector...")); + resp.broadcastPrefixed(text("Running garbage collector...")); System.gc(); } - resp.broadcastPrefixed(TextComponent.of("Creating a new heap dump summary, please wait...")); + resp.broadcastPrefixed(text("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)); + resp.broadcastPrefixed(text("An error occurred whilst inspecting the heap.", RED)); e.printStackTrace(); return; } @@ -81,16 +82,17 @@ public class HeapAnalysisModule implements CommandModule { String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, SPARK_HEAP_MEDIA_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) + resp.broadcastPrefixed(text("Heap dump summmary output:", GOLD)); + resp.broadcast(text() + .content(url) + .color(GRAY) .clickEvent(ClickEvent.openUrl(url)) .build() ); platform.getActivityLog().addToLog(Activity.urlActivity(sender, System.currentTimeMillis(), "Heap dump summary", url)); } catch (IOException e) { - resp.broadcastPrefixed(TextComponent.of("An error occurred whilst uploading the data.", TextColor.RED)); + resp.broadcastPrefixed(text("An error occurred whilst uploading the data.", RED)); e.printStackTrace(); } }); @@ -117,22 +119,24 @@ public class HeapAnalysisModule implements CommandModule { boolean liveOnly = !arguments.boolFlag("include-non-live"); if (arguments.boolFlag("run-gc-before")) { - resp.broadcastPrefixed(TextComponent.of("Running garbage collector...")); + resp.broadcastPrefixed(text("Running garbage collector...")); System.gc(); } - resp.broadcastPrefixed(TextComponent.of("Creating a new heap dump, please wait...")); + resp.broadcastPrefixed(text("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)); + resp.broadcastPrefixed(text("An error occurred whilst creating a heap dump.", RED)); e.printStackTrace(); return; } - resp.broadcastPrefixed(TextComponent.builder("Heap dump written to: ", TextColor.GOLD) - .append(TextComponent.of(file.toString(), TextColor.GRAY)) + resp.broadcastPrefixed(text() + .content("Heap dump written to: ") + .color(GOLD) + .append(text(file.toString(), GRAY)) .build() ); platform.getActivityLog().addToLog(Activity.fileActivity(sender, System.currentTimeMillis(), "Heap dump", file.toString())); @@ -149,7 +153,7 @@ public class HeapAnalysisModule implements CommandModule { } if (compress != null) { - resp.broadcastPrefixed(TextComponent.of("Compressing heap dump, please wait...")); + resp.broadcastPrefixed(text("Compressing heap dump, please wait...")); try { long size = Files.size(file); AtomicLong lastReport = new AtomicLong(System.currentTimeMillis()); @@ -160,14 +164,15 @@ public class HeapAnalysisModule implements CommandModule { lastReport.set(System.currentTimeMillis()); platform.getPlugin().executeAsync(() -> { - resp.broadcastPrefixed(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of("Compressed ")) - .append(TextComponent.of(FormatUtil.formatBytes(progress), TextColor.GOLD)) - .append(TextComponent.of(" / ")) - .append(TextComponent.of(FormatUtil.formatBytes(size), TextColor.GOLD)) - .append(TextComponent.of(" so far... (")) - .append(TextComponent.of(FormatUtil.percent(progress, size), TextColor.GREEN)) - .append(TextComponent.of(")")) + resp.broadcastPrefixed(text() + .color(GRAY) + .append(text("Compressed ")) + .append(text(FormatUtil.formatBytes(progress), GOLD)) + .append(text(" / ")) + .append(text(FormatUtil.formatBytes(size), GOLD)) + .append(text(" so far... (")) + .append(text(FormatUtil.percent(progress, size), GREEN)) + .append(text(")")) .build() ); }); @@ -177,19 +182,22 @@ public class HeapAnalysisModule implements CommandModule { Path compressedFile = compress.compress(file, progressHandler); long compressedSize = Files.size(compressedFile); - resp.broadcastPrefixed(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of("Compression complete: ")) - .append(TextComponent.of(FormatUtil.formatBytes(size), TextColor.GOLD)) - .append(TextComponent.of(" --> ")) - .append(TextComponent.of(FormatUtil.formatBytes(compressedSize), TextColor.GOLD)) - .append(TextComponent.of(" (")) - .append(TextComponent.of(FormatUtil.percent(compressedSize, size), TextColor.GREEN)) - .append(TextComponent.of(")")) + resp.broadcastPrefixed(text() + .color(GRAY) + .append(text("Compression complete: ")) + .append(text(FormatUtil.formatBytes(size), GOLD)) + .append(text(" --> ")) + .append(text(FormatUtil.formatBytes(compressedSize), GOLD)) + .append(text(" (")) + .append(text(FormatUtil.percent(compressedSize, size), GREEN)) + .append(text(")")) .build() ); - resp.broadcastPrefixed(TextComponent.builder("Compressed heap dump written to: ", TextColor.GOLD) - .append(TextComponent.of(compressedFile.toString(), TextColor.GRAY)) + resp.broadcastPrefixed(text() + .content("Compressed heap dump written to: ") + .color(GOLD) + .append(text(compressedFile.toString(), GRAY)) .build() ); } catch (IOException e) { 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 7a3755b..d9d8b44 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 @@ -36,9 +36,7 @@ import me.lucko.spark.common.sampler.ThreadNodeOrder; import me.lucko.spark.common.sampler.node.MergeMode; import me.lucko.spark.common.sampler.tick.TickHook; import me.lucko.spark.common.util.MethodDisambiguator; -import net.kyori.text.TextComponent; -import net.kyori.text.event.ClickEvent; -import net.kyori.text.format.TextColor; +import net.kyori.adventure.text.event.ClickEvent; import okhttp3.MediaType; import java.io.IOException; @@ -51,6 +49,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import static net.kyori.adventure.text.Component.*; +import static net.kyori.adventure.text.format.NamedTextColor.*; + public class SamplerModule implements CommandModule { private static final MediaType SPARK_SAMPLER_MEDIA_TYPE = MediaType.parse("application/x-spark-sampler"); @@ -87,38 +88,38 @@ public class SamplerModule implements CommandModule { .executor((platform, sender, resp, arguments) -> { if (arguments.boolFlag("info")) { if (this.activeSampler == null) { - resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running.")); + resp.replyPrefixed(text("There isn't an active sampling task running.")); } else { long timeout = this.activeSampler.getEndTime(); if (timeout == -1) { - resp.replyPrefixed(TextComponent.of("There is an active sampler currently running, with no defined timeout.")); + resp.replyPrefixed(text("There is an active sampler currently running, with no defined timeout.")); } else { long timeoutDiff = (timeout - System.currentTimeMillis()) / 1000L; - resp.replyPrefixed(TextComponent.of("There is an active sampler currently running, due to timeout in " + timeoutDiff + " seconds.")); + resp.replyPrefixed(text("There is an active sampler currently running, due to timeout in " + timeoutDiff + " seconds.")); } long runningTime = (System.currentTimeMillis() - this.activeSampler.getStartTime()) / 1000L; - resp.replyPrefixed(TextComponent.of("It has been sampling for " + runningTime + " seconds so far.")); + resp.replyPrefixed(text("It has been sampling for " + runningTime + " seconds so far.")); } return; } if (arguments.boolFlag("cancel")) { if (this.activeSampler == null) { - resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running.")); + resp.replyPrefixed(text("There isn't an active sampling task running.")); } else { close(); - resp.broadcastPrefixed(TextComponent.of("The active sampling task has been cancelled.", TextColor.GOLD)); + resp.broadcastPrefixed(text("The active sampling task has been cancelled.", GOLD)); } return; } if (arguments.boolFlag("stop") || arguments.boolFlag("upload")) { if (this.activeSampler == null) { - resp.replyPrefixed(TextComponent.of("There isn't an active sampling task running.")); + resp.replyPrefixed(text("There isn't an active sampling task running.")); } else { this.activeSampler.cancel(); - resp.broadcastPrefixed(TextComponent.of("The active sampling operation has been stopped! Uploading results...")); + resp.broadcastPrefixed(text("The active sampling operation has been stopped! Uploading results...")); ThreadNodeOrder threadOrder = arguments.boolFlag("order-by-time") ? ThreadNodeOrder.BY_TIME : ThreadNodeOrder.BY_NAME; String comment = Iterables.getFirst(arguments.stringFlag("comment"), null); MethodDisambiguator methodDisambiguator = new MethodDisambiguator(); @@ -131,13 +132,13 @@ public class SamplerModule implements CommandModule { int timeoutSeconds = arguments.intFlag("timeout"); if (timeoutSeconds != -1 && timeoutSeconds <= 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)); + resp.replyPrefixed(text("The specified timeout is not long enough for accurate results to be formed. " + + "Please choose a value greater than 10.", RED)); return; } if (timeoutSeconds != -1 && timeoutSeconds < 30) { - resp.replyPrefixed(TextComponent.of("The accuracy of the output will significantly improve when sampling is able to run for longer periods. " + + resp.replyPrefixed(text("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.")); } @@ -179,17 +180,17 @@ public class SamplerModule implements CommandModule { if (ticksOver != -1) { tickHook = platform.getTickHook(); if (tickHook == null) { - resp.replyPrefixed(TextComponent.of("Tick counting is not supported!", TextColor.RED)); + resp.replyPrefixed(text("Tick counting is not supported!", RED)); return; } } if (this.activeSampler != null) { - resp.replyPrefixed(TextComponent.of("An active sampler is already running.")); + resp.replyPrefixed(text("An active sampler is already running.")); return; } - resp.broadcastPrefixed(TextComponent.of("Initializing a new profiler, please wait...")); + resp.broadcastPrefixed(text("Initializing a new profiler, please wait...")); SamplerBuilder builder = new SamplerBuilder(); builder.threadDumper(threadDumper); @@ -205,11 +206,11 @@ public class SamplerModule implements CommandModule { } Sampler sampler = this.activeSampler = builder.start(); - resp.broadcastPrefixed(TextComponent.of("Profiler now active!", TextColor.GOLD)); + resp.broadcastPrefixed(text("Profiler now active!", GOLD)); if (timeoutSeconds == -1) { - resp.broadcastPrefixed(TextComponent.of("Use '/" + platform.getPlugin().getCommandName() + " sampler --stop' to stop profiling and upload the results.")); + resp.broadcastPrefixed(text("Use '/" + platform.getPlugin().getCommandName() + " sampler --stop' to stop profiling and upload the results.")); } else { - resp.broadcastPrefixed(TextComponent.of("The results will be automatically returned after the profiler has been running for " + timeoutSeconds + " seconds.")); + resp.broadcastPrefixed(text("The results will be automatically returned after the profiler has been running for " + timeoutSeconds + " seconds.")); } CompletableFuture<Sampler> future = this.activeSampler.getFuture(); @@ -217,7 +218,7 @@ public class SamplerModule implements CommandModule { // send message if profiling fails future.whenCompleteAsync((s, throwable) -> { if (throwable != null) { - resp.broadcastPrefixed(TextComponent.of("Sampling operation failed unexpectedly. Error: " + throwable.toString(), TextColor.RED)); + resp.broadcastPrefixed(text("Sampling operation failed unexpectedly. Error: " + throwable.toString(), RED)); throwable.printStackTrace(); } }); @@ -236,7 +237,7 @@ public class SamplerModule implements CommandModule { MethodDisambiguator methodDisambiguator = new MethodDisambiguator(); MergeMode mergeMode = arguments.boolFlag("separate-parent-calls") ? MergeMode.separateParentCalls(methodDisambiguator) : MergeMode.sameMethod(methodDisambiguator); future.thenAcceptAsync(s -> { - resp.broadcastPrefixed(TextComponent.of("The active sampling operation has completed! Uploading results...")); + resp.broadcastPrefixed(text("The active sampling operation has completed! Uploading results...")); handleUpload(platform, resp, s, threadOrder, comment, mergeMode); }); } @@ -272,16 +273,17 @@ public class SamplerModule implements CommandModule { String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, SPARK_SAMPLER_MEDIA_TYPE, false).key(); String url = SparkPlatform.VIEWER_URL + key; - resp.broadcastPrefixed(TextComponent.of("Sampling results:", TextColor.GOLD)); - resp.broadcast(TextComponent.builder(url) - .color(TextColor.GRAY) + resp.broadcastPrefixed(text("Sampling results:", GOLD)); + resp.broadcast(text() + .content(url) + .color(GRAY) .clickEvent(ClickEvent.openUrl(url)) .build() ); platform.getActivityLog().addToLog(Activity.urlActivity(resp.sender(), System.currentTimeMillis(), "Sampler", url)); } catch (IOException e) { - resp.broadcastPrefixed(TextComponent.of("An error occurred whilst uploading the results.", TextColor.RED)); + resp.broadcastPrefixed(text("An error occurred whilst uploading the results.", 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 bef5d78..043bc65 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 @@ -28,12 +28,13 @@ import me.lucko.spark.common.command.tabcomplete.TabCompleter; import me.lucko.spark.common.monitor.tick.TickMonitor; import me.lucko.spark.common.monitor.tick.TickMonitor.ReportPredicate; import me.lucko.spark.common.sampler.tick.TickHook; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import java.util.function.Consumer; +import static net.kyori.adventure.text.Component.*; + public class TickMonitoringModule implements CommandModule { /** The tick hook instance currently running, if any */ @@ -61,7 +62,7 @@ public class TickMonitoringModule implements CommandModule { this.tickHook = platform.getTickHook(); } if (this.tickHook == null) { - resp.replyPrefixed(TextComponent.of("Not supported!", TextColor.RED)); + resp.replyPrefixed(text("Not supported!", NamedTextColor.RED)); return; } @@ -81,7 +82,7 @@ public class TickMonitoringModule implements CommandModule { this.tickHook.addCallback(this.activeTickMonitor); } else { close(); - resp.broadcastPrefixed(TextComponent.of("Tick monitor disabled.")); + resp.broadcastPrefixed(text("Tick monitor disabled.")); } }) .tabCompleter((platform, sender, arguments) -> TabCompleter.completeForOpts(arguments, "--threshold", "--threshold-tick", "--without-gc")) diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/sender/CommandSender.java b/spark-common/src/main/java/me/lucko/spark/common/command/sender/CommandSender.java index ef56185..b10c7d8 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/sender/CommandSender.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/sender/CommandSender.java @@ -24,7 +24,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import me.lucko.spark.proto.SparkProtos.CommandSenderData; -import net.kyori.text.Component; +import net.kyori.adventure.text.Component; import java.util.UUID; 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 de94dc6..6b74cef 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 @@ -24,9 +24,8 @@ import com.sun.management.GarbageCollectionNotificationInfo; import me.lucko.spark.common.SparkPlatform; import me.lucko.spark.common.monitor.memory.GarbageCollectionMonitor; import me.lucko.spark.common.sampler.tick.TickHook; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import java.text.DecimalFormat; import java.util.DoubleSummaryStatistics; @@ -81,7 +80,7 @@ public abstract class TickMonitor implements TickHook.Callback, GarbageCollectio if (this.state == null) { this.state = State.SETUP; this.lastTickTime = now; - sendMessage(TextComponent.of("Tick monitor started. Before the monitor becomes fully active, the server's " + + sendMessage(Component.text("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; } @@ -102,29 +101,32 @@ public abstract class TickMonitor implements TickHook.Callback, GarbageCollectio // move onto the next state if (this.averageTickTime.getCount() >= 120) { this.platform.getPlugin().executeAsync(() -> { - sendMessage(TextComponent.of("Analysis is now complete.", TextColor.GOLD)); - sendMessage(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of(">", TextColor.WHITE)) - .append(TextComponent.space()) - .append(TextComponent.of("Max: ")) - .append(TextComponent.of(df.format(this.averageTickTime.getMax()))) - .append(TextComponent.of("ms")) + sendMessage(Component.text("Analysis is now complete.", NamedTextColor.GOLD)); + sendMessage(Component.text() + .color(NamedTextColor.GRAY) + .append(Component.text(">", NamedTextColor.WHITE)) + .append(Component.space()) + .append(Component.text("Max: ")) + .append(Component.text(df.format(this.averageTickTime.getMax()))) + .append(Component.text("ms")) .build() ); - sendMessage(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of(">", TextColor.WHITE)) - .append(TextComponent.space()) - .append(TextComponent.of("Min: ")) - .append(TextComponent.of(df.format(this.averageTickTime.getMin()))) - .append(TextComponent.of("ms")) + sendMessage(Component.text() + .color(NamedTextColor.GRAY) + .append(Component.text(">", NamedTextColor.WHITE)) + .append(Component.space()) + .append(Component.text("Min: ")) + .append(Component.text(df.format(this.averageTickTime.getMin()))) + .append(Component.text("ms")) .build() ); - sendMessage(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of(">", TextColor.WHITE)) - .append(TextComponent.space()) - .append(TextComponent.of("Average: ")) - .append(TextComponent.of(df.format(this.averageTickTime.getAverage()))) - .append(TextComponent.of("ms")) + sendMessage(Component.text() + .color(NamedTextColor.GRAY) + .append(Component.text(">", NamedTextColor.WHITE)) + .append(Component.space()) + .append(Component.text("Average: ")) + .append(Component.text(df.format(this.averageTickTime.getAverage()))) + .append(Component.text("ms")) .build() ); sendMessage(this.reportPredicate.monitoringStartMessage()); @@ -140,15 +142,16 @@ public abstract class TickMonitor implements TickHook.Callback, GarbageCollectio double percentageChange = (increase * 100d) / this.avg; if (this.reportPredicate.shouldReport(tickDuration, increase, percentageChange)) { this.platform.getPlugin().executeAsync(() -> { - sendMessage(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of("Tick ")) - .append(TextComponent.of("#" + getCurrentTick(), TextColor.DARK_GRAY)) - .append(TextComponent.of(" lasted ")) - .append(TextComponent.of(df.format(tickDuration), TextColor.GOLD)) - .append(TextComponent.of(" ms. ")) - .append(TextComponent.of("(")) - .append(TextComponent.of(df.format(percentageChange) + "%", TextColor.GOLD)) - .append(TextComponent.of(" increase from avg)")) + sendMessage(Component.text() + .color(NamedTextColor.GRAY) + .append(Component.text("Tick ")) + .append(Component.text("#" + getCurrentTick(), NamedTextColor.DARK_GRAY)) + .append(Component.text(" lasted ")) + .append(Component.text(df.format(tickDuration), NamedTextColor.GOLD)) + .append(Component.text(" ms. ")) + .append(Component.text("(")) + .append(Component.text(df.format(percentageChange) + "%", NamedTextColor.GOLD)) + .append(Component.text(" increase from avg)")) .build() ); }); @@ -174,14 +177,15 @@ public abstract class TickMonitor implements TickHook.Callback, GarbageCollectio } this.platform.getPlugin().executeAsync(() -> { - sendMessage(TextComponent.builder("").color(TextColor.GRAY) - .append(TextComponent.of("Tick ")) - .append(TextComponent.of("#" + 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 + ")")) + sendMessage(Component.text() + .color(NamedTextColor.GRAY) + .append(Component.text("Tick ")) + .append(Component.text("#" + getCurrentTick(), NamedTextColor.DARK_GRAY)) + .append(Component.text(" included ")) + .append(Component.text("GC", NamedTextColor.RED)) + .append(Component.text(" lasting ")) + .append(Component.text(df.format(data.getGcInfo().getDuration()), NamedTextColor.GOLD)) + .append(Component.text(" ms. (type = " + gcType + ")")) .build() ); }); @@ -226,7 +230,7 @@ public abstract class TickMonitor implements TickHook.Callback, GarbageCollectio @Override public Component monitoringStartMessage() { - return TextComponent.of("Starting now, any ticks with >" + this.threshold + "% increase in " + + return Component.text("Starting now, any ticks with >" + this.threshold + "% increase in " + "duration compared to the average will be reported."); } } @@ -248,7 +252,7 @@ public abstract class TickMonitor implements TickHook.Callback, GarbageCollectio @Override public Component monitoringStartMessage() { - return TextComponent.of("Starting now, any ticks with duration >" + this.threshold + " will be reported."); + return Component.text("Starting now, any ticks with duration >" + this.threshold + " will be reported."); } } diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/pagination/Pagination.java b/spark-common/src/main/java/me/lucko/spark/common/util/pagination/Pagination.java new file mode 100644 index 0000000..a92926f --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/pagination/Pagination.java @@ -0,0 +1,320 @@ +/* + * This file is part of text, licensed under the MIT License. + * + * Copyright (c) 2017-2020 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package me.lucko.spark.common.util.pagination; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; + +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; + +/** + * Pagination. + * + * @param <T> the content type + */ +@FunctionalInterface +public interface Pagination<T> { + /** + * The default interface width. + */ + int WIDTH = 55; + /** + * The default number of results per page. + */ + int RESULTS_PER_PAGE = 6; + /** + * The default line character. + */ + char LINE_CHARACTER = '-'; + /** + * The default line style. + */ + Style LINE_STYLE = Style.style(NamedTextColor.DARK_GRAY); + /** + * The default character for the previous page button. + */ + char PREVIOUS_PAGE_BUTTON_CHARACTER = '\u00AB'; // « + /** + * The default style for the next page button. + */ + Style PREVIOUS_PAGE_BUTTON_STYLE = Style.style() + .color(NamedTextColor.RED) + .hoverEvent(HoverEvent.showText(Component.text("Previous Page", NamedTextColor.RED))) + .build(); + /** + * The default character for the next page button. + */ + char NEXT_PAGE_BUTTON_CHARACTER = '\u00BB'; // » + /** + * The default style for the next page button. + */ + Style NEXT_PAGE_BUTTON_STYLE = Style.style() + .color(NamedTextColor.GREEN) + .hoverEvent(HoverEvent.showText(Component.text("Next Page", NamedTextColor.GREEN))) + .build(); + + /** + * The default interface renderer. + */ + Renderer DEFAULT_RENDERER = new Renderer() { + @Override + public String toString() { + return "Pagination.DEFAULT_RENDERER"; + } + }; + + /** + * Creates a pagination builder. + * + * @return a builder + */ + static Builder builder() { + return new PaginationBuilder(); + } + + /** + * Renders. + * + * @param content the content to render + * @param page the page number + * @return the rendered results + */ + List<Component> render(final Collection<? extends T> content, final int page); + + /** + * A pagination renderer. + */ + interface Renderer { + Component GRAY_LEFT_ROUND_BRACKET = Component.text("(", NamedTextColor.GRAY); + Component GRAY_LEFT_SQUARE_BRACKET = Component.text("[", NamedTextColor.GRAY); + Component GRAY_RIGHT_ROUND_BRACKET = Component.text(")", NamedTextColor.GRAY); + Component GRAY_RIGHT_SQUARE_BRACKET = Component.text("]", NamedTextColor.GRAY); + Component GRAY_FORWARD_SLASH = Component.text("/", NamedTextColor.GRAY); + + /** + * Renders an empty result. + * + * <p>No header or footer are rendered.</p> + * + * @return the rendered component + */ + default Component renderEmpty() { + return Component.text("No results match.", NamedTextColor.GRAY); + } + + /** + * Renders an unknown page. + * + * <p>No header or footer are rendered.</p> + * + * @param page the unknown page + * @param pages the total number of pages + * @return the rendered component + */ + default Component renderUnknownPage(final int page, final int pages) { + return Component.text("Unknown page selected. " + pages + " total pages.", NamedTextColor.GRAY); + } + + /** + * Renders a header. + * + * @param title the title + * @param page the page + * @param pages the total number of pages + * @return the rendered component + */ + default Component renderHeader(final Component title, final int page, final int pages) { + return Component.text() + .append(Component.space()) + .append(title) + .append(Component.space()) + .append(GRAY_LEFT_ROUND_BRACKET) + .append(Component.text(page, NamedTextColor.WHITE)) + .append(GRAY_FORWARD_SLASH) + .append(Component.text(pages, NamedTextColor.WHITE)) + .append(GRAY_RIGHT_ROUND_BRACKET) + .append(Component.space()) + .build(); + } + + /** + * Renders a previous page button. + * + * @param character the button character + * @param style the button style + * @param clickEvent the click event for the button + * @return the rendered component + */ + default Component renderPreviousPageButton(final char character, final Style style, final ClickEvent clickEvent) { + return Component.text() + .append(Component.space()) + .append(GRAY_LEFT_SQUARE_BRACKET) + .append(Component.text(character, style.clickEvent(clickEvent))) + .append(GRAY_RIGHT_SQUARE_BRACKET) + .append(Component.space()) + .build(); + } + + /** + * Renders a next page button. + * + * @param character the button character + * @param style the button style + * @param clickEvent the click event for the button + * @return the rendered component + */ + default Component renderNextPageButton(final char character, final Style style, final ClickEvent clickEvent) { + return Component.text() + .append(Component.space()) + .append(GRAY_LEFT_SQUARE_BRACKET) + .append(Component.text(character, style.clickEvent(clickEvent))) + .append(GRAY_RIGHT_SQUARE_BRACKET) + .append(Component.space()) + .build(); + } + + /** + * A row renderer. + * + * @param <T> the content type + */ + @FunctionalInterface + interface RowRenderer<T> { + /** + * Renders a row. + * + * @param value the value + * @param index the index + * @return the rendered row + */ + Collection<Component> renderRow(final T value, final int index); + } + } + + /** + * A page command function. + */ + @FunctionalInterface + interface PageCommandFunction { + /** + * Gets the command to display the page. + * + * @param page the page + * @return the command + */ + String pageCommand(final int page); + } + + /** + * A pagination builder. + */ + interface Builder { + /** + * Sets the width. + * + * @param width the width + * @return this builder + */ + Builder width(final int width); + + /** + * Sets the number of results per page. + * + * @param resultsPerPage the number of results per page + * @return this builder + */ + Builder resultsPerPage(final int resultsPerPage); + + /** + * Sets the renderer. + * + * @param renderer the renderer + * @return this builder + */ + Builder renderer(final Renderer renderer); + + /** + * Sets the line character and style. + * + * @param line the line consumer + * @return this builder + */ + Builder line(final Consumer<CharacterAndStyle> line); + + /** + * Sets the previous button. + * + * @param previousButton the button consumer + * @return this builder + */ + Builder previousButton(final Consumer<CharacterAndStyle> previousButton); + + /** + * Sets the next button. + * + * @param nextButton the button consumer + * @return this builder + */ + Builder nextButton(final Consumer<CharacterAndStyle> nextButton); + + /** + * Builds. + * + * @param title the title + * @param rowRenderer the row renderer + * @param pageCommand the page command + * @param <T> the content type + * @return pagination + * @throws IllegalStateException if the title has not been set + * @throws IllegalStateException if the row renderer has not been set + */ + <T> Pagination<T> build(final Component title, final Renderer.RowRenderer<T> rowRenderer, final PageCommandFunction pageCommand); + + /** + * A builder for a character and style pair. + */ + interface CharacterAndStyle { + /** + * Sets the character. + * + * @param character the character + * @return this builder + */ + CharacterAndStyle character(final char character); + + /** + * Sets the style. + * + * @param style the style + * @return this builder + */ + CharacterAndStyle style(final Style style); + } + } +}
\ No newline at end of file diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/pagination/PaginationBuilder.java b/spark-common/src/main/java/me/lucko/spark/common/util/pagination/PaginationBuilder.java new file mode 100644 index 0000000..807b7b9 --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/pagination/PaginationBuilder.java @@ -0,0 +1,134 @@ +/* + * This file is part of text, licensed under the MIT License. + * + * Copyright (c) 2017-2020 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package me.lucko.spark.common.util.pagination; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.Style; + +import java.util.function.Consumer; + +final class PaginationBuilder implements Pagination.Builder { + private int width = Pagination.WIDTH; + private int resultsPerPage = Pagination.RESULTS_PER_PAGE; + + private char lineCharacter = Pagination.LINE_CHARACTER; + private Style lineStyle = Pagination.LINE_STYLE; + + private Pagination.Renderer renderer = Pagination.DEFAULT_RENDERER; + + private char previousPageButtonCharacter = Pagination.PREVIOUS_PAGE_BUTTON_CHARACTER; + private Style previousPageButtonStyle = Pagination.PREVIOUS_PAGE_BUTTON_STYLE; + private char nextPageButtonCharacter = Pagination.NEXT_PAGE_BUTTON_CHARACTER; + private Style nextPageButtonStyle = Pagination.NEXT_PAGE_BUTTON_STYLE; + + @Override + public Pagination.Builder width(final int width) { + this.width = width; + return this; + } + + @Override + public Pagination.Builder resultsPerPage(final int resultsPerPage) { + this.resultsPerPage = resultsPerPage; + return this; + } + + @Override + public Pagination.Builder renderer(final Pagination.Renderer renderer) { + this.renderer = renderer; + return this; + } + + @Override + public Pagination.Builder line(final Consumer<CharacterAndStyle> line) { + line.accept(new CharacterAndStyle() { + @Override + public CharacterAndStyle character(final char character) { + PaginationBuilder.this.lineCharacter = character; + return this; + } + + @Override + public CharacterAndStyle style(final Style style) { + PaginationBuilder.this.lineStyle = style; + return this; + } + }); + return this; + } + + @Override + public Pagination.Builder previousButton(final Consumer<CharacterAndStyle> previousButton) { + previousButton.accept(new CharacterAndStyle() { + @Override + public CharacterAndStyle character(final char character) { + PaginationBuilder.this.previousPageButtonCharacter = character; + return this; + } + + @Override + public CharacterAndStyle style(final Style style) { + PaginationBuilder.this.previousPageButtonStyle = style; + return this; + } + }); + return this; + } + + @Override + public Pagination.Builder nextButton(final Consumer<CharacterAndStyle> nextButton) { + nextButton.accept(new CharacterAndStyle() { + @Override + public CharacterAndStyle character(final char character) { + PaginationBuilder.this.nextPageButtonCharacter = character; + return this; + } + + @Override + public CharacterAndStyle style(final Style style) { + PaginationBuilder.this.nextPageButtonStyle = style; + return this; + } + }); + return this; + } + + @Override + public <T> Pagination<T> build(final Component title, final Pagination.Renderer.RowRenderer<T> rowRenderer, final Pagination.PageCommandFunction pageCommand) { + return new PaginationImpl<>( + this.width, + this.resultsPerPage, + this.renderer, + this.lineCharacter, + this.lineStyle, + this.previousPageButtonCharacter, + this.previousPageButtonStyle, + this.nextPageButtonCharacter, + this.nextPageButtonStyle, + title, + rowRenderer, + pageCommand + ); + } +}
\ No newline at end of file diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/pagination/PaginationImpl.java b/spark-common/src/main/java/me/lucko/spark/common/util/pagination/PaginationImpl.java new file mode 100644 index 0000000..4a3bde0 --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/pagination/PaginationImpl.java @@ -0,0 +1,226 @@ +/* + * This file is part of text, licensed under the MIT License. + * + * Copyright (c) 2017-2020 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package me.lucko.spark.common.util.pagination; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.Style; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +final class PaginationImpl<T> implements Pagination<T> { + private static final int LINE_CHARACTER_LENGTH = 1; + + private final int width; + private final int resultsPerPage; + + private final Renderer renderer; + + private final char lineCharacter; + private final Style lineStyle; + + private final char previousPageButtonCharacter; + private final Style previousPageButtonStyle; + private final char nextPageButtonCharacter; + private final Style nextPageButtonStyle; + + private final Component title; + private final Renderer.RowRenderer<T> rowRenderer; + private final PageCommandFunction pageCommand; + + PaginationImpl(final int width, final int resultsPerPage, final Renderer renderer, final char lineCharacter, final Style lineStyle, final char previousPageButtonCharacter, final Style previousPageButtonStyle, final char nextPageButtonCharacter, final Style nextPageButtonStyle, final Component title, final Renderer.RowRenderer<T> rowRenderer, final PageCommandFunction pageCommand) { + this.width = width; + this.resultsPerPage = resultsPerPage; + this.renderer = renderer; + this.lineCharacter = lineCharacter; + this.lineStyle = lineStyle; + this.previousPageButtonCharacter = previousPageButtonCharacter; + this.previousPageButtonStyle = previousPageButtonStyle; + this.nextPageButtonCharacter = nextPageButtonCharacter; + this.nextPageButtonStyle = nextPageButtonStyle; + this.title = title; + this.rowRenderer = rowRenderer; + this.pageCommand = pageCommand; + } + + @Override + public List<Component> render(final Collection<? extends T> content, final int page) { + if(content.isEmpty()) { + return Collections.singletonList(this.renderer.renderEmpty()); + } + + final int pages = pages(this.resultsPerPage, content.size()); + + if(!pageInRange(page, pages)) { + return Collections.singletonList(this.renderer.renderUnknownPage(page, pages)); + } + + final List<Component> components = new ArrayList<>(); + components.add(this.renderHeader(page, pages)); + Paginator.forEachPageEntry(content, this.resultsPerPage, page, (value, index) -> { + components.addAll(this.rowRenderer.renderRow(value, index)); + }); + components.add(this.renderFooter(page, pages)); + return Collections.unmodifiableList(components); + } + + private Component renderHeader(final int page, final int pages) { + final Component header = this.renderer.renderHeader(this.title, page, pages); + final Component dashes = this.line(header); + + return Component.text() + .append(dashes) + .append(header) + .append(dashes) + .build(); + } + + private Component renderFooter(final int page, final int pages) { + if(page == 1 && page == pages) { + return this.line(this.width); + } + + final Component buttons = this.renderFooterButtons(page, pages); + final Component dashes = this.line(buttons); + + return Component.text() + .append(dashes) + .append(buttons) + .append(dashes) + .build(); + } + + private Component renderFooterButtons(final int page, final int pages) { + final boolean hasPreviousPage = page > 1 && pages > 1; + final boolean hasNextPage = (page < pages && page == 1) || ((hasPreviousPage && page > 1) && page != pages); + + final TextComponent.Builder buttons = Component.text(); + if(hasPreviousPage) { + buttons.append(this.renderer.renderPreviousPageButton(this.previousPageButtonCharacter, this.previousPageButtonStyle, ClickEvent.runCommand(this.pageCommand.pageCommand(page - 1)))); + + if(hasNextPage) { + buttons.append(this.line(8)); + } + } + + if(hasNextPage) { + buttons.append(this.renderer.renderNextPageButton(this.nextPageButtonCharacter, this.nextPageButtonStyle, ClickEvent.runCommand(this.pageCommand.pageCommand(page + 1)))); + } + + return buttons.build(); + } + + private Component line(final Component component) { + return this.line((this.width - length(component)) / (LINE_CHARACTER_LENGTH * 2)); + } + + private Component line(final int characters) { + return Component.text(repeat(String.valueOf(this.lineCharacter), characters), this.lineStyle); + } + + static int length(final Component component) { + int length = 0; + if(component instanceof TextComponent) { + length += ((TextComponent) component).content().length(); + } + for(final Component child : component.children()) { + length += length(child); + } + return length; + } + + static String repeat(final String character, final int count) { + return String.join("", Collections.nCopies(count, character)); + } + + static int pages(final int pageSize, final int count) { + final int pages = count / pageSize + 1; + if(count % pageSize == 0) { + return pages - 1; + } + return pages; + } + + static boolean pageInRange(final int page, final int pages) { + return page > 0 && page <= pages; + } + + @Override + public String toString() { + return "PaginationImpl{" + + "width=" + this.width + + ", resultsPerPage=" + this.resultsPerPage + + ", renderer=" + this.renderer + + ", lineCharacter=" + this.lineCharacter + + ", lineStyle=" + this.lineStyle + + ", previousPageButtonCharacter=" + this.previousPageButtonCharacter + + ", previousPageButtonStyle=" + this.previousPageButtonStyle + + ", nextPageButtonCharacter=" + this.nextPageButtonCharacter + + ", nextPageButtonStyle=" + this.nextPageButtonStyle + + ", title=" + this.title + + ", rowRenderer=" + this.rowRenderer + + ", pageCommand=" + this.pageCommand + + '}'; + } + + @Override + public boolean equals(final Object other) { + if(this == other) return true; + if(other == null || this.getClass() != other.getClass()) return false; + final PaginationImpl<?> that = (PaginationImpl<?>) other; + if(this.width != that.width) return false; + if(this.resultsPerPage != that.resultsPerPage) return false; + if(this.lineCharacter != that.lineCharacter) return false; + if(this.previousPageButtonCharacter != that.previousPageButtonCharacter) return false; + if(this.nextPageButtonCharacter != that.nextPageButtonCharacter) return false; + if(!this.renderer.equals(that.renderer)) return false; + if(!this.lineStyle.equals(that.lineStyle)) return false; + if(!this.previousPageButtonStyle.equals(that.previousPageButtonStyle)) return false; + if(!this.nextPageButtonStyle.equals(that.nextPageButtonStyle)) return false; + if(!this.title.equals(that.title)) return false; + if(!this.rowRenderer.equals(that.rowRenderer)) return false; + return this.pageCommand.equals(that.pageCommand); + } + + @Override + public int hashCode() { + int result = this.width; + result = (31 * result) + this.resultsPerPage; + result = (31 * result) + this.renderer.hashCode(); + result = (31 * result) + (int) this.lineCharacter; + result = (31 * result) + this.lineStyle.hashCode(); + result = (31 * result) + (int) this.previousPageButtonCharacter; + result = (31 * result) + this.previousPageButtonStyle.hashCode(); + result = (31 * result) + (int) this.nextPageButtonCharacter; + result = (31 * result) + this.nextPageButtonStyle.hashCode(); + result = (31 * result) + this.title.hashCode(); + result = (31 * result) + this.rowRenderer.hashCode(); + result = (31 * result) + this.pageCommand.hashCode(); + return result; + } +}
\ No newline at end of file diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/pagination/Paginator.java b/spark-common/src/main/java/me/lucko/spark/common/util/pagination/Paginator.java new file mode 100644 index 0000000..83b08bf --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/pagination/Paginator.java @@ -0,0 +1,56 @@ +/* + * This file is part of text, licensed under the MIT License. + * + * Copyright (c) 2017-2020 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package me.lucko.spark.common.util.pagination; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.RandomAccess; +import java.util.function.ObjIntConsumer; + +interface Paginator { + @SuppressWarnings("unchecked") + static <T> void forEachPageEntry(final Collection<? extends T> content, final int pageSize, final int page, final ObjIntConsumer<? super T> consumer) { + final int size = content.size(); + final int start = pageSize * (page - 1); + final int end = pageSize * page; + if(content instanceof List<?> && content instanceof RandomAccess) { + final List<? extends T> list = (List<? extends T>) content; + for(int i = start; i < end && i < size; i++) { + consumer.accept(list.get(i), i); + } + } else { + final Iterator<? extends T> it = content.iterator(); + + // skip entries on previous pages + for(int i = 0; i < start; i++) { + it.next(); + } + + for(int i = start; i < end && i < size; i++) { + consumer.accept(it.next(), i); + } + } + } +}
\ No newline at end of file |