chore(history): squash 100 commit(s) from 2026-09-24

- fix(backend): case-insensitive unique email, revoke PUBLIC schema access, pin Argon2id params
- test(backend): assert password length cap boundary (256 ok, 257 rejected)
- docs(backend): plan — typed JWT token kinds so refresh/device tokens cannot pass as access tokens
- feat(backend): JWT access/refresh token issue and verify
- feat(backend): accounts repository (create/find_by_email/find_by_id)
- refactor(gui): LoVisualAddonManagerScreen 989→10 файлов addon/ (8.5.2)
- docs(backend): plan — fix sqlx::migrate! path in integration tests
- feat(backend): POST /auth/register and /auth/login
- refactor(settings): SettingsPanelComponent 715→81 + 6 helpers (8.5.2)
- docs(backend): plan — harden device flow (single-use codes, bounded store, 404/429)
- feat(backend): OAuth device authorization grant for mod login
- fix(backend): first confirm wins for device codes
- docs(backend): plan — split Task 8 (refactor) and Task 9 (avatars), harden avatar handling
- refactor(mixins): LocalPlayerMixin 691→111 + 4 handlers (8.5.2)
- refactor(visuals): Trails 687→130 (8.5.2)
- refactor(render): ItemBatchRenderer 677->100 (8.5.2)
- refactor(visuals): ReimaginedVisual 674→118 + 5 helpers (8.5.2)
- refactor(config): ConfigSerializer 668→91 + 4 helpers (8.5.2)
- refactor(hud): DynamicIsland 661→158 + 4 helpers (8.5.2)
- refactor(render): GlStencilFramebufferSupport 666→169 (8.5.2)
- refactor(gui): MenuScreen 669→128 + 4 helpers (8.5.2)
- refactor(render): UiStyle 644→170 + 3 helpers (8.5.2)
- refactor(gui): ModuleComponent 613→98 + 4 helpers (8.5.2)
- refactor(media): MediaSessionService 616→200 + 4 helpers (8.5.2)
- refactor(gui): RelationsComponent 661→59 + 4 helpers (8.5.2)
- chore(license): strip GPL file headers from all Java sources
- refactor(aiming): PointTracker 583→168 + 2 helpers (8.5.2)
- refactor(gui): LoVisualProxyManagerScreen 591→132 + 2 helpers (8.5.2)
- refactor(visuals): KillEffect 588→96 + 4 helpers (8.5.2)
- refactor(render): MeshBuilder +4 helpers (8.5.2)
- refactor(visuals): extract WorldParticlesRender helper (8.5.2)
- refactor(world): ExplosionDamageUtil 551→116 + 2 helpers (8.5.2)
- refactor(visuals): TazikHat 596->179 + Model + Palette in hats/tazik (8.5.2)
- chore(license): strip GPL header from remaining 30 files and make strip script variant-aware
- refactor(gui): ThemeComponent 561->166 + CardRenderer + ScrollState (8.5.2)
- refactor(hud): CustomHotbar 556→178 + Renderer + Selection + SelectionGradient (8.5.2)
- refactor(gui): ThemeCardRenderer perf + readability polish
- refactor(clickgui): CooldownRulesSetting 596->198 + Editor + DetailRenderer (8.5.2)
- refactor(hud): HudNotifier 561->200 + Painter + runtime/HudNotifierRuntime (8.5.2)
- refactor(theme): Themes 555->168 + impl/Transition + impl/Blending + impl/ProfileCodec (8.5.2)
- refactor(theme): EditableClickGuiTheme 205->185 + JavaDoc (8.5.2)
- refactor(theme): ThemeStore 491->128 + store/ThemeStoreJson + store/ThemeStoreIO (8.5.2)
- refactor(clickgui): ClickGuiRenderer 604->200 compacted one-line delegators + JavaDoc (8.5.2)
- refactor(mainmenu): LoVisualMainMenuScreen 551->161 + impl/Painter + impl/Renderer + impl/TextUtil (8.5.2)
- refactor(clickgui): ClickGuiTextEditorState 531->187 + impl/EditorCaret + impl/EditorPainter (8.5.2)
- refactor(tab): TabListModel 525->139 + model/Collector + model/Reader + model/Signature + model/TextSplitter (8.5.2)
- refactor(backend): shared bearer helper and test helpers, build_app takes Config, validate JWT secret strength
- refactor(module): ModuleManager 521->198 + impl/Registrar + impl/Dispatcher (8.5.2)
- feat(backend): avatar upload with decode, square crop, PNG re-encode and S3 storage
- refactor(clip): ClipFunction 512->146 + impl/Geometry + impl/Debug (8.5.2)
- docs(backend): implementation plans for gateway (auth hardening, gRPC, rate limits) and configs-service
- refactor(iris-patch): ShaderPatchEngine 499->146 + impl/Repo (8.5.2)
- chore(frontend): add router, react-query, fonts and vitest; dev proxy to gateway
- refactor(hud): ScriptedListHudPanel 499->158 + panel/Props + panel/Signature (8.5.2)
- refactor(hud): BaseHudElement 499->199 + impl/Registry + impl/Namer + impl/Prewarm (8.5.2)
- refactor(clickgui): Setting 498->170 + impl/Localization + impl/I18n (8.5.2)
- refact(viewmodel): split swing animations into camera/swing package
- refact(kineticlyrics): split module into stage, playback and modes
- rename(holeesp): module HoleESP -> CrystalHoles
- refact(crystalholes): split module into crystal scanner, renderer and safety
- refact(addonmanager): split manager into lifecycle, runtime, descriptors and profiles
- refact(accountconfig): split config into store, session and value helpers
- refactor(render): CustomTextRenderer 229->195, extract glyph-pass into GradientTexts helper
- docs(TODO): mark AddonManager split done; close 9.2 refactor gate
- refactor(media): LinuxMediaSession 441->148, split reader + track/seek state
- refactor(nametags): split NameTags into facade + impl helpers
- refactor(clickgui): split MainSettingsComponent into facade + scroll + model
- refactor(hud): split CustomBar into facade, model and BarSettings
- docs(frontend): implementation plan with design system from the mod theme
- feat(frontend): design tokens from the mod theme, fonts and shared UI kit
- fix(accounts): run migrations on startup, offload Argon2, validate register input, JSON error shape
- docs(gateway): plan note on splitting auth handlers before refresh endpoints
- feat(frontend): API client with silent refresh, error descriptions and test helpers
- style(mod): group compact one-line bulk query methods in ModuleManager
- feat(frontend): session restore, login and registration with client-side validation
- refactor(hud): split CustomHealthBar into facade + painter + script renderer
- docs(mod): record the 2026-09-24 HUD/settings split wave in TODO phase 8.5
- refactor(rhi): split GlStencilShapeClipBackend into facade + native-state + pass-lifecycle helpers
- refactor(rhi): split VulkanRenderStateBridge into facade + MSAA and stencil state helpers
- refactor(backtrack): split BacktrackController into facade + model + impl helpers
- refactor(svg): split SvgPathParser into facade + arc geometry + command/curve helpers
- refactor(mixin): split ClientPacketListenerMixin into hook-only mixin + handlers
- refactor(renderer3d): un-nest batch bindings + culling into sibling impl types
- refactor(renderwarp): extract static factories + geometry into impl helpers
- feat(backend): add common crate with shared JWT, internal gateway contract and accounts proto
- refactor(guimixin): move hook bodies into handlers, keep mixin as hooks + shadows
- feat(accounts): accept only gateway traffic, read identity from gateway header
- refactor(cacheduiscriptruntime): extract engine, hashing and frame stats into impl
- refactor(customskyboxrenderer): extract projection, shader passes and sun into impl
- refactor(betterchatstoremanager): extract persistence, key/path and hover helpers into impl
- feat(accounts): rotating opaque refresh tokens in httpOnly cookie, /auth/refresh and /auth/logout
- refactor(targetesp): extract crystal rendering subsystem into impl/TargetEspCrystalRenderer
- refactor(betterchathovercache): extract disk codec and lookup indexing into impl/ChatHoverCacheCodec
- refactor(microsoftauth): split HTTP transport, device-code and Xbox flows into impl/
- refactor(pvpcooldowns): extract local item-rule engine and defaults into impl/PvpCooldownRules
- refactor(lovisual): extract HUD/world render orchestration into HudRender helper
- refactor(statuseffectheuristics): extract palette/inference into ParticlePalette and color utils into ParticleColors
- refactor(dropesp): extract overlay/label render subsystem into impl/DropEspOverlayRenderer
- refactor(proxy): extract SOCKS handshake message builders into ProxyProtocolMessages
- refactor(eagleutil): promote EdgeRecovery controller and RecoveryMode to top-level class
This commit is contained in:
loki5512344 2026-09-24 23:52:12 +02:00
parent 9d08fa910a
commit 72bc4c7148
1897 changed files with 36199 additions and 39289 deletions

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud;
import net.minecraft.client.gui.components.DebugScreenOverlay;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud;
import dev.loki.lovisual.util.screen.ClientScreen;

