From 42fb9083c306fd7ba4fdf8348e5729a7e5243782 Mon Sep 17 00:00:00 2001 From: Tas <103238549+0xTas@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:34:07 -0700 Subject: [PATCH] Add player join/leave messages to Notifier (#4952) Co-authored-by: Wide_Cat --- .../systems/modules/misc/Notifier.java | 159 +++++++++++++++--- 1 file changed, 137 insertions(+), 22 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java index 1388450438..063a03dc51 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java @@ -10,6 +10,7 @@ import meteordevelopment.meteorclient.events.entity.EntityAddedEvent; import meteordevelopment.meteorclient.events.entity.EntityRemovedEvent; import meteordevelopment.meteorclient.events.game.GameJoinedEvent; +import meteordevelopment.meteorclient.events.game.GameLeftEvent; import meteordevelopment.meteorclient.events.packets.PacketEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.settings.*; @@ -20,16 +21,20 @@ import meteordevelopment.meteorclient.utils.player.ChatUtils; import meteordevelopment.meteorclient.utils.player.PlayerUtils; import meteordevelopment.orbit.EventHandler; +import net.minecraft.client.network.PlayerListEntry; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.thrown.EnderPearlEntity; import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import net.minecraft.util.collection.ArrayListDeque; import net.minecraft.util.math.Vec3d; import java.util.*; @@ -40,6 +45,7 @@ public class Notifier extends Module { private final SettingGroup sgTotemPops = settings.createGroup("Totem Pops"); private final SettingGroup sgVisualRange = settings.createGroup("Visual Range"); private final SettingGroup sgPearl = settings.createGroup("Pearl"); + private final SettingGroup sgJoinsLeaves = settings.createGroup("Joins/Leaves"); // Totem Pops @@ -156,9 +162,37 @@ public class Notifier extends Module { .build() ); + // Joins/Leaves + + private final Setting joinsLeavesMode = sgJoinsLeaves.add(new EnumSetting.Builder() + .name("player-joins-leaves") + .description("How to handle player join/leave notifications.") + .defaultValue(JoinLeaveModes.None) + .build() + ); + + private final Setting notificationDelay = sgJoinsLeaves.add(new IntSetting.Builder() + .name("notification-delay") + .description("How long to wait in ticks before posting the next join/leave notification in your chat.") + .range(0, 1000) + .sliderRange(0, 100) + .defaultValue(0) + .build() + ); + + private final Setting simpleNotifications = sgJoinsLeaves.add(new BoolSetting.Builder() + .name("simple-notifications") + .description("Display join/leave notifications without a prefix, to reduce chat clutter.") + .defaultValue(true) + .build() + ); + + private int timer; + private boolean loginPacket = true; private final Object2IntMap totemPopMap = new Object2IntOpenHashMap<>(); private final Object2IntMap chatIdMap = new Object2IntOpenHashMap<>(); private final Map pearlStartPosMap = new HashMap<>(); + private final ArrayListDeque messageQueue = new ArrayListDeque<>(); private final Random random = new Random(); @@ -187,10 +221,8 @@ private void onEntityAdded(EntityAddedEvent event) { } } - if (pearl.get()) { - if (event.entity instanceof EnderPearlEntity pearl) { - pearlStartPosMap.put(pearl.getId(), new Vec3d(pearl.getX(), pearl.getY(), pearl.getZ())); - } + if (pearl.get() && event.entity instanceof EnderPearlEntity pearlEntity) { + pearlStartPosMap.put(pearlEntity.getId(), new Vec3d(pearlEntity.getX(), pearlEntity.getY(), pearlEntity.getZ())); } } @@ -229,7 +261,7 @@ private void onEntityRemoved(EntityRemovedEvent event) { } } - // Totem Pops + // Totem Pops && Joins/Leaves @Override public void onActivate() { @@ -238,42 +270,76 @@ public void onActivate() { pearlStartPosMap.clear(); } + @Override + public void onDeactivate() { + timer = 0; + messageQueue.clear(); + } + @EventHandler private void onGameJoin(GameJoinedEvent event) { + timer = 0; totemPopMap.clear(); chatIdMap.clear(); + messageQueue.clear(); pearlStartPosMap.clear(); } @EventHandler - private void onReceivePacket(PacketEvent.Receive event) { - if (!totemPops.get()) return; - if (!(event.packet instanceof EntityStatusS2CPacket p)) return; - - if (p.getStatus() != 35) return; + private void onGameLeave(GameLeftEvent event) { + loginPacket = true; + } - Entity entity = p.getEntity(mc.world); + @EventHandler + private void onReceivePacket(PacketEvent.Receive event) { + switch (event.packet) { + case PlayerListS2CPacket packet when joinsLeavesMode.get().equals(JoinLeaveModes.Both) || joinsLeavesMode.get().equals(JoinLeaveModes.Joins) -> { + if (loginPacket) { + loginPacket = false; + return; + } - if (!(entity instanceof PlayerEntity)) return; + if (packet.getActions().contains(PlayerListS2CPacket.Action.ADD_PLAYER)) { + createJoinNotifications(packet); + } + } + case PlayerRemoveS2CPacket packet when joinsLeavesMode.get().equals(JoinLeaveModes.Both) || joinsLeavesMode.get().equals(JoinLeaveModes.Leaves) -> + createLeaveNotification(packet); - if ((entity.equals(mc.player) && totemsIgnoreOwn.get()) - || (Friends.get().isFriend(((PlayerEntity) entity)) && totemsIgnoreOthers.get()) - || (!Friends.get().isFriend(((PlayerEntity) entity)) && totemsIgnoreFriends.get()) - ) return; + case EntityStatusS2CPacket packet when totemPops.get() && packet.getStatus() == 35 && packet.getEntity(mc.world) instanceof PlayerEntity entity -> { + if ((entity.equals(mc.player) && totemsIgnoreOwn.get()) + || (Friends.get().isFriend(entity) && totemsIgnoreOthers.get()) + || (!Friends.get().isFriend(entity) && totemsIgnoreFriends.get()) + ) return; - synchronized (totemPopMap) { - int pops = totemPopMap.getOrDefault(entity.getUuid(), 0); - totemPopMap.put(entity.getUuid(), ++pops); + synchronized (totemPopMap) { + int pops = totemPopMap.getOrDefault(entity.getUuid(), 0); + totemPopMap.put(entity.getUuid(), ++pops); - double distance = PlayerUtils.distanceTo(entity); - if (totemsDistanceCheck.get() && distance > totemsDistance.get()) return; + double distance = PlayerUtils.distanceTo(entity); + if (totemsDistanceCheck.get() && distance > totemsDistance.get()) return; - ChatUtils.sendMsg(getChatId(entity), Formatting.GRAY, "(highlight)%s (default)popped (highlight)%d (default)%s.", entity.getName().getString(), pops, pops == 1 ? "totem" : "totems"); + ChatUtils.sendMsg(getChatId(entity), Formatting.GRAY, "(highlight)%s (default)popped (highlight)%d (default)%s.", entity.getName().getString(), pops, pops == 1 ? "totem" : "totems"); + } + } + default -> {} } } @EventHandler private void onTick(TickEvent.Post event) { + if (joinsLeavesMode.get() != JoinLeaveModes.None) { + timer++; + while (timer >= notificationDelay.get() && !messageQueue.isEmpty()) { + timer = 0; + if (simpleNotifications.get()) { + mc.player.sendMessage(messageQueue.removeFirst()); + } else { + ChatUtils.sendMsg(messageQueue.removeFirst()); + } + } + } + if (!totemPops.get()) return; synchronized (totemPopMap) { for (PlayerEntity player : mc.world.getPlayers()) { @@ -293,9 +359,58 @@ private int getChatId(Entity entity) { return chatIdMap.computeIfAbsent(entity.getUuid(), value -> random.nextInt()); } + private void createJoinNotifications(PlayerListS2CPacket packet) { + for (PlayerListS2CPacket.Entry entry : packet.getPlayerAdditionEntries()) { + if (entry.profile() == null) continue; + + if (simpleNotifications.get()) { + messageQueue.addLast(Text.literal( + Formatting.GRAY + "[" + + Formatting.GREEN + "+" + + Formatting.GRAY + "] " + + entry.profile().getName() + )); + } else { + messageQueue.addLast(Text.literal( + Formatting.WHITE + + entry.profile().getName() + + Formatting.GRAY + " joined." + )); + } + } + } + + private void createLeaveNotification(PlayerRemoveS2CPacket packet) { + if (mc.getNetworkHandler() == null) return; + + for (UUID id : packet.profileIds()) { + PlayerListEntry toRemove = mc.getNetworkHandler().getPlayerListEntry(id); + if (toRemove == null) continue; + + if (simpleNotifications.get()) { + messageQueue.addLast(Text.literal( + Formatting.GRAY + "[" + + Formatting.RED + "-" + + Formatting.GRAY + "] " + + toRemove.getProfile().getName() + )); + } else { + messageQueue.addLast(Text.literal( + Formatting.WHITE + + toRemove.getProfile().getName() + + Formatting.GRAY + " left." + )); + } + } + } + public enum Event { Spawn, Despawn, Both } + + public enum JoinLeaveModes { + None, Joins, Leaves, Both + } }