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:
parent
9d08fa910a
commit
72bc4c7148
1897 changed files with 36199 additions and 39289 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue