diff --git a/src/main/java/com/lambda/mixin/baritone/MixinLookBehavior.java b/src/main/java/com/lambda/mixin/baritone/MixinLookBehavior.java
index 599f7906a..0ba82c42d 100644
--- a/src/main/java/com/lambda/mixin/baritone/MixinLookBehavior.java
+++ b/src/main/java/com/lambda/mixin/baritone/MixinLookBehavior.java
@@ -36,7 +36,7 @@ void onTargetUpdate(Rotation rotation, boolean blockInteract, CallbackInfo ci) {
LookBehavior instance = ((LookBehavior) (Object) this);
if (instance.baritone != BaritoneUtils.getPrimary()) return;
- RotationManager.BaritoneProcessor.handleBaritoneRotation(rotation.getYaw(), rotation.getPitch());
+ RotationManager.handleBaritoneRotation(rotation.getYaw(), rotation.getPitch());
ci.cancel();
}
diff --git a/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java b/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java
index c47dddad4..c31ed4b87 100644
--- a/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java
+++ b/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java
@@ -37,7 +37,6 @@
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.MovementType;
import net.minecraft.util.Hand;
-import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -60,63 +59,43 @@ public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) {
super(world, profile);
}
- @Shadow protected abstract void autoJump(float dx, float dz);
-
- /**
- * Post movement events and applies the modified player velocity
- */
- @Inject(method = "move", at = @At("HEAD"), cancellable = true)
- void onMove(MovementType movementType, Vec3d movement, CallbackInfo ci) {
- ClientPlayerEntity self = (ClientPlayerEntity) (Object) this;
- if (self != Lambda.getMc().player) return;
-
- ci.cancel();
-
- float prevX = (float) self.getX();
- float prevZ = (float) self.getZ();
-
+ @Redirect(method = "move", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V"))
+ private void emitMovementEvents(AbstractClientPlayerEntity instance, MovementType movementType, Vec3d movement) {
EventFlow.post(new MovementEvent.Player.Pre(movementType, movement));
super.move(movementType, movement);
EventFlow.post(new MovementEvent.Player.Post(movementType, movement));
-
- float deltaX = (float) self.getX() - prevX;
- float deltaZ = (float) self.getZ() - prevZ;
-
- this.autoJump(deltaX, deltaZ);
- this.distanceMoved = this.distanceMoved + MathHelper.hypot(deltaX, deltaZ) * 0.6F;
}
@Redirect(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick()V"))
void processMovement(Input input) {
input.tick();
RotationManager.processRotations();
- RotationManager.BaritoneProcessor.processPlayerMovement(input);
+ RotationManager.redirectStrafeInputs(input);
EventFlow.post(new MovementEvent.InputUpdate(input));
}
/**
- * Posts the {@link MovementEvent.Sprint} event
- *
{@code
- * if (this.isSprinting()) {
- * boolean bl8 = !this.input.hasForwardMovement() || !this.canSprint();
- * boolean bl9 = bl8 || this.horizontalCollision && !this.collidedSoftly || this.isTouchingWater() && !this.isSubmergedInWater();
- * if (this.isSwimming()) {
- * if (!this.isOnGround() && !this.input.sneaking && bl8 || !this.isTouchingWater()) {
- * this.setSprinting(false);
- * }
- * } else if (bl9) {
- * this.setSprinting(false);
- * }
- * }
- * }
+ * Overwrites the movement packet update function to use our code
*/
+ @Inject(method = "sendMovementPackets", at = @At(value = "HEAD"), cancellable = true)
+ void sendLambdaMovement(CallbackInfo ci) {
+ ci.cancel();
+ PlayerPacketManager.sendPlayerPackets();
+ autoJumpEnabled = Lambda.getMc().options.getAutoJump().getValue();
+ }
+
+ @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;sendSneakingPacket()V"))
+ void sendSneakingPacket(ClientPlayerEntity entity) {
+ PlayerPacketManager.sendSneakPackets();
+ }
+
@Redirect(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isSprinting()Z"))
boolean isSprinting(ClientPlayerEntity entity) {
return EventFlow.post(new MovementEvent.Sprint(entity.isSprinting())).getSprint();
}
@Inject(method = "isSneaking", at = @At(value = "HEAD"), cancellable = true)
- void redirectSneaking(CallbackInfoReturnable cir) {
+ void injectSneakingInput(CallbackInfoReturnable cir) {
ClientPlayerEntity self = (ClientPlayerEntity) (Object) this;
if (self != Lambda.getMc().player) return;
@@ -124,16 +103,6 @@ void redirectSneaking(CallbackInfoReturnable cir) {
cir.setReturnValue(EventFlow.post(new MovementEvent.Sneak(self.input.playerInput.sneak())).getSneak());
}
- /**
- * Overwrites the movement packet update function to use our code
- */
- @Inject(method = "sendMovementPackets", at = @At(value = "HEAD"), cancellable = true)
- void sendBegin(CallbackInfo ci) {
- ci.cancel();
- PlayerPacketManager.sendPlayerPackets();
- autoJumpEnabled = Lambda.getMc().options.getAutoJump().getValue();
- }
-
@WrapMethod(method = "tick")
void onTick(Operation original) {
EventFlow.post(TickEvent.Player.Pre.INSTANCE);
diff --git a/src/main/java/com/lambda/mixin/render/LivingEntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/LivingEntityRendererMixin.java
index 3f83d2733..ce93b0ff5 100644
--- a/src/main/java/com/lambda/mixin/render/LivingEntityRendererMixin.java
+++ b/src/main/java/com/lambda/mixin/render/LivingEntityRendererMixin.java
@@ -23,10 +23,11 @@
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.entity.LivingEntity;
+import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
-import java.util.Objects;
+import static com.lambda.util.math.LinearKt.lerp;
// This mixin's purpose is to set the player's pitch the current render pitch to correctly show the rotation
// regardless of the camera position
@@ -48,9 +49,12 @@ public class LivingEntityRendererMixin {
* }
*/
@WrapOperation(method = "updateRenderState(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/client/render/entity/state/LivingEntityRenderState;F)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;getLerpedPitch(F)F"))
- private float wrapGetLerpedPitch(LivingEntity instance, float v, Operation original) {
- return (instance == Lambda.getMc().player)
- ? Objects.requireNonNullElse(RotationManager.getHeadPitch(), original.call(instance, v))
- : original.call(instance, v);
+ private float wrapGetLerpedPitch(LivingEntity livingEntity, float v, Operation original) {
+ Float headPitch = RotationManager.getHeadPitch();
+ if (livingEntity != Lambda.getMc().player || headPitch == null) {
+ return original.call(livingEntity, v);
+ }
+
+ return lerp(v, RotationManager.getPrevServerRotation().getPitchF(), headPitch);
}
}
diff --git a/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt b/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt
index 9a98d011d..fea59387d 100644
--- a/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt
+++ b/src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt
@@ -30,7 +30,6 @@ sealed class PlayerPacketEvent {
var rotation: Rotation,
var onGround: Boolean,
var isSprinting: Boolean,
- var isSneaking: Boolean,
var isCollidingHorizontally: Boolean,
) : ICancellable by Cancellable()
diff --git a/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt b/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt
index 72d94f117..b092a05c6 100644
--- a/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt
+++ b/src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt
@@ -22,15 +22,11 @@ import com.lambda.event.EventFlow.post
import com.lambda.event.EventFlow.postChecked
import com.lambda.event.events.PlayerPacketEvent
import com.lambda.interaction.request.rotating.Rotation
+import com.lambda.interaction.request.rotating.Rotation.Companion.rotation
import com.lambda.interaction.request.rotating.RotationManager
import com.lambda.threading.runSafe
import com.lambda.util.collections.LimitedOrderedSet
import com.lambda.util.math.approximate
-import com.lambda.util.math.component1
-import com.lambda.util.math.component2
-import com.lambda.util.math.component3
-import com.lambda.util.player.MovementUtils.motionX
-import com.lambda.util.player.MovementUtils.motionZ
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.LookAndOnGround
@@ -46,6 +42,7 @@ object PlayerPacketManager {
var lastSprint = false
var lastSneak = false
var lastOnGround = false
+ var lastHorizontalCollision = false
private var sendTicks = 0
@@ -57,7 +54,6 @@ object PlayerPacketManager {
RotationManager.activeRotation,
player.isOnGround,
player.isSprinting,
- player.isSneaking,
player.horizontalCollision,
).post {
updatePlayerPackets(this)
@@ -65,72 +61,59 @@ object PlayerPacketManager {
}
}
+ @JvmStatic
+ fun sendSneakPackets() {
+ runSafe {
+ val sneaking = player.isSneaking
+ if (sneaking == lastSneak) return@runSafe
+ val mode = if (sneaking) {
+ ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY
+ } else {
+ ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY
+ }
+ connection.sendPacket(ClientCommandC2SPacket(player, mode))
+ lastSneak = sneaking
+ }
+ }
+
private fun SafeContext.updatePlayerPackets(new: PlayerPacketEvent.Pre) {
configurations.add(new)
reportSprint(lastSprint, new.isSprinting)
- reportSneak(lastSneak, new.isSneaking)
if (mc.cameraEntity != player) return
- val rotation = new.rotation
val position = new.position
- val (yaw, pitch) = rotation.float
+ val (yaw, pitch) = new.rotation
val onGround = new.onGround
val isCollidingHorizontally = new.isCollidingHorizontally
- if (player.hasVehicle()) {
- connection.sendPacket(
- Full(
- player.motionX,
- -999.0,
- player.motionZ,
- yaw,
- pitch,
- onGround,
- isCollidingHorizontally,
- )
- )
-
- return
- }
-
- val updatePosition = position.approximate(lastPosition, 2.0E-4) || ++sendTicks >= 20
- // has to be different in float precision
- val updateRotation = !rotation.equalFloat(lastRotation)
-
- val (x, y, z) = position
-
- val packet = when {
- updatePosition && updateRotation ->
- Full(x, y, z, yaw, pitch, onGround, isCollidingHorizontally)
-
- updatePosition ->
- PositionAndOnGround(x, y, z, onGround, isCollidingHorizontally)
+ val updatePosition = position.approximate(lastPosition) || ++sendTicks >= 20
+ val updateRotation = lastRotation.yaw != yaw || lastRotation.pitch != pitch
- updateRotation ->
- LookAndOnGround(yaw, pitch, onGround, isCollidingHorizontally)
-
- lastOnGround != onGround ->
+ when {
+ updatePosition && updateRotation -> Full(position, yaw.toFloat(), pitch.toFloat(), onGround, isCollidingHorizontally)
+ updatePosition -> PositionAndOnGround(position, onGround, isCollidingHorizontally)
+ updateRotation -> LookAndOnGround(yaw.toFloat(), pitch.toFloat(), onGround, isCollidingHorizontally)
+ lastOnGround != onGround || lastHorizontalCollision != isCollidingHorizontally -> {
OnGroundOnly(onGround, isCollidingHorizontally)
-
+ }
else -> null
- }
-
- packet?.let {
+ }?.let {
PlayerPacketEvent.Send(it).postChecked {
connection.sendPacket(this.packet)
if (updatePosition) {
- sendTicks = 0
lastPosition = position
+ sendTicks = 0
}
if (updateRotation) {
- lastRotation = rotation
+ lastRotation = new.rotation
}
lastOnGround = onGround
+ lastHorizontalCollision = isCollidingHorizontally
}
}
@@ -152,19 +135,6 @@ object PlayerPacketManager {
connection.sendPacket(ClientCommandC2SPacket(player, state))
lastSprint = new
}
-
- fun SafeContext.reportSneak(previous: Boolean, new: Boolean) {
- if (previous == new) return
-
- val state = if (new) {
- ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY
- } else {
- ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY
- }
-
- connection.sendPacket(ClientCommandC2SPacket(player, state))
- lastSneak = new
- }
}
diff --git a/src/main/kotlin/com/lambda/interaction/request/rotating/Rotation.kt b/src/main/kotlin/com/lambda/interaction/request/rotating/Rotation.kt
index bd141cccd..7d17bbe20 100644
--- a/src/main/kotlin/com/lambda/interaction/request/rotating/Rotation.kt
+++ b/src/main/kotlin/com/lambda/interaction/request/rotating/Rotation.kt
@@ -108,42 +108,31 @@ data class Rotation(val yaw: Double, val pitch: Double) {
fun Rotation.lerp(other: Rotation, delta: Double): Rotation {
// Calculate the wrapped difference to ensure we take the shortest path
val yawDiff = wrap(other.yaw - this.yaw)
- val pitchDiff = wrap(other.pitch - this.pitch)
+ val pitchDiff = other.pitch - this.pitch
- // Apply the delta to the wrapped difference
- val yaw = wrap(this.yaw + delta * yawDiff)
- val pitch = wrap(this.pitch + delta * pitchDiff)
+ // Apply without wrapping the absolute yaw (keep it continuous)
+ val yaw = this.yaw + delta * yawDiff
+ val pitch = (this.pitch + delta * pitchDiff).coerceIn(-90.0, 90.0)
return Rotation(yaw, pitch)
}
fun Rotation.slerp(other: Rotation, speed: Double): Rotation {
val yawDiff = wrap(other.yaw - yaw)
- val pitchDiff = wrap(other.pitch - pitch)
+ val pitchDiff = other.pitch - pitch
- val diff = hypot(yawDiff, pitchDiff)
+ val diff = hypot(yawDiff, pitchDiff).let { if (it == 0.0) 1.0 else it }
val yawSpeed = abs(yawDiff / diff) * speed
val pitchSpeed = abs(pitchDiff / diff) * speed
- val yaw = wrap(yaw + yawDiff.coerceIn(-yawSpeed, yawSpeed))
- val pitch = wrap(pitch + pitchDiff.coerceIn(-pitchSpeed, pitchSpeed))
+ // Apply without wrapping the absolute yaw (keep it continuous)
+ val yaw = yaw + yawDiff.coerceIn(-yawSpeed, yawSpeed)
+ val pitch = (pitch + pitchDiff.coerceIn(-pitchSpeed, pitchSpeed)).coerceIn(-90.0, 90.0)
return Rotation(yaw, pitch)
}
- fun Rotation.fixSensitivity(prev: Rotation): Rotation {
- val f = mc.options.mouseSensitivity.value * 0.6 + 0.2
- val gcd = f * f * f * 8.0 * 0.15F
-
- val r1 = Vec2d(prev.yaw, prev.pitch)
- val r2 = Vec2d(this.yaw, this.pitch)
- val delta = ((r2 - r1) / gcd).roundToInt() * gcd
- val fixed = r1 + delta
-
- return Rotation(fixed.x, fixed.y.coerceIn(-90.0, 90.0))
- }
-
fun Vec3d.rotationTo(vec: Vec3d): Rotation {
val diffX = vec.x - x
val diffY = vec.y - y
@@ -152,8 +141,9 @@ data class Rotation(val yaw: Double, val pitch: Double) {
val yawRad = atan2(diffZ, diffX)
val pitchRad = -atan2(diffY, hypot(diffX, diffZ))
- val yaw = wrap(yawRad.toDegree() - 90.0)
- val pitch = wrap(pitchRad.toDegree())
+ // Target yaw can be normalized; our slerp keeps absolute yaw continuous
+ val yaw = yawRad.toDegree() - 90.0
+ val pitch = pitchRad.toDegree().coerceIn(-90.0, 90.0)
return Rotation(yaw, pitch)
}
diff --git a/src/main/kotlin/com/lambda/interaction/request/rotating/RotationManager.kt b/src/main/kotlin/com/lambda/interaction/request/rotating/RotationManager.kt
index dbc0d474c..d14bbcead 100644
--- a/src/main/kotlin/com/lambda/interaction/request/rotating/RotationManager.kt
+++ b/src/main/kotlin/com/lambda/interaction/request/rotating/RotationManager.kt
@@ -22,14 +22,12 @@ import com.lambda.context.SafeContext
import com.lambda.event.EventFlow.post
import com.lambda.event.events.ConnectionEvent
import com.lambda.event.events.PacketEvent
-import com.lambda.event.events.RotationEvent
import com.lambda.event.events.TickEvent
import com.lambda.event.events.UpdateManagerEvent
import com.lambda.event.listener.SafeListener.Companion.listen
import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe
import com.lambda.interaction.request.RequestHandler
import com.lambda.interaction.request.rotating.Rotation.Companion.slerp
-import com.lambda.interaction.request.rotating.Rotation.Companion.wrap
import com.lambda.interaction.request.rotating.visibilty.lookAt
import com.lambda.module.modules.client.Baritone
import com.lambda.threading.runGameScheduled
@@ -41,10 +39,11 @@ import com.lambda.util.math.Vec2d
import com.lambda.util.math.lerp
import net.minecraft.client.input.Input
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket
+import net.minecraft.util.PlayerInput
import net.minecraft.util.math.Vec2f
+import kotlin.math.PI
+import kotlin.math.atan2
import kotlin.math.cos
-import kotlin.math.round
-import kotlin.math.sign
import kotlin.math.sin
object RotationManager : RequestHandler(
@@ -56,6 +55,7 @@ object RotationManager : RequestHandler(
) {
var activeRotation = Rotation.ZERO
var serverRotation = Rotation.ZERO
+ @JvmStatic
var prevServerRotation = Rotation.ZERO
var activeRequest: RotationRequest? = null
@@ -120,11 +120,95 @@ object RotationManager : RequestHandler(
}
}
+ @JvmStatic
+ fun handleBaritoneRotation(yaw: Float, pitch: Float) {
+ lookAt(Rotation(yaw, pitch)).requestBy(Baritone.rotation)
+ }
+
+ @JvmStatic
+ fun redirectStrafeInputs(input: Input) = runSafe {
+ val movementYaw = movementYaw ?: return@runSafe
+ val playerYaw = player.yaw
+
+ if (movementYaw.minus(playerYaw).rem(360f).let { it * it } < 0.001f) return@runSafe
+
+ val originalStrafe = input.movementVector.x
+ val originalForward = input.movementVector.y
+
+ if (originalStrafe == 0.0f && originalForward == 0.0f) return@runSafe
+
+ val deltaYawRad = (playerYaw - movementYaw).toRadian()
+
+ val cos = cos(deltaYawRad)
+ val sin = sin(deltaYawRad)
+ val newStrafe = originalStrafe * cos - originalForward * sin
+ val newForward = originalStrafe * sin + originalForward * cos
+
+ val angle = atan2(newStrafe.toDouble(), newForward.toDouble())
+
+ // Define the boundaries for our 8 sectors (in radians). Each sector is 45 degrees (PI/4).
+ val sector = (PI / 4.0).toFloat()
+ val boundary = (PI / 8.0).toFloat() // The halfway point between sectors (22.5 degrees)
+
+ var pressForward = false
+ var pressBackward = false
+ var pressLeft = false
+ var pressRight = false
+
+ // Determine which 45-degree sector the angle falls into and set the corresponding keys.
+ when {
+ angle > -boundary && angle <= boundary -> {
+ pressForward = true
+ }
+ angle > boundary && angle <= boundary + sector -> {
+ pressForward = true
+ pressLeft = true
+ }
+ angle > boundary + sector && angle <= boundary + 2 * sector -> {
+ pressLeft = true
+ }
+ angle > boundary + 2 * sector && angle <= boundary + 3 * sector -> {
+ pressBackward = true
+ pressLeft = true
+ }
+ angle > boundary + 3 * sector || angle <= -(boundary + 3 * sector) -> {
+ pressBackward = true
+ }
+ angle > -(boundary + 3 * sector) && angle <= -(boundary + 2 * sector) -> {
+ pressBackward = true
+ pressRight = true
+ }
+ angle > -(boundary + 2 * sector) && angle <= -(boundary + sector) -> {
+ pressRight = true
+ }
+ angle > -(boundary + sector) && angle <= -boundary -> {
+ pressForward = true
+ pressRight = true
+ }
+ }
+
+ input.playerInput = PlayerInput(
+ pressForward,
+ pressBackward,
+ pressLeft,
+ pressRight,
+ input.playerInput.jump(),
+ input.playerInput.sneak(),
+ input.playerInput.sprint()
+ )
+
+ val x = multiplier(input.playerInput.left(), input.playerInput.right())
+ val y = multiplier(input.playerInput.forward(), input.playerInput.backward())
+ input.movementVector = Vec2f(x, y).normalize()
+ }
+
+ private fun multiplier(positive: Boolean, negative: Boolean) =
+ ((if (positive) 1 else 0) - (if (negative) 1 else 0)).toFloat()
+
fun onRotationSend() {
prevServerRotation = serverRotation
- serverRotation = activeRotation/*.fixSensitivity(prevServerRotation)*/
+ serverRotation = activeRotation
- // Handle LOCK mode
if (activeRequest?.rotationMode == RotationMode.Lock) {
mc.player?.yaw = serverRotation.yawF
mc.player?.pitch = serverRotation.pitchF
@@ -141,7 +225,8 @@ object RotationManager : RequestHandler(
val speedMultiplier = if (request.keepTicks < 0) 1.0 else request.speedMultiplier
val turnSpeed = request.turnSpeed * speedMultiplier
- serverRotation.slerp(rotationTo, turnSpeed).wrap()
+ // Important: do NOT wrap the result yaw; keep it continuous to match vanilla packets
+ serverRotation.slerp(rotationTo, turnSpeed)
} ?: player.rotation
}
@@ -197,80 +282,5 @@ object RotationManager : RequestHandler(
return Vec2d(rot.yaw, rot.pitch)
}
- object BaritoneProcessor {
- private var baritoneContext: RotationRequest? = null
-
- private val movementYawList = arrayOf(
- 0.0, 45.0,
- 90.0, 135.0,
- 180.0, 225.0,
- 270.0, 315.0,
- )
-
- @JvmStatic
- fun handleBaritoneRotation(yaw: Float, pitch: Float) {
- baritoneContext = lookAt(Rotation(yaw, pitch)).requestBy(Baritone.rotation)
- }
-
- init {
- listenUnsafe {
- baritoneContext = null
- }
- }
-
- @JvmStatic
- fun processPlayerMovement(input: Input) = runSafe {
- // The yaw relative to which the movement was constructed
- val baritoneYaw = baritoneContext?.target?.targetRotation?.value?.yaw
- val strafeEvent = RotationEvent.StrafeInput(baritoneYaw ?: player.yaw.toDouble(), input)
- val movementYaw = strafeEvent.post().strafeYaw
-
- // No changes are needed, when we don't modify the yaw used to move the player
- // val config = currentContext?.config ?: return@runSafe
- // if (config.rotationMode == RotationMode.SILENT && !input.handledByBaritone && baritoneContext == null) return@runSafe
-
- // Sign it to remove previous speed modifier
- input.hasForwardMovement()
- val signForward = sign(input.movementVector.y)
- val signStrafe = sign(input.movementVector.x)
-
- // No changes are needed when no inputs are pressed
- if (signForward <= 1.0E-5f && signStrafe <= 1.0E-5F) return@runSafe
-
- // Actual yaw used by the physics engine
- var actualYaw = activeRotation.yaw
-
- if (activeRequest?.rotationMode == RotationMode.Silent) {
- actualYaw = player.yaw.toDouble()
- }
-
- val yawRad = (movementYaw - actualYaw).toRadian()
-
- val cosDelta = cos(yawRad)
- val sinDelta = sin(yawRad)
-
- val newX = signStrafe * cosDelta - signForward * sinDelta
- val newZ = signForward * cosDelta + signStrafe * sinDelta
-
- // Apply new movement
- input.apply {
- movementVector = Vec2f(
- round(newX).toFloat(),
- round(newZ).toFloat(),
- )
- }
-
- baritoneYaw ?: return@runSafe
-
- // Makes baritone movement safe
- // when yaw difference is too big to compensate it by modifying keyboard input
- val minYawDist = movementYawList
- .map { activeRotation.yaw + it } // all possible movement directions (including diagonals)
- .minOf { Rotation.angleDifference(it, baritoneYaw) }
-
- if (minYawDist > 5.0) input.movementVector = Vec2f.ZERO
- }
- }
-
override fun preEvent() = UpdateManagerEvent.Rotation.post()
}
diff --git a/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt
new file mode 100644
index 000000000..c2e7145e7
--- /dev/null
+++ b/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2025 Lambda
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see .
+ */
+
+package com.lambda.module.modules.debug
+
+import com.lambda.config.groups.RotationSettings
+import com.lambda.event.events.TickEvent
+import com.lambda.event.listener.SafeListener.Companion.listen
+import com.lambda.interaction.request.rotating.visibilty.lookAtHit
+import com.lambda.module.Module
+import com.lambda.module.tag.ModuleTag
+import com.lambda.util.Communication.info
+import com.lambda.util.combat.DamageUtils.fallDamage
+import com.lambda.util.combat.DamageUtils.isFallDeadly
+import net.minecraft.util.hit.HitResult
+import net.minecraft.util.math.Vec3d
+
+object RotationTest : Module(
+ name = "RotationTest",
+ tag = ModuleTag.DEBUG,
+) {
+ var rotation = RotationSettings(this)
+ var hitPos: HitResult? = null
+
+ init {
+ onEnable {
+ hitPos = mc.crosshairTarget
+ }
+
+ listen {
+ hitPos?.let { lookAtHit(it)?.requestBy(rotation) }
+ }
+ }
+}
diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt b/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt
index 25ab7cc7b..165c11f53 100644
--- a/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt
+++ b/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt
@@ -57,10 +57,6 @@ object Speed : Module(
// Grim
private val diagonal by setting("Diagonal", true) { mode == Mode.GRIM_STRAFE }
- private val grimEntityBoost by setting("Entity Boost", 1.0, 0.0..2.0, 0.01) { mode == Mode.GRIM_STRAFE }
- private val grimCollideMultiplier by setting("Entity Collide Multiplier", 0.5, 0.0..1.0, 0.01) { mode == Mode.GRIM_STRAFE && grimEntityBoost > 0.0 }
- private val grimBoatBoost by setting("Boat Boost", 0.4, 0.0..1.0, 0.01) { mode == Mode.GRIM_STRAFE }
- private val grimMaxSpeed by setting("Max Speed", 1.0, 0.2..1.0, 0.01) { mode == Mode.GRIM_STRAFE }
// NCP
private val strict by setting("Strict", true) { mode == Mode.NCP_STRAFE }
@@ -68,15 +64,11 @@ object Speed : Module(
private val ncpAutoJump by setting("Auto Jump", false) { mode == Mode.NCP_STRAFE }
private val ncpTimerBoost by setting("Timer Boost", 1.08, 1.0..1.1, 0.01) { mode == Mode.NCP_STRAFE }
- // Grim
private val rotationConfig = RotationConfig.Instant(RotationMode.Sync)
- private var prevTickJumping = false
-
- // NCP
+ // NCP state variables
const val NCP_BASE_SPEED = 0.2873
private const val NCP_AIR_DECAY = 0.9937
-
private var ncpPhase = NCPPhase.SLOWDOWN
private var ncpSpeed = NCP_BASE_SPEED
private var lastDistance = 0.0
@@ -99,9 +91,8 @@ object Speed : Module(
return@listen
}
- when (mode) {
- Mode.GRIM_STRAFE -> handleGrim()
- Mode.NCP_STRAFE -> handleStrafe()
+ if (mode == Mode.NCP_STRAFE) {
+ handleStrafe()
}
}
@@ -119,43 +110,19 @@ object Speed : Module(
if (mode == Mode.NCP_STRAFE && shouldWork()) it.cancel()
}
- listen(Int.MIN_VALUE) {
- if (mode != Mode.GRIM_STRAFE || !shouldWork()) return@listen
-
- // Delay jumping key state by 1 tick to let the rotation predict jump timing
- it.input.apply {
- val jump = jumping
- jumping = prevTickJumping
- prevTickJumping = jump
- }
- }
-
listen {
- if (mode != Mode.GRIM_STRAFE) return@listen
- if (!shouldWork()) return@listen
+ if (mode != Mode.GRIM_STRAFE || !shouldWork()) return@listen
- var yaw = player.yaw
val input = newMovementInput()
-
if (!input.isInputting) return@listen
- run {
- if (!diagonal) return@run
- if (player.isOnGround && input.playerInput.jump) return@run
-
- val forward = input.roundedForward.toFloat()
- var strafe = input.roundedStrafing.toFloat()
-
- if (strafe == 0f) strafe = -1f
- if (forward == 0f) strafe *= -1
-
- yaw -= 45 * strafe
- }
-
- val moveYaw = calcMoveYaw(yaw, input.roundedForward, input.roundedStrafing)
+ val intendedMoveYaw = calcMoveYaw(player.yaw, input.roundedForward, input.roundedStrafing)
+ val targetYaw = if (diagonal && !(input.playerInput.jump && player.isOnGround)) {
+ intendedMoveYaw - 45.0f
+ } else intendedMoveYaw
lookAt(
- Rotation(moveYaw, 0.0)
+ Rotation(targetYaw, player.pitch.toDouble())
).requestBy(rotationConfig)
}
@@ -164,25 +131,6 @@ object Speed : Module(
}
}
- private fun SafeContext.handleGrim() {
- if (!isInputting) return
- if (player.moveDelta > grimMaxSpeed) return
-
- var boostAmount = 0.0
-
- boostAmount += entitySearch(3.0) {
- player.boundingBox.expand(1.0) in it.boundingBox && it !is ArmorStandEntity
- }.sumOf { 0.08 * grimEntityBoost }
-
- if (grimBoatBoost > 0.0) {
- boostAmount += entitySearch(4.0) {
- player.boundingBox in it.boundingBox.expand(0.01)
- }.sumOf { grimBoatBoost }
- }
-
- addSpeed(boostAmount)
- }
-
private fun SafeContext.handleStrafe() {
val shouldJump = player.input.playerInput.jump || (ncpAutoJump && isInputting)
@@ -230,13 +178,8 @@ object Speed : Module(
if (player.abilities.flying || player.isElytraFlying || player.isTouchingWater || player.isInLava) return false
return when (mode) {
- Mode.GRIM_STRAFE -> {
- !player.input.handledByBaritone && !TargetStrafe.isActive
- }
-
- Mode.NCP_STRAFE -> {
- !player.isSneaking
- }
+ Mode.GRIM_STRAFE -> !player.input.handledByBaritone
+ Mode.NCP_STRAFE -> !player.isSneaking
}
}
@@ -244,4 +187,4 @@ object Speed : Module(
ncpPhase = NCPPhase.SLOWDOWN
ncpSpeed = NCP_BASE_SPEED
}
-}
+}
\ No newline at end of file
diff --git a/src/test/kotlin/RotationTest.kt b/src/test/kotlin/RotationTest.kt
index a02c136c5..d103eb346 100644
--- a/src/test/kotlin/RotationTest.kt
+++ b/src/test/kotlin/RotationTest.kt
@@ -226,25 +226,6 @@ class RotationTest {
assertTrue(result3.pitch < rotation2.pitch)
}
- @Test
- fun `test slerp with angle wrapping`() {
- // Test slerp across the -180/180 boundary
- val rotation1 = Rotation(170.0, 0.0)
- val rotation2 = Rotation(-170.0, 0.0)
-
- // With a very high speed, should go directly to rotation2
- val result = rotation1.slerp(rotation2, 1000.0)
- assertEquals(rotation2.yaw, result.yaw, 0.001)
- assertEquals(rotation2.pitch, result.pitch, 0.001)
-
- // With a limited speed, should move in the correct direction (clockwise)
- val partialResult = rotation1.slerp(rotation2, 10.0)
-
- // The yaw should be greater than 170 (moving towards 180/-180)
- // or less than -170 (already crossed the boundary)
- assertTrue(partialResult.yaw > 170.0 || partialResult.yaw < -170.0)
- }
-
@Test
fun `test dist method`() {
val rotation1 = Rotation(0.0, 0.0)