View file

@ -1,67 +1,37 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.Hud;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.Holder;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.scores.Objective;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import dev.loki.lovisual.events.Events;
import dev.loki.lovisual.events.impl.pvp.PvpOverlayEvent;
import dev.loki.lovisual.features.gui.hud.draggable.impl.panels.Scoreboard;
import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry;
import dev.loki.lovisual.features.gui.hud.draggable.impl.status.Potions;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.buttons.SwapTooltip;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.CustomBar;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.CustomHealthBar;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.hotbar.CustomHotbar;
import dev.loki.lovisual.features.module.lifecycle.Modules;
import dev.loki.lovisual.features.module.modules.misc.protect.MessageFilter;
import dev.loki.lovisual.features.module.modules.visuals.player.Crosshair;
import dev.loki.lovisual.features.module.modules.visuals.visibility.NoRender;
import dev.loki.lovisual.mixininterface.render.IGuiGraphics;
import dev.loki.lovisual.render.engine.core.system.LoVisualRenderSystem;
import dev.loki.lovisual.render.engine.core.frame.RenderPhase;
import dev.loki.lovisual.render.engine.core.frame.RenderPhaseScope;
import dev.loki.lovisual.render.engine.core.context.ViewportContext;
// import dev.loki.lovisual.render.engine.debug.RenderThread2DDebugRenderer; // disabled: debug probes are manual-only
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
import dev.loki.lovisual.Lifecycle;
import dev.loki.lovisual.util.item.food.IllegalItemUtil;
import dev.loki.lovisual.util.item.rarity.RarityColorUtil;
import dev.loki.lovisual.util.item.enchant.TopEnchantUtil;
import dev.loki.lovisual.util.logging.DebugLog;
import dev.loki.lovisual.util.text.format.TextJsonUtil;
/**
* Hooks into vanilla {@link Hud} state extraction. All bodies live in the {@code handlers} package:
* overlay toggles ({@link GuiOverlayHandler}), custom bar/hotbar/health rendering
* ({@link GuiHudBarHandler}), heart-layout redirects ({@link GuiHealthLayoutHandler}) and held-item
* tooltip recoloring ({@link GuiTooltipHandler}).
*/
@Mixin(Hud.class)
public abstract class GuiMixin {
@Shadow
private int toolHighlightTimer;
@Shadow
private net.minecraft.world.item.ItemStack lastToolHighlight;
private ItemStack lastToolHighlight;
@Shadow
@Final
private Minecraft minecraft;
@ -71,359 +41,74 @@ public abstract class GuiMixin {
// RenderThread2DDebugRenderer.extractGuiStateProbe(ctx);
}
@Unique
private static void lovisual$renderCustomBarOnly(GuiGraphicsExtractor ctx,
DeltaTracker tickCounter,
Minecraft mc,
CustomBar bar) {
boolean useJump = CustomBar.shouldUseJumpBar(mc);
boolean useLocator = !useJump && CustomBar.shouldUseLocator(mc, bar);
boolean drawXp = !useJump && !useLocator;
LoVisualRenderSystem.ensureFrameContext();
try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_bar")) {
Renderer2D.withDeferredLayer(LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER, () -> {
ViewportContext.beginUnscaled(ctx);
Renderer2D.COLOR.begin();
if (drawXp) {
CustomBar.renderXpBarBackground(Renderer2D.COLOR, mc);
}
if (useJump) {
CustomBar.renderJumpBarBackground(Renderer2D.COLOR, mc);
}
if (useLocator) {
CustomBar.renderLocatorBackground(Renderer2D.COLOR, mc);
}
Renderer2D.COLOR.render();
ViewportContext.end(ctx);
if (drawXp) {
CustomBar.renderXpBarText(ctx, mc);
}
});
lovisual$appendVanillaHudReplacementMarker(ctx);
}
}
@Unique
private static final Renderer2D.Deferred2DLayer LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER =
Renderer2D.Deferred2DLayer.HUD_AFTER_MISC_OVERLAYS;
@Unique
private static void lovisual$appendVanillaHudReplacementMarker(GuiGraphicsExtractor ctx) {
if (!(ctx instanceof IGuiGraphics graphics)) return;
ctx.nextStratum();
graphics.lovisual$addDeferredHudMarker(LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER);
ctx.nextStratum();
}
@Unique
private static int argbFrom(float[] rgba) {
if (rgba == null || rgba.length < 3) return 0xFFFFFFFF;
float r = rgba[0], g = rgba[1], b = rgba[2];
float a = rgba.length > 3 ? rgba[3] : 1f;
int ai = (int) (a * 255) & 0xFF;
int ri = (int) (r * 255) & 0xFF;
int gi = (int) (g * 255) & 0xFF;
int bi = (int) (b * 255) & 0xFF;
return (ai << 24) | (ri << 16) | (gi << 8) | bi;
}
@Inject(
method = "displayScoreboardSidebar(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/world/scores/Objective;)V",
at = @At("HEAD"),
cancellable = true
)
@Inject(method = "displayScoreboardSidebar(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/world/scores/Objective;)V", at = @At("HEAD"), cancellable = true)
private void lovisual$hideScoreboardSidebar(GuiGraphicsExtractor context, Objective objective, CallbackInfo ci) {
NoRender noRender = Modules.get(NoRender.class);
if ((noRender != null && noRender.hideScoreboard()) || Scoreboard.shouldReplaceVanilla()) {
ci.cancel();
}
GuiOverlayHandler.hideScoreboardSidebar(ci);
}
@Inject(
method = "setOverlayMessage(Lnet/minecraft/network/chat/Component;Z)V",
at = @At("HEAD"),
cancellable = true
)
private void lovisual$filterOverlayMessage(net.minecraft.network.chat.Component message, boolean tinted, CallbackInfo ci) {
if (DebugLog.serverOnly()) {
if (message == null) {
// DebugLog.server("HUD overlay message: tinted=%s raw=null", tinted);
} else {
String raw = message.getString();
String json = TextJsonUtil.toJson(message);
// DebugLog.server("HUD overlay message: tinted=%s raw=\"%s\" json=%s", tinted, raw, json);
}
}
if (Events.BUS.hasListeners(PvpOverlayEvent.class)) {
Events.BUS.post(new PvpOverlayEvent(message, tinted));
}
MessageFilter messageFilter = Modules.get(MessageFilter.class);
if (messageFilter != null && messageFilter.shouldHideHud(message)) {
ci.cancel();
}
@Inject(method = "setOverlayMessage(Lnet/minecraft/network/chat/Component;Z)V", at = @At("HEAD"), cancellable = true)
private void lovisual$filterOverlayMessage(Component message, boolean tinted, CallbackInfo ci) {
GuiOverlayHandler.filterOverlayMessage(message, tinted, ci);
}
@Inject(
method = "extractEffects(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V",
at = @At("HEAD"),
cancellable = true
)
@Inject(method = "extractEffects(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V", at = @At("HEAD"), cancellable = true)
private void lovisual$hideVanillaPotions(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) {
Minecraft mc = Minecraft.getInstance();
if (mc == null || mc.player == null) return;
if (!DraggableHudElementRegistry.isEnabled(Potions.class)) return;
if (mc.player.getActiveEffects().isEmpty()) return;
ci.cancel();
GuiOverlayHandler.hideVanillaPotions(ci);
}
@Inject(
method = "extractCrosshair(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V",
at = @At("HEAD"),
cancellable = true
)
@Inject(method = "extractCrosshair(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V", at = @At("HEAD"), cancellable = true)
private void lovisual$replaceCrosshair(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) {
Crosshair crosshair = Modules.get(Crosshair.class);
if (crosshair != null && crosshair.shouldHideVanilla()) {
ci.cancel();
}
GuiOverlayHandler.replaceCrosshair(ci);
}
@Inject(
method = "extractVignette(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/world/entity/Entity;)V",
at = @At("HEAD"),
cancellable = true
)
@Inject(method = "extractVignette(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/world/entity/Entity;)V", at = @At("HEAD"), cancellable = true)
private void lovisual$killVignette(GuiGraphicsExtractor context, Entity entity, CallbackInfo ci) {
// Completely remove vanilla vignette post-processing
ci.cancel();
GuiOverlayHandler.killVignette(ci);
}
@Inject(
method = "extractItemHotbar(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V",
at = @At("HEAD"),
cancellable = true
)
@Inject(method = "extractItemHotbar(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V", at = @At("HEAD"), cancellable = true)
private void lovisual$customHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) {
Minecraft mc = Minecraft.getInstance();
if (mc == null || mc.player == null) return;
CustomHotbar hotbar = CustomHotbar.get();
CustomBar bar = CustomBar.get();
if (hotbar == null && bar == null) return;
boolean hotbarEnabled = hotbar != null && hotbar.isHudHotbarEnabled();
boolean barEnabled = bar != null && bar.isHudBarEnabled() && bar.isHotbarXpBarEnabled();
if (!hotbarEnabled && !barEnabled) return;
if (!hotbarEnabled) return;
boolean useJump = barEnabled && CustomBar.shouldUseJumpBar(mc);
boolean useLocator = barEnabled && !useJump && CustomBar.shouldUseLocator(mc, bar);
boolean drawXp = barEnabled && !useJump && !useLocator;
LoVisualRenderSystem.ensureFrameContext();
try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_hotbar")) {
Renderer2D.withDeferredLayer(LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER, () -> {
ViewportContext.beginUnscaled(ctx);
Renderer2D.COLOR.begin();
if (hotbarEnabled) {
CustomHotbar.renderBackground(Renderer2D.COLOR, mc);
}
if (drawXp) {
CustomBar.renderXpBarBackground(Renderer2D.COLOR, mc);
}
if (barEnabled && useJump) {
CustomBar.renderJumpBarBackground(Renderer2D.COLOR, mc);
}
if (barEnabled && useLocator) {
CustomBar.renderLocatorBackground(Renderer2D.COLOR, mc);
}
Renderer2D.COLOR.render();
ViewportContext.end(ctx);
if (hotbarEnabled) {
CustomHotbar.renderItems(ctx, tickCounter, mc);
}
});
lovisual$appendVanillaHudReplacementMarker(ctx);
if (drawXp) {
CustomBar.renderXpBarText(ctx, mc);
}
if (hotbarEnabled) {
ci.cancel();
}
}
GuiHudBarHandler.renderHotbar(ctx, tickCounter, ci);
}
@Inject(
method = "extractItemHotbar(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V",
at = @At("TAIL")
)
@Inject(method = "extractItemHotbar(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V", at = @At("TAIL"))
private void lovisual$customBarAfterVanillaHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) {
Minecraft mc = Minecraft.getInstance();
if (mc == null || mc.player == null) return;
CustomHotbar hotbar = CustomHotbar.get();
if (hotbar != null && hotbar.isHudHotbarEnabled()) return;
CustomBar bar = CustomBar.get();
if (bar == null || !bar.isHudBarEnabled() || !bar.isHotbarXpBarEnabled()) return;
lovisual$renderCustomBarOnly(ctx, tickCounter, mc, bar);
GuiHudBarHandler.afterVanillaHotbar(ctx, tickCounter);
}
@Inject(
method = "extractPortalOverlay(Lnet/minecraft/client/gui/GuiGraphicsExtractor;F)V",
at = @At("HEAD"),
cancellable = true
)
@Inject(method = "extractPortalOverlay(Lnet/minecraft/client/gui/GuiGraphicsExtractor;F)V", at = @At("HEAD"), cancellable = true)
private void lovisual$disableVanillaPortalOverlay(GuiGraphicsExtractor context, float nauseaStrength, CallbackInfo ci) {
ci.cancel();
GuiOverlayHandler.disablePortalOverlay(ci);
}
@Inject(
method = "extractSleepOverlay(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V",
at = @At("HEAD"),
cancellable = true
)
@Inject(method = "extractSleepOverlay(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/client/DeltaTracker;)V", at = @At("HEAD"), cancellable = true)
private void lovisual$disableVanillaSleepOverlay(GuiGraphicsExtractor context, DeltaTracker tickCounter, CallbackInfo ci) {
ci.cancel();
GuiOverlayHandler.disableSleepOverlay(ci);
}
@Inject(
method = "extractHearts(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/world/entity/player/Player;IIIIFIIIZ)V",
at = @At("HEAD"),
cancellable = true
)
@Inject(method = "extractHearts(Lnet/minecraft/client/gui/GuiGraphicsExtractor;Lnet/minecraft/world/entity/player/Player;IIIIFIIIZ)V", at = @At("HEAD"), cancellable = true)
private void lovisual$renderHealthBar(GuiGraphicsExtractor context,
Player player,
int x, int y, int lines,
int regeneratingHeartIndex, float maxHealth,
int lastHealth, int health,
int absorption, boolean blinking,
CallbackInfo ci) {
if (!Lifecycle.canRunHud()) return;
if (!(player instanceof LocalPlayer clientPlayer)) return;
Minecraft mc = Minecraft.getInstance();
if (mc == null) return;
if (!CustomHealthBar.shouldRenderHealthBar(mc, clientPlayer, maxHealth)) return;
LoVisualRenderSystem.ensureFrameContext();
try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_health")) {
Renderer2D.withDeferredLayer(LOVISUAL$VANILLA_HUD_REPLACEMENT_LAYER, () -> {
ViewportContext.beginUnscaled(context);
Renderer2D.COLOR.begin();
CustomHealthBar.HealthTextInfo textInfo =
CustomHealthBar.renderHealthBarBackground(
Renderer2D.COLOR,
mc,
clientPlayer,
x,
y,
maxHealth
);
CustomHealthBar.renderHealthBarText(textInfo);
Renderer2D.COLOR.render();
ViewportContext.end(context);
});
lovisual$appendVanillaHudReplacementMarker(context);
ci.cancel();
}
Player player,
int x, int y, int lines,
int regeneratingHeartIndex, float maxHealth,
int lastHealth, int health,
int absorption, boolean blinking,
CallbackInfo ci) {
GuiHudBarHandler.renderHealth(context, player, x, y, maxHealth, ci);
}
@Inject(method = "extractSelectedItemName", at = @At("HEAD"), cancellable = true)
private void lovisual$colorizeHeldItemTooltip(GuiGraphicsExtractor context, CallbackInfo ci) {
if (!Lifecycle.canRunHud()) return;
SwapTooltip swapTooltip = SwapTooltip.get();
if (swapTooltip == null || !swapTooltip.isEnabled()) {
return;
}
if (this.toolHighlightTimer <= 0 || this.lastToolHighlight == null || this.lastToolHighlight.isEmpty()) {
SwapTooltip.clear();
return;
}
MutableComponent name = Component.empty().append(this.lastToolHighlight.getHoverName());
if (this.lastToolHighlight.has(net.minecraft.core.component.DataComponents.CUSTOM_NAME)) {
name.withStyle(net.minecraft.ChatFormatting.ITALIC);
}
int illegalColor = IllegalItemUtil.illegalColor();
int topColor = TopEnchantUtil.topColor();
int rarityColor = argbFrom(RarityColorUtil.INSTANCE.getRarityColor(this.lastToolHighlight));
boolean hasIllegal = IllegalItemUtil.isIllegal(this.lastToolHighlight);
boolean hasTop = !hasIllegal && TopEnchantUtil.hasTopEnchant(this.lastToolHighlight);
int nameColor = hasIllegal ? illegalColor : (hasTop ? topColor : rarityColor);
int alpha = (int) ((float) this.toolHighlightTimer * 256.0F / 10.0F);
if (alpha > 255) alpha = 255;
if (alpha <= 0) {
SwapTooltip.clear();
return;
}
float fade = alpha / 255f;
int argb = 0xFF000000 | (nameColor & 0x00FFFFFF);
SwapTooltip.capture(
name.getString(),
argb,
fade,
this.minecraft.gameMode.canHurtPlayer()
);
ci.cancel();
GuiTooltipHandler.colorizeHeldItem(this.toolHighlightTimer, this.lastToolHighlight, this.minecraft, ci);
}
@Redirect(
method = "extractPlayerHealth(Lnet/minecraft/client/gui/GuiGraphicsExtractor;)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Player;getAbsorptionAmount()F"
)
)
@Redirect(method = "extractPlayerHealth(Lnet/minecraft/client/gui/GuiGraphicsExtractor;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getAbsorptionAmount()F"))
private float lovisual$ignoreAbsorptionForLayout(Player player) {
if (!Lifecycle.canRunHud()) {
return player.getAbsorptionAmount();
}
Minecraft mc = Minecraft.getInstance();
if (mc != null && player instanceof LocalPlayer clientPlayer) {
float actualMaxHealth = (float) player.getAttributeValue(Attributes.MAX_HEALTH);
if (CustomHealthBar.shouldRenderHealthBar(mc, clientPlayer, actualMaxHealth)) {
return 0.0f;
}
}
return player.getAbsorptionAmount();
return GuiHealthLayoutHandler.ignoreAbsorptionForLayout(player);
}
@Redirect(
method = "extractPlayerHealth(Lnet/minecraft/client/gui/GuiGraphicsExtractor;)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Player;getAttributeValue(Lnet/minecraft/core/Holder;)D"
)
)
@Redirect(method = "extractPlayerHealth(Lnet/minecraft/client/gui/GuiGraphicsExtractor;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getAttributeValue(Lnet/minecraft/core/Holder;)D"))
private double lovisual$clampMaxHealthForLayout(Player player, Holder<Attribute> attribute) {
if (!Lifecycle.canRunHud()) {
return player.getAttributes().getValue(attribute);
}
if (attribute == Attributes.MAX_HEALTH) {
Minecraft mc = Minecraft.getInstance();
if (mc != null && player instanceof LocalPlayer clientPlayer) {
float actualMaxHealth = (float) player.getAttributes().getValue(attribute);
if (CustomHealthBar.shouldRenderHealthBar(mc, clientPlayer, actualMaxHealth)) {
return 20.0;
}
}
}
return player.getAttributes().getValue(attribute);
return GuiHealthLayoutHandler.clampMaxHealthForLayout(player, attribute);
}
}

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud;
import com.mojang.blaze3d.ProjectionType;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.accessibility;
import net.minecraft.client.GameNarrator;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.accessibility;
import net.minecraft.client.Minecraft;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.bars;
import dev.loki.lovisual.events.Events;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.bars;
import net.minecraft.client.DeltaTracker;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.bars;
import net.minecraft.client.DeltaTracker;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.bars;
import net.minecraft.client.DeltaTracker;

