LoVisual/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/PlayerEntityMixin.java
loki5512344 52d87368c9 chore(history): squash 10 commit(s) from 2026-07-31
- 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)
2026-07-31 23:14:14 +02:00

154 lines
5.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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;
}
}