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 = "TPS: MSPT: 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 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 toRemove = new ArrayList<>(); + + for (Map.Entry 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 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>"; + 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>"; + 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>"; + 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 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());