mirror of
https://github.com/Samsuik/Sakura.git
synced 2025-12-27 02:39:06 +00:00
Upstream has released updates that appear to apply and compile correctly Paper Changes: PaperMC/Paper@c0a3d51 Start update, apply API patches PaperMC/Paper@172c7dc Work PaperMC/Paper@ab9a3db More work PaperMC/Paper@c60e47f More more work PaperMC/Paper@bd55e32 More more more work PaperMC/Paper@5265287 More more more more work PaperMC/Paper@4601dc9 Some fixes, start updating CustomModelData API PaperMC/Paper@2331dad Even more work PaperMC/Paper@dc74c6f moonrise PaperMC/Paper@d7d2f88 Apply remaining patches, fix API PaperMC/Paper@f863bb7 Update generated classes PaperMC/Paper@71a4ef8 Set java launcher for api generate task PaperMC/Paper@b8aeecb Compilation fixes PaperMC/Paper@6c35392 Tests succeed (by removing one) PaperMC/Paper@b0603da Fix jd gson version, move back mc util diff PaperMC/Paper@e2dd1d5 Add back post_teleport chunk ticket PaperMC/Paper@7045b2a Update DataConverter PaperMC/Paper@65633e3 Update Moonrise
657 lines
30 KiB
Diff
657 lines
30 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Samsuik <kfian294ma4@gmail.com>
|
|
Date: Sun, 19 Sep 2021 01:10:02 +0100
|
|
Subject: [PATCH] Track Tick Information
|
|
|
|
Keeps track of useful information every tick such as the tick rate,
|
|
entities, chunks and displays them with the tps command.
|
|
|
|
diff --git a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
|
index cbb2e57f9ab3b48a6e5f792711c4c6fd2d34d445..8e93fc5d7e1bc200f79b0e54edb62dc4d0bf5e74 100644
|
|
--- a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
|
+++ b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
|
@@ -4,6 +4,7 @@ import me.samsuik.sakura.command.subcommands.ConfigCommand;
|
|
import me.samsuik.sakura.command.subcommands.FPSCommand;
|
|
import me.samsuik.sakura.command.subcommands.VisualCommand;
|
|
import me.samsuik.sakura.player.visibility.VisibilityTypes;
|
|
+import me.samsuik.sakura.command.subcommands.TPSCommand;
|
|
import net.minecraft.server.MinecraftServer;
|
|
import org.bukkit.command.Command;
|
|
|
|
@@ -18,6 +19,7 @@ public final class SakuraCommands {
|
|
COMMANDS.put("fps", new FPSCommand("fps"));
|
|
COMMANDS.put("tntvisibility", new VisualCommand(VisibilityTypes.TNT, "tnttoggle"));
|
|
COMMANDS.put("sandvisibility", new VisualCommand(VisibilityTypes.SAND, "sandtoggle"));
|
|
+ COMMANDS.put("tps", new TPSCommand("tps"));
|
|
}
|
|
|
|
public static void registerCommands(MinecraftServer server) {
|
|
diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..db6d03c1ed1c1d0390826dd3f96e774e2bea8a1a
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java
|
|
@@ -0,0 +1,92 @@
|
|
+package me.samsuik.sakura.command.subcommands;
|
|
+
|
|
+import com.google.common.base.Strings;
|
|
+import com.google.common.collect.ImmutableList;
|
|
+import me.samsuik.sakura.command.BaseSubCommand;
|
|
+import me.samsuik.sakura.tps.ServerTickInformation;
|
|
+import me.samsuik.sakura.tps.graph.BuiltComponentCanvas;
|
|
+import me.samsuik.sakura.tps.graph.DetailedTPSGraph;
|
|
+import me.samsuik.sakura.tps.graph.GraphComponents;
|
|
+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.NamedTextColor;
|
|
+import net.kyori.adventure.text.format.Style;
|
|
+import net.kyori.adventure.text.format.TextDecoration;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.bukkit.command.CommandSender;
|
|
+import org.jspecify.annotations.NullMarked;
|
|
+
|
|
+@NullMarked
|
|
+public final class TPSCommand extends BaseSubCommand {
|
|
+ private static final int GRAPH_WIDTH = 71;
|
|
+ private static final int GRAPH_HEIGHT = 10;
|
|
+ private static final Style GRAY_WITH_STRIKETHROUGH = Style.style(NamedTextColor.GRAY, TextDecoration.STRIKETHROUGH);
|
|
+
|
|
+ public TPSCommand(String name) {
|
|
+ super(name);
|
|
+ this.description = "Displays the current ticks per second";
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void execute(CommandSender sender, String[] args) {
|
|
+ ServerTickInformation tickInformation = MinecraftServer.getServer().latestTickInformation();
|
|
+ long identifier = this.parseLong(args, 1).orElse(tickInformation.identifier());
|
|
+ double scale = this.parseDouble(args, 0).orElse(-1.0);
|
|
+ if (scale < 0.0) {
|
|
+ scale = this.dynamicScale(identifier);
|
|
+ }
|
|
+
|
|
+ ImmutableList<ServerTickInformation> tickHistory = MinecraftServer.getServer().tickHistory(identifier - GRAPH_WIDTH, identifier);
|
|
+ DetailedTPSGraph graph = new DetailedTPSGraph(GRAPH_WIDTH, GRAPH_HEIGHT, scale, tickHistory);
|
|
+ BuiltComponentCanvas canvas = graph.plot();
|
|
+ canvas.appendLeft(Component.text(":", NamedTextColor.BLACK));
|
|
+ canvas.appendRight(Component.text(":", NamedTextColor.BLACK));
|
|
+ canvas.header(this.createHeaderComponent(tickInformation, identifier));
|
|
+ canvas.footer(Component.text("*", NamedTextColor.DARK_GRAY)
|
|
+ .append(Component.text(Strings.repeat(" ", GRAPH_WIDTH - 1), GRAY_WITH_STRIKETHROUGH))
|
|
+ .append(Component.text("*")));
|
|
+
|
|
+ for (Component component : canvas.components()) {
|
|
+ sender.sendMessage(component);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private double dynamicScale(long identifier) {
|
|
+ ImmutableList<ServerTickInformation> tickHistory = MinecraftServer.getServer().tickHistory(identifier - 5, identifier);
|
|
+ double averageTps = tickHistory.stream()
|
|
+ .mapToDouble(ServerTickInformation::tps)
|
|
+ .average()
|
|
+ .orElse(0.0);
|
|
+ return 20 / averageTps;
|
|
+ }
|
|
+
|
|
+ private Component createHeaderComponent(ServerTickInformation tickInformation, long identifier) {
|
|
+ int scrollAmount = GRAPH_WIDTH / 3 * 2;
|
|
+ double memoryUsage = memoryUsage();
|
|
+ TextComponent.Builder builder = Component.text();
|
|
+ builder.color(NamedTextColor.DARK_GRAY);
|
|
+ builder.append(Component.text("< ")
|
|
+ .clickEvent(ClickEvent.runCommand("/tps -1 " + (identifier + scrollAmount))));
|
|
+ builder.append(Component.text(Strings.repeat(" ", 19), GRAY_WITH_STRIKETHROUGH));
|
|
+ builder.append(Component.text(" ( "));
|
|
+ builder.append(Component.text("Now: ", NamedTextColor.WHITE)
|
|
+ .append(Component.text("%.1f".formatted(tickInformation.tps()), tickInformation.colour())));
|
|
+ builder.appendSpace();
|
|
+ builder.append(Component.text("Mem: ", NamedTextColor.WHITE)
|
|
+ .append(Component.text("%.1f".formatted(memoryUsage * 100), GraphComponents.colour(1 - (float) memoryUsage))));
|
|
+ builder.append(Component.text("% ) "));
|
|
+ builder.append(Component.text(Strings.repeat(" ", 18), GRAY_WITH_STRIKETHROUGH));
|
|
+ builder.append(Component.text(" >")
|
|
+ .clickEvent(ClickEvent.runCommand("/tps -1 " + (identifier - scrollAmount))));
|
|
+ return builder.build();
|
|
+ }
|
|
+
|
|
+ private static double memoryUsage() {
|
|
+ Runtime runtime = Runtime.getRuntime();
|
|
+ double free = runtime.freeMemory();
|
|
+ double max = runtime.maxMemory();
|
|
+ double alloc = runtime.totalMemory();
|
|
+ return (alloc - free) / max;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java b/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..9a65a3dac75834a2fe10d2c6d6ae594ceb208fef
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java
|
|
@@ -0,0 +1,37 @@
|
|
+package me.samsuik.sakura.tps;
|
|
+
|
|
+import me.samsuik.sakura.configuration.GlobalConfiguration;
|
|
+import me.samsuik.sakura.tps.graph.GraphComponents;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.TextComponent;
|
|
+import net.kyori.adventure.text.format.TextColor;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.jspecify.annotations.NullMarked;
|
|
+
|
|
+@NullMarked
|
|
+public record ServerTickInformation(long identifier, double tps, double averageTick, long longestTick, float targetTickRate, int chunks, int entities) {
|
|
+ public static final ServerTickInformation FILLER = new ServerTickInformation(0, 0.0, 0.0, 0, 0.0f, 0, 0);
|
|
+
|
|
+ public TextColor colour() {
|
|
+ float lag = (float) this.tps / this.targetTickRate;
|
|
+ return GraphComponents.colour(lag);
|
|
+ }
|
|
+
|
|
+ public Component hoverComponent(TextColor colour) {
|
|
+ TextComponent.Builder builder = Component.text();
|
|
+ builder.append(Component.text("TPS: ")
|
|
+ .append(Component.text("%.1f".formatted(this.tps), colour)));
|
|
+ builder.appendNewline();
|
|
+ builder.append(Component.text("MSPT: ")
|
|
+ .append(Component.text("%.1f".formatted(this.averageTick), colour))
|
|
+ .append(Component.text("/"))
|
|
+ .append(Component.text(this.longestTick, colour)));
|
|
+ if (GlobalConfiguration.get().messages.tpsShowEntityAndChunkCount) {
|
|
+ builder.appendNewline();
|
|
+ builder.append(Component.text("Entities: " + this.entities));
|
|
+ builder.appendNewline();
|
|
+ builder.append(Component.text("Chunks: " + this.chunks));
|
|
+ }
|
|
+ return builder.build();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java b/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..5f88e17db0cf8eca161d98cc8cdac8383903e694
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java
|
|
@@ -0,0 +1,71 @@
|
|
+package me.samsuik.sakura.tps;
|
|
+
|
|
+import com.google.common.collect.ImmutableList;
|
|
+import it.unimi.dsi.fastutil.longs.LongArrayList;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import org.jspecify.annotations.NullMarked;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.List;
|
|
+
|
|
+@NullMarked
|
|
+public final class TickInformationCollector {
|
|
+ private static final int TEN_MINUTES = 10 * 60;
|
|
+ private final ObjectArrayList<ServerTickInformation> collectedInformation = new ObjectArrayList<>();
|
|
+ private final LongArrayList tickSamples = new LongArrayList();
|
|
+ private long identifier = 0;
|
|
+
|
|
+ public ServerTickInformation latestTickInformation() {
|
|
+ return this.collectedInformation.getLast();
|
|
+ }
|
|
+
|
|
+ public void levelData(Collection<ServerLevel> levels, double tps) {
|
|
+ int chunks = 0;
|
|
+ int entities = 0;
|
|
+ for (ServerLevel level : levels) {
|
|
+ chunks += level.chunkSource.getFullChunksCount();
|
|
+ entities += level.entityTickList.entities.size();
|
|
+ }
|
|
+
|
|
+ double averageTick = this.tickSamples.longStream()
|
|
+ .average()
|
|
+ .orElse(0.0);
|
|
+ long longestTick = this.tickSamples.longStream()
|
|
+ .max()
|
|
+ .orElse(0);
|
|
+ float targetTickRate = MinecraftServer.getServer().tickRateManager().tickrate();
|
|
+
|
|
+ ServerTickInformation tickInformation = new ServerTickInformation(
|
|
+ this.identifier++, tps, averageTick, longestTick, targetTickRate, chunks, entities
|
|
+ );
|
|
+
|
|
+ this.collectedInformation.add(tickInformation);
|
|
+ this.tickSamples.clear();
|
|
+
|
|
+ if (this.collectedInformation.size() > TEN_MINUTES) {
|
|
+ this.collectedInformation.subList(0, 60).clear();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void tickDuration(long timeTaken) {
|
|
+ this.tickSamples.add(timeTaken);
|
|
+ }
|
|
+
|
|
+ public ImmutableList<ServerTickInformation> collect(long from, long to) {
|
|
+ List<ServerTickInformation> collected = new ObjectArrayList<>();
|
|
+ for (ServerTickInformation tickInformation : this.collectedInformation.reversed()) {
|
|
+ if (tickInformation.identifier() >= from && tickInformation.identifier() < to) {
|
|
+ collected.add(tickInformation);
|
|
+ }
|
|
+ }
|
|
+ long ahead = to - this.identifier;
|
|
+ long missing = to - from - collected.size();
|
|
+ for (int i = 0; i < missing; ++i) {
|
|
+ int ind = (i < ahead) ? 0 : collected.size();
|
|
+ collected.add(ind, ServerTickInformation.FILLER);
|
|
+ }
|
|
+ return ImmutableList.copyOf(collected);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java b/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..bf3e953c99825274b800d19c74019c904620ec74
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java
|
|
@@ -0,0 +1,36 @@
|
|
+package me.samsuik.sakura.tps.graph;
|
|
+
|
|
+import com.google.common.collect.ImmutableList;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import org.jspecify.annotations.NullMarked;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+@NullMarked
|
|
+public final class BuiltComponentCanvas {
|
|
+ private final List<Component> components;
|
|
+
|
|
+ BuiltComponentCanvas(List<Component> components) {
|
|
+ this.components = components;
|
|
+ }
|
|
+
|
|
+ public void appendLeft(Component component) {
|
|
+ this.components.replaceAll(component::append);
|
|
+ }
|
|
+
|
|
+ public void appendRight(Component component) {
|
|
+ this.components.replaceAll(row -> row.append(component));
|
|
+ }
|
|
+
|
|
+ public void header(Component component) {
|
|
+ this.components.addFirst(component);
|
|
+ }
|
|
+
|
|
+ public void footer(Component component) {
|
|
+ this.components.add(component);
|
|
+ }
|
|
+
|
|
+ public ImmutableList<Component> components() {
|
|
+ return ImmutableList.copyOf(this.components);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java b/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..42024655f1b1cad12ba1db66086bb978c5ee8f02
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java
|
|
@@ -0,0 +1,63 @@
|
|
+package me.samsuik.sakura.tps.graph;
|
|
+
|
|
+import com.google.common.base.Preconditions;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.JoinConfiguration;
|
|
+import org.jspecify.annotations.NullMarked;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+@NullMarked
|
|
+public final class ComponentCanvas {
|
|
+ private final int width;
|
|
+ private final int height;
|
|
+ private final Component[][] components;
|
|
+
|
|
+ public ComponentCanvas(int width, int height) {
|
|
+ this.width = width;
|
|
+ this.height = height;
|
|
+ // [x, y] is flipped as it makes converting the components into a list easier
|
|
+ this.components = new Component[height][width];
|
|
+ }
|
|
+
|
|
+ public void flip() {
|
|
+ for (int y = 0; y < this.height; ++y) {
|
|
+ if (y >= this.height / 2) {
|
|
+ Component[] row = this.components[y];
|
|
+ int relocatingRow = this.height - 1 - y;
|
|
+ this.components[y] = this.components[relocatingRow];
|
|
+ this.components[relocatingRow] = row;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void fill(Component component) {
|
|
+ for (int x = 0; x < this.width; ++x) {
|
|
+ for (int y = 0; y < this.height; ++y) {
|
|
+ this.set(x, y, component);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public Component get(int x, int y) {
|
|
+ Component component = this.components[y][x];
|
|
+ return Preconditions.checkNotNull(component, "missing component at x:{} y:{}", x, y);
|
|
+ }
|
|
+
|
|
+ public void set(int x, int y, Component component) {
|
|
+ this.components[y][x] = component;
|
|
+ }
|
|
+
|
|
+ public BuiltComponentCanvas build() {
|
|
+ return new BuiltComponentCanvas(this.joinComponents());
|
|
+ }
|
|
+
|
|
+ private List<Component> joinComponents() {
|
|
+ List<Component> componentList = new ObjectArrayList<>(this.height);
|
|
+ for (Component[] row : this.components) {
|
|
+ componentList.add(Component.join(JoinConfiguration.noSeparators(), row));
|
|
+ }
|
|
+ return componentList;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java b/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..bebc61d33a5cbb6a46c7f5ac0a9b453e0ab48655
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java
|
|
@@ -0,0 +1,102 @@
|
|
+package me.samsuik.sakura.tps.graph;
|
|
+
|
|
+import me.samsuik.sakura.tps.ServerTickInformation;
|
|
+import org.jspecify.annotations.NullMarked;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+@NullMarked
|
|
+public final class DetailedTPSGraph extends TPSGraph {
|
|
+ public DetailedTPSGraph(int width, int height, double scale, List<ServerTickInformation> tickInformation) {
|
|
+ super(width, height, scale, tickInformation);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public BuiltComponentCanvas plot() {
|
|
+ ComponentCanvas canvas = new ComponentCanvas(this.width, this.height);
|
|
+ canvas.fill(GraphComponents.BACKGROUND);
|
|
+
|
|
+ this.basicOutline(canvas);
|
|
+ this.prettifyOutline(canvas);
|
|
+ this.addColourAndHoverInformation(canvas);
|
|
+
|
|
+ canvas.flip();
|
|
+ return canvas.build();
|
|
+ }
|
|
+
|
|
+ private void basicOutline(ComponentCanvas canvas) {
|
|
+ for (int x = 0; x < this.width; ++x) {
|
|
+ int row = this.rowFromColumn(x);
|
|
+ int nextRow = this.rowFromColumn(x + 1);
|
|
+ int minRow = Math.min(row, nextRow);
|
|
+ int maxRow = Math.max(row, nextRow);
|
|
+
|
|
+ if (maxRow - minRow >= 2) {
|
|
+ canvas.set(x, minRow, GraphComponents.TOP_DOTTED_LINE);
|
|
+ canvas.set(x, maxRow, GraphComponents.BOTTOM_DOTTED_LINE);
|
|
+
|
|
+ for (int y = minRow + 1; y < maxRow; ++y) {
|
|
+ canvas.set(x, y, GraphComponents.VERTICAL_LINE);
|
|
+ }
|
|
+ } else {
|
|
+ canvas.set(x, row, GraphComponents.HORIZONTAL_LINE);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void prettifyOutline(ComponentCanvas canvas) {
|
|
+ for (int x = 0; x < this.width; ++x) {
|
|
+ int row = this.rowFromColumn(x);
|
|
+ int nextRow = this.rowFromColumn(x + 1);
|
|
+ int prevRow = this.rowFromColumn(x - 1);
|
|
+ int minRow = Math.min(row, nextRow);
|
|
+ int maxRow = Math.max(row, nextRow);
|
|
+
|
|
+ if (maxRow - minRow >= 2) {
|
|
+ this.prettifyVerticalOutline(canvas, x, row, nextRow, prevRow, minRow, maxRow);
|
|
+ } else {
|
|
+ this.prettifySlopes(canvas, x, row, nextRow, prevRow);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void prettifyVerticalOutline(ComponentCanvas canvas, int x, int row, int nextRow, int prevRow, int minRow, int maxRow) {
|
|
+ if (minRow == nextRow) {
|
|
+ canvas.set(x, minRow, GraphComponents.CONE_BOTTOM_LEFT);
|
|
+ } else if (prevRow <= minRow) {
|
|
+ canvas.set(x, minRow, GraphComponents.CONE_BOTTOM_RIGHT);
|
|
+ }
|
|
+ if (prevRow == row + 1 && nextRow < row) {
|
|
+ canvas.set(x, maxRow, GraphComponents.CONE_TOP_RIGHT);
|
|
+ }
|
|
+ if (maxRow == row && Math.abs(nextRow - maxRow) > 1 && Math.abs(prevRow - maxRow) > 1 && prevRow < maxRow) {
|
|
+ canvas.set(x - 1, maxRow, GraphComponents.CONE_TOP_LEFT);
|
|
+ canvas.set(x, maxRow, GraphComponents.CONE_TOP_RIGHT);
|
|
+ }
|
|
+ if (minRow == row && Math.abs(nextRow - minRow) > 1 && Math.abs(prevRow - minRow) > 1 && prevRow > minRow) {
|
|
+ canvas.set(x - 1, minRow, GraphComponents.CONE_BOTTOM_LEFT);
|
|
+ canvas.set(x, minRow, GraphComponents.CONE_BOTTOM_RIGHT);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void prettifySlopes(ComponentCanvas canvas, int x, int row, int nextRow, int prevRow) {
|
|
+ int slopeDirection = nextRow - prevRow;
|
|
+ int slopeChange = Math.abs(slopeDirection);
|
|
+
|
|
+ if (slopeChange >= 2 && Math.max(nextRow, prevRow) == row + 1) {
|
|
+ canvas.set(x, row, slopeDirection < 0 ? GraphComponents.TL_TO_BR : GraphComponents.BL_TO_TR);
|
|
+ } else if (Math.abs(row - nextRow) == 1 || slopeDirection == 0) {
|
|
+ if (row < nextRow) {
|
|
+ canvas.set(x, row, GraphComponents.TOP_DOTTED_LINE);
|
|
+ } else if (row > nextRow) {
|
|
+ canvas.set(x, row, GraphComponents.BOTTOM_DOTTED_LINE);
|
|
+ }
|
|
+ } else if (Math.abs(row - prevRow) == 1) {
|
|
+ if (prevRow > row) {
|
|
+ canvas.set(x, row, GraphComponents.TOP_DOTTED_LINE);
|
|
+ } else if (prevRow < row) {
|
|
+ canvas.set(x, row, GraphComponents.BOTTOM_DOTTED_LINE);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java b/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..95d3c8031e4708d2d0a0a12213060acd9ab65522
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java
|
|
@@ -0,0 +1,42 @@
|
|
+package me.samsuik.sakura.tps.graph;
|
|
+
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
|
+import net.kyori.adventure.text.format.Style;
|
|
+import net.kyori.adventure.text.format.TextColor;
|
|
+import net.kyori.adventure.text.format.TextDecoration;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+public final class GraphComponents {
|
|
+ private static final Style STRIKE_THROUGH_STYLE = Style.style(TextDecoration.STRIKETHROUGH);
|
|
+ private static final Style REMOVE_STRIKE_THROUGH_STYLE = Style.style(TextDecoration.STRIKETHROUGH.withState(false));
|
|
+
|
|
+ public static final Component BACKGROUND = Component.text("::");
|
|
+ public static final Component HORIZONTAL_LINE = Component.text(" ", STRIKE_THROUGH_STYLE);
|
|
+ public static final Component VERTICAL_LINE = Component.text("||");
|
|
+ public static final Component TOP_DOTTED_LINE = Component.text("''");
|
|
+ public static final Component BOTTOM_DOTTED_LINE = Component.text("..");
|
|
+ public static final Component BL_TO_TR = Component.text(".", STRIKE_THROUGH_STYLE).append(Component.text("'", REMOVE_STRIKE_THROUGH_STYLE));
|
|
+ public static final Component TL_TO_BR = Component.text("'").append(Component.text(".", STRIKE_THROUGH_STYLE));
|
|
+ public static final Component CONE_TOP_LEFT = Component.text(".!");
|
|
+ public static final Component CONE_TOP_RIGHT = Component.text("!.");
|
|
+ public static final Component CONE_BOTTOM_LEFT = Component.text("'!");
|
|
+ public static final Component CONE_BOTTOM_RIGHT = Component.text("!'");
|
|
+
|
|
+ private static final List<TextColor> COLOURS = List.of(
|
|
+ NamedTextColor.GREEN, NamedTextColor.YELLOW, NamedTextColor.GOLD,
|
|
+ NamedTextColor.RED, NamedTextColor.DARK_GRAY, TextColor.color(40, 40, 40)
|
|
+ );
|
|
+
|
|
+ public static TextColor colour(float num) {
|
|
+ float segment = 1.0f / COLOURS.size();
|
|
+ float a = (1.0f - num) / segment;
|
|
+ float t = a % 1.0f;
|
|
+ int startIndex = Math.clamp((int) a, 0, COLOURS.size() - 2);
|
|
+ int endIndex = startIndex + 1;
|
|
+ TextColor startColour = COLOURS.get(startIndex);
|
|
+ TextColor endColour = COLOURS.get(endIndex);
|
|
+ return TextColor.lerp(t, startColour, endColour);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java b/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..27b6b071ad38589d37e35ea7fdf1d45924079f49
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java
|
|
@@ -0,0 +1,60 @@
|
|
+package me.samsuik.sakura.tps.graph;
|
|
+
|
|
+import com.google.common.base.Preconditions;
|
|
+import me.samsuik.sakura.tps.ServerTickInformation;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.event.HoverEvent;
|
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
|
+import net.kyori.adventure.text.format.TextColor;
|
|
+import net.minecraft.util.Mth;
|
|
+import org.jspecify.annotations.NullMarked;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+@NullMarked
|
|
+public abstract class TPSGraph {
|
|
+ protected final List<ServerTickInformation> tickInformation;
|
|
+ protected final int width;
|
|
+ protected final int height;
|
|
+ protected final double scale;
|
|
+
|
|
+ public TPSGraph(int width, int height, double scale, List<ServerTickInformation> tickInformation) {
|
|
+ Preconditions.checkArgument(tickInformation.size() == width);
|
|
+ this.width = width;
|
|
+ this.height = height;
|
|
+ this.scale = scale;
|
|
+ this.tickInformation = tickInformation;
|
|
+ }
|
|
+
|
|
+ public abstract BuiltComponentCanvas plot();
|
|
+
|
|
+ protected final int rowFromColumn(int x) {
|
|
+ int clamped = Math.clamp(x, 0, this.width - 1);
|
|
+ ServerTickInformation tickInformation = this.tickInformation.get(clamped);
|
|
+ return this.rowFromTPS(tickInformation.tps());
|
|
+ }
|
|
+
|
|
+ protected final int rowFromTPS(double tps) {
|
|
+ int row = Mth.floor((tps / 3) * this.scale);
|
|
+ return Mth.clamp(row, 0, this.height - 1);
|
|
+ }
|
|
+
|
|
+ protected final void addColourAndHoverInformation(ComponentCanvas canvas) {
|
|
+ for (int x = 0; x < this.width; ++x) {
|
|
+ ServerTickInformation tickInformation = this.tickInformation.get(x);
|
|
+ TextColor colourFromTPS = tickInformation.colour();
|
|
+ Component hoverComponent = tickInformation.hoverComponent(colourFromTPS);
|
|
+ HoverEvent<Component> hoverEvent = HoverEvent.showText(hoverComponent);
|
|
+
|
|
+ for (int y = 0; y < this.height; ++y) {
|
|
+ Component component = canvas.get(x, y);
|
|
+ if (component == GraphComponents.BACKGROUND) {
|
|
+ component = component.color(NamedTextColor.BLACK);
|
|
+ } else {
|
|
+ component = component.color(colourFromTPS);
|
|
+ }
|
|
+ canvas.set(x, y, component.hoverEvent(hoverEvent));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 1d0462b970304f543ff949f7aa32c67a1860ba4f..733541e91b0064d50de6c5c0985e9c472685c20c 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -427,6 +427,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
}
|
|
}
|
|
// Paper end - rewrite chunk system
|
|
+ // Sakura start - track tick information
|
|
+ private final me.samsuik.sakura.tps.TickInformationCollector tickInformationCollector = new me.samsuik.sakura.tps.TickInformationCollector();
|
|
+
|
|
+ public final me.samsuik.sakura.tps.ServerTickInformation latestTickInformation() {
|
|
+ return this.tickInformationCollector.latestTickInformation();
|
|
+ }
|
|
+
|
|
+ public final ImmutableList<me.samsuik.sakura.tps.ServerTickInformation> tickHistory(long from, long to) {
|
|
+ return this.tickInformationCollector.collect(from, to);
|
|
+ }
|
|
+ // Sakura end - track tick information
|
|
|
|
public MinecraftServer(OptionSet options, WorldLoader.DataLoadContext worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, Proxy proxy, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) {
|
|
super("Server");
|
|
@@ -1301,6 +1312,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
if (++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0) {
|
|
final long diff = currentTime - tickSection;
|
|
final java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
|
|
+ this.tickInformationCollector.levelData(this.levels.values(), currentTps.doubleValue()); // Sakura - track tick information
|
|
tps1.add(currentTps, diff);
|
|
tps5.add(currentTps, diff);
|
|
tps15.add(currentTps, diff);
|
|
@@ -1343,6 +1355,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
throw new RuntimeException("Chunk system crash propagated to tick()", crash);
|
|
}
|
|
// Paper end - rewrite chunk system
|
|
+ this.tickInformationCollector.tickDuration((System.nanoTime() - currentTime) / 1_000_000L); // Sakura - track tick information
|
|
this.tickFrame.end();
|
|
gameprofilerfiller.popPush("nextTickWait");
|
|
this.mayHaveDelayedTasks = true;
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
index 0c1587b8ccf05e7a0a5df5a64c483cee434e1c0f..e1f0da0b20ec310470160718338920bbd5b088de 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -201,7 +201,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
private final MinecraftServer server;
|
|
public final PrimaryLevelData serverLevelData; // CraftBukkit - type
|
|
private int lastSpawnChunkRadius;
|
|
- final EntityTickList entityTickList = new EntityTickList();
|
|
+ public final EntityTickList entityTickList = new EntityTickList(); // Sakura - package-private -> public
|
|
// Paper - rewrite chunk system
|
|
private final GameEventDispatcher gameEventDispatcher;
|
|
public boolean noSave;
|
|
diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
|
index d8b4196adf955f8d414688dc451caac2d9c609d9..0859aecb141261638b8547fb8854768fb6b6f5c7 100644
|
|
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
|
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
|
@@ -9,7 +9,7 @@ import javax.annotation.Nullable;
|
|
import net.minecraft.world.entity.Entity;
|
|
|
|
public class EntityTickList {
|
|
- private final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system
|
|
+ public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Sakura - track tick information; expose entity list // Paper - rewrite chunk system
|
|
|
|
private void ensureActiveIsNotIterated() {
|
|
// Paper - rewrite chunk system
|
|
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
|
index 4dbb109d0526afee99b9190fc256585121aac9b5..019ae7104a644f23495e42510a80573a7ac06a37 100644
|
|
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
|
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
|
@@ -279,7 +279,7 @@ public class SpigotConfig
|
|
|
|
private static void tpsCommand()
|
|
{
|
|
- SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) );
|
|
+ // SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) ); // Sakura - TPS Graph
|
|
}
|
|
|
|
public static int playerSample;
|