- feat: Фаза 1 ребрендинг combatant → lovisual + восстановление config - refactor: Фаза 2 — выкинуть Runtime/JarReplacement, заменить на Lifecycle - refactor: Фаза 3.5 — удалить читерские модули, ESP под легит - refactor: Фаза 3 — разбить Renderer2D (3379→2150 фасад + 14 хелперов ≤200) - refactor: Фаза 3 — разбить BetterChatRenderer (2870→210 фасад + 21 хелпер ≤200) - refactor: Фаза 3 — разбить UnifiedSettingRenderer (2798→208 фасад + 24 хелпера ≤200) - refactor: Фаза 3 — разбить ClickGuiRenderer (1887→542 фасад + 15 хелперов ≤200) - refactor: Фаза 3 — разбить NameTags (1791→438 фасад + 11 хелперов ≤200) - refactor: Фаза 3 — разбить TargetHud (1655→340 фасад + 11 хелперов ≤200) - refactor: Фаза 3 — разбить ESP (1538→269 фасад + 11 хелперов ≤200)
154 lines
5.5 KiB
Java
154 lines
5.5 KiB
Java
/*
|
||
* This file is part of the LoVisual Client distribution.
|
||
* LoVisual modifications copyright (c) 2026 pivosos2007.
|
||
*
|
||
* Portions of this file are based on LiquidBounce
|
||
* (https://github.com/CCBlueX/LiquidBounce).
|
||
* Copyright (c) 2015-2026 CCBlueX.
|
||
*
|
||
* LiquidBounce portions are licensed under GPLv3-or-later.
|
||
* LoVisual modifications are licensed under GPLv3.
|
||
* See THIRD_PARTY_NOTICES.md for details.
|
||
*/
|
||
|
||
package dev.loki.lovisual.mixins;
|
||
|
||
/*
|
||
* Parts of attack rotation and keep-sprint related hooks are adapted from
|
||
* LiquidBounce (https://github.com/CCBlueX/LiquidBounce).
|
||
* Original copyright (c) CCBlueX.
|
||
*/
|
||
|
||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||
import net.minecraft.client.Minecraft;
|
||
import net.minecraft.core.registries.BuiltInRegistries;
|
||
import net.minecraft.world.entity.player.Player;
|
||
import net.minecraft.world.item.ItemCooldowns;
|
||
import net.minecraft.world.item.Items;
|
||
import net.minecraft.world.phys.Vec3;
|
||
import org.spongepowered.asm.mixin.Final;
|
||
import org.spongepowered.asm.mixin.Mixin;
|
||
import org.spongepowered.asm.mixin.Shadow;
|
||
import org.spongepowered.asm.mixin.injection.At;
|
||
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.events.Events;
|
||
import dev.loki.lovisual.events.impl.PlayerSafeWalkEvent;
|
||
import dev.loki.lovisual.features.module.Modules;
|
||
import dev.loki.lovisual.features.module.modules.player.NoDelay;
|
||
import dev.loki.lovisual.features.module.modules.combat.TPSSync;
|
||
import dev.loki.lovisual.mixininterface.IPlayerAttackCooldown;
|
||
import dev.loki.lovisual.util.aiming.RotationManager;
|
||
|
||
@Mixin(Player.class)
|
||
public abstract class PlayerEntityMixin implements IPlayerAttackCooldown {
|
||
|
||
@Shadow
|
||
@Final
|
||
private ItemCooldowns cooldowns;
|
||
|
||
@Inject(method = "isStayingOnGroundSurface", at = @At("RETURN"), cancellable = true)
|
||
private void lovisual$safeWalk(CallbackInfoReturnable<Boolean> cir) {
|
||
if (cir.getReturnValue()) return;
|
||
if ((Object) this != Minecraft.getInstance().player) return;
|
||
if (!Events.BUS.hasListeners(PlayerSafeWalkEvent.class)) return;
|
||
|
||
PlayerSafeWalkEvent event = new PlayerSafeWalkEvent();
|
||
Events.BUS.post(event);
|
||
if (event.isSafeWalk()) {
|
||
cir.setReturnValue(true);
|
||
}
|
||
}
|
||
|
||
@Inject(method = "isMobilityRestricted", at = @At("HEAD"), cancellable = true)
|
||
private void lovisual$noStunBlindnessSprint(CallbackInfoReturnable<Boolean> cir) {
|
||
// NoStun module removed; no mobility override remains.
|
||
}
|
||
|
||
@ModifyExpressionValue(
|
||
method = "causeExtraKnockback",
|
||
at = @At(
|
||
value = "INVOKE",
|
||
target = "Lnet/minecraft/world/entity/player/Player;getYRot()F"
|
||
)
|
||
)
|
||
private float lovisual$fixKnockbackYaw(float original) {
|
||
if ((Object) this != Minecraft.getInstance().player) {
|
||
return original;
|
||
}
|
||
return RotationManager.INSTANCE.getMovementRotation().yaw();
|
||
}
|
||
|
||
@ModifyExpressionValue(
|
||
method = "doSweepAttack",
|
||
at = @At(
|
||
value = "INVOKE",
|
||
target = "Lnet/minecraft/world/entity/player/Player;getYRot()F"
|
||
)
|
||
)
|
||
private float lovisual$fixSweepYaw(float original) {
|
||
if ((Object) this != Minecraft.getInstance().player) {
|
||
return original;
|
||
}
|
||
return RotationManager.INSTANCE.getMovementRotation().yaw();
|
||
}
|
||
|
||
@ModifyExpressionValue(
|
||
method = "travel",
|
||
at = @At(
|
||
value = "INVOKE",
|
||
target = "Lnet/minecraft/world/entity/player/Player;getLookAngle()Lnet/minecraft/world/phys/Vec3;"
|
||
)
|
||
)
|
||
private Vec3 lovisual$fixTravelRotationVector(Vec3 original) {
|
||
if ((Object) this != Minecraft.getInstance().player) {
|
||
return original;
|
||
}
|
||
return RotationManager.INSTANCE.getMovementRotation().directionVector();
|
||
}
|
||
|
||
@Inject(method = "tick", at = @At("HEAD"))
|
||
private void handleShieldCooldown(CallbackInfo ci) {
|
||
NoDelay noDelay = Modules.get(NoDelay.class);
|
||
if (noDelay == null || !noDelay.shouldDisableShieldCooldown()) return;
|
||
|
||
cooldowns.removeCooldown(BuiltInRegistries.ITEM.getKey(Items.SHIELD));
|
||
}
|
||
|
||
/**
|
||
* Синхронизация attack cooldown с серверным TPS.
|
||
* НЕ трогает ItemCooldownManager.
|
||
* НЕ влияет на shield.
|
||
*/
|
||
@ModifyReturnValue(
|
||
method = "getCurrentItemAttackStrengthDelay",
|
||
at = @At("RETURN")
|
||
)
|
||
private float lovisual$tpsSyncAttackCooldown(float original) {
|
||
float result = original;
|
||
|
||
TPSSync tpsSync = Modules.get(TPSSync.class);
|
||
if (tpsSync != null && tpsSync.isEnabled()) {
|
||
float serverDelta = tpsSync.getServerTickDelta();
|
||
if (serverDelta > 0.0f && serverDelta < 1.0f) {
|
||
// замедляем заполнение cooldown’а под TPS
|
||
result = result / serverDelta;
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
@Override
|
||
public float lovisual$getAttackCooldownProgress(float tickDelta) {
|
||
Player self = (Player) (Object) this;
|
||
return self.getAttackStrengthScale(tickDelta);
|
||
}
|
||
|
||
@Override
|
||
public boolean lovisual$isAttackCharged(float tickDelta) {
|
||
return lovisual$getAttackCooldownProgress(tickDelta) >= 1.0f;
|
||
}
|
||
}
|