Files
Purpur/patches/server/0120-Implement-TPSBar.patch

470 lines
21 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Sat, 12 Dec 2020 21:19:05 -0600
Subject: [PATCH] Implement TPSBar
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index 277fb799d898ca726205519b1516861901be33c5..144e83bac0d8885c48d97d7fbb4b712d4c0fc4b3 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -225,6 +225,7 @@ public class Commands {
org.purpurmc.purpur.command.CreditsCommand.register(this.dispatcher); // Purpur
org.purpurmc.purpur.command.DemoCommand.register(this.dispatcher); // Purpur
org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur
+ org.purpurmc.purpur.command.TPSBarCommand.register(this.dispatcher); // Purpur
}
if (environment.includeIntegrated) {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 52487bc86a28a2f2c1c677b07c9fec77685f2af0..de9e19d9979ad6981fcda881d22b18a613c4138d 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1026,6 +1026,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.safeShutdown(waitForShutdown, false);
}
public void safeShutdown(boolean waitForShutdown, boolean isRestarting) {
+ org.purpurmc.purpur.task.BossBarTask.stopAll(); // Purpur
this.isRestarting = isRestarting;
this.hasLoggedStop = true; // Paper
if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index ca6a2fee12ac8a89dae57aa2787462f190463cd0..e0b2819d6c73a9ca1fa60ff71d29e201360370a8 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -351,6 +351,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
if (gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning) mobSpawnExecutor.start(); // Pufferfish
+ org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur
+
return true;
}
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index dc1cffa39659505f44ee81a38066c274fda09a43..a7f674f456be825bbabb2c86c93afde77db96a33 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -277,6 +277,7 @@ public class ServerPlayer extends Player {
public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - there are a lot of changes to do if we change all methods leading to the event
public boolean purpurClient = false; // Purpur
public boolean acceptingResourcePack = false; // Purpur
+ private boolean tpsBar = false; // Purpur
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) {
super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile);
@@ -516,6 +517,7 @@ public class ServerPlayer extends Player {
}
}
+ if (nbt.contains("Purpur.TPSBar")) { this.tpsBar = nbt.getBoolean("Purpur.TPSBar"); } // Purpur
}
@Override
@@ -582,6 +584,7 @@ public class ServerPlayer extends Player {
}
this.getBukkitEntity().setExtraData(nbt); // CraftBukkit
+ nbt.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur
}
// CraftBukkit start - World fallback code, either respawn location or global spawn
@@ -2685,5 +2688,13 @@ public class ServerPlayer extends Player {
this.server.getPlayerList().respawn(this, toLevel, true, to, !toLevel.paperConfig().environment.disableTeleportationSuffocationCheck, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.DEATH);
}
}
+
+ public boolean tpsBar() {
+ return this.tpsBar;
+ }
+
+ public void tpsBar(boolean tpsBar) {
+ this.tpsBar = tpsBar;
+ }
// Purpur end
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 2069633c7fc3af7cef94e92ff03da6c9198c4524..25be7c9e59666f27161d8f08129019764a70a512 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -467,6 +467,7 @@ public abstract class PlayerList {
scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
}
// Paper end
+ org.purpurmc.purpur.task.BossBarTask.addToAll(player); // Purpur
// CraftBukkit - Moved from above, added world
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
}
@@ -576,6 +577,8 @@ public abstract class PlayerList {
}
public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer, net.kyori.adventure.text.Component leaveMessage) {
// Paper end
+ org.purpurmc.purpur.task.BossBarTask.removeFromAll(entityplayer.getBukkitEntity()); // Purpur
+
ServerLevel worldserver = entityplayer.getLevel();
entityplayer.awardStat(Stats.LEAVE_GAME);
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 126eb32d182b78b07add872aad6a821334639662..5b0625955e2a65f689c8a128d73170bc1f0c8025 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -181,6 +181,7 @@ public class PurpurConfig {
public static String creditsCommandOutput = "<green>%s has been shown the end credits";
public static String demoCommandOutput = "<green>%s has been shown the demo screen";
public static String pingCommandOutput = "<green>%s's ping is %sms";
+ public static String tpsbarCommandOutput = "<green>Tpsbar toggled <onoff> for <target>";
private static void messages() {
cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob);
afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway);
@@ -190,6 +191,7 @@ public class PurpurConfig {
creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput);
demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput);
pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput);
+ tpsbarCommandOutput = getString("settings.messages.tpsbar-command-output", tpsbarCommandOutput);
}
public static String serverModName = "Purpur";
@@ -212,6 +214,29 @@ public class PurpurConfig {
disableGiveCommandDrops = getBoolean("settings.disable-give-dropping", disableGiveCommandDrops);
}
+ public static String commandTPSBarTitle = "<gray>TPS<yellow>:</yellow> <tps> MSPT<yellow>:</yellow> <mspt> Ping<yellow>:</yellow> <ping>ms";
+ public static BossBar.Overlay commandTPSBarProgressOverlay = BossBar.Overlay.NOTCHED_20;
+ public static TPSBarTask.FillMode commandTPSBarProgressFillMode = TPSBarTask.FillMode.MSPT;
+ public static BossBar.Color commandTPSBarProgressColorGood = BossBar.Color.GREEN;
+ public static BossBar.Color commandTPSBarProgressColorMedium = BossBar.Color.YELLOW;
+ public static BossBar.Color commandTPSBarProgressColorLow = BossBar.Color.RED;
+ public static String commandTPSBarTextColorGood = "<gradient:#55ff55:#00aa00><text></gradient>";
+ public static String commandTPSBarTextColorMedium = "<gradient:#ffff55:#ffaa00><text></gradient>";
+ public static String commandTPSBarTextColorLow = "<gradient:#ff5555:#aa0000><text></gradient>";
+ public static int commandTPSBarTickInterval = 20;
+ private static void commandSettings() {
+ commandTPSBarTitle = getString("settings.command.tpsbar.title", commandTPSBarTitle);
+ commandTPSBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.tpsbar.overlay", commandTPSBarProgressOverlay.name()));
+ commandTPSBarProgressFillMode = TPSBarTask.FillMode.valueOf(getString("settings.command.tpsbar.fill-mode", commandTPSBarProgressFillMode.name()));
+ commandTPSBarProgressColorGood = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.good", commandTPSBarProgressColorGood.name()));
+ commandTPSBarProgressColorMedium = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.medium", commandTPSBarProgressColorMedium.name()));
+ commandTPSBarProgressColorLow = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.low", commandTPSBarProgressColorLow.name()));
+ commandTPSBarTextColorGood = getString("settings.command.tpsbar.text-color.good", commandTPSBarTextColorGood);
+ commandTPSBarTextColorMedium = getString("settings.command.tpsbar.text-color.medium", commandTPSBarTextColorMedium);
+ commandTPSBarTextColorLow = getString("settings.command.tpsbar.text-color.low", commandTPSBarTextColorLow);
+ commandTPSBarTickInterval = getInt("settings.command.tpsbar.tick-interval", commandTPSBarTickInterval);
+ }
+
public static int barrelRows = 3;
public static boolean enderChestSixRows = false;
public static boolean enderChestPermissionRows = false;
diff --git a/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java b/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8f9b044107ff7c29a83eb5378aa9f5465ba1995
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java
@@ -0,0 +1,44 @@
+package org.purpurmc.purpur.command;
+
+import com.mojang.brigadier.CommandDispatcher;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+import net.minecraft.commands.arguments.EntityArgument;
+import net.minecraft.server.level.ServerPlayer;
+import org.purpurmc.purpur.PurpurConfig;
+import org.purpurmc.purpur.task.TPSBarTask;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class TPSBarCommand {
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
+ dispatcher.register(Commands.literal("tpsbar")
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.tpsbar"))
+ .executes(context -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())))
+ .then(Commands.argument("targets", EntityArgument.players())
+ .requires(listener -> listener.hasPermission(2, "bukkit.command.tpsbar.other"))
+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets")))
+ )
+ );
+ }
+
+ private static int execute(CommandSourceStack sender, Collection<ServerPlayer> targets) {
+ for (ServerPlayer player : targets) {
+ boolean result = TPSBarTask.instance().togglePlayer(player.getBukkitEntity());
+ player.tpsBar(result);
+
+ Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.tpsbarCommandOutput,
+ Placeholder.component("onoff", Component.translatable(result ? "options.on" : "options.off")
+ .color(result ? NamedTextColor.GREEN : NamedTextColor.RED)),
+ Placeholder.parsed("target", player.getGameProfile().getName()));
+
+ sender.sendSuccess(output, false);
+ }
+ return targets.size();
+ }
+}
diff --git a/src/main/java/org/purpurmc/purpur/task/BossBarTask.java b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..d38b3c4a722396cc3b61a9a8ed7e39cea4ae65cb
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java
@@ -0,0 +1,109 @@
+package org.purpurmc.purpur.task;
+
+import net.kyori.adventure.bossbar.BossBar;
+import net.minecraft.server.level.ServerPlayer;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+
+public abstract class BossBarTask extends BukkitRunnable {
+ private final Map<UUID, BossBar> bossbars = new HashMap<>();
+ private boolean started;
+
+ abstract BossBar createBossBar();
+
+ abstract void updateBossBar(BossBar bossbar, Player player);
+
+ @Override
+ public void run() {
+ Iterator<Map.Entry<UUID, BossBar>> iter = bossbars.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry<UUID, BossBar> entry = iter.next();
+ Player player = Bukkit.getPlayer(entry.getKey());
+ if (player == null) {
+ iter.remove();
+ continue;
+ }
+ updateBossBar(entry.getValue(), player);
+ }
+ }
+
+ @Override
+ public void cancel() {
+ super.cancel();
+ new HashSet<>(this.bossbars.keySet()).forEach(uuid -> {
+ Player player = Bukkit.getPlayer(uuid);
+ if (player != null) {
+ removePlayer(player);
+ }
+ });
+ this.bossbars.clear();
+ }
+
+ public boolean removePlayer(Player player) {
+ BossBar bossbar = this.bossbars.remove(player.getUniqueId());
+ if (bossbar != null) {
+ player.hideBossBar(bossbar);
+ return true;
+ }
+ return false;
+ }
+
+ public void addPlayer(Player player) {
+ removePlayer(player);
+ BossBar bossbar = createBossBar();
+ this.bossbars.put(player.getUniqueId(), bossbar);
+ this.updateBossBar(bossbar, player);
+ player.showBossBar(bossbar);
+ }
+
+ public boolean hasPlayer(UUID uuid) {
+ return this.bossbars.containsKey(uuid);
+ }
+
+ public boolean togglePlayer(Player player) {
+ if (removePlayer(player)) {
+ return false;
+ }
+ addPlayer(player);
+ return true;
+ }
+
+ public void start() {
+ stop();
+ this.runTaskTimerAsynchronously(new MinecraftInternalPlugin(), 1, 1);
+ started = true;
+ }
+
+ public void stop() {
+ if (started) {
+ cancel();
+ }
+ }
+
+ public static void startAll() {
+ TPSBarTask.instance().start();
+ }
+
+ public static void stopAll() {
+ TPSBarTask.instance().stop();
+ }
+
+ public static void addToAll(ServerPlayer player) {
+ Player bukkit = player.getBukkitEntity();
+ if (player.tpsBar()) {
+ TPSBarTask.instance().addPlayer(bukkit);
+ }
+ }
+
+ public static void removeFromAll(Player player) {
+ TPSBarTask.instance().removePlayer(player);
+ }
+}
diff --git a/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java b/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..8769993e7ca59da309087051a3cd38fc562c15d1
--- /dev/null
+++ b/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java
@@ -0,0 +1,142 @@
+package org.purpurmc.purpur.task;
+
+import net.kyori.adventure.bossbar.BossBar;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
+import org.purpurmc.purpur.PurpurConfig;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class TPSBarTask extends BossBarTask {
+ private static TPSBarTask instance;
+ private double tps = 20.0D;
+ private double mspt = 0.0D;
+ private int tick = 0;
+
+ public static TPSBarTask instance() {
+ if (instance == null) {
+ instance = new TPSBarTask();
+ }
+ return instance;
+ }
+
+ @Override
+ BossBar createBossBar() {
+ return BossBar.bossBar(Component.text(""), 0.0F, instance().getBossBarColor(), PurpurConfig.commandTPSBarProgressOverlay);
+ }
+
+ @Override
+ void updateBossBar(BossBar bossbar, Player player) {
+ bossbar.progress(getBossBarProgress());
+ bossbar.color(getBossBarColor());
+ bossbar.name(MiniMessage.miniMessage().deserialize(PurpurConfig.commandTPSBarTitle,
+ Placeholder.component("tps", getTPSColor()),
+ Placeholder.component("mspt", getMSPTColor()),
+ Placeholder.component("ping", getPingColor(player.getPing()))
+ ));
+ }
+
+ @Override
+ public void run() {
+ if (++tick < PurpurConfig.commandTPSBarTickInterval) {
+ return;
+ }
+ tick = 0;
+
+ this.tps = Math.max(Math.min(Bukkit.getTPS()[0], 20.0D), 0.0D);
+ this.mspt = Bukkit.getAverageTickTime();
+
+ super.run();
+ }
+
+ private float getBossBarProgress() {
+ if (PurpurConfig.commandTPSBarProgressFillMode == FillMode.MSPT) {
+ return Math.max(Math.min((float) mspt / 50.0F, 1.0F), 0.0F);
+ } else {
+ return Math.max(Math.min((float) tps / 20.0F, 1.0F), 0.0F);
+ }
+ }
+
+ private BossBar.Color getBossBarColor() {
+ if (isGood(PurpurConfig.commandTPSBarProgressFillMode)) {
+ return PurpurConfig.commandTPSBarProgressColorGood;
+ } else if (isMedium(PurpurConfig.commandTPSBarProgressFillMode)) {
+ return PurpurConfig.commandTPSBarProgressColorMedium;
+ } else {
+ return PurpurConfig.commandTPSBarProgressColorLow;
+ }
+ }
+
+ private boolean isGood(FillMode mode) {
+ return isGood(mode, 0);
+ }
+
+ private boolean isGood(FillMode mode, int ping) {
+ if (mode == FillMode.MSPT) {
+ return mspt < 40;
+ } else if (mode == FillMode.TPS) {
+ return tps >= 19;
+ } else if (mode == FillMode.PING) {
+ return ping < 100;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isMedium(FillMode mode) {
+ return isMedium(mode, 0);
+ }
+
+ private boolean isMedium(FillMode mode, int ping) {
+ if (mode == FillMode.MSPT) {
+ return mspt < 50;
+ } else if (mode == FillMode.TPS) {
+ return tps >= 15;
+ } else if (mode == FillMode.PING) {
+ return ping < 200;
+ } else {
+ return false;
+ }
+ }
+
+ private Component getTPSColor() {
+ String color;
+ if (isGood(FillMode.TPS)) {
+ color = PurpurConfig.commandTPSBarTextColorGood;
+ } else if (isMedium(FillMode.TPS)) {
+ color = PurpurConfig.commandTPSBarTextColorMedium;
+ } else {
+ color = PurpurConfig.commandTPSBarTextColorLow;
+ }
+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%.2f", tps)));
+ }
+
+ private Component getMSPTColor() {
+ String color;
+ if (isGood(FillMode.MSPT)) {
+ color = PurpurConfig.commandTPSBarTextColorGood;
+ } else if (isMedium(FillMode.MSPT)) {
+ color = PurpurConfig.commandTPSBarTextColorMedium;
+ } else {
+ color = PurpurConfig.commandTPSBarTextColorLow;
+ }
+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%.2f", mspt)));
+ }
+
+ private Component getPingColor(int ping) {
+ String color;
+ if (isGood(FillMode.PING, ping)) {
+ color = PurpurConfig.commandTPSBarTextColorGood;
+ } else if (isMedium(FillMode.PING, ping)) {
+ color = PurpurConfig.commandTPSBarTextColorMedium;
+ } else {
+ color = PurpurConfig.commandTPSBarTextColorLow;
+ }
+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%s", ping)));
+ }
+
+ public enum FillMode {
+ TPS, MSPT, PING
+ }
+}