Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Nextgen/BetterTab) #5077

Merged
merged 4 commits into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,180 @@
*/
package net.ccbluex.liquidbounce.injection.mixins.minecraft.gui;

import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.ref.LocalIntRef;
import net.ccbluex.liquidbounce.features.misc.FriendManager;
import net.ccbluex.liquidbounce.features.module.modules.misc.ModuleAntiStaff;
import net.ccbluex.liquidbounce.features.module.modules.misc.ModuleBetterTab;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.PlayerListHud;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.util.math.MathHelper;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;

import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

@Mixin(PlayerListHud.class)
public class MixinPlayerListHud {
public abstract class MixinPlayerListHud {

@Shadow
protected abstract List<PlayerListEntry> collectPlayerEntries();

@ModifyConstant(constant = @Constant(longValue = 80L), method = "collectPlayerEntries")
private long hookTabSize(long count) {
return ModuleBetterTab.INSTANCE.getRunning() ?
ModuleBetterTab.Limits.INSTANCE.getTabSize() : count;
}

@WrapOperation(method = "collectPlayerEntries", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;sorted(Ljava/util/Comparator;)Ljava/util/stream/Stream;"))
private Stream<PlayerListEntry> hookSort(Stream<PlayerListEntry> instance, Comparator<PlayerListEntry> defaultComparator, Operation<Stream<PlayerListEntry>> original) {
var sorting = ModuleBetterTab.INSTANCE.getSorting();

boolean running = ModuleBetterTab.INSTANCE.getRunning();
var customComparator = sorting.getComparator();

var comparator = running
? (customComparator != null ? customComparator : defaultComparator)
: defaultComparator;

return original.call(instance, comparator);
}

@ModifyExpressionValue(method = "render", at = @At(
value = "FIELD",
target = "Lnet/minecraft/client/gui/hud/PlayerListHud;header:Lnet/minecraft/text/Text;",
ordinal = 0
))
private Text hookHeader(Text original) {
if (!ModuleBetterTab.INSTANCE.getRunning()) {
return original;
}

return ModuleBetterTab.Visibility.INSTANCE.getHeader() ?
original : null;
}

@ModifyExpressionValue(method = "render", at = @At(
value = "FIELD",
target = "Lnet/minecraft/client/gui/hud/PlayerListHud;footer:Lnet/minecraft/text/Text;",
ordinal = 0
))
private Text hookFooter(Text original) {
if (!ModuleBetterTab.INSTANCE.getRunning()) {
return original;
}

return ModuleBetterTab.Visibility.INSTANCE.getFooter() ?
original : null;
}

@ModifyExpressionValue(method = "render", at = @At(
value = "FIELD",
target = "Lnet/minecraft/client/gui/hud/PlayerListHud$ScoreDisplayEntry;name:Lnet/minecraft/text/Text;"
))
private Text hookVisibilityName(Text original, @Local(ordinal = 0) PlayerListEntry entry) {
if (!ModuleBetterTab.INSTANCE.getRunning()) {
return original;
}

return ModuleBetterTab.Visibility.INSTANCE.getNameOnly() ?
Text.of(entry.getProfile().getName()) : original;

}

@ModifyExpressionValue(method = "render", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/gui/hud/PlayerListHud;getPlayerName(Lnet/minecraft/client/network/PlayerListEntry;)Lnet/minecraft/text/Text;"
))
private Text hookWidthVisibilityName(Text original, @Local(ordinal = 0) PlayerListEntry entry) {
if (!ModuleBetterTab.INSTANCE.getRunning()) {
return original;
}

return ModuleBetterTab.Visibility.INSTANCE.getNameOnly() ?
Text.of(entry.getProfile().getName()) : original;
}

@Inject(method = "render", at = @At(value = "INVOKE", target = "Ljava/lang/Math;min(II)I", shift = At.Shift.BEFORE))
private void hookTabColumnHeight(CallbackInfo ci, @Local(ordinal = 5) LocalIntRef o, @Local(ordinal = 6)LocalIntRef p) {
if (!ModuleBetterTab.INSTANCE.getRunning()) {
return;
}

int totalPlayers = collectPlayerEntries().size();
int columns = 1;
int rows = totalPlayers;

while (rows > ModuleBetterTab.Limits.INSTANCE.getHeight()) {
columns++;
rows = (totalPlayers + columns - 1) / columns;
}

o.set(rows);
p.set(columns);
}

@ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Ljava/lang/Math;min(II)I"), index = 0)
private int hookWidth(int width) {
return ModuleBetterTab.INSTANCE.getRunning() && ModuleBetterTab.AccurateLatency.INSTANCE.getRunning() ? width + 30 : width;
}

@Inject(method = "renderLatencyIcon", at = @At("HEAD"), cancellable = true)
private void hookOnRenderLatencyIcon(DrawContext context, int width, int x, int y, PlayerListEntry entry, CallbackInfo ci) {
var accurateLatency = ModuleBetterTab.AccurateLatency.INSTANCE;
if (ModuleBetterTab.INSTANCE.getRunning() && accurateLatency.getRunning()) {
TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;

int latency = MathHelper.clamp(entry.getLatency(), 0, 9999);
int color = latency < 150 ? 0x00E970 : latency < 300 ? 0xE7D020 : 0xD74238;
String text = latency + (accurateLatency.getSuffix() ? "ms" : "");
context.drawTextWithShadow(textRenderer, text, x + width - textRenderer.getWidth(text), y, color);
ci.cancel();
}
}

@ModifyArgs(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;fill(IIIII)V", ordinal = 2))
private void hookRenderPlayerBackground(Args args, @Local(ordinal = 13) int w, @Local(ordinal = 0) List<PlayerListEntry> entries) {
if (!ModuleBetterTab.INSTANCE.getRunning()) {
return;
}

var highlight = ModuleBetterTab.Highlight.INSTANCE;
if (!highlight.getRunning()) {
return;
}

if (w < entries.size()) {
var entry = entries.get(w);
if (highlight.getSelf().getRunning()) {
if (Objects.equals(entry.getProfile().getName(), MinecraftClient.getInstance().player.getGameProfile().getName())) {
args.set(4, highlight.getSelf().getColor().toARGB());
return;
}
}

if (highlight.getFriends().getRunning()) {
if (FriendManager.INSTANCE.isFriend(entry.getProfile().getName())) {
args.set(4, highlight.getFriends().getColor().toARGB());
}
}
}
}

@ModifyReturnValue(method = "getPlayerName", at = @At("RETURN"))
private Text modifyPlayerName(Text original, PlayerListEntry entry) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ import net.ccbluex.liquidbounce.features.module.modules.client.ModuleRichPresenc
import net.ccbluex.liquidbounce.features.module.modules.client.ModuleTargets
import net.ccbluex.liquidbounce.features.module.modules.combat.*
import net.ccbluex.liquidbounce.features.module.modules.combat.aimbot.ModuleAutoBow
import net.ccbluex.liquidbounce.features.module.modules.combat.aimbot.ModuleDroneControl
import net.ccbluex.liquidbounce.features.module.modules.combat.aimbot.ModuleProjectileAimbot
import net.ccbluex.liquidbounce.features.module.modules.combat.autoarmor.ModuleAutoArmor
import net.ccbluex.liquidbounce.features.module.modules.combat.criticals.ModuleCriticals
import net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura.ModuleCrystalAura
Expand Down Expand Up @@ -216,6 +214,7 @@ object ModuleManager : EventListener, Iterable<ClientModule> by modules {

// Misc
ModuleAntiBot,
ModuleBetterTab,
ModuleBetterChat,
ModuleMiddleClickAction,
ModuleInventoryTracker,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package net.ccbluex.liquidbounce.features.module.modules.misc

import net.ccbluex.liquidbounce.config.types.Configurable
import net.ccbluex.liquidbounce.config.types.NamedChoice
import net.ccbluex.liquidbounce.config.types.ToggleableConfigurable
import net.ccbluex.liquidbounce.features.module.Category
import net.ccbluex.liquidbounce.features.module.ClientModule
import net.ccbluex.liquidbounce.render.engine.Color4b
import net.minecraft.client.network.PlayerListEntry
import net.minecraft.text.Text

/**
* ModuleBetterTab
*
* @author sqlerrorthing
* @since 12/28/2024
**/
object ModuleBetterTab : ClientModule("BetterTab", Category.MISC) {

init {
treeAll(
Limits,
Visibility,
Highlight,
AccurateLatency,
)
}

val sorting by enumChoice("Sorting", Sorting.VANILLA)

object Limits : Configurable("Limits") {
val tabSize by int("TabSize", 80, 1..1000)
val height by int("ColumnHeight", 20, 1..100)
}

object Visibility : Configurable("Visibility") {
val header by boolean("Header", true)
val footer by boolean("Footer", true)
val nameOnly by boolean("NameOnly", false)
}

object Highlight : ToggleableConfigurable(ModuleBetterTab, "Highlight", true) {
class HighlightColored(name: String, color: Color4b) : ToggleableConfigurable(this, name, true) {
sqlerrorthing marked this conversation as resolved.
Show resolved Hide resolved
val color by color("Color", color)
}

val self = tree(HighlightColored("Self", Color4b(50, 193, 50, 80)))
val friends = tree(HighlightColored("Friends", Color4b(16, 89, 203, 80)))
}

object AccurateLatency : ToggleableConfigurable(ModuleBetterTab, "AccurateLatency", true) {
val suffix by boolean("AppendMSSuffix", true)
}
}

@Suppress("unused")
enum class Sorting(
override val choiceName: String,
val comparator: Comparator<PlayerListEntry>?
) : NamedChoice {
VANILLA("Vanilla", null),
PING("Ping", Comparator.comparingInt { it.latency }),
LENGTH("NameLength", Comparator.comparingInt { it.profile.name.length }),
SCORE_LENGTH("DisplayNameLength", Comparator.comparingInt { (it.displayName ?: Text.empty()).string.length }),
ALPHABETICAL("Alphabetical", Comparator.comparing { it.profile.name }),
REVERSE_ALPHABETICAL("ReverseAlphabetical", Comparator.comparing({ it.profile.name }, Comparator.reverseOrder())),
NONE("None", { _, _ -> 0 })
}


1 change: 1 addition & 0 deletions src/main/resources/assets/liquidbounce/lang/de_de.json
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@
"liquidbounce.module.autoPearl.description": "Zielt und wirft automatisch eine Enderperle auf die Flugbahn der feindlichen Enderperle.",
"liquidbounce.module.holeFiller.description": "Füllt automatisch sichere Orte mit Blöcken für Crystal PvP.",
"liquidbounce.module.itemChams.description": "Wendet visuelle Effekte auf Gegenstände in deiner Hand an.",
"liquidbounce.module.betterTab.description": "Verschiedene Verbesserungen an der Tab-Liste.",
"liquidbounce.module.itemTags.description": "Zeigt Bilder und Mengenangaben fallengelassener Gegenstände an.",
"liquidbounce.module.baritone.description": "Einstellungen für Baritone."
}
1 change: 1 addition & 0 deletions src/main/resources/assets/liquidbounce/lang/en_pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -434,5 +434,6 @@
"liquidbounce.command.script.subcommand.edit.result.opened": "Opened script named %s.",
"liquidbounce.liquidchat.authenticationFailed": "Authentication failed! LiquidChat requires Minecraft premium account.",
"liquidbounce.module.autoBalls.description": "Automatically throws snowballs at your enemies.",
"liquidbounce.module.betterTab.description": "Multiple enhancements to the tab list.",
"liquidbounce.module.autoPearl.description": "Mira e lança uma pérola na trajetória da pérola inimiga."
}
1 change: 1 addition & 0 deletions src/main/resources/assets/liquidbounce/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -618,5 +618,6 @@
"liquidbounce.module.packetMine.description": "Allows you to mine blocks by clicking them once.",
"liquidbounce.module.fastExp.description": "Automatically repairs your armor.",
"liquidbounce.module.itemChams.description": "Applies visual effects to your held items.",
"liquidbounce.module.betterTab.description": "Multiple improvements to the tab list.",
"liquidbounce.module.autoPearl.description": "Aims and throws a pearl at an enemies pearl trajectory."
}
3 changes: 2 additions & 1 deletion src/main/resources/assets/liquidbounce/lang/ja_jp.json
Original file line number Diff line number Diff line change
Expand Up @@ -500,5 +500,6 @@
"liquidbounce.module.xRay.description": "選択したブロックのみをレンダリングします。",
"liquidbounce.module.zoot.description": "すべての悪い効果/火を取り除きます。",
"modmenu.descriptionTranslation.liquidbounce": "無料でオープンソースのハッククライアント",
"liquidbounce.module.autoPearl.description": "敵の真珠の軌道に向けて真珠を狙い投げる."
"liquidbounce.module.betterTab.description": "タブリストに複数の改良を加えました。",
"liquidbounce.module.autoPearl.description": "敵の真珠の軌道に向けて真珠を狙い投げる."
}
1 change: 1 addition & 0 deletions src/main/resources/assets/liquidbounce/lang/pt_br.json
Original file line number Diff line number Diff line change
Expand Up @@ -501,5 +501,6 @@
"liquidbounce.module.autoFish.value.castDelay.description": "Atraso de lançamento.",
"liquidbounce.module.autoFish.value.reelDelay.description": "Atraso de recolhimento.",
"liquidbounce.module.autoFish.value.recastDelay.description": "Atraso de novo lançamento.",
"liquidbounce.module.betterTab.description": "Diversas melhorias na lista de abas.",
"liquidbounce.module.autoPearl.description": "Mira e lança uma pérola na trajetória da pérola inimiga."
}
1 change: 1 addition & 0 deletions src/main/resources/assets/liquidbounce/lang/ru_ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -622,5 +622,6 @@
"liquidbounce.module.tpAura.description": "Автоматически телепортирует и атакует врагов вокруг.",
"liquidbounce.module.packetMine.description": "Позволяет добывать блоки, щелкая по ним один раз.",
"liquidbounce.module.fastExp.description": "Автоматически чинит вашу броню.",
"liquidbounce.module.betterTab.description": "Различные улучшения в таб-листе.",
"liquidbounce.module.autoPearl.description": "Прицеливается и бросает пёрл по траектории движения вражеского пёрла."
}
1 change: 1 addition & 0 deletions src/main/resources/assets/liquidbounce/lang/ua_ua.json
Original file line number Diff line number Diff line change
Expand Up @@ -505,5 +505,6 @@
"liquidbounce.module.autoShop.description": "Опис автоматичного магазину",
"liquidbounce.module.autoShop.messages.reloadSuccess": "Перезавантаження успішне",
"liquidbounce.module.autoShop.messages.loadError": "Помилка завантаження",
"liquidbounce.module.betterTab.description": "Різноманітні покращення списку вкладок.",
"liquidbounce.module.autoPearl.description": "Прицілюється та кидає перлину по траєкторії ворожої перлини."
}
1 change: 1 addition & 0 deletions src/main/resources/assets/liquidbounce/lang/zh_cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -617,5 +617,6 @@
"liquidbounce.module.surround.description": "自动在周围建造安全方块,保护你免受爆炸伤害。",
"liquidbounce.module.packetMine.description": "使你能通过单次点击破坏方块。",
"liquidbounce.module.fastExp.description": "自动用经验瓶修复你的装备。",
"liquidbounce.module.betterTab.description": "对标签列表进行了多项改进。",
"liquidbounce.module.autoPearl.description": "瞄准并向敌方珍珠的轨迹投掷一颗珍珠。"
}
Loading