View file

@ -0,0 +1,50 @@
package dev.loki.lovisual.mixins.hud;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.Holder;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import dev.loki.lovisual.Lifecycle;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.CustomHealthBar;
/**
* Vanilla heart-layout redirects for {@link GuiMixin}. When the custom health bar takes over, the
* vanilla {@code extractPlayerHealth} pass is fed neutral values (absorption 0, max health 20) so it
* reserves the correct space without drawing hearts we replace ourselves.
*/
final class GuiHealthLayoutHandler {
private GuiHealthLayoutHandler() {
}
static float ignoreAbsorptionForLayout(Player player) {
if (!Lifecycle.canRunHud()) {
return player.getAbsorptionAmount();
}
Minecraft mc = Minecraft.getInstance();
if (mc != null && player instanceof LocalPlayer clientPlayer) {
float actualMaxHealth = (float) player.getAttributeValue(Attributes.MAX_HEALTH);
if (CustomHealthBar.shouldRenderHealthBar(mc, clientPlayer, actualMaxHealth)) {
return 0.0f;
}
}
return player.getAbsorptionAmount();
}
static double clampMaxHealthForLayout(Player player, Holder<Attribute> attribute) {
if (!Lifecycle.canRunHud()) {
return player.getAttributes().getValue(attribute);
}
if (attribute == Attributes.MAX_HEALTH) {
Minecraft mc = Minecraft.getInstance();
if (mc != null && player instanceof LocalPlayer clientPlayer) {
float actualMaxHealth = (float) player.getAttributes().getValue(attribute);
if (CustomHealthBar.shouldRenderHealthBar(mc, clientPlayer, actualMaxHealth)) {
return 20.0;
}
}
}
return player.getAttributes().getValue(attribute);
}
}

