diff --git a/src/main/java/me/chayapak1/chomensbot_mabe/Bot.java b/src/main/java/me/chayapak1/chomensbot_mabe/Bot.java index a0d3d03..9b9311d 100644 --- a/src/main/java/me/chayapak1/chomensbot_mabe/Bot.java +++ b/src/main/java/me/chayapak1/chomensbot_mabe/Bot.java @@ -39,6 +39,7 @@ public class Bot { @Getter private final ChatCommandHandlerPlugin chatCommandHandler; @Getter private final HashingPlugin hashing; @Getter private final MusicPlayerPlugin music; + @Getter private final TPSPlugin tps; public Bot (String host, int port, String _username, List allBots, Configuration config) { this.host = host; @@ -55,6 +56,7 @@ public class Bot { this.chatCommandHandler = new ChatCommandHandlerPlugin(this); this.hashing = new HashingPlugin(this); this.music = new MusicPlayerPlugin(this); + this.tps = new TPSPlugin(this); reconnect(); } @@ -124,7 +126,7 @@ public class Bot { public void run() { reconnect(); } - }, reconnectDelay, 1); + }, 1, reconnectDelay); } }); diff --git a/src/main/java/me/chayapak1/chomensbot_mabe/commands/TPSBarCommand.java b/src/main/java/me/chayapak1/chomensbot_mabe/commands/TPSBarCommand.java new file mode 100644 index 0000000..01fdc88 --- /dev/null +++ b/src/main/java/me/chayapak1/chomensbot_mabe/commands/TPSBarCommand.java @@ -0,0 +1,64 @@ +package me.chayapak1.chomensbot_mabe.commands; + +import me.chayapak1.chomensbot_mabe.Bot; +import me.chayapak1.chomensbot_mabe.command.Command; +import me.chayapak1.chomensbot_mabe.command.CommandContext; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; + +import java.util.ArrayList; +import java.util.List; + +public class TPSBarCommand implements Command { + public String name() { return "tpsbar"; } + + public String description() { + return "Shows the server's TPS using Minecraft Bossbar"; + } + + public List usage() { + final List usages = new ArrayList<>(); + usages.add(""); + + return usages; + } + + public List alias() { + final List aliases = new ArrayList<>(); + aliases.add("tps"); + + return aliases; + } + + public int trustLevel() { + return 0; + } + + public Component execute(CommandContext context, String[] args, String[] fullArgs) { + final Bot bot = context.bot(); + + switch (args[0]) { + case "on" -> { + bot.tps().on(); + context.sendOutput( + Component.empty() + .append(Component.text("TPSBar is now ")) + .append(Component.text("enabled").color(NamedTextColor.GREEN)) + ); + } + case "off" -> { + bot.tps().off(); + context.sendOutput( + Component.empty() + .append(Component.text("TPSBar is now ")) + .append(Component.text("disabled").color(NamedTextColor.RED)) + ); + } + default -> { + return Component.text("Invalid argument").color(NamedTextColor.RED); + } + } + + return Component.text("success"); + } +} diff --git a/src/main/java/me/chayapak1/chomensbot_mabe/plugins/CommandHandlerPlugin.java b/src/main/java/me/chayapak1/chomensbot_mabe/plugins/CommandHandlerPlugin.java index 2c41364..93036e1 100644 --- a/src/main/java/me/chayapak1/chomensbot_mabe/plugins/CommandHandlerPlugin.java +++ b/src/main/java/me/chayapak1/chomensbot_mabe/plugins/CommandHandlerPlugin.java @@ -30,6 +30,7 @@ public class CommandHandlerPlugin { registerCommand(new MusicCommand()); registerCommand(new RandomTeleportCommand()); registerCommand(new BotVisibilityCommand()); + registerCommand(new TPSBarCommand()); } public void registerCommand (Command command) { diff --git a/src/main/java/me/chayapak1/chomensbot_mabe/plugins/MusicPlayerPlugin.java b/src/main/java/me/chayapak1/chomensbot_mabe/plugins/MusicPlayerPlugin.java index c2fb7e8..d3f4471 100644 --- a/src/main/java/me/chayapak1/chomensbot_mabe/plugins/MusicPlayerPlugin.java +++ b/src/main/java/me/chayapak1/chomensbot_mabe/plugins/MusicPlayerPlugin.java @@ -114,6 +114,7 @@ public class MusicPlayerPlugin extends SessionAdapter { bot.core().run("minecraft:bossbar set " + bossbarName + " name " + GsonComponentSerializer.gson().serialize(generateBossbar())); bot.core().run("minecraft:bossbar set " + bossbarName + " color yellow"); bot.core().run("minecraft:bossbar set " + bossbarName + " visible true"); + bot.core().run("minecraft:bossbar set " + bossbarName + " style progress"); bot.core().run("minecraft:bossbar set " + bossbarName + " value " + (int) Math.floor(currentSong.time)); bot.core().run("minecraft:bossbar set " + bossbarName + " max " + currentSong.length); diff --git a/src/main/java/me/chayapak1/chomensbot_mabe/plugins/TPSPlugin.java b/src/main/java/me/chayapak1/chomensbot_mabe/plugins/TPSPlugin.java new file mode 100644 index 0000000..5198aeb --- /dev/null +++ b/src/main/java/me/chayapak1/chomensbot_mabe/plugins/TPSPlugin.java @@ -0,0 +1,108 @@ +package me.chayapak1.chomensbot_mabe.plugins; + +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket; +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSetTimePacket; +import com.github.steveice10.packetlib.Session; +import com.github.steveice10.packetlib.event.session.SessionAdapter; +import com.github.steveice10.packetlib.packet.Packet; +import me.chayapak1.chomensbot_mabe.Bot; +import me.chayapak1.chomensbot_mabe.util.NumberUtilities; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; + +import java.util.Arrays; +import java.util.Timer; +import java.util.TimerTask; + +public class TPSPlugin extends SessionAdapter { + private final Bot bot; + + private boolean enabled = false; + + private final float[] tickRates = new float[20]; + private int nextIndex = 0; + private long timeLastTimeUpdate = -1; + private long timeGameJoined; + + private final String bossbarName = "chomens_bot:tpsbar"; + + public TPSPlugin (Bot bot) { + this.bot = bot; + + bot.addListener(this); + + final Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + updateTPSBar(); + } + }, 1, 50); + } + + public void on () { + enabled = true; + } + + public void off () { + enabled = false; + bot.core().run("minecraft:bossbar remove " + bossbarName); + } + + private void updateTPSBar () { + if (!enabled) return; + + final float floatTickRate = getTickRate(); + final double tickRate = Math.round(floatTickRate); + + final Component component = Component.translatable( + "TPS - %s", + Component.text(tickRate).color(NamedTextColor.GREEN) + ).color(NamedTextColor.GRAY); + + // TODO: move these to like a bossbar manager of some sort + bot.core().run("minecraft:bossbar add " + bossbarName + " \"\""); + bot.core().run("minecraft:bossbar set " + bossbarName + " players @a"); + bot.core().run("minecraft:bossbar set " + bossbarName + " name " + GsonComponentSerializer.gson().serialize(component)); + bot.core().run("minecraft:bossbar set " + bossbarName + " color yellow"); + bot.core().run("minecraft:bossbar set " + bossbarName + " visible true"); + bot.core().run("minecraft:bossbar set " + bossbarName + " style progress"); + bot.core().run("minecraft:bossbar set " + bossbarName + " value " + (int) tickRate); + bot.core().run("minecraft:bossbar set " + bossbarName + " max 20"); + } + + @Override + public void packetReceived (Session session, Packet packet) { + if (packet instanceof ClientboundSetTimePacket) packetReceived((ClientboundSetTimePacket) packet); + else if (packet instanceof ClientboundLoginPacket) packetReceived((ClientboundLoginPacket) packet); + } + + public void packetReceived (ClientboundSetTimePacket ignoredPacket) { + long now = System.currentTimeMillis(); + float timeElapsed = (float) (now - timeLastTimeUpdate) / 1000.0F; + tickRates[nextIndex] = NumberUtilities.clamp(20.0f / timeElapsed, 0.0f, 20.0f); + nextIndex = (nextIndex + 1) % tickRates.length; + timeLastTimeUpdate = now; + } + + public void packetReceived (ClientboundLoginPacket ignoredPacket) { + Arrays.fill(tickRates, 0); + nextIndex = 0; + timeGameJoined = timeLastTimeUpdate = System.currentTimeMillis(); + } + + public float getTickRate() { + if (System.currentTimeMillis() - timeGameJoined < 4000) return 20; + + int numTicks = 0; + float sumTickRates = 0.0f; + for (float tickRate : tickRates) { + if (tickRate > 0) { + sumTickRates += tickRate; + numTicks++; + } + } + return sumTickRates / numTicks; + } +} diff --git a/src/main/java/me/chayapak1/chomensbot_mabe/util/NumberUtilities.java b/src/main/java/me/chayapak1/chomensbot_mabe/util/NumberUtilities.java index 2a3500e..3a9eafc 100644 --- a/src/main/java/me/chayapak1/chomensbot_mabe/util/NumberUtilities.java +++ b/src/main/java/me/chayapak1/chomensbot_mabe/util/NumberUtilities.java @@ -6,4 +6,9 @@ public class NumberUtilities { Math.random() * (max - min) + min ); } + + public static float clamp (float value, float min, float max) { + if (value < min) return min; + return Math.min(value, max); + } }