diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/client/MixinKeyboardInput.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/client/MixinKeyboardInput.java
index e91e7d6fac2..2f51380e9a7 100644
--- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/client/MixinKeyboardInput.java
+++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/client/MixinKeyboardInput.java
@@ -25,6 +25,7 @@
import net.ccbluex.liquidbounce.event.events.MovementInputEvent;
import net.ccbluex.liquidbounce.event.events.SprintEvent;
import net.ccbluex.liquidbounce.features.module.modules.movement.ModuleInventoryMove;
+import net.ccbluex.liquidbounce.utils.aiming.MovementCorrection;
import net.ccbluex.liquidbounce.utils.aiming.RotationManager;
import net.ccbluex.liquidbounce.utils.input.InputTracker;
import net.ccbluex.liquidbounce.utils.movement.DirectionalInput;
@@ -113,7 +114,8 @@ private DirectionalInput transformDirection(DirectionalInput input) {
float z = KeyboardInput.getMovementMultiplier(input.getForwards(), input.getBackwards());
float x = KeyboardInput.getMovementMultiplier(input.getLeft(), input.getRight());
- if (configurable == null || !configurable.getApplyVelocityFix() || rotation == null || player == null) {
+ if (configurable == null || configurable.getMovementCorrection() != MovementCorrection.SILENT
+ || rotation == null || player == null) {
return input;
}
diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinLivingEntity.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinLivingEntity.java
index 5fca9c5afdc..fdc7560981d 100644
--- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinLivingEntity.java
+++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinLivingEntity.java
@@ -26,6 +26,7 @@
import net.ccbluex.liquidbounce.features.module.modules.movement.*;
import net.ccbluex.liquidbounce.features.module.modules.render.ModuleAntiBlind;
import net.ccbluex.liquidbounce.features.module.modules.world.scaffold.ModuleScaffold;
+import net.ccbluex.liquidbounce.utils.aiming.MovementCorrection;
import net.ccbluex.liquidbounce.utils.aiming.RotationManager;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.LivingEntity;
@@ -176,7 +177,7 @@ private Vec3d hookFixRotation(Vec3d original) {
return original;
}
- if (configurable == null || !configurable.getApplyVelocityFix() || rotation == null) {
+ if (configurable == null || configurable.getMovementCorrection() == MovementCorrection.OFF || rotation == null) {
return original;
}
@@ -248,7 +249,7 @@ private float hookModifyFallFlyingPitch(float original) {
var rotation = rotationManager.getCurrentRotation();
var configurable = rotationManager.getWorkingAimPlan();
- if (rotation == null || configurable == null || !configurable.getApplyVelocityFix() || configurable.getChangeLook()) {
+ if (rotation == null || configurable == null || configurable.getMovementCorrection() == MovementCorrection.OFF) {
return original;
}
@@ -268,7 +269,7 @@ private Vec3d hookModifyFallFlyingRotationVector(Vec3d original) {
var rotation = rotationManager.getCurrentRotation();
var configurable = rotationManager.getWorkingAimPlan();
- if (rotation == null || configurable == null || !configurable.getApplyVelocityFix() || configurable.getChangeLook()) {
+ if (rotation == null || configurable == null || configurable.getMovementCorrection() == MovementCorrection.OFF) {
return original;
}
diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinPlayerEntity.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinPlayerEntity.java
index c5abd307622..0806acb85d4 100644
--- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinPlayerEntity.java
+++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/entity/MixinPlayerEntity.java
@@ -35,6 +35,7 @@
import net.ccbluex.liquidbounce.features.module.modules.player.nofall.modes.NoFallNoGround;
import net.ccbluex.liquidbounce.features.module.modules.world.ModuleNoSlowBreak;
import net.ccbluex.liquidbounce.utils.aiming.AimPlan;
+import net.ccbluex.liquidbounce.utils.aiming.MovementCorrection;
import net.ccbluex.liquidbounce.utils.aiming.Rotation;
import net.ccbluex.liquidbounce.utils.aiming.RotationManager;
import net.minecraft.client.MinecraftClient;
@@ -96,7 +97,7 @@ private float hookFixRotation(float original) {
Rotation rotation = rotationManager.getCurrentRotation();
AimPlan configurable = rotationManager.getWorkingAimPlan();
- if (configurable == null || !configurable.getApplyVelocityFix() || rotation == null) {
+ if (configurable == null || configurable.getMovementCorrection() == MovementCorrection.OFF || rotation == null) {
return original;
}
diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/render/MixinCamera.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/render/MixinCamera.java
index 5e951e13b29..63252b4147b 100644
--- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/render/MixinCamera.java
+++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/render/MixinCamera.java
@@ -22,6 +22,7 @@
import net.ccbluex.liquidbounce.features.module.modules.combat.aimbot.ModuleDroneControl;
import net.ccbluex.liquidbounce.features.module.modules.render.*;
import net.ccbluex.liquidbounce.utils.aiming.AimPlan;
+import net.ccbluex.liquidbounce.utils.aiming.MovementCorrection;
import net.ccbluex.liquidbounce.utils.aiming.RotationManager;
import net.minecraft.client.render.Camera;
import net.minecraft.entity.Entity;
@@ -107,7 +108,7 @@ private void modifyCameraOrientation(BlockView area, Entity focusedEntity, boole
var currentRotation = RotationManager.INSTANCE.getCurrentRotation();
boolean shouldModifyRotation = ModuleRotations.INSTANCE.getRunning() && ModuleRotations.INSTANCE.getCamera()
- || aimPlan != null && aimPlan.getChangeLook();
+ || aimPlan != null && aimPlan.getMovementCorrection() == MovementCorrection.CHANGE_LOOK;
if (currentRotation == null || previousRotation == null || !shouldModifyRotation) {
return;
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/movement/ModuleSprint.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/movement/ModuleSprint.kt
index 4caf8e1097c..f3c0628ba5f 100644
--- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/movement/ModuleSprint.kt
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/movement/ModuleSprint.kt
@@ -25,6 +25,7 @@ import net.ccbluex.liquidbounce.event.handler
import net.ccbluex.liquidbounce.features.module.Category
import net.ccbluex.liquidbounce.features.module.ClientModule
import net.ccbluex.liquidbounce.features.module.modules.world.scaffold.features.ScaffoldSprintControlFeature
+import net.ccbluex.liquidbounce.utils.aiming.MovementCorrection
import net.ccbluex.liquidbounce.utils.aiming.Rotation
import net.ccbluex.liquidbounce.utils.aiming.RotationManager
import net.ccbluex.liquidbounce.utils.aiming.RotationsConfigurable
@@ -121,7 +122,7 @@ object ModuleSprint : ClientModule("Sprint", Category.MOVEMENT) {
MathHelper.sin(deltaYaw * 0.017453292f) > 1.0E-5
val preventSprint = (if (player.isOnGround) stopOnGround else stopOnAir)
&& !shouldSprintOmnidirectional
- && RotationManager.workingAimPlan?.applyVelocityFix == false && !hasForwardMovement
+ && RotationManager.workingAimPlan?.movementCorrection == MovementCorrection.OFF && !hasForwardMovement
return running && preventSprint
}
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/script/bindings/api/ScriptRotationUtil.kt b/src/main/kotlin/net/ccbluex/liquidbounce/script/bindings/api/ScriptRotationUtil.kt
index 82dd819cb22..aa839903e29 100644
--- a/src/main/kotlin/net/ccbluex/liquidbounce/script/bindings/api/ScriptRotationUtil.kt
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/script/bindings/api/ScriptRotationUtil.kt
@@ -22,10 +22,7 @@ import net.ccbluex.liquidbounce.event.EventListener
import net.ccbluex.liquidbounce.features.module.Category
import net.ccbluex.liquidbounce.features.module.ClientModule
import net.ccbluex.liquidbounce.script.bindings.api.ScriptRotationUtil.newRotationEntity
-import net.ccbluex.liquidbounce.utils.aiming.Rotation
-import net.ccbluex.liquidbounce.utils.aiming.RotationManager
-import net.ccbluex.liquidbounce.utils.aiming.RotationsConfigurable
-import net.ccbluex.liquidbounce.utils.aiming.raytraceBox
+import net.ccbluex.liquidbounce.utils.aiming.*
import net.ccbluex.liquidbounce.utils.client.mc
import net.ccbluex.liquidbounce.utils.kotlin.Priority
import net.minecraft.entity.Entity
@@ -91,10 +88,9 @@ object ScriptRotationUtil {
RotationManager.aimAt(
rotation,
configurable = RotationsConfigurable(
- object : EventListener { }
- ).also {
- it.fixVelocity = fixVelocity
- }, priority = Priority.NORMAL, provider = ClientModule("ScriptAPI", Category.MISC)
+ object : EventListener { },
+ movementCorrection = if (fixVelocity) MovementCorrection.SILENT else MovementCorrection.OFF
+ ), priority = Priority.NORMAL, provider = ClientModule("ScriptAPI", Category.MISC)
)
}
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/AimPlan.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/AimPlan.kt
index a84d6fed70f..a0a3bf127bd 100644
--- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/AimPlan.kt
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/AimPlan.kt
@@ -54,8 +54,7 @@ class AimPlan(
* Consider if the inventory is open or not. If the inventory is open, we might not want to continue updating.
*/
val considerInventory: Boolean,
- val applyVelocityFix: Boolean,
- val changeLook: Boolean,
+ val movementCorrection: MovementCorrection,
/**
* What should be done if the target rotation has been reached. Can be `null`.
*/
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/MovementCorrection.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/MovementCorrection.kt
new file mode 100644
index 00000000000..b4141ddcc0e
--- /dev/null
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/MovementCorrection.kt
@@ -0,0 +1,52 @@
+/*
+ * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
+ *
+ * Copyright (c) 2015 - 2025 CCBlueX
+ *
+ * LiquidBounce is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiquidBounce is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LiquidBounce. If not, see .
+ */
+package net.ccbluex.liquidbounce.utils.aiming
+
+import net.ccbluex.liquidbounce.config.types.NamedChoice
+
+/**
+ * Corrects movement when aiming away from client-side view direction.
+ */
+enum class MovementCorrection(override val choiceName: String) : NamedChoice {
+
+ /**
+ * No movement correction is applied. This feels the best, as it does not
+ * change the movement of the player and also not affects Sprinting.
+ * However, this can be detected by anti-cheats.
+ */
+ OFF("Off"),
+
+ /**
+ * Corrects movement by changing the yaw when updating the movement.
+ */
+ STRICT("Strict"),
+
+ /**
+ * Correct movement by changing the yaw when updating the movement,
+ * but also tweaks the keyboard input to not aggressively change the
+ * players walk direction.
+ */
+ SILENT("Silent"),
+
+ /**
+ * Corrects movement by changing the actual look direction of the player.
+ */
+ CHANGE_LOOK("ChangeLook")
+
+}
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationManager.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationManager.kt
index 5647fe17cff..b4ba50695b9 100644
--- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationManager.kt
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationManager.kt
@@ -116,7 +116,7 @@ object RotationManager : EventListener {
aimPlanHandler.request(
RequestHandler.Request(
- if (plan.changeLook) 1 else plan.ticksUntilReset,
+ if (plan.movementCorrection == MovementCorrection.CHANGE_LOOK) 1 else plan.ticksUntilReset,
priority.priority,
provider,
plan
@@ -156,7 +156,8 @@ object RotationManager : EventListener {
val diff = rotation.angleTo(playerRotation)
- if (aimPlan == null && (workingAimPlan.changeLook || diff <= workingAimPlan.resetThreshold)) {
+ if (aimPlan == null && (workingAimPlan.movementCorrection == MovementCorrection.CHANGE_LOOK
+ || diff <= workingAimPlan.resetThreshold)) {
currentRotation?.let { currentRotation ->
player.yaw = player.withFixedYaw(currentRotation)
player.renderYaw = player.yaw
@@ -166,7 +167,7 @@ object RotationManager : EventListener {
currentRotation = null
previousAimPlan = null
} else {
- if (workingAimPlan.changeLook) {
+ if (workingAimPlan.movementCorrection == MovementCorrection.CHANGE_LOOK) {
player.setRotation(rotation)
}
@@ -198,7 +199,7 @@ object RotationManager : EventListener {
@Suppress("unused")
private val velocityHandler = handler { event ->
- if (workingAimPlan?.applyVelocityFix == true) {
+ if (workingAimPlan?.movementCorrection != MovementCorrection.OFF) {
val rotation = currentRotation ?: return@handler
event.velocity = Entity.movementInputToVelocity(
diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationsConfigurable.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationsConfigurable.kt
index f5868e4db26..350a514d965 100644
--- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationsConfigurable.kt
+++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationsConfigurable.kt
@@ -12,8 +12,7 @@ import net.minecraft.util.math.Vec3d
*/
open class RotationsConfigurable(
owner: EventListener,
- fixVelocity: Boolean = true,
- changeLook: Boolean = false,
+ movementCorrection: MovementCorrection = MovementCorrection.SILENT,
combatSpecific: Boolean = false
) : Configurable("Rotations") {
@@ -31,10 +30,9 @@ open class RotationsConfigurable(
private var shortStop = ShortStop(owner).takeIf { combatSpecific }?.also { tree(it) }
private val failFocus = FailFocus(owner).takeIf { combatSpecific }?.also { tree(it) }
- var fixVelocity by boolean("FixVelocity", fixVelocity)
+ private val movementCorrection by enumChoice("MovementCorrection", movementCorrection)
private val resetThreshold by float("ResetThreshold", 2f, 1f..180f)
private val ticksUntilReset by int("TicksUntilReset", 5, 1..30, "ticks")
- private val changeLook by boolean("ChangeLook", changeLook)
fun toAimPlan(
rotation: Rotation,
@@ -53,8 +51,7 @@ open class RotationsConfigurable(
ticksUntilReset,
resetThreshold,
considerInventory,
- fixVelocity,
- changeLook,
+ movementCorrection,
whenReached
)