Files
LuminolMC/patches/server/0015-Add-a-simple-tpsbar.patch
2023-12-20 20:05:38 +08:00

393 lines
17 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: M2ke4U <79621885+MrHua269@users.noreply.github.com>
Date: Sun, 26 Nov 2023 15:19:16 +0800
Subject: [PATCH] Add a simple tpsbar
diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java
index 90a6cfd011aaefe66fda79f887380ab2d62a07b1..0657fce8aabb956a400b3cead53c28ef52e67fe9 100644
--- a/src/main/java/me/earthme/luminol/LuminolConfig.java
+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java
@@ -2,11 +2,15 @@ package me.earthme.luminol;
import dev.kaiijumc.kaiiju.region.RegionFileFormat;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
+import me.earthme.luminol.commands.TpsBarCommand;
+import me.earthme.luminol.functions.GlobalServerTpsBar;
import net.minecraft.server.level.ServerLevel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.bukkit.Bukkit;
import java.util.Arrays;
+import java.util.List;
import java.util.logging.Level;
import java.io.File;
import java.io.IOException;
@@ -20,6 +24,10 @@ public class LuminolConfig {
public static String serverModName = "Luminol";
public static boolean fakeVanillaModeEnabled = false;
public static boolean disableChatSign = false;
+ public static boolean tpsbarEnabled = false;
+ public static String tpsBarFormat = "<gray>TPS<yellow>:</yellow> <tps> MSPT<yellow>:</yellow> <mspt> Ping<yellow>:</yellow> <ping>ms";
+ public static String[] tpsColors = new String[]{"GREEN","YELLOW","RED","PURPLE"};
+ public static String[] pingColors = new String[]{"GREEN","YELLOW","RED","PURPLE"};
public static boolean safeTeleportation = true;
public static boolean enableSandDuping = false;
@@ -46,10 +54,25 @@ public class LuminolConfig {
MAIN_CONFIG.save();
}
+ public static void initTpsbar(){
+ if (tpsbarEnabled){
+ GlobalServerTpsBar.init();
+ Bukkit.getCommandMap().register("tpsbar","luminol",new TpsBarCommand("tpsbar"));
+ }
+ }
+
public static void initValues(){
serverModName = get("misc.server_mod_name",serverModName,"The servermod name will be sent to players,and you can see it in F3 or motd responses");
fakeVanillaModeEnabled = get("misc.enable_fake_vanilla_mode",fakeVanillaModeEnabled,"Enable this to make the ping response of your server like a vanilla server");
disableChatSign = get("misc.disable_chat_sign",disableChatSign,"Set this to true to disable mojang's chat sign");
+ tpsbarEnabled = get("misc.enable_tpsbar",tpsbarEnabled,"When this enabled,You or your players can see the tps,mspt and ping through a simple bossbar");
+ tpsBarFormat = get("misc.tpsbar_title_format",tpsBarFormat,"The format of tpsbar.");
+ tpsColors = get("misc.tpsbar_range_colors", List.of(tpsColors),"The bar and text color of each tps ranges.The last is the color of initial bar's color").toArray(String[]::new);
+ pingColors = get("misc.tpsbar_ping_range_colors",List.of(pingColors),"As same as the tpsColors").toArray(String[]::new);
+
+ if (tpsbarEnabled){
+ initTpsbar();
+ }
safeTeleportation = get("fixes.enable_safe_teleportation",safeTeleportation,"If this enabled,the end portals will not teleport removed entities.");
enableSandDuping = get("fixes.enable_sand_duping",enableSandDuping,"If this enabled,The value of safe teleportation will always be false and sand duping will be enabled");
diff --git a/src/main/java/me/earthme/luminol/commands/TpsBarCommand.java b/src/main/java/me/earthme/luminol/commands/TpsBarCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..ac8f0e3bf130ba6dfd7202e2f480352218154cdc
--- /dev/null
+++ b/src/main/java/me/earthme/luminol/commands/TpsBarCommand.java
@@ -0,0 +1,40 @@
+package me.earthme.luminol.commands;
+
+import me.earthme.luminol.functions.GlobalServerTpsBar;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+public class TpsBarCommand extends Command {
+ public TpsBarCommand(@NotNull String name) {
+ super(name);
+ this.setPermission("luminol.commands.tpsbar");
+ this.setDescription("Show the tps and mspt through a bossbar");
+ this.setUsage("/tpsbar");
+ }
+
+ @Override
+ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
+ if (!testPermission(sender)){
+ return true;
+ }
+
+ if (!(sender instanceof Player player)){
+ sender.sendMessage(ChatColor.RED+"Only player can use this command!");
+ return true;
+ }
+
+ if (GlobalServerTpsBar.isPlayerVisible(player)) {
+ player.sendMessage(ChatColor.BLUE + "Disabled tps bar");
+ GlobalServerTpsBar.setVisibilityForPlayer(player,false);
+ return true;
+ }
+
+ player.sendMessage(ChatColor.GREEN + "Enabled tps bar");
+ GlobalServerTpsBar.setVisibilityForPlayer(player,true);
+
+ return true;
+ }
+}
diff --git a/src/main/java/me/earthme/luminol/functions/GlobalServerTpsBar.java b/src/main/java/me/earthme/luminol/functions/GlobalServerTpsBar.java
new file mode 100644
index 0000000000000000000000000000000000000000..baec715e0c20e920ccb99f2f07d84fcb6f2b434e
--- /dev/null
+++ b/src/main/java/me/earthme/luminol/functions/GlobalServerTpsBar.java
@@ -0,0 +1,204 @@
+package me.earthme.luminol.functions;
+
+import com.google.common.collect.Lists;
+import io.papermc.paper.threadedregions.ThreadedRegionizer;
+import io.papermc.paper.threadedregions.TickData;
+import io.papermc.paper.threadedregions.TickRegions;
+import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
+import me.earthme.luminol.LuminolConfig;
+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 net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+public class GlobalServerTpsBar {
+ protected static final MinecraftInternalPlugin NULL_PLUGIN = new MinecraftInternalPlugin();
+ protected static final Map<UUID,BossBar> uuid2Bossbars = new HashMap<>();
+ protected static volatile ScheduledTask tpsbarTask = null;
+
+ public static void init(){
+ Bukkit.getAsyncScheduler().runAtFixedRate(NULL_PLUGIN,c -> {
+ tpsbarTask = c;
+ try {
+ update();
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ },1,1, TimeUnit.SECONDS);
+ }
+
+ public static void cancelBarUpdateTask(){
+ if (tpsbarTask == null){
+ return;
+ }
+
+ tpsbarTask.cancel();
+ }
+
+ public static boolean isPlayerVisible(Player player){
+ return ((CraftPlayer) player).getHandle().isTpsBarVisible;
+ }
+
+ public static void setVisibilityForPlayer(Player target,boolean canSee){
+ ((CraftPlayer) target).getHandle().isTpsBarVisible = canSee;
+ }
+
+ private static void update(){
+ updateBarValues();
+ cleanUpPlayers();
+ }
+
+ private static void cleanUpPlayers(){
+ final List<UUID> toRemove = new ArrayList<>();
+
+ for (Map.Entry<UUID,BossBar> bossBarEntry : uuid2Bossbars.entrySet()){
+ final UUID uuid = bossBarEntry.getKey();
+ boolean shouldRemove = true;
+
+ final Player target = Bukkit.getPlayer(uuid);
+ if (target != null){
+ shouldRemove = !isPlayerVisible(target);
+ }
+
+ if (shouldRemove){
+ toRemove.add(uuid);
+ }
+ }
+
+ for (UUID uuid : toRemove){
+ final BossBar removed = uuid2Bossbars.remove(uuid);
+ if (removed != null){
+ final Player targetPlayer = Bukkit.getPlayer(uuid);
+ if (targetPlayer != null){
+ targetPlayer.hideBossBar(removed);
+ }
+ }
+ }
+ }
+
+ private static void updateBarValues(){
+ for (Player apiPlayer : Bukkit.getOnlinePlayers()){
+ final ServerPlayer nmsPlayer = ((CraftPlayer) apiPlayer).getHandle();
+ final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region = ((ServerLevel) nmsPlayer.level()).regioniser.getRegionAtUnsynchronised(nmsPlayer.sectionX,nmsPlayer.sectionZ);
+
+ if (region == null){
+ continue;
+ }
+
+ final TickData.TickReportData reportData = region.getData().getRegionSchedulingHandle().getTickReport5s(System.nanoTime());
+
+ BossBar targetBossbar = uuid2Bossbars.get(nmsPlayer.getUUID());
+
+ if (targetBossbar == null && isPlayerVisible(apiPlayer)){
+ targetBossbar = BossBar.bossBar(Component.text(""),0.0F, BossBar.Color.valueOf(LuminolConfig.tpsColors[3]), BossBar.Overlay.NOTCHED_20);
+ uuid2Bossbars.put(nmsPlayer.getUUID(),targetBossbar);
+ apiPlayer.showBossBar(targetBossbar);
+ }
+
+ if (reportData != null && targetBossbar != null){
+ final TickData.SegmentData tpsData = reportData.tpsData().segmentAll();
+ final double mspt = reportData.timePerTickData().segmentAll().average() / 1.0E6;
+ updateTpsBar(tpsData.average(),mspt,targetBossbar,apiPlayer);
+ }
+ }
+ }
+
+ private static void updateTpsBar(double tps, double mspt, @NotNull BossBar bar, @NotNull Player player){
+ bar.name(MiniMessage.miniMessage().deserialize(
+ LuminolConfig.tpsBarFormat,
+ Placeholder.component("tps",getTpsComponent(tps)),
+ Placeholder.component("mspt",getMsptComponent(mspt)),
+ Placeholder.component("ping",getPingComponent(player.getPing()))
+ ));
+ bar.color(barColorFromTps(tps));
+ bar.progress((float) Math.min((float)1,Math.max(mspt / 50,0)));
+ }
+
+ private static @NotNull Component getPingComponent(int ping){
+ final BossBar.Color colorBukkit = barColorFromPing(ping);
+ final String colorString = colorBukkit.name();
+
+ final String content = "<%s><text></%s>";
+ final String replaced = String.format(content,colorString,colorString);
+
+ return MiniMessage.miniMessage().deserialize(replaced,Placeholder.parsed("text", String.valueOf(ping)));
+ }
+
+ private static BossBar.Color barColorFromPing(int ping){
+ if (ping == -1){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[3]);
+ }
+
+ if (ping <= 80){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[0]);
+ }
+
+ if (ping <= 160){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[1]);
+ }
+
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[2]);
+ }
+
+ private static @NotNull Component getMsptComponent(double mspt){
+ final BossBar.Color colorBukkit = barColorFromMspt(mspt);
+ final String colorString = colorBukkit.name();
+
+ final String content = "<%s><text></%s>";
+ final String replaced = String.format(content,colorString,colorString);
+
+ return MiniMessage.miniMessage().deserialize(replaced,Placeholder.parsed("text", String.format("%.2f", mspt)));
+ }
+
+ private static BossBar.Color barColorFromMspt(double mspt){
+ if (mspt == -1){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[3]);
+ }
+
+ if (mspt <= 25){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[0]);
+ }
+
+ if (mspt <= 50){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[1]);
+ }
+
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[2]);
+ }
+
+ private static @NotNull Component getTpsComponent(double tps){
+ final BossBar.Color colorBukkit = barColorFromTps(tps);
+ final String colorString = colorBukkit.name();
+
+ final String content = "<%s><text></%s>";
+ final String replaced = String.format(content,colorString,colorString);
+
+ return MiniMessage.miniMessage().deserialize(replaced,Placeholder.parsed("text", String.format("%.2f", tps)));
+ }
+
+ private static BossBar.Color barColorFromTps(double tps){
+ if (tps == -1){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[3]);
+ }
+
+ if (tps >= 18){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[0]);
+ }
+
+ if (tps >= 15){
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[1]);
+ }
+
+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[2]);
+ }
+}
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index f0bf57a7acd77eeffbeeb6743ba58166823022fd..4a1e068c27853a38db0641806626e7ac740bd8de 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -1,20 +1,16 @@
package net.minecraft.server.dedicated;
-import com.google.common.collect.Lists;
+import me.earthme.luminol.functions.GlobalServerTpsBar;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.DataFixer;
import com.mojang.logging.LogUtils;
-import java.io.BufferedReader;
+
import java.io.BufferedWriter;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Proxy;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.Collections;
-import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.BooleanSupplier;
@@ -829,6 +825,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@Override
public void stopServer() {
+ GlobalServerTpsBar.cancelBarUpdateTask(); //Luminol - Tpsbar
super.stopServer();
//Util.shutdownExecutors(); // Paper - moved into super
SkullBlockEntity.clear();
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 97bfb92e52c3c5ef1cd22afe2b97c204eb45025a..d7a280427442bac8cc8ccb542d24d4e0901df70a 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -278,6 +278,7 @@ public class ServerPlayer extends Player {
// Paper start - replace player chunk loader
private final java.util.concurrent.atomic.AtomicReference<io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances> viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1));
public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader;
+ public volatile boolean isTpsBarVisible = false;
public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances getViewDistances() {
return this.viewDistances.get();
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 6c8f6e26687b557fcdcd65c657d8b35d3fde805e..06c92a2d3ecb3b747c2303819f72c1c41967af8c 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2216,6 +2216,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
handle.expToDrop = data.getInt("expToDrop");
handle.keepLevel = data.getBoolean("keepLevel");
}
+
+ //Luminol start - Tpsbar
+ getHandle().isTpsBarVisible = data.getBoolean("tpsbarVisible");
+ //Luminol end
}
}
@@ -2237,6 +2241,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
data.putLong("lastPlayed", System.currentTimeMillis());
data.putString("lastKnownName", handle.getScoreboardName());
+ //Luminol start - Tpsbar
+ data.putBoolean("tpsbarVisible",handle.isTpsBarVisible);
+ //Luminol end
+
// Paper start - persist for use in offline save data
if (!nbttagcompound.contains("Paper")) {
nbttagcompound.put("Paper", new CompoundTag());