View file

@ -0,0 +1,170 @@
package dev.loki.lovisual.mixins.hud;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import dev.loki.lovisual.Lifecycle;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.CustomBar;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.CustomHealthBar;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.CustomXpBarRenderer;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.jump.CustomJumpBarRenderer;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.locator.panel.CustomLocatorRenderer;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.hotbar.CustomHotbar;
import dev.loki.lovisual.mixininterface.render.IGuiGraphics;
import dev.loki.lovisual.render.engine.core.system.LoVisualRenderSystem;
import dev.loki.lovisual.render.engine.core.frame.RenderPhase;
import dev.loki.lovisual.render.engine.core.frame.RenderPhaseScope;
import dev.loki.lovisual.render.engine.core.context.ViewportContext;
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
/**
* Custom HUD replacement rendering for {@link GuiMixin}: hotbar, XP/jump/locator bars and the
* health bar. All passes are emitted through a deferred {@link Renderer2D} layer so they land after
* vanilla misc overlays, then drop a stratum marker via {@link IGuiGraphics}.
*/
final class GuiHudBarHandler {
private GuiHudBarHandler() {
}
static final Renderer2D.Deferred2DLayer VANILLA_HUD_REPLACEMENT_LAYER =
Renderer2D.Deferred2DLayer.HUD_AFTER_MISC_OVERLAYS;
static void renderHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter, CallbackInfo ci) {
Minecraft mc = Minecraft.getInstance();
if (mc == null || mc.player == null) return;
CustomHotbar hotbar = CustomHotbar.get();
CustomBar bar = CustomBar.get();
if (hotbar == null && bar == null) return;
boolean hotbarEnabled = hotbar != null && hotbar.isHudHotbarEnabled();
boolean barEnabled = bar != null && bar.isHudBarEnabled() && bar.isHotbarXpBarEnabled();
if (!hotbarEnabled && !barEnabled) return;
if (!hotbarEnabled) return;
boolean useJump = barEnabled && CustomJumpBarRenderer.shouldUseJumpBar(mc);
boolean useLocator = barEnabled && !useJump && CustomBar.shouldUseLocator(mc, bar);
boolean drawXp = barEnabled && !useJump && !useLocator;
LoVisualRenderSystem.ensureFrameContext();
try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_hotbar")) {
Renderer2D.withDeferredLayer(VANILLA_HUD_REPLACEMENT_LAYER, () -> {
ViewportContext.beginUnscaled(ctx);
Renderer2D.COLOR.begin();
if (hotbarEnabled) {
CustomHotbar.renderBackground(Renderer2D.COLOR, mc);
}
if (drawXp) {
CustomXpBarRenderer.renderXpBarBackground(Renderer2D.COLOR, mc);
}
if (barEnabled && useJump) {
CustomJumpBarRenderer.renderJumpBarBackground(Renderer2D.COLOR, mc);
}
if (barEnabled && useLocator) {
CustomLocatorRenderer.renderLocatorBackground(Renderer2D.COLOR, mc);
}
Renderer2D.COLOR.render();
ViewportContext.end(ctx);
if (hotbarEnabled) {
CustomHotbar.renderItems(ctx, tickCounter, mc);
}
});
appendVanillaHudReplacementMarker(ctx);
if (drawXp) {
CustomXpBarRenderer.renderXpBarText(ctx, mc);
}
if (hotbarEnabled) {
ci.cancel();
}
}
}
static void afterVanillaHotbar(GuiGraphicsExtractor ctx, DeltaTracker tickCounter) {
Minecraft mc = Minecraft.getInstance();
if (mc == null || mc.player == null) return;
CustomHotbar hotbar = CustomHotbar.get();
if (hotbar != null && hotbar.isHudHotbarEnabled()) return;
CustomBar bar = CustomBar.get();
if (bar == null || !bar.isHudBarEnabled() || !bar.isHotbarXpBarEnabled()) return;
renderCustomBarOnly(ctx, tickCounter, mc, bar);
}
static void renderHealth(GuiGraphicsExtractor context, Player player, int x, int y, float maxHealth, CallbackInfo ci) {
if (!Lifecycle.canRunHud()) return;
if (!(player instanceof LocalPlayer clientPlayer)) return;
Minecraft mc = Minecraft.getInstance();
if (mc == null) return;
if (!CustomHealthBar.shouldRenderHealthBar(mc, clientPlayer, maxHealth)) return;
LoVisualRenderSystem.ensureFrameContext();
try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_health")) {
Renderer2D.withDeferredLayer(VANILLA_HUD_REPLACEMENT_LAYER, () -> {
ViewportContext.beginUnscaled(context);
Renderer2D.COLOR.begin();
CustomHealthBar.HealthTextInfo textInfo =
CustomHealthBar.renderHealthBarBackground(
Renderer2D.COLOR,
mc,
clientPlayer,
x,
y,
maxHealth
);
CustomHealthBar.renderHealthBarText(textInfo);
Renderer2D.COLOR.render();
ViewportContext.end(context);
});
appendVanillaHudReplacementMarker(context);
ci.cancel();
}
}
private static void renderCustomBarOnly(GuiGraphicsExtractor ctx,
DeltaTracker tickCounter,
Minecraft mc,
CustomBar bar) {
boolean useJump = CustomJumpBarRenderer.shouldUseJumpBar(mc);
boolean useLocator = !useJump && CustomBar.shouldUseLocator(mc, bar);
boolean drawXp = !useJump && !useLocator;
LoVisualRenderSystem.ensureFrameContext();
try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.HUD_MAIN, "2d:hud:custom_bar")) {
Renderer2D.withDeferredLayer(VANILLA_HUD_REPLACEMENT_LAYER, () -> {
ViewportContext.beginUnscaled(ctx);
Renderer2D.COLOR.begin();
if (drawXp) {
CustomXpBarRenderer.renderXpBarBackground(Renderer2D.COLOR, mc);
}
if (useJump) {
CustomJumpBarRenderer.renderJumpBarBackground(Renderer2D.COLOR, mc);
}
if (useLocator) {
CustomLocatorRenderer.renderLocatorBackground(Renderer2D.COLOR, mc);
}
Renderer2D.COLOR.render();
ViewportContext.end(ctx);
if (drawXp) {
CustomXpBarRenderer.renderXpBarText(ctx, mc);
}
});
appendVanillaHudReplacementMarker(ctx);
}
}
private static void appendVanillaHudReplacementMarker(GuiGraphicsExtractor ctx) {
if (!(ctx instanceof IGuiGraphics graphics)) return;
ctx.nextStratum();
graphics.lovisual$addDeferredHudMarker(VANILLA_HUD_REPLACEMENT_LAYER);
ctx.nextStratum();
}
}

View file

@ -0,0 +1,81 @@
package dev.loki.lovisual.mixins.hud;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import dev.loki.lovisual.events.Events;
import dev.loki.lovisual.events.impl.pvp.PvpOverlayEvent;
import dev.loki.lovisual.features.gui.hud.draggable.impl.panels.Scoreboard;
import dev.loki.lovisual.features.gui.hud.draggable.DraggableHudElementRegistry;
import dev.loki.lovisual.features.gui.hud.draggable.impl.status.Potions;
import dev.loki.lovisual.features.module.lifecycle.Modules;
import dev.loki.lovisual.features.module.modules.misc.protect.MessageFilter;
import dev.loki.lovisual.features.module.modules.visuals.player.Crosshair;
import dev.loki.lovisual.features.module.modules.visuals.visibility.NoRender;
import dev.loki.lovisual.util.logging.DebugLog;
import dev.loki.lovisual.util.text.format.TextJsonUtil;
/**
* Vanilla HUD element hide/replace toggles for {@link GuiMixin}: scoreboard, overlay messages,
* potion effects, crosshair, vignette and the portal/sleep overlays. Each entry point cancels the
* vanilla {@code extract*}/{@code display*} call when a module or custom HUD takes over.
*/
final class GuiOverlayHandler {
private GuiOverlayHandler() {
}
static void hideScoreboardSidebar(CallbackInfo ci) {
NoRender noRender = Modules.get(NoRender.class);
if ((noRender != null && noRender.hideScoreboard()) || Scoreboard.shouldReplaceVanilla()) {
ci.cancel();
}
}
static void filterOverlayMessage(Component message, boolean tinted, CallbackInfo ci) {
if (DebugLog.serverOnly()) {
if (message == null) {
// DebugLog.server("HUD overlay message: tinted=%s raw=null", tinted);
} else {
String raw = message.getString();
String json = TextJsonUtil.toJson(message);
// DebugLog.server("HUD overlay message: tinted=%s raw=\"%s\" json=%s", tinted, raw, json);
}
}
if (Events.BUS.hasListeners(PvpOverlayEvent.class)) {
Events.BUS.post(new PvpOverlayEvent(message, tinted));
}
MessageFilter messageFilter = Modules.get(MessageFilter.class);
if (messageFilter != null && messageFilter.shouldHideHud(message)) {
ci.cancel();
}
}
static void hideVanillaPotions(CallbackInfo ci) {
Minecraft mc = Minecraft.getInstance();
if (mc == null || mc.player == null) return;
if (!DraggableHudElementRegistry.isEnabled(Potions.class)) return;
if (mc.player.getActiveEffects().isEmpty()) return;
ci.cancel();
}
static void replaceCrosshair(CallbackInfo ci) {
Crosshair crosshair = Modules.get(Crosshair.class);
if (crosshair != null && crosshair.shouldHideVanilla()) {
ci.cancel();
}
}
static void killVignette(CallbackInfo ci) {
// Completely remove vanilla vignette post-processing
ci.cancel();
}
static void disablePortalOverlay(CallbackInfo ci) {
ci.cancel();
}
static void disableSleepOverlay(CallbackInfo ci) {
ci.cancel();
}
}

View file

@ -0,0 +1,74 @@
package dev.loki.lovisual.mixins.hud;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import dev.loki.lovisual.Lifecycle;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.buttons.SwapTooltip;
import dev.loki.lovisual.util.item.food.IllegalItemUtil;
import dev.loki.lovisual.util.item.rarity.RarityColorUtil;
import dev.loki.lovisual.util.item.enchant.TopEnchantUtil;
/**
* Held-item tooltip recoloring for {@link GuiMixin}. Captures the vanilla swap-item tooltip with a
* rarity / illegal / top-enchant derived name color and a fade driven by the highlight timer,
* cancelling the vanilla render when the custom SwapTooltip is active.
*/
final class GuiTooltipHandler {
private GuiTooltipHandler() {
}
static void colorizeHeldItem(int toolHighlightTimer, ItemStack lastToolHighlight, Minecraft minecraft, CallbackInfo ci) {
if (!Lifecycle.canRunHud()) return;
SwapTooltip swapTooltip = SwapTooltip.get();
if (swapTooltip == null || !swapTooltip.isEnabled()) {
return;
}
if (toolHighlightTimer <= 0 || lastToolHighlight == null || lastToolHighlight.isEmpty()) {
SwapTooltip.clear();
return;
}
MutableComponent name = Component.empty().append(lastToolHighlight.getHoverName());
if (lastToolHighlight.has(DataComponents.CUSTOM_NAME)) {
name.withStyle(ChatFormatting.ITALIC);
}
int illegalColor = IllegalItemUtil.illegalColor();
int topColor = TopEnchantUtil.topColor();
int rarityColor = argbFrom(RarityColorUtil.INSTANCE.getRarityColor(lastToolHighlight));
boolean hasIllegal = IllegalItemUtil.isIllegal(lastToolHighlight);
boolean hasTop = !hasIllegal && TopEnchantUtil.hasTopEnchant(lastToolHighlight);
int nameColor = hasIllegal ? illegalColor : (hasTop ? topColor : rarityColor);
int alpha = (int) ((float) toolHighlightTimer * 256.0F / 10.0F);
if (alpha > 255) alpha = 255;
if (alpha <= 0) {
SwapTooltip.clear();
return;
}
float fade = alpha / 255f;
int argb = 0xFF000000 | (nameColor & 0x00FFFFFF);
SwapTooltip.capture(
name.getString(),
argb,
fade,
minecraft.gameMode.canHurtPlayer()
);
ci.cancel();
}
private static int argbFrom(float[] rgba) {
if (rgba == null || rgba.length < 3) return 0xFFFFFFFF;
float r = rgba[0], g = rgba[1], b = rgba[2];
float a = rgba.length > 3 ? rgba[3] : 1f;
int ai = (int) (a * 255) & 0xFF;
int ri = (int) (r * 255) & 0xFF;
int gi = (int) (g * 255) & 0xFF;
int bi = (int) (b * 255) & 0xFF;
return (ai << 24) | (ri << 16) | (gi << 8) | bi;
}
}

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.tablist;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.tab.CustomTabList;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.tooltips;
import net.minecraft.client.gui.components.toasts.Toast;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins.hud.tooltips;
import com.mojang.blaze3d.pipeline.RenderPipeline;