From 829a42982c56dc4563a8feaa7be3e23b47ee5001 Mon Sep 17 00:00:00 2001 From: sqlerrorthing <148702857+sqlerrorthing@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:18:03 +0800 Subject: [PATCH] feat(BetterTab): PlayerHider & Highlight others (#5123) --- .../minecraft/gui/MixinPlayerListHud.java | 17 +++++- .../module/modules/misc/ModuleBetterTab.kt | 54 ++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/gui/MixinPlayerListHud.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/gui/MixinPlayerListHud.java index 9ddb6642faa..103712e580b 100644 --- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/gui/MixinPlayerListHud.java +++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/gui/MixinPlayerListHud.java @@ -62,14 +62,19 @@ private long hookTabSize(long count) { private Stream hookSort(Stream instance, Comparator defaultComparator, Operation> original) { var sorting = ModuleBetterTab.INSTANCE.getSorting(); - boolean running = ModuleBetterTab.INSTANCE.getRunning(); + var betterTab = ModuleBetterTab.INSTANCE; + var running = betterTab.getRunning(); var customComparator = sorting.getComparator(); var comparator = running ? (customComparator != null ? customComparator : defaultComparator) : defaultComparator; - return original.call(instance, comparator); + var playerHider = ModuleBetterTab.PlayerHider.INSTANCE; + var hided = running && playerHider.getRunning() + ? instance.filter(player -> !playerHider.getFilter().isInFilter(player)) : instance; + + return original.call(hided, comparator); } @ModifyExpressionValue(method = "render", at = @At( @@ -188,6 +193,14 @@ private void hookRenderPlayerBackground(Args args, @Local(ordinal = 13) int w, @ if (highlight.getFriends().getRunning()) { if (FriendManager.INSTANCE.isFriend(entry.getProfile().getName())) { args.set(4, highlight.getFriends().getColor().toARGB()); + return; + } + } + + var others = highlight.getOthers(); + if (others.getRunning()) { + if (others.getFilter().isInFilter(entry)) { + args.set(4, others.getColor().toARGB()); } } } diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/misc/ModuleBetterTab.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/misc/ModuleBetterTab.kt index 62ad7954513..712670080d1 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/misc/ModuleBetterTab.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/misc/ModuleBetterTab.kt @@ -23,6 +23,7 @@ object ModuleBetterTab : ClientModule("BetterTab", Category.MISC) { Visibility, Highlight, AccurateLatency, + PlayerHider ) } @@ -40,17 +41,68 @@ object ModuleBetterTab : ClientModule("BetterTab", Category.MISC) { } object Highlight : ToggleableConfigurable(ModuleBetterTab, "Highlight", true) { - class HighlightColored(name: String, color: Color4b) : ToggleableConfigurable(this, name, true) { + open class HighlightColored( + name: String, + color: Color4b + ) : ToggleableConfigurable(this, name, true) { val color by color("Color", color) } + class Others(color: Color4b) : HighlightColored("Others", color) { + val filter = tree(PlayerFilter()) + } + val self = tree(HighlightColored("Self", Color4b(50, 193, 50, 80))) val friends = tree(HighlightColored("Friends", Color4b(16, 89, 203, 80))) + val others = tree(Others(Color4b(35, 35, 35, 80))) } object AccurateLatency : ToggleableConfigurable(ModuleBetterTab, "AccurateLatency", true) { val suffix by boolean("AppendMSSuffix", true) } + + object PlayerHider : ToggleableConfigurable(ModuleBetterTab, "PlayerHider", false) { + val filter = tree(PlayerFilter()) + } +} + +class PlayerFilter: Configurable("Filter") { + private var filters = setOf() + + private val filterType by enumChoice("FilterBy", Filter.BOTH) + + @Suppress("unused") + private val names by textArray("Names", mutableListOf()).onChanged { newValue -> + filters = newValue.mapTo(HashSet(newValue.size, 1.0F)) { + val regexPattern = it + .replace("*", ".*") + .replace("?", ".") + + Regex("^$regexPattern\$") + } + } + + fun isInFilter(entry: PlayerListEntry) = filters.any { regex -> + filterType.matches(entry, regex) + } + + @Suppress("unused") + private enum class Filter( + override val choiceName: String, + val matches: PlayerListEntry.(Regex) -> Boolean + ) : NamedChoice { + BOTH("Both", { regex -> + DISPLAY_NAME.matches(this, regex) || PLAYER_NAME.matches(this, regex) + }), + + DISPLAY_NAME("DisplayName", { regex -> + this.displayName?.string?.let { regex.matches(it) } ?: false + }), + + PLAYER_NAME("PlayerName", { regex -> + regex.matches(this.profile.name) + }) + } } @Suppress("unused")