From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Sat, 2 Mar 2024 18:22:15 -0500 Subject: [PATCH] Improve Purpur AFK system TODO - Dreeam: Configurable afk title time AFK command & command cooldown AFK title message diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java index c0bd91b1cab7066f9582d2c734f61ee50e76098d..13d066f4d0c115445b807db22d365ad14926b734 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -250,6 +250,7 @@ public class Commands { StopCommand.register(this.dispatcher); TransferCommand.register(this.dispatcher); WhitelistCommand.register(this.dispatcher); + org.purpurmc.purpur.command.AFKCommand.register(this.dispatcher); // Purpur 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 diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 3bbb3b5444976c859d7f357aa4283947b45f3100..cc9f8e8f871b64028351e4d061b7f01d1b9ca0be 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -2369,6 +2369,8 @@ public class ServerPlayer extends Player { // Purpur Start private boolean isAfk = false; + public boolean isCommandAfk = false; + public boolean commandAfkStatus = false; @Override public void setAfk(boolean afk) { @@ -2406,6 +2408,9 @@ public class ServerPlayer extends Player { String prefix = (split.length > 0 ? split[0] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix, ""); String suffix = (split.length > 1 ? split[1] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, ""); if (afk) { + net.kyori.adventure.title.Title tile = net.kyori.adventure.title.Title.title(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.afkTitleAway), net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.afkSubTitleAway), net.kyori.adventure.title.Title.Times.times(net.kyori.adventure.util.Ticks.duration(10), net.kyori.adventure.util.Ticks.duration(70), net.kyori.adventure.util.Ticks.duration(20))); + getBukkitEntity().showTitle(tile); + getBukkitEntity().setPlayerListName(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix + prefix + scoreboardName + suffix + org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, true); } else { getBukkitEntity().setPlayerListName(prefix + scoreboardName + suffix, true); diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index cc9c30b8555e0509162a82c4a01de9fc51ba59af..7830e21dce33ad389441227d728750606dcd3c56 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -2254,8 +2254,34 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl } } + private final Map cooldown = new java.util.concurrent.ConcurrentHashMap<>(); // Purpur + @Override public void handleChatCommand(ServerboundChatCommandPacket packet) { + // Purpur start + if (this.server.getPlayerIdleTimeout() > 0 && packet.command().equals("afk")) { + player.commandAfkStatus = player.isAfk(); + player.isCommandAfk = true; + if (org.purpurmc.purpur.PurpurConfig.afkCommandCooldown > 0) { + UUID uuid = player.getUUID(); + long currentTime = System.nanoTime(); + if (cooldown.containsKey(uuid) && (currentTime - cooldown.get(uuid)) / 1000000000 <= org.purpurmc.purpur.PurpurConfig.afkCommandCooldown) { + String msg = org.purpurmc.purpur.PurpurConfig.afkCooldown; + if (msg != null && !msg.isEmpty()) + player.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(msg.replace("%time%", String.valueOf(org.purpurmc.purpur.PurpurConfig.afkCommandCooldown - (currentTime - cooldown.get(uuid)) / 1000000000)))); + return; + } else { + cooldown.put(uuid, currentTime); + } + // Dreeam - is this necessary? + /* + if (cooldown.size() > 200) { + cooldown = new java.util.concurrent.ConcurrentHashMap<>(); + } + */ + } + } + // Purpur end this.tryHandleChat(packet.command(), () -> { // CraftBukkit start - SPIGOT-7346: Prevent disconnected players from executing commands if (this.player.hasDisconnected()) { diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java index 276e605eae9034a19a382c36df04fcef8b7e3d9f..fef833511a749593d4ecf4ec82f940855ace1598 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java @@ -176,9 +176,13 @@ public class PurpurConfig { public static String cannotRideMob = "You cannot mount that mob"; public static String afkBroadcastAway = "%s is now AFK"; public static String afkBroadcastBack = "%s is no longer AFK"; + public static String afkTitleAway = "AFK"; + public static String afkSubTitleAway = "You are now AFK..."; public static boolean afkBroadcastUseDisplayName = false; public static String afkTabListPrefix = "[AFK] "; public static String afkTabListSuffix = ""; + public static int afkCommandCooldown = 0; + public static String afkCooldown = "You need to wait %time%s to use /afk."; public static String creditsCommandOutput = "%s has been shown the end credits"; public static String demoCommandOutput = "%s has been shown the demo screen"; public static String pingCommandOutput = "%s's ping is %sms"; @@ -195,9 +199,13 @@ public class PurpurConfig { cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); + afkTitleAway = getString("settings.messages.afk-title-away", afkTitleAway); + afkSubTitleAway = getString("settings.messages.afk-sub-title-away", afkSubTitleAway); afkBroadcastUseDisplayName = getBoolean("settings.messages.afk-broadcast-use-display-name", afkBroadcastUseDisplayName); afkTabListPrefix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix))); afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix))); + afkCommandCooldown = getInt("settings.messages.afk-command-cooldown", afkCommandCooldown); + afkCooldown = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-command-cooldown-msg", afkCooldown))); creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput); demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput); pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); diff --git a/src/main/java/org/purpurmc/purpur/command/AFKCommand.java b/src/main/java/org/purpurmc/purpur/command/AFKCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..8dca966c25f8e3f5622ef8f5862fdb43eae3813f --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/command/AFKCommand.java @@ -0,0 +1,34 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.server.level.ServerPlayer; + +import java.util.Collection; +import java.util.Collections; + +public class AFKCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("afk") + .requires((listener) -> listener.hasPermission(2, "bukkit.command.afk")) + .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) + .then(Commands.argument("targets", EntityArgument.players()) + .requires(listener -> listener.hasPermission(2, "bukkit.command.afk.other")) + .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) + ) + ); + } + + private static int execute(CommandSourceStack sender, Collection targets) { + for (ServerPlayer player : targets) { + boolean afk = player.isCommandAfk ? !player.commandAfkStatus : !player.isAfk(); + if (afk) { + player.setAfk(true); + } + player.isCommandAfk = false; + } + return targets.size(); + } +}