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;
import net.fabricmc.loader.api.FabricLoader;

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.accessors.blaze3d;
import com.mojang.blaze3d.GpuFormat;

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.accessors.blaze3d;
import com.mojang.blaze3d.systems.GpuDevice;

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.accessors.blaze3d;
import net.minecraft.client.renderer.PostChainConfig;

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.accessors.blaze3d;
import com.mojang.blaze3d.shaders.ShaderType;

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.accessors.chat;
import com.mojang.brigadier.suggestion.Suggestions;

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.accessors.chat;
import net.minecraft.client.gui.components.EditBox;

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.accessors.chat;
import net.minecraft.client.gui.components.CommandSuggestions;

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.accessors.chat;
import net.minecraft.client.gui.components.CommandSuggestions;

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.accessors.entity;
import net.minecraft.world.entity.Entity;

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.accessors.entity;
import net.minecraft.world.entity.Entity;

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.accessors.entity;
import net.minecraft.world.entity.LivingEntity;

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.accessors.entity;
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.accessors.hud;
import net.minecraft.client.gui.components.BossHealthOverlay;

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.accessors.hud;
import com.mojang.blaze3d.vertex.PoseStack;

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.accessors.hud;
import net.minecraft.client.gui.components.PlayerTabOverlay;

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.accessors.hud;
import net.minecraft.client.gui.components.SpriteIconButton;

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.accessors.inventory;
import org.spongepowered.asm.mixin.Mixin;

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.accessors.inventory;
import net.minecraft.resources.Identifier;

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.accessors.inventory;
import net.minecraft.world.entity.player.Inventory;

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.accessors.inventory;
import net.minecraft.world.inventory.Slot;

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.accessors.misc;
import net.minecraft.client.player.ClientInput;

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.accessors.misc;
import com.mojang.blaze3d.platform.InputConstants;

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.accessors.misc;
import com.mojang.authlib.minecraft.UserApiService;

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.accessors.misc;
import net.minecraft.client.multiplayer.MultiPlayerGameMode;

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.accessors.packet;
import net.minecraft.network.protocol.game.ClientboundExplodePacket;

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.accessors.packet;
import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket;

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.accessors.packet;
import net.minecraft.network.protocol.game.ServerboundInteractPacket;

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.accessors.packet;
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;

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.accessors.projectile;
import net.minecraft.world.entity.projectile.arrow.AbstractArrow;

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.accessors.renderer;
import com.mojang.blaze3d.vertex.PoseStack;

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.accessors.renderer;
import net.minecraft.client.renderer.entity.EntityRenderer;

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.accessors.renderer;
import com.mojang.blaze3d.vertex.PoseStack;

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.accessors.renderer;
import net.minecraft.client.renderer.rendertype.RenderSetup;

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.accessors.state;
import net.minecraft.core.particles.SpellParticleOption;

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.accessors.state;
import net.minecraft.world.item.component.Fireworks;

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.accessors.state;
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;

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.accessors.widget;
import net.minecraft.client.gui.components.AbstractWidget;

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.accessors.widget;
import net.minecraft.client.gui.components.CycleButton;

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.accessors.widget;
import net.minecraft.client.gui.components.AbstractSliderButton;

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.accessors.widget;
import net.minecraft.client.gui.components.EditBox;

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.accessors.world;
import net.minecraft.client.multiplayer.ClientLevel;

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.accessors.world;
import net.minecraft.client.renderer.entity.state.EntityRenderState;

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.accessors.world;
import com.mojang.blaze3d.textures.GpuSampler;

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.accessors.world;
import net.minecraft.world.level.Level;

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.blaze3d.device;
import com.mojang.blaze3d.opengl.DirectStateAccess;

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.blaze3d.device;
import com.mojang.blaze3d.GpuFormat;

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.blaze3d.device;
import com.mojang.blaze3d.systems.GpuSurface;

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.blaze3d.device;
import com.mojang.blaze3d.GpuFormat;
@ -32,6 +25,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import dev.loki.lovisual.render.engine.rhi.backend.vulkan.util.VulkanRenderStateBridge;
import dev.loki.lovisual.render.engine.rhi.backend.vulkan.util.VulkanPipelineVariantKey;
import dev.loki.lovisual.util.logging.DebugLog;
import java.util.HashMap;
@ -46,7 +40,7 @@ public abstract class VulkanDeviceMixin {
private ShaderSource defaultShaderSource;
@Unique
private final Map<VulkanRenderStateBridge.PipelineVariantKey, VulkanRenderPipeline> lovisual$pipelineVariants = new HashMap<>();
private final Map<VulkanPipelineVariantKey, VulkanRenderPipeline> lovisual$pipelineVariants = new HashMap<>();
@Invoker("compilePipeline")
protected abstract VulkanRenderPipeline lovisual$compilePipelineVariant(RenderPipeline pipeline, ShaderSource source);
@ -136,7 +130,7 @@ public abstract class VulkanDeviceMixin {
CallbackInfoReturnable<VulkanRenderPipeline> cir) {
if (!VulkanRenderStateBridge.needsPipelineVariant(pipeline)) return;
VulkanRenderStateBridge.PipelineVariantKey key = VulkanRenderStateBridge.pipelineVariantKey(pipeline);
VulkanPipelineVariantKey key = VulkanRenderStateBridge.pipelineVariantKey(pipeline);
VulkanRenderPipeline variant = lovisual$pipelineVariants.get(key);
if (variant != null) {
cir.setReturnValue(variant);

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.blaze3d.encoder;
import net.minecraft.client.renderer.SubmitNodeCollection;

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.blaze3d.encoder;
import com.mojang.blaze3d.systems.CommandEncoder;

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.blaze3d.encoder;
import com.llamalad7.mixinextras.sugar.Local;

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.blaze3d.pipeline;
import com.mojang.blaze3d.pipeline.RenderPipeline;

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.blaze3d.pipeline;
import com.mojang.blaze3d.pipeline.RenderPipeline;

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.blaze3d.pipeline;
import com.mojang.blaze3d.pipeline.RenderPipeline;

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.blaze3d.pipeline;
import com.llamalad7.mixinextras.sugar.Local;

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.blaze3d.shader;
import net.minecraft.client.renderer.DynamicUniformStorage;

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.blaze3d.shader;
import com.mojang.blaze3d.opengl.GlStateManager;

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.blaze3d.shader;
import com.google.common.collect.ImmutableMap;

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.blaze3d.texture;
import org.spongepowered.asm.mixin.Mixin;

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.blaze3d.texture;
import com.mojang.blaze3d.opengl.GlTexture;

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.blaze3d.texture;
import com.mojang.blaze3d.GpuFormat;

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.blaze3d.texture;
import com.mojang.blaze3d.GpuFormat;

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.entity.inventory;
import net.minecraft.resources.Identifier;

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.entity.inventory;
import net.minecraft.world.entity.player.Player;

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.entity.inventory;
import net.minecraft.network.chat.Component;

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.entity.inventory;
import net.minecraft.world.entity.player.Inventory;

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.entity.living;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;

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.entity.living;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;

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.entity.player;
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.entity.player;
import dev.loki.lovisual.features.module.lifecycle.Modules;

View file

@ -1,35 +1,11 @@
/*
* 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.entity.player;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import dev.loki.lovisual.events.Events;
import dev.loki.lovisual.events.impl.input.SprintControlEvent;
import dev.loki.lovisual.events.impl.movement.MovementInputEvent;
import dev.loki.lovisual.events.impl.network.EventPostSync;
import dev.loki.lovisual.events.impl.network.EventSync;
import dev.loki.lovisual.events.impl.player.PostPlayerUpdateEvent;
import dev.loki.lovisual.events.impl.world.EventPushOutOfBlocks;
import dev.loki.lovisual.util.combat.rotation.SprintController;
import dev.loki.lovisual.util.screen.ClientScreen;
import dev.loki.lovisual.mixininterface.entity.ILocalPlayer;
import net.minecraft.client.player.ClientInput;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.PortalProcessor;
import net.minecraft.world.entity.player.Input;
import net.minecraft.world.entity.projectile.throwableitemprojectile.ThrownEnderpearl;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@ -37,655 +13,92 @@ 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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import dev.loki.lovisual.features.module.lifecycle.Modules;
import dev.loki.lovisual.features.module.modules.visuals.camera.Freecam;
import dev.loki.lovisual.mixininterface.entity.ILocalPlayer;
import dev.loki.lovisual.mixins.accessors.entity.EntityAccessor;
import dev.loki.lovisual.mixins.accessors.misc.InputAccessor;
import dev.loki.lovisual.mixins.accessors.entity.LocalPlayerAccessor;
import dev.loki.lovisual.util.aiming.rotation.RotationManager;
import dev.loki.lovisual.util.aiming.data.Rotation;
import java.util.ArrayList;
import java.util.List;
@Mixin(LocalPlayer.class)
public abstract class LocalPlayerMixin implements ILocalPlayer {
@Shadow
public ClientInput input;
@Unique
private float lovisual$lastYaw;
@Unique
private float lovisual$lastPitch;
@Unique
private double lovisual$rotationPrevX;
@Unique
private double lovisual$rotationPrevZ;
@Unique
private float lovisual$rotationPrevBodyYaw;
@Unique
private boolean lovisual$rotationBodyYawInitialized;
@Unique
private float freecam$lastHealth = Float.NaN;
@Unique
private boolean frozen = false;
@Unique
private Vec3 savedVelocity = Vec3.ZERO;
@Unique
private double savedX, savedY, savedZ;
@Unique
private float savedBodyYaw;
@Unique
private float savedHeadYaw;
@Unique
private Runnable lovisual$eventPostAction;
@Unique
private EventSync lovisual$activeSyncEvent;
@Unique
private boolean lovisual$postUpdateLock = false;
@Unique
private Input lastInput;
@Unique
private boolean pendingSpoof = false;
@Unique
private int boostTicks = 0;
@Unique
private double boostX = 0, boostZ = 0;
@Unique
private boolean wasGround = true;
@Shadow public ClientInput input;
@Shadow protected abstract void sendPosition();
@Unique
private static boolean lovisual$sameInput(Input a, Input b) {
if (a == b) return true;
if (a == null || b == null) return false;
return a.forward() == b.forward()
&& a.backward() == b.backward()
&& a.left() == b.left()
&& a.right() == b.right()
&& a.jump() == b.jump()
&& a.shift() == b.shift()
&& a.sprint() == b.sprint();
}
@Unique
private static float lovisual$impulse(boolean positive, boolean negative) {
if (positive == negative) {
return 0.0f;
}
return positive ? 1.0f : -1.0f;
}
@Unique
private static float lovisual$simulateBodyYaw(
float yaw,
float prevBodyYaw,
double prevX,
double prevZ,
double currentX,
double currentZ,
float handSwingProgress
) {
double motionX = currentX - prevX;
double motionZ = currentZ - prevZ;
float motionSquared = (float) (motionX * motionX + motionZ * motionZ);
float bodyYaw = prevBodyYaw;
if (motionSquared > 0.0025000002F) {
float movementYaw = (float) Mth.atan2(motionZ, motionX) * Mth.RAD_TO_DEG - 90.0F;
float yawDiff = Math.abs(Mth.wrapDegrees(yaw) - movementYaw);
bodyYaw = (yawDiff > 95.0F && yawDiff < 265.0F) ? movementYaw - 180.0F : movementYaw;
}
if (handSwingProgress - 0.2F > 0.0F) {
bodyYaw = yaw;
}
float deltaYaw = Mth.wrapDegrees(bodyYaw - prevBodyYaw);
bodyYaw = prevBodyYaw + deltaYaw * 0.3F;
float yawOffsetDiff = Mth.wrapDegrees(yaw - bodyYaw);
float maxHeadRotation = 52.0F;
if (Math.abs(yawOffsetDiff) > maxHeadRotation) {
bodyYaw += yawOffsetDiff - Math.signum(yawOffsetDiff) * maxHeadRotation;
}
return bodyYaw;
}
@Unique private float lovisual$lastYaw;
@Unique private float lovisual$lastPitch;
@Unique private final LocalPlayerInputHandler lovisual$inputHandler = new LocalPlayerInputHandler();
@Unique private final LocalPlayerRotationHandler lovisual$rotationHandler = new LocalPlayerRotationHandler();
@Unique private final LocalPlayerNetworkHandler lovisual$networkHandler = new LocalPlayerNetworkHandler();
@Unique private final LocalPlayerMovementHandler lovisual$movementHandler = new LocalPlayerMovementHandler();
@Inject(method = "tick", at = @At("HEAD"))
private void lovisual$cacheLastRotations(CallbackInfo ci) {
LocalPlayer self = (LocalPlayer) (Object) this;
lovisual$lastYaw = self.getYRot();
lovisual$lastPitch = self.getXRot();
RotationManager.INSTANCE.runTickLifecycle();
if (!lovisual$rotationBodyYawInitialized) {
lovisual$rotationPrevX = self.getX();
lovisual$rotationPrevZ = self.getZ();
lovisual$rotationPrevBodyYaw = self.getVisualRotationYInDegrees();
lovisual$rotationBodyYawInitialized = true;
}
lovisual$rotationHandler.onTickCache((LocalPlayer) (Object) this);
}
@Inject(method = "handlePortalTransitionEffect", at = @At("HEAD"), cancellable = true)
private void lovisual$disablePortalNausea(boolean inPortal, CallbackInfo ci) {
LocalPlayer self = (LocalPlayer) (Object) this;
PortalProcessor portalManager = null;
if (self instanceof EntityAccessor accessor) {
portalManager = accessor.lovisual$getPortalManager();
}
if (portalManager != null && portalManager.isInsidePortalThisTick()) {
if (self instanceof LocalPlayerAccessor accessor) {
accessor.lovisual$setNauseaIntensity(0.0f);
accessor.lovisual$setLastNauseaIntensity(0.0f);
}
ci.cancel();
}
lovisual$movementHandler.onPortalNausea((LocalPlayer) (Object) this, ci);
}
@Override
public float lovisual$getLastYaw() {
return lovisual$lastYaw;
}
@Override public float lovisual$getLastYaw() { return lovisual$lastYaw; }
@Override public float lovisual$getLastPitch() { return lovisual$lastPitch; }
@Override public void lovisual$setLastYaw(float yaw) { lovisual$lastYaw = yaw; }
@Override public void lovisual$setLastPitch(float pitch) { lovisual$lastPitch = pitch; }
@Override
public float lovisual$getLastPitch() {
return lovisual$lastPitch;
}
@Override
public void lovisual$setLastYaw(float yaw) {
this.lovisual$lastYaw = yaw;
}
@Override
public void lovisual$setLastPitch(float pitch) {
this.lovisual$lastPitch = pitch;
}
@ModifyExpressionValue(
method = "aiStep",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;canStartSprinting()Z"
)
)
@ModifyExpressionValue(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;canStartSprinting()Z"))
private boolean lovisual$sprintMovementStart(boolean original) {
return lovisual$postSprintControl(original, SprintControlEvent.Source.MOVEMENT_TICK);
return lovisual$inputHandler.postSprintControl((LocalPlayer) (Object) this, original, SprintControlEvent.Source.MOVEMENT_TICK);
}
@ModifyExpressionValue(
method = "aiStep",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Input;sprint()Z"
)
)
@ModifyExpressionValue(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Input;sprint()Z"))
private boolean lovisual$sprintMovementInput(boolean original) {
return lovisual$postSprintControl(original, SprintControlEvent.Source.MOVEMENT_TICK);
return lovisual$inputHandler.postSprintControl((LocalPlayer) (Object) this, original, SprintControlEvent.Source.MOVEMENT_TICK);
}
@ModifyExpressionValue(
method = "sendIsSprintingIfNeeded",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;isSprinting()Z"
)
)
@ModifyExpressionValue(method = "sendIsSprintingIfNeeded", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;isSprinting()Z"))
private boolean lovisual$sprintNetwork(boolean original) {
if (SprintController.INSTANCE.isSprintBlocked()) {
return false;
}
return original;
return lovisual$networkHandler.shouldBlockSprintNetwork(original);
}
@Unique
private boolean lovisual$postSprintControl(boolean original, SprintControlEvent.Source source) {
LocalPlayer self = (LocalPlayer) (Object) this;
if (self.input == null) {
return original;
}
if (!Events.BUS.hasListeners(SprintControlEvent.class)) {
return original;
}
Vec2 movement = self.input.getMoveVector();
SprintControlEvent event = new SprintControlEvent(
movement.y,
movement.x,
original,
source
);
Events.BUS.post(event);
return event.shouldSprint();
}
@Inject(method = "modifyInput", at = @At("RETURN"), cancellable = true)
private void boostWhenUsing(Vec2 input, CallbackInfoReturnable<Vec2> cir) {
// NoStun module removed; no item-use speed boost remains.
}
@Inject(method = "aiStep", at = @At("HEAD"))
private void lovisual$elytraFlyVanilla(CallbackInfo ci) {
// ElytraFly module removed; no vanilla elytra override remains.
}
@Shadow
protected abstract void sendPosition();
@Inject(method = "applyInput", at = @At("HEAD"), cancellable = true)
private void freecam$blockWASD(CallbackInfo ci) {
Freecam fc = Modules.get(Freecam.class);
if (fc != null && fc.isEnabled() && fc.isCameraInput()) {
ci.cancel();
}
}
private void freecam$blockWASD(CallbackInfo ci) { if (lovisual$inputHandler.shouldBlockWASD()) ci.cancel(); }
@Inject(
method = "aiStep",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/ClientInput;tick()V",
shift = At.Shift.AFTER
)
)
private void freecam$afterInputTick(CallbackInfo ci) {
Freecam fc = Modules.get(Freecam.class);
if (fc == null || !fc.isEnabled() || !fc.isCameraInput()) return;
@Inject(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/ClientInput;tick()V", shift = At.Shift.AFTER))
private void freecam$afterInputTick(CallbackInfo ci) { lovisual$inputHandler.handleFreecamAfterInputTick((LocalPlayer) (Object) this); }
((InputAccessor) this.input).setMovementVector(Vec2.ZERO);
@Inject(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/ClientInput;tick()V", shift = At.Shift.AFTER))
private void lovisual$afterInputTickSprint(CallbackInfo ci) { lovisual$inputHandler.handleAfterInputTickSprint((LocalPlayer) (Object) this); }
boolean sneak = false;
boolean sprint = this.input.keyPresses.sprint();
@Redirect(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Input;shift()Z", ordinal = 0))
private boolean freecam$noFlyDown0(Input in) { return lovisual$inputHandler.redirectShift(in, (LocalPlayer) (Object) this); }
this.input.keyPresses = new Input(
false, false, false, false,
false,
sneak,
sprint
);
}
@Inject(
method = "aiStep",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/ClientInput;tick()V",
shift = At.Shift.AFTER
)
)
private void lovisual$afterInputTickSprint(CallbackInfo ci) {
if (this.input == null) return;
Input original = this.input.keyPresses;
if (original == null) return;
Input input = original;
if (Events.BUS.hasListeners(MovementInputEvent.class)) {
MovementInputEvent event = new MovementInputEvent(input);
Events.BUS.post(event);
Input eventInput = event.toPlayerInput();
if (!lovisual$sameInput(input, eventInput)) {
input = eventInput;
}
}
Input transformedInput = lovisual$transformDirection(input);
if (!lovisual$sameInput(input, transformedInput)) {
input = transformedInput;
}
if (Events.BUS.hasListeners(SprintControlEvent.class)) {
float forward = lovisual$impulse(input.forward(), input.backward());
float sideways = lovisual$impulse(input.left(), input.right());
SprintControlEvent event = new SprintControlEvent(
forward,
sideways,
input.sprint(),
SprintControlEvent.Source.INPUT
);
Events.BUS.post(event);
if (event.shouldSprint() != input.sprint()) {
input = new Input(
input.forward(),
input.backward(),
input.left(),
input.right(),
input.jump(),
input.shift(),
event.shouldSprint()
);
}
}
if (!lovisual$sameInput(original, input)) {
lovisual$applyPlayerInput(input);
}
}
@Unique
private void lovisual$applyPlayerInput(Input input) {
if (this.input == null || input == null) {
return;
}
InputAccessor accessor = (InputAccessor) this.input;
accessor.setPlayerInput(input);
float forward = lovisual$impulse(input.forward(), input.backward());
float sideways = lovisual$impulse(input.left(), input.right());
accessor.setMovementVector(new Vec2(sideways, forward).normalized());
}
@Unique
private Input lovisual$transformDirection(Input input) {
// Free correction now runs at KeyboardInput.tick(), matching the input pipeline.
// Keep this post-input hook inert to avoid double-transforming movement input.
return input;
}
@Redirect(
method = "aiStep",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Input;shift()Z",
ordinal = 0
)
)
private boolean freecam$noFlyDown0(Input in) {
Freecam fc = Modules.get(Freecam.class);
if (fc != null && fc.isEnabled() && fc.isCameraInput()) {
LocalPlayer self = (LocalPlayer) (Object) this;
if (self.getAbilities().flying) return false;
}
return in.shift();
}
@Redirect(
method = "aiStep",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Input;shift()Z",
ordinal = 1
),
require = 0
)
private boolean freecam$noFlyDown1(Input in) {
Freecam fc = Modules.get(Freecam.class);
if (fc != null && fc.isEnabled() && fc.isCameraInput()) {
LocalPlayer self = (LocalPlayer) (Object) this;
if (self.getAbilities().flying) return false;
}
return in.shift();
}
@Redirect(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Input;shift()Z", ordinal = 1), require = 0)
private boolean freecam$noFlyDown1(Input in) { return lovisual$inputHandler.redirectShift(in, (LocalPlayer) (Object) this); }
@Inject(method = "hurtTo", at = @At("HEAD"))
private void freecam$onUpdateHealth(float newHealth, CallbackInfo ci) {
Freecam fc = Modules.get(Freecam.class);
if (fc == null || !fc.isEnabled() || !fc.disableOnDamage()) {
freecam$lastHealth = newHealth;
return;
}
if (!Float.isNaN(freecam$lastHealth) && newHealth < freecam$lastHealth) {
fc.toggle();
}
freecam$lastHealth = newHealth;
}
@Unique
private boolean shouldFreezeNow() {
Freecam freecam = Modules.get(Freecam.class);
return freecam != null && freecam.freezePlayer() && freecam.isCameraInput();
}
private void freecam$onUpdateHealth(float newHealth, CallbackInfo ci) { lovisual$movementHandler.onHurt(newHealth); }
@Inject(method = "sendPosition", at = @At("HEAD"), cancellable = true)
private void lovisual$eventSync(CallbackInfo ci) {
if (!Events.BUS.hasListeners(EventSync.class)) return;
lovisual$eventPostAction = null;
LocalPlayer self = (LocalPlayer) (Object) this;
EventSync event = new EventSync(self.getYRot(), self.getXRot());
Events.BUS.post(event);
lovisual$activeSyncEvent = event;
lovisual$eventPostAction = event.getPostAction();
if (event.isCancelled()) {
lovisual$activeSyncEvent = null;
lovisual$eventPostAction = null;
ci.cancel();
}
}
private void lovisual$eventSync(CallbackInfo ci) { lovisual$networkHandler.onSendPositionHead((LocalPlayer) (Object) this, ci); }
@Inject(method = "sendPosition", at = @At("RETURN"))
private void lovisual$eventPostSync(CallbackInfo ci) {
if (Events.BUS.hasListeners(EventPostSync.class)) {
Events.BUS.post(new EventPostSync());
}
if (lovisual$eventPostAction != null) {
lovisual$eventPostAction.run();
lovisual$eventPostAction = null;
}
lovisual$activeSyncEvent = null;
}
private void lovisual$eventPostSync(CallbackInfo ci) { lovisual$networkHandler.onSendPositionReturn(); }
@ModifyExpressionValue(
method = "sendPosition",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;getYRot()F"
)
)
private float lovisual$eventSyncYaw(float original) {
lovisual$updateVisualBodyYaw();
@ModifyExpressionValue(method = "sendPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getYRot()F"))
private float lovisual$eventSyncYaw(float original) { return lovisual$rotationHandler.resolveSendYaw((LocalPlayer) (Object) this, original, lovisual$networkHandler.getActiveSyncEvent()); }
EventSync event = lovisual$activeSyncEvent;
if (event != null && event.hasRotationOverride()) return event.getYaw();
@ModifyExpressionValue(method = "sendPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getXRot()F"))
private float lovisual$eventSyncPitch(float original) { return lovisual$rotationHandler.resolveSendPitch(original, lovisual$networkHandler.getActiveSyncEvent()); }
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
return rotation != null ? rotation.yaw() : original;
}
@ModifyExpressionValue(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getYRot()F"))
private float lovisual$visualTickYaw(float original) { return lovisual$rotationHandler.resolveTickYaw((LocalPlayer) (Object) this, original); }
@ModifyExpressionValue(
method = "sendPosition",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;getXRot()F"
)
)
private float lovisual$eventSyncPitch(float original) {
EventSync event = lovisual$activeSyncEvent;
if (event != null && event.hasRotationOverride()) return Mth.clamp(event.getPitch(), -90.0f, 90.0f);
@ModifyExpressionValue(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getXRot()F"))
private float lovisual$visualTickPitch(float original) { return lovisual$rotationHandler.resolveTickPitch(original); }
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
return rotation != null ? Mth.clamp(rotation.pitch(), -90.0f, 90.0f) : original;
}
@ModifyExpressionValue(
method = "tick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;getYRot()F"
)
)
private float lovisual$visualTickYaw(float original) {
lovisual$updateVisualBodyYaw();
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
return rotation != null ? rotation.yaw() : original;
}
@ModifyExpressionValue(
method = "tick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;getXRot()F"
)
)
private float lovisual$visualTickPitch(float original) {
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
return rotation != null ? Mth.clamp(rotation.pitch(), -90.0f, 90.0f) : original;
}
@Inject(
method = "tick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;sendPosition()V",
ordinal = 0,
shift = At.Shift.AFTER
),
cancellable = true
)
private void lovisual$postPlayerUpdate(CallbackInfo ci) {
if (!Events.BUS.hasListeners(PostPlayerUpdateEvent.class)) return;
if (lovisual$postUpdateLock) return;
PostPlayerUpdateEvent event = new PostPlayerUpdateEvent();
Events.BUS.post(event);
if (!event.isCancelled()) return;
ci.cancel();
int iterations = event.getIterations();
if (iterations <= 0) return;
LocalPlayer self = (LocalPlayer) (Object) this;
for (int i = 0; i < iterations; i++) {
lovisual$postUpdateLock = true;
self.tick();
lovisual$postUpdateLock = false;
sendPosition();
}
}
@Inject(method = "sendPosition", at = @At("HEAD"), cancellable = true)
private void cancelPackets(CallbackInfo ci) {
// Freeze module removed; only Freecam may still freeze movement.
}
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;sendPosition()V", ordinal = 0, shift = At.Shift.AFTER), cancellable = true)
private void lovisual$postPlayerUpdate(CallbackInfo ci) { lovisual$networkHandler.onPostPlayerUpdate((LocalPlayer) (Object) this, ci, this::sendPosition); }
@Inject(method = "aiStep", at = @At("HEAD"), cancellable = true)
private void lovisual$freezeTickMovement(CallbackInfo ci) {
LocalPlayer p = (LocalPlayer) (Object) this;
if (!shouldFreezeNow()) {
if (frozen) {
p.setDeltaMovement(savedVelocity);
frozen = false;
}
return;
}
if (!frozen) {
frozen = true;
savedX = p.getX();
savedY = p.getY();
savedZ = p.getZ();
savedVelocity = p.getDeltaMovement();
if (Modules.get(Freecam.class) == null || !Modules.get(Freecam.class).isEnabled()) {
savedBodyYaw = p.yBodyRot;
savedHeadYaw = p.yHeadRot;
}
}
p.setDeltaMovement(Vec3.ZERO);
p.absSnapTo(savedX, savedY, savedZ);
if (Modules.get(Freecam.class) == null || !Modules.get(Freecam.class).isEnabled()) {
p.yBodyRot = savedBodyYaw;
p.yHeadRot = savedHeadYaw;
}
ci.cancel();
}
@Inject(method = "aiStep", at = @At("HEAD"))
private void lovisual$noStunTickMovement(CallbackInfo ci) {
// NoStun module removed; no hurt-time input override remains.
}
@Unique
private void lovisual$updateVisualBodyYaw() {
LocalPlayer self = (LocalPlayer) (Object) this;
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
if (rotation == null) {
lovisual$rotationPrevX = self.getX();
lovisual$rotationPrevZ = self.getZ();
lovisual$rotationPrevBodyYaw = self.getVisualRotationYInDegrees();
return;
}
float newBodyYaw = lovisual$simulateBodyYaw(
rotation.yaw(),
lovisual$rotationPrevBodyYaw,
lovisual$rotationPrevX,
lovisual$rotationPrevZ,
self.getX(),
self.getZ(),
self.attackAnim
);
self.setYBodyRot(newBodyYaw);
lovisual$rotationPrevBodyYaw = newBodyYaw;
lovisual$rotationPrevX = self.getX();
lovisual$rotationPrevZ = self.getZ();
}
@Inject(method = "tick", at = @At("HEAD"))
private void detectPearlImpact(CallbackInfo ci) {
// NoPush module removed; no pearl-phase spoofing remains.
}
@Inject(method = "sendPosition", at = @At("HEAD"))
private void sendSpoofAfterPearl(CallbackInfo ci) {
// NoPush module removed; no pearl-phase spoofing remains.
}
@Inject(method = "aiStep", at = @At("TAIL"))
private void onCollideBoost(CallbackInfo ci) {
// Speed module removed; no entity-collision boost remains.
}
@Inject(method = "aiStep", at = @At("TAIL"))
private void omniLongJump(CallbackInfo ci) {
// Speed module removed; no jump boost remains.
}
@Inject(method = "modifyInput", at = @At("RETURN"), cancellable = true)
private void applyLegitSpeed(Vec2 input, CallbackInfoReturnable<Vec2> cir) {
// Speed module removed; no input speed multiplier remains.
}
@Inject(method = "closeContainer", at = @At("HEAD"), cancellable = true)
private void lovisual$inventoryMove$deferCloseHandledScreen(CallbackInfo ci) {
// InventoryMove module removed; no container close deferral remains.
}
@Inject(method = "closeContainer", at = @At("HEAD"), cancellable = true)
private void lovisual$keepInventoryOpen(CallbackInfo ci) {
// XCarry module removed; no inventory close suppression remains.
}
private void lovisual$freezeTickMovement(CallbackInfo ci) { lovisual$movementHandler.onFreezeTick((LocalPlayer) (Object) this, ci); }
@Inject(method = "moveTowardsClosestSpace", at = @At("HEAD"), cancellable = true)
private void lovisual$noPushOutOfBlocks(double x, double z, CallbackInfo ci) {
if (!Events.BUS.hasListeners(EventPushOutOfBlocks.class)) return;
EventPushOutOfBlocks event = new EventPushOutOfBlocks(x, z);
Events.BUS.post(event);
if (event.isCancelled()) {
ci.cancel();
}
}
private void lovisual$noPushOutOfBlocks(double x, double z, CallbackInfo ci) { lovisual$movementHandler.onPushOutOfBlocks(x, z, ci); }
}

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.entity.player;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;

View file

@ -0,0 +1,90 @@
package dev.loki.lovisual.mixins.entity.player;
import dev.loki.lovisual.events.Events;
import dev.loki.lovisual.events.impl.input.SprintControlEvent;
import dev.loki.lovisual.events.impl.movement.MovementInputEvent;
import dev.loki.lovisual.features.module.lifecycle.Modules;
import dev.loki.lovisual.features.module.modules.visuals.camera.Freecam;
import dev.loki.lovisual.mixins.accessors.misc.InputAccessor;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.player.Input;
import net.minecraft.world.phys.Vec2;
final class LocalPlayerInputHandler {
boolean shouldBlockWASD() {
Freecam fc = Modules.get(Freecam.class);
return fc != null && fc.isEnabled() && fc.isCameraInput();
}
void handleFreecamAfterInputTick(LocalPlayer self) {
Freecam fc = Modules.get(Freecam.class);
if (fc == null || !fc.isEnabled() || !fc.isCameraInput()) return;
if (self.input == null) return;
((InputAccessor) self.input).setMovementVector(Vec2.ZERO);
boolean sprint = self.input.keyPresses.sprint();
self.input.keyPresses = new Input(false, false, false, false, false, false, sprint);
}
void handleAfterInputTickSprint(LocalPlayer self) {
if (self.input == null) return;
Input original = self.input.keyPresses;
if (original == null) return;
Input input = original;
if (Events.BUS.hasListeners(MovementInputEvent.class)) {
MovementInputEvent event = new MovementInputEvent(input);
Events.BUS.post(event);
Input converted = event.toPlayerInput();
if (!sameInput(input, converted)) input = converted;
}
Input transformed = transformDirection(input);
if (!sameInput(input, transformed)) input = transformed;
if (Events.BUS.hasListeners(SprintControlEvent.class)) {
float forward = impulse(input.forward(), input.backward());
float sideways = impulse(input.left(), input.right());
SprintControlEvent event = new SprintControlEvent(forward, sideways, input.sprint(), SprintControlEvent.Source.INPUT);
Events.BUS.post(event);
if (event.shouldSprint() != input.sprint()) {
input = new Input(input.forward(), input.backward(), input.left(), input.right(), input.jump(), input.shift(), event.shouldSprint());
}
}
if (!sameInput(original, input)) applyPlayerInput(self, input);
}
void applyPlayerInput(LocalPlayer self, Input input) {
if (self.input == null || input == null) return;
InputAccessor accessor = (InputAccessor) self.input;
accessor.setPlayerInput(input);
float forward = impulse(input.forward(), input.backward());
float sideways = impulse(input.left(), input.right());
accessor.setMovementVector(new Vec2(sideways, forward).normalized());
}
Input transformDirection(Input input) { return input; }
boolean postSprintControl(LocalPlayer self, boolean original, SprintControlEvent.Source source) {
if (self.input == null) return original;
if (!Events.BUS.hasListeners(SprintControlEvent.class)) return original;
Vec2 movement = self.input.getMoveVector();
SprintControlEvent event = new SprintControlEvent(movement.y, movement.x, original, source);
Events.BUS.post(event);
return event.shouldSprint();
}
boolean redirectShift(Input in, LocalPlayer self) {
Freecam fc = Modules.get(Freecam.class);
if (fc != null && fc.isEnabled() && fc.isCameraInput() && self.getAbilities().flying) return false;
return in.shift();
}
boolean sameInput(Input a, Input b) {
if (a == b) return true;
if (a == null || b == null) return false;
return a.forward() == b.forward() && a.backward() == b.backward() && a.left() == b.left() && a.right() == b.right() && a.jump() == b.jump() && a.shift() == b.shift() && a.sprint() == b.sprint();
}
float impulse(boolean positive, boolean negative) {
if (positive == negative) return 0.0f;
return positive ? 1.0f : -1.0f;
}
}

View file

@ -0,0 +1,73 @@
package dev.loki.lovisual.mixins.entity.player;
import dev.loki.lovisual.events.Events;
import dev.loki.lovisual.events.impl.world.EventPushOutOfBlocks;
import dev.loki.lovisual.features.module.lifecycle.Modules;
import dev.loki.lovisual.features.module.modules.visuals.camera.Freecam;
import dev.loki.lovisual.mixins.accessors.entity.EntityAccessor;
import dev.loki.lovisual.mixins.accessors.entity.LocalPlayerAccessor;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.PortalProcessor;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
final class LocalPlayerMovementHandler {
private float lastHealth = Float.NaN;
private boolean frozen;
private Vec3 savedVelocity = Vec3.ZERO;
private double savedX, savedY, savedZ;
private float savedBodyYaw, savedHeadYaw;
void onPortalNausea(LocalPlayer self, CallbackInfo ci) {
PortalProcessor portal = null;
if (self instanceof EntityAccessor accessor) portal = accessor.lovisual$getPortalManager();
if (portal != null && portal.isInsidePortalThisTick()) {
if (self instanceof LocalPlayerAccessor acc) {
acc.lovisual$setNauseaIntensity(0.0f);
acc.lovisual$setLastNauseaIntensity(0.0f);
}
ci.cancel();
}
}
void onHurt(float newHealth) {
Freecam fc = Modules.get(Freecam.class);
if (fc == null || !fc.isEnabled() || !fc.disableOnDamage()) { lastHealth = newHealth; return; }
if (!Float.isNaN(lastHealth) && newHealth < lastHealth) fc.toggle();
lastHealth = newHealth;
}
void onPushOutOfBlocks(double x, double z, CallbackInfo ci) {
if (!Events.BUS.hasListeners(EventPushOutOfBlocks.class)) return;
EventPushOutOfBlocks event = new EventPushOutOfBlocks(x, z);
Events.BUS.post(event);
if (event.isCancelled()) ci.cancel();
}
boolean shouldFreezeNow() {
Freecam freecam = Modules.get(Freecam.class);
return freecam != null && freecam.freezePlayer() && freecam.isCameraInput();
}
void onFreezeTick(LocalPlayer self, CallbackInfo ci) {
if (!shouldFreezeNow()) {
if (frozen) { self.setDeltaMovement(savedVelocity); frozen = false; }
return;
}
if (!frozen) {
frozen = true;
savedX = self.getX(); savedY = self.getY(); savedZ = self.getZ();
savedVelocity = self.getDeltaMovement();
if (Modules.get(Freecam.class) == null || !Modules.get(Freecam.class).isEnabled()) {
savedBodyYaw = self.yBodyRot; savedHeadYaw = self.yHeadRot;
}
}
self.setDeltaMovement(Vec3.ZERO);
self.absSnapTo(savedX, savedY, savedZ);
if (Modules.get(Freecam.class) == null || !Modules.get(Freecam.class).isEnabled()) {
self.yBodyRot = savedBodyYaw; self.yHeadRot = savedHeadYaw;
}
ci.cancel();
}
}

View file

@ -0,0 +1,63 @@
package dev.loki.lovisual.mixins.entity.player;
import dev.loki.lovisual.events.Events;
import dev.loki.lovisual.events.impl.network.EventPostSync;
import dev.loki.lovisual.events.impl.network.EventSync;
import dev.loki.lovisual.events.impl.player.PostPlayerUpdateEvent;
import dev.loki.lovisual.util.combat.rotation.SprintController;
import net.minecraft.client.player.LocalPlayer;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
final class LocalPlayerNetworkHandler {
private Runnable eventPostAction;
private EventSync activeSyncEvent;
private boolean postUpdateLock;
boolean onSendPositionHead(LocalPlayer self, CallbackInfo ci) {
if (!Events.BUS.hasListeners(EventSync.class)) return false;
eventPostAction = null;
EventSync event = new EventSync(self.getYRot(), self.getXRot());
Events.BUS.post(event);
activeSyncEvent = event;
eventPostAction = event.getPostAction();
if (event.isCancelled()) {
activeSyncEvent = null;
eventPostAction = null;
ci.cancel();
return true;
}
return false;
}
void onSendPositionReturn() {
if (Events.BUS.hasListeners(EventPostSync.class)) Events.BUS.post(new EventPostSync());
if (eventPostAction != null) { eventPostAction.run(); eventPostAction = null; }
activeSyncEvent = null;
}
EventSync getActiveSyncEvent() { return activeSyncEvent; }
boolean onPostPlayerUpdate(LocalPlayer self, CallbackInfo ci, Runnable sendPosition) {
if (!Events.BUS.hasListeners(PostPlayerUpdateEvent.class)) return false;
if (postUpdateLock) return false;
PostPlayerUpdateEvent event = new PostPlayerUpdateEvent();
Events.BUS.post(event);
if (!event.isCancelled()) return false;
ci.cancel();
int iterations = event.getIterations();
if (iterations <= 0) return true;
for (int i = 0; i < iterations; i++) {
postUpdateLock = true;
self.tick();
postUpdateLock = false;
sendPosition.run();
}
return true;
}
boolean shouldBlockSprintNetwork(boolean original) {
if (SprintController.INSTANCE.isSprintBlocked()) return false;
return original;
}
}

View file

@ -0,0 +1,87 @@
package dev.loki.lovisual.mixins.entity.player;
import dev.loki.lovisual.events.impl.network.EventSync;
import dev.loki.lovisual.mixininterface.entity.ILocalPlayer;
import dev.loki.lovisual.util.aiming.data.Rotation;
import dev.loki.lovisual.util.aiming.rotation.RotationManager;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.util.Mth;
final class LocalPlayerRotationHandler {
private double rotationPrevX;
private double rotationPrevZ;
private float rotationPrevBodyYaw;
private boolean rotationBodyYawInitialized;
void onTickCache(LocalPlayer self) {
if (self instanceof ILocalPlayer access) {
access.lovisual$setLastYaw(self.getYRot());
access.lovisual$setLastPitch(self.getXRot());
}
RotationManager.INSTANCE.runTickLifecycle();
if (!rotationBodyYawInitialized) {
rotationPrevX = self.getX();
rotationPrevZ = self.getZ();
rotationPrevBodyYaw = self.getVisualRotationYInDegrees();
rotationBodyYawInitialized = true;
}
}
float resolveSendYaw(LocalPlayer self, float original, EventSync active) {
updateVisualBodyYaw(self);
if (active != null && active.hasRotationOverride()) return active.getYaw();
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
return rotation != null ? rotation.yaw() : original;
}
float resolveSendPitch(float original, EventSync active) {
if (active != null && active.hasRotationOverride()) return Mth.clamp(active.getPitch(), -90.0f, 90.0f);
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
return rotation != null ? Mth.clamp(rotation.pitch(), -90.0f, 90.0f) : original;
}
float resolveTickYaw(LocalPlayer self, float original) {
updateVisualBodyYaw(self);
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
return rotation != null ? rotation.yaw() : original;
}
float resolveTickPitch(float original) {
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
return rotation != null ? Mth.clamp(rotation.pitch(), -90.0f, 90.0f) : original;
}
void updateVisualBodyYaw(LocalPlayer self) {
Rotation rotation = RotationManager.INSTANCE.getCurrentRotation();
if (rotation == null) {
rotationPrevX = self.getX();
rotationPrevZ = self.getZ();
rotationPrevBodyYaw = self.getVisualRotationYInDegrees();
return;
}
float newBodyYaw = simulateBodyYaw(rotation.yaw(), rotationPrevBodyYaw, rotationPrevX, rotationPrevZ, self.getX(), self.getZ(), self.attackAnim);
self.setYBodyRot(newBodyYaw);
rotationPrevBodyYaw = newBodyYaw;
rotationPrevX = self.getX();
rotationPrevZ = self.getZ();
}
float simulateBodyYaw(float yaw, float prevBodyYaw, double prevX, double prevZ, double currentX, double currentZ, float handSwing) {
double motionX = currentX - prevX;
double motionZ = currentZ - prevZ;
float motionSquared = (float) (motionX * motionX + motionZ * motionZ);
float bodyYaw = prevBodyYaw;
if (motionSquared > 0.0025000002F) {
float movementYaw = (float) Mth.atan2(motionZ, motionX) * Mth.RAD_TO_DEG - 90.0F;
float yawDiff = Math.abs(Mth.wrapDegrees(yaw) - movementYaw);
bodyYaw = (yawDiff > 95.0F && yawDiff < 265.0F) ? movementYaw - 180.0F : movementYaw;
}
if (handSwing - 0.2F > 0.0F) bodyYaw = yaw;
float deltaYaw = Mth.wrapDegrees(bodyYaw - prevBodyYaw);
bodyYaw = prevBodyYaw + deltaYaw * 0.3F;
float yawOffsetDiff = Mth.wrapDegrees(yaw - bodyYaw);
if (Math.abs(yawOffsetDiff) > 52.0F) bodyYaw += yawOffsetDiff - Math.signum(yawOffsetDiff) * 52.0F;
return bodyYaw;
}
}

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.entity.world;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;

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.entity.world;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;

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.entity.world;
import net.minecraft.world.entity.Entity;

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.gui.chat;
import net.minecraft.client.gui.Font;

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.gui.chat;
import net.minecraft.client.gui.ActiveTextCollector;

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.gui.chat;
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.gui.core;
import dev.loki.lovisual.features.module.lifecycle.Modules;

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.gui.core;
import net.minecraft.client.gui.GuiGraphicsExtractor;

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.gui.core;
import dev.loki.lovisual.util.screen.ClientScreen;

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.gui.core;
import net.minecraft.client.gui.components.AbstractWidget;

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.gui.multiplayer;
import dev.loki.lovisual.features.theme.Theme;

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.gui.multiplayer;
import net.minecraft.client.gui.screens.inventory.AbstractRecipeBookScreen;

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.gui.screens;
import com.llamalad7.mixinextras.sugar.Local;
@ -25,6 +18,8 @@ import dev.loki.lovisual.features.gui.clickgui.picker.screen.ClickGuiPickerScree
import dev.loki.lovisual.features.gui.clickgui.render.ClickGuiRenderer;
import dev.loki.lovisual.features.gui.clickgui.screen.ClickGuiScreen;
import dev.loki.lovisual.features.gui.hud.nondraggable.impl.bars.CustomBar;
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.dynamicisland.DynamicIsland;
import dev.loki.lovisual.features.module.modules.misc.ClickGui;
import dev.loki.lovisual.render.engine.core.system.LoVisualRenderSystem;
@ -43,12 +38,12 @@ public abstract class GuiScreenMixin {
CustomBar bar = CustomBar.get();
if (bar == null || !bar.isHudBarEnabled() || !bar.isHotbarXpBarEnabled()) return;
if (CustomBar.shouldUseJumpBar(mc) || !CustomBar.shouldUseLocator(mc, bar)) return;
if (CustomJumpBarRenderer.shouldUseJumpBar(mc) || !CustomBar.shouldUseLocator(mc, bar)) return;
LoVisualRenderSystem.ensureFrameContext();
try (RenderPhaseScope ignored = LoVisualRenderSystem.phase(RenderPhase.SCREEN_TOP, "2d:hud:custom_bar_heads")) {
Renderer2D.withDeferredLayer(Renderer2D.Deferred2DLayer.AFTER_VANILLA_GUI, () -> {
CustomBar.renderLocatorHeads(drawContext, tickCounter, mc);
CustomLocatorRenderer.renderLocatorHeads(drawContext, tickCounter, mc);
Renderer2D.COLOR.render();
});
}

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.gui.screens;
import net.minecraft.client.gui.GuiGraphicsExtractor;

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.gui.screens;
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.gui.screens;
import dev.loki.lovisual.util.screen.ClientScreen;

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.gui.widgets;
import dev.loki.lovisual.util.screen.ClientScreen;

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.gui.widgets;
import dev.loki.lovisual.util.screen.ClientScreen;

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.gui.widgets;
import dev.loki.lovisual.util.screen.ClientScreen;

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.gui.widgets;
import dev.loki.lovisual.util.screen.ClientScreen;

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);
}
}

Some files were not shown because too many files have changed in this diff Show more