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 aee4004eef..b5f3ef0a73 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java @@ -17,6 +17,7 @@ import meteordevelopment.meteorclient.systems.friends.Friends; import meteordevelopment.meteorclient.systems.modules.Categories; import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.entity.EntityUtils; import meteordevelopment.meteorclient.utils.entity.fakeplayer.FakePlayerEntity; import meteordevelopment.meteorclient.utils.player.ChatUtils; import meteordevelopment.meteorclient.utils.player.PlayerUtils; @@ -39,6 +40,8 @@ import net.minecraft.util.math.Vec3d; import java.util.*; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import static meteordevelopment.meteorclient.utils.player.ChatUtils.formatCoords; @@ -79,6 +82,7 @@ public class Notifier extends Module { .name("ignore-own") .description("Ignores your own totem pops.") .defaultValue(false) + .visible(totemPops::get) .build() ); @@ -86,6 +90,7 @@ public class Notifier extends Module { .name("ignore-friends") .description("Ignores friends totem pops.") .defaultValue(false) + .visible(totemPops::get) .build() ); @@ -93,8 +98,27 @@ public class Notifier extends Module { .name("ignore-others") .description("Ignores other players totem pops.") .defaultValue(false) + .visible(totemPops::get) + .build() + ); + + private final Setting totemsFilterMode = sgTotemPops.add(new EnumSetting.Builder() + .name("filter-mode") + .description("Mode of the regex filter.") + .defaultValue(FilterMode.None) + .visible(totemPops::get) + .build() + ); + + private final Setting totemsFilterRegex = sgTotemPops.add(new StringSetting.Builder() + .name("filter-regex") + .description("Regex pattern for filtering player names.") + .defaultValue("^.+$") + .visible(() -> totemPops.get() && totemsFilterMode.get() != FilterMode.None) + .onChanged(s -> totemsFilterPattern = compileRegex(s)) .build() ); + private Pattern totemsFilterPattern = Pattern.compile("^.+$"); // Visual Range @@ -109,6 +133,7 @@ public class Notifier extends Module { .name("event") .description("When to log the entities.") .defaultValue(Event.Both) + .visible(visualRange::get) .build() ); @@ -116,6 +141,7 @@ public class Notifier extends Module { .name("entities") .description("Which entities to notify about.") .defaultValue(EntityType.PLAYER) + .visible(visualRange::get) .build() ); @@ -123,6 +149,7 @@ public class Notifier extends Module { .name("ignore-friends") .description("Ignores friends.") .defaultValue(true) + .visible(visualRange::get) .build() ); @@ -130,6 +157,7 @@ public class Notifier extends Module { .name("ignore-fake-players") .description("Ignores fake players.") .defaultValue(true) + .visible(visualRange::get) .build() ); @@ -137,8 +165,27 @@ public class Notifier extends Module { .name("sound") .description("Emits a sound effect on enter / leave") .defaultValue(true) + .visible(visualRange::get) + .build() + ); + + private final Setting visualRangeFilterMode = sgVisualRange.add(new EnumSetting.Builder() + .name("filter-mode") + .description("Mode of the regex filter.") + .defaultValue(FilterMode.None) + .visible(visualRange::get) + .build() + ); + + private final Setting visualRangeFilterRegex = sgVisualRange.add(new StringSetting.Builder() + .name("filter-regex") + .description("Regex pattern for filtering entity names.") + .defaultValue("^.+$") + .visible(() -> visualRange.get() && visualRangeFilterMode.get() != FilterMode.None) + .onChanged(s -> visualRangeFilterPattern = compileRegex(s)) .build() ); + private Pattern visualRangeFilterPattern = Pattern.compile("^.+$"); // Pearl @@ -153,6 +200,7 @@ public class Notifier extends Module { .name("ignore-own") .description("Ignores your own pearls.") .defaultValue(false) + .visible(pearl::get) .build() ); @@ -160,9 +208,28 @@ public class Notifier extends Module { .name("ignore-friends") .description("Ignores friends pearls.") .defaultValue(false) + .visible(pearl::get) .build() ); + private final Setting pearlFilterMode = sgPearl.add(new EnumSetting.Builder() + .name("filter-mode") + .description("Mode of the regex filter.") + .defaultValue(FilterMode.None) + .visible(pearl::get) + .build() + ); + + private final Setting pearlFilterRegex = sgPearl.add(new StringSetting.Builder() + .name("filter-regex") + .description("Regex pattern for filtering player names.") + .defaultValue("^.+$") + .visible(() -> pearl.get() && pearlFilterMode.get() != FilterMode.None) + .onChanged(s -> pearlFilterPattern = compileRegex(s)) + .build() + ); + private Pattern pearlFilterPattern = Pattern.compile("^.+$"); + // Joins/Leaves private final Setting joinsLeavesMode = sgJoinsLeaves.add(new EnumSetting.Builder() @@ -178,6 +245,7 @@ public class Notifier extends Module { .range(0, 1000) .sliderRange(0, 100) .defaultValue(0) + .visible(() -> joinsLeavesMode.get() != JoinLeaveModes.None) .build() ); @@ -185,9 +253,44 @@ public class Notifier extends Module { .name("simple-notifications") .description("Display join/leave notifications without a prefix, to reduce chat clutter.") .defaultValue(true) + .visible(() -> joinsLeavesMode.get() != JoinLeaveModes.None) + .build() + ); + + private final Setting joinsLeavesIgnoreFriends = sgJoinsLeaves.add(new BoolSetting.Builder() + .name("ignore-friends") + .description("Ignores friends joining/leaving.") + .defaultValue(false) + .visible(() -> joinsLeavesMode.get() != JoinLeaveModes.None) + .build() + ); + + private final Setting joinsLeavesIgnoreOthers = sgJoinsLeaves.add(new BoolSetting.Builder() + .name("ignore-others") + .description("Ignores non-friends joining/leaving.") + .defaultValue(false) + .visible(() -> joinsLeavesMode.get() != JoinLeaveModes.None) .build() ); + private final Setting joinsLeavesFilterMode = sgJoinsLeaves.add(new EnumSetting.Builder() + .name("filter-mode") + .description("Mode of the regex filter.") + .defaultValue(FilterMode.None) + .visible(() -> joinsLeavesMode.get() != JoinLeaveModes.None) + .build() + ); + + private final Setting joinsLeavesFilterRegex = sgJoinsLeaves.add(new StringSetting.Builder() + .name("filter-regex") + .description("Regex pattern for filtering player names.") + .defaultValue("^.+$") + .visible(() -> joinsLeavesMode.get() != JoinLeaveModes.None && joinsLeavesFilterMode.get() != FilterMode.None) + .onChanged(s -> joinsLeavesFilterPattern = compileRegex(s)) + .build() + ); + private Pattern joinsLeavesFilterPattern = Pattern.compile("^.+$"); + private int timer; private boolean loginPacket = true; private final Object2IntMap totemPopMap = new Object2IntOpenHashMap<>(); @@ -201,24 +304,57 @@ public Notifier() { super(Categories.Misc, "notifier", "Notifies you of different events."); } + private static Pattern compileRegex(String regex) { + try { + return Pattern.compile(regex); + } catch (PatternSyntaxException e) { + return null; + } + } + + private boolean shouldNotify(String name, FilterMode filterMode, Pattern filterPattern, boolean isOwn, boolean ignoreOwn, boolean isFriend, boolean ignoreFriends, boolean ignoreOthers) { + if (filterMode != FilterMode.None && filterPattern != null) { + boolean matches = filterPattern.matcher(name).matches(); + if (filterMode == FilterMode.AlwaysNotify && matches) return true; + if (filterMode == FilterMode.AlwaysIgnore && matches) return false; + } + + if (isOwn && ignoreOwn) return false; + if (isFriend && ignoreFriends) return false; + if (!isFriend && !isOwn && ignoreOthers) return false; + + return true; + } + // Visual Range @EventHandler private void onEntityAdded(EntityAddedEvent event) { if (!event.entity.getUuid().equals(mc.player.getUuid()) && entities.get().contains(event.entity.getType()) && visualRange.get() && this.event.get() != Event.Despawn) { - if (event.entity instanceof PlayerEntity) { - if ((!visualRangeIgnoreFriends.get() || !Friends.get().isFriend(((PlayerEntity) event.entity))) && (!visualRangeIgnoreFakes.get() || !(event.entity instanceof FakePlayerEntity))) { - ChatUtils.sendMsg(event.entity.getId() + 100, Formatting.GRAY, "(highlight)%s(default) has entered your visual range!", event.entity.getName().getString()); + if (event.entity instanceof PlayerEntity player) { + if (visualRangeIgnoreFakes.get() && (event.entity instanceof FakePlayerEntity || EntityUtils.getGameMode(player) == null)) return; + + String name = player.getName().getString(); + boolean isFriend = Friends.get().isFriend(player); + + if (shouldNotify(name, visualRangeFilterMode.get(), visualRangeFilterPattern, + false, false, isFriend, visualRangeIgnoreFriends.get(), false)) { + ChatUtils.sendMsg(event.entity.getId() + 100, Formatting.GRAY, "(highlight)%s(default) has entered your visual range!", name); if (visualMakeSound.get()) mc.world.playSoundFromEntity(mc.player, mc.player, SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.AMBIENT, 3.0F, 1.0F); } } else { - MutableText text = Text.literal(event.entity.getType().getName().getString()).formatted(Formatting.WHITE); - text.append(Text.literal(" has spawned at ").formatted(Formatting.GRAY)); - text.append(formatCoords(event.entity.getEntityPos())); - text.append(Text.literal(".").formatted(Formatting.GRAY)); - info(text); + String entityName = event.entity.getType().getName().getString(); + + if (shouldNotify(entityName, visualRangeFilterMode.get(), visualRangeFilterPattern, + false, false, false, false, false)) { + MutableText text = Text.literal(entityName).formatted(Formatting.WHITE); + text.append(Text.literal(" has spawned at ").formatted(Formatting.GRAY)); + text.append(formatCoords(event.entity.getEntityPos())); + text.append(Text.literal(".").formatted(Formatting.GRAY)); + info(text); + } } } @@ -230,19 +366,30 @@ private void onEntityAdded(EntityAddedEvent event) { @EventHandler private void onEntityRemoved(EntityRemovedEvent event) { if (!event.entity.getUuid().equals(mc.player.getUuid()) && entities.get().contains(event.entity.getType()) && visualRange.get() && this.event.get() != Event.Spawn) { - if (event.entity instanceof PlayerEntity) { - if ((!visualRangeIgnoreFriends.get() || !Friends.get().isFriend(((PlayerEntity) event.entity))) && (!visualRangeIgnoreFakes.get() || !(event.entity instanceof FakePlayerEntity))) { - ChatUtils.sendMsg(event.entity.getId() + 100, Formatting.GRAY, "(highlight)%s(default) has left your visual range!", event.entity.getName().getString()); + if (event.entity instanceof PlayerEntity player) { + if (visualRangeIgnoreFakes.get() && (event.entity instanceof FakePlayerEntity || EntityUtils.getGameMode(player) == null)) return; + + String name = player.getName().getString(); + boolean isFriend = Friends.get().isFriend(player); + + if (shouldNotify(name, visualRangeFilterMode.get(), visualRangeFilterPattern, + false, false, isFriend, visualRangeIgnoreFriends.get(), false)) { + ChatUtils.sendMsg(event.entity.getId() + 100, Formatting.GRAY, "(highlight)%s(default) has left your visual range!", name); if (visualMakeSound.get()) mc.world.playSoundFromEntity(mc.player, mc.player, SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.AMBIENT, 3.0F, 1.0F); } } else { - MutableText text = Text.literal(event.entity.getType().getName().getString()).formatted(Formatting.WHITE); - text.append(Text.literal(" has despawned at ").formatted(Formatting.GRAY)); - text.append(formatCoords(event.entity.getEntityPos())); - text.append(Text.literal(".").formatted(Formatting.GRAY)); - info(text); + String entityName = event.entity.getType().getName().getString(); + + if (shouldNotify(entityName, visualRangeFilterMode.get(), visualRangeFilterPattern, + false, false, false, false, false)) { + MutableText text = Text.literal(entityName).formatted(Formatting.WHITE); + text.append(Text.literal(" has despawned at ").formatted(Formatting.GRAY)); + text.append(formatCoords(event.entity.getEntityPos())); + text.append(Text.literal(".").formatted(Formatting.GRAY)); + info(text); + } } } @@ -250,11 +397,15 @@ private void onEntityRemoved(EntityRemovedEvent event) { Entity e = event.entity; int i = e.getId(); if (pearlStartPosMap.containsKey(i)) { - EnderPearlEntity pearl = (EnderPearlEntity) e; - if (pearl.getOwner() != null && pearl.getOwner() instanceof PlayerEntity p) { - double d = pearlStartPosMap.get(i).distanceTo(e.getEntityPos()); - if ((!Friends.get().isFriend(p) || !pearlIgnoreFriends.get()) && (!p.equals(mc.player) || !pearlIgnoreOwn.get())) { - info("(highlight)%s's(default) pearl landed at %d, %d, %d (highlight)(%.1fm away, travelled %.1fm)(default).", pearl.getOwner().getName().getString(), pearl.getBlockPos().getX(), pearl.getBlockPos().getY(), pearl.getBlockPos().getZ(), pearl.distanceTo(mc.player), d); + EnderPearlEntity pearlEntity = (EnderPearlEntity) e; + if (pearlEntity.getOwner() != null && pearlEntity.getOwner() instanceof PlayerEntity p) { + String ownerName = p.getName().getString(); + boolean isFriend = Friends.get().isFriend(p); + boolean isOwn = p.equals(mc.player); + + if (shouldNotify(ownerName, pearlFilterMode.get(), pearlFilterPattern, isOwn, pearlIgnoreOwn.get(), isFriend, pearlIgnoreFriends.get(), false)) { + double d = pearlStartPosMap.get(i).distanceTo(e.getEntityPos()); + info("(highlight)%s's(default) pearl landed at %d, %d, %d (highlight)(%.1fm away, travelled %.1fm)(default).", ownerName, pearlEntity.getBlockPos().getX(), pearlEntity.getBlockPos().getY(), pearlEntity.getBlockPos().getZ(), pearlEntity.distanceTo(mc.player), d); } } pearlStartPosMap.remove(i); @@ -308,10 +459,14 @@ private void onReceivePacket(PacketEvent.Receive event) { createLeaveNotification(packet); case EntityStatusS2CPacket packet when totemPops.get() && packet.getStatus() == EntityStatuses.USE_TOTEM_OF_UNDYING && 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; + String name = entity.getName().getString(); + boolean isFriend = Friends.get().isFriend(entity); + boolean isOwn = entity.equals(mc.player); + + if (!shouldNotify(name, totemsFilterMode.get(), totemsFilterPattern, + isOwn, totemsIgnoreOwn.get(), isFriend, totemsIgnoreFriends.get(), totemsIgnoreOthers.get())) { + return; + } synchronized (totemPopMap) { int pops = totemPopMap.getOrDefault(entity.getUuid(), 0); @@ -320,7 +475,7 @@ private void onReceivePacket(PacketEvent.Receive event) { 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.", name, pops, pops == 1 ? "totem" : "totems"); } } default -> {} @@ -364,19 +519,22 @@ private void createJoinNotifications(PlayerListS2CPacket packet) { for (PlayerListS2CPacket.Entry entry : packet.getPlayerAdditionEntries()) { if (entry.profile() == null) continue; + String name = entry.profile().name(); + boolean isFriend = Friends.get().get(name) != null; + + if (!shouldNotify(name, joinsLeavesFilterMode.get(), joinsLeavesFilterPattern, + false, false, isFriend, joinsLeavesIgnoreFriends.get(), joinsLeavesIgnoreOthers.get())) { + continue; + } + if (simpleNotifications.get()) { - messageQueue.addLast(Text.literal( - Formatting.GRAY + "[" - + Formatting.GREEN + "+" - + Formatting.GRAY + "] " - + entry.profile().name() - )); + messageQueue.addLast(Text.literal("[").formatted(Formatting.GRAY) + .append(Text.literal("+").formatted(Formatting.GREEN)) + .append(Text.literal("] ").formatted(Formatting.GRAY)) + .append(Text.literal(name).formatted(Formatting.WHITE))); } else { - messageQueue.addLast(Text.literal( - Formatting.WHITE - + entry.profile().name() - + Formatting.GRAY + " joined." - )); + messageQueue.addLast(Text.literal(name).formatted(Formatting.WHITE) + .append(Text.literal(" joined.").formatted(Formatting.GRAY))); } } } @@ -388,19 +546,22 @@ private void createLeaveNotification(PlayerRemoveS2CPacket packet) { PlayerListEntry toRemove = mc.getNetworkHandler().getPlayerListEntry(id); if (toRemove == null) continue; + String name = toRemove.getProfile().name(); + boolean isFriend = Friends.get().get(name) != null; + + if (!shouldNotify(name, joinsLeavesFilterMode.get(), joinsLeavesFilterPattern, + false, false, isFriend, joinsLeavesIgnoreFriends.get(), joinsLeavesIgnoreOthers.get())) { + continue; + } + if (simpleNotifications.get()) { - messageQueue.addLast(Text.literal( - Formatting.GRAY + "[" - + Formatting.RED + "-" - + Formatting.GRAY + "] " - + toRemove.getProfile().name() - )); + messageQueue.addLast(Text.literal("[").formatted(Formatting.GRAY) + .append(Text.literal("-").formatted(Formatting.RED)) + .append(Text.literal("] ").formatted(Formatting.GRAY)) + .append(Text.literal(name).formatted(Formatting.WHITE))); } else { - messageQueue.addLast(Text.literal( - Formatting.WHITE - + toRemove.getProfile().name() - + Formatting.GRAY + " left." - )); + messageQueue.addLast(Text.literal(name).formatted(Formatting.WHITE) + .append(Text.literal(" left.").formatted(Formatting.GRAY))); } } } @@ -414,4 +575,10 @@ public enum Event { public enum JoinLeaveModes { None, Joins, Leaves, Both } + + public enum FilterMode { + None, + AlwaysIgnore, + AlwaysNotify + } }