Skip to content

Commit d3ee772

Browse files
Migrate movement processing to latest version (#142)
Minecraft moved sneak packet sending elsewhere. Also we cant do continuous movement vector on inputs so i changed it to discrete inputs. --------- Co-authored-by: beanbag44 <pidgeonmaster64@gmail.com>
1 parent 5c119f2 commit d3ee772

File tree

10 files changed

+221
-307
lines changed

10 files changed

+221
-307
lines changed

src/main/java/com/lambda/mixin/baritone/MixinLookBehavior.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ void onTargetUpdate(Rotation rotation, boolean blockInteract, CallbackInfo ci) {
3636
LookBehavior instance = ((LookBehavior) (Object) this);
3737
if (instance.baritone != BaritoneUtils.getPrimary()) return;
3838

39-
RotationManager.BaritoneProcessor.handleBaritoneRotation(rotation.getYaw(), rotation.getPitch());
39+
RotationManager.handleBaritoneRotation(rotation.getYaw(), rotation.getPitch());
4040
ci.cancel();
4141
}
4242

src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java

Lines changed: 17 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import net.minecraft.client.world.ClientWorld;
3838
import net.minecraft.entity.MovementType;
3939
import net.minecraft.util.Hand;
40-
import net.minecraft.util.math.MathHelper;
4140
import net.minecraft.util.math.Vec3d;
4241
import org.spongepowered.asm.mixin.Final;
4342
import org.spongepowered.asm.mixin.Mixin;
@@ -60,80 +59,50 @@ public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) {
6059
super(world, profile);
6160
}
6261

63-
@Shadow protected abstract void autoJump(float dx, float dz);
64-
65-
/**
66-
* Post movement events and applies the modified player velocity
67-
*/
68-
@Inject(method = "move", at = @At("HEAD"), cancellable = true)
69-
void onMove(MovementType movementType, Vec3d movement, CallbackInfo ci) {
70-
ClientPlayerEntity self = (ClientPlayerEntity) (Object) this;
71-
if (self != Lambda.getMc().player) return;
72-
73-
ci.cancel();
74-
75-
float prevX = (float) self.getX();
76-
float prevZ = (float) self.getZ();
77-
62+
@Redirect(method = "move", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V"))
63+
private void emitMovementEvents(AbstractClientPlayerEntity instance, MovementType movementType, Vec3d movement) {
7864
EventFlow.post(new MovementEvent.Player.Pre(movementType, movement));
7965
super.move(movementType, movement);
8066
EventFlow.post(new MovementEvent.Player.Post(movementType, movement));
81-
82-
float deltaX = (float) self.getX() - prevX;
83-
float deltaZ = (float) self.getZ() - prevZ;
84-
85-
this.autoJump(deltaX, deltaZ);
86-
this.distanceMoved = this.distanceMoved + MathHelper.hypot(deltaX, deltaZ) * 0.6F;
8767
}
8868

8969
@Redirect(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick()V"))
9070
void processMovement(Input input) {
9171
input.tick();
9272
RotationManager.processRotations();
93-
RotationManager.BaritoneProcessor.processPlayerMovement(input);
73+
RotationManager.redirectStrafeInputs(input);
9474
EventFlow.post(new MovementEvent.InputUpdate(input));
9575
}
9676

9777
/**
98-
* Posts the {@link MovementEvent.Sprint} event
99-
* <pre>{@code
100-
* if (this.isSprinting()) {
101-
* boolean bl8 = !this.input.hasForwardMovement() || !this.canSprint();
102-
* boolean bl9 = bl8 || this.horizontalCollision && !this.collidedSoftly || this.isTouchingWater() && !this.isSubmergedInWater();
103-
* if (this.isSwimming()) {
104-
* if (!this.isOnGround() && !this.input.sneaking && bl8 || !this.isTouchingWater()) {
105-
* this.setSprinting(false);
106-
* }
107-
* } else if (bl9) {
108-
* this.setSprinting(false);
109-
* }
110-
* }
111-
* }</pre>
78+
* Overwrites the movement packet update function to use our code
11279
*/
80+
@Inject(method = "sendMovementPackets", at = @At(value = "HEAD"), cancellable = true)
81+
void sendLambdaMovement(CallbackInfo ci) {
82+
ci.cancel();
83+
PlayerPacketManager.sendPlayerPackets();
84+
autoJumpEnabled = Lambda.getMc().options.getAutoJump().getValue();
85+
}
86+
87+
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;sendSneakingPacket()V"))
88+
void sendSneakingPacket(ClientPlayerEntity entity) {
89+
PlayerPacketManager.sendSneakPackets();
90+
}
91+
11392
@Redirect(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isSprinting()Z"))
11493
boolean isSprinting(ClientPlayerEntity entity) {
11594
return EventFlow.post(new MovementEvent.Sprint(entity.isSprinting())).getSprint();
11695
}
11796

11897
@Inject(method = "isSneaking", at = @At(value = "HEAD"), cancellable = true)
119-
void redirectSneaking(CallbackInfoReturnable<Boolean> cir) {
98+
void injectSneakingInput(CallbackInfoReturnable<Boolean> cir) {
12099
ClientPlayerEntity self = (ClientPlayerEntity) (Object) this;
121100
if (self != Lambda.getMc().player) return;
122101

123102
if (self.input == null) return;
124103
cir.setReturnValue(EventFlow.post(new MovementEvent.Sneak(self.input.playerInput.sneak())).getSneak());
125104
}
126105

127-
/**
128-
* Overwrites the movement packet update function to use our code
129-
*/
130-
@Inject(method = "sendMovementPackets", at = @At(value = "HEAD"), cancellable = true)
131-
void sendBegin(CallbackInfo ci) {
132-
ci.cancel();
133-
PlayerPacketManager.sendPlayerPackets();
134-
autoJumpEnabled = Lambda.getMc().options.getAutoJump().getValue();
135-
}
136-
137106
@WrapMethod(method = "tick")
138107
void onTick(Operation<Void> original) {
139108
EventFlow.post(TickEvent.Player.Pre.INSTANCE);

src/main/java/com/lambda/mixin/render/LivingEntityRendererMixin.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@
2323
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
2424
import net.minecraft.client.render.entity.LivingEntityRenderer;
2525
import net.minecraft.entity.LivingEntity;
26+
import org.jetbrains.annotations.Nullable;
2627
import org.spongepowered.asm.mixin.Mixin;
2728
import org.spongepowered.asm.mixin.injection.At;
2829

29-
import java.util.Objects;
30+
import static com.lambda.util.math.LinearKt.lerp;
3031

3132
// This mixin's purpose is to set the player's pitch the current render pitch to correctly show the rotation
3233
// regardless of the camera position
@@ -48,9 +49,12 @@ public class LivingEntityRendererMixin {
4849
* }</pre>
4950
*/
5051
@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"))
51-
private float wrapGetLerpedPitch(LivingEntity instance, float v, Operation<Float> original) {
52-
return (instance == Lambda.getMc().player)
53-
? Objects.requireNonNullElse(RotationManager.getHeadPitch(), original.call(instance, v))
54-
: original.call(instance, v);
52+
private float wrapGetLerpedPitch(LivingEntity livingEntity, float v, Operation<Float> original) {
53+
Float headPitch = RotationManager.getHeadPitch();
54+
if (livingEntity != Lambda.getMc().player || headPitch == null) {
55+
return original.call(livingEntity, v);
56+
}
57+
58+
return lerp(v, RotationManager.getPrevServerRotation().getPitchF(), headPitch);
5559
}
5660
}

src/main/kotlin/com/lambda/event/events/PlayerPacketEvent.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ sealed class PlayerPacketEvent {
3030
var rotation: Rotation,
3131
var onGround: Boolean,
3232
var isSprinting: Boolean,
33-
var isSneaking: Boolean,
3433
var isCollidingHorizontally: Boolean,
3534
) : ICancellable by Cancellable()
3635

src/main/kotlin/com/lambda/interaction/PlayerPacketManager.kt

Lines changed: 30 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,11 @@ import com.lambda.event.EventFlow.post
2222
import com.lambda.event.EventFlow.postChecked
2323
import com.lambda.event.events.PlayerPacketEvent
2424
import com.lambda.interaction.request.rotating.Rotation
25+
import com.lambda.interaction.request.rotating.Rotation.Companion.rotation
2526
import com.lambda.interaction.request.rotating.RotationManager
2627
import com.lambda.threading.runSafe
2728
import com.lambda.util.collections.LimitedOrderedSet
2829
import com.lambda.util.math.approximate
29-
import com.lambda.util.math.component1
30-
import com.lambda.util.math.component2
31-
import com.lambda.util.math.component3
32-
import com.lambda.util.player.MovementUtils.motionX
33-
import com.lambda.util.player.MovementUtils.motionZ
3430
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket
3531
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full
3632
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.LookAndOnGround
@@ -46,6 +42,7 @@ object PlayerPacketManager {
4642
var lastSprint = false
4743
var lastSneak = false
4844
var lastOnGround = false
45+
var lastHorizontalCollision = false
4946

5047
private var sendTicks = 0
5148

@@ -57,80 +54,66 @@ object PlayerPacketManager {
5754
RotationManager.activeRotation,
5855
player.isOnGround,
5956
player.isSprinting,
60-
player.isSneaking,
6157
player.horizontalCollision,
6258
).post {
6359
updatePlayerPackets(this)
6460
}
6561
}
6662
}
6763

64+
@JvmStatic
65+
fun sendSneakPackets() {
66+
runSafe {
67+
val sneaking = player.isSneaking
68+
if (sneaking == lastSneak) return@runSafe
69+
val mode = if (sneaking) {
70+
ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY
71+
} else {
72+
ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY
73+
}
74+
connection.sendPacket(ClientCommandC2SPacket(player, mode))
75+
lastSneak = sneaking
76+
}
77+
}
78+
6879
private fun SafeContext.updatePlayerPackets(new: PlayerPacketEvent.Pre) {
6980
configurations.add(new)
7081

7182
reportSprint(lastSprint, new.isSprinting)
72-
reportSneak(lastSneak, new.isSneaking)
7383

7484
if (mc.cameraEntity != player) return
7585

76-
val rotation = new.rotation
7786
val position = new.position
78-
val (yaw, pitch) = rotation.float
87+
val (yaw, pitch) = new.rotation
7988
val onGround = new.onGround
8089
val isCollidingHorizontally = new.isCollidingHorizontally
8190

82-
if (player.hasVehicle()) {
83-
connection.sendPacket(
84-
Full(
85-
player.motionX,
86-
-999.0,
87-
player.motionZ,
88-
yaw,
89-
pitch,
90-
onGround,
91-
isCollidingHorizontally,
92-
)
93-
)
94-
95-
return
96-
}
97-
98-
val updatePosition = position.approximate(lastPosition, 2.0E-4) || ++sendTicks >= 20
99-
// has to be different in float precision
100-
val updateRotation = !rotation.equalFloat(lastRotation)
101-
102-
val (x, y, z) = position
103-
104-
val packet = when {
105-
updatePosition && updateRotation ->
106-
Full(x, y, z, yaw, pitch, onGround, isCollidingHorizontally)
107-
108-
updatePosition ->
109-
PositionAndOnGround(x, y, z, onGround, isCollidingHorizontally)
91+
val updatePosition = position.approximate(lastPosition) || ++sendTicks >= 20
92+
val updateRotation = lastRotation.yaw != yaw || lastRotation.pitch != pitch
11093

111-
updateRotation ->
112-
LookAndOnGround(yaw, pitch, onGround, isCollidingHorizontally)
113-
114-
lastOnGround != onGround ->
94+
when {
95+
updatePosition && updateRotation -> Full(position, yaw.toFloat(), pitch.toFloat(), onGround, isCollidingHorizontally)
96+
updatePosition -> PositionAndOnGround(position, onGround, isCollidingHorizontally)
97+
updateRotation -> LookAndOnGround(yaw.toFloat(), pitch.toFloat(), onGround, isCollidingHorizontally)
98+
lastOnGround != onGround || lastHorizontalCollision != isCollidingHorizontally -> {
11599
OnGroundOnly(onGround, isCollidingHorizontally)
116-
100+
}
117101
else -> null
118-
}
119-
120-
packet?.let {
102+
}?.let {
121103
PlayerPacketEvent.Send(it).postChecked {
122104
connection.sendPacket(this.packet)
123105

124106
if (updatePosition) {
125-
sendTicks = 0
126107
lastPosition = position
108+
sendTicks = 0
127109
}
128110

129111
if (updateRotation) {
130-
lastRotation = rotation
112+
lastRotation = new.rotation
131113
}
132114

133115
lastOnGround = onGround
116+
lastHorizontalCollision = isCollidingHorizontally
134117
}
135118
}
136119

@@ -152,19 +135,6 @@ object PlayerPacketManager {
152135
connection.sendPacket(ClientCommandC2SPacket(player, state))
153136
lastSprint = new
154137
}
155-
156-
fun SafeContext.reportSneak(previous: Boolean, new: Boolean) {
157-
if (previous == new) return
158-
159-
val state = if (new) {
160-
ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY
161-
} else {
162-
ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY
163-
}
164-
165-
connection.sendPacket(ClientCommandC2SPacket(player, state))
166-
lastSneak = new
167-
}
168138
}
169139

170140

src/main/kotlin/com/lambda/interaction/request/rotating/Rotation.kt

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -108,42 +108,31 @@ data class Rotation(val yaw: Double, val pitch: Double) {
108108
fun Rotation.lerp(other: Rotation, delta: Double): Rotation {
109109
// Calculate the wrapped difference to ensure we take the shortest path
110110
val yawDiff = wrap(other.yaw - this.yaw)
111-
val pitchDiff = wrap(other.pitch - this.pitch)
111+
val pitchDiff = other.pitch - this.pitch
112112

113-
// Apply the delta to the wrapped difference
114-
val yaw = wrap(this.yaw + delta * yawDiff)
115-
val pitch = wrap(this.pitch + delta * pitchDiff)
113+
// Apply without wrapping the absolute yaw (keep it continuous)
114+
val yaw = this.yaw + delta * yawDiff
115+
val pitch = (this.pitch + delta * pitchDiff).coerceIn(-90.0, 90.0)
116116

117117
return Rotation(yaw, pitch)
118118
}
119119

120120
fun Rotation.slerp(other: Rotation, speed: Double): Rotation {
121121
val yawDiff = wrap(other.yaw - yaw)
122-
val pitchDiff = wrap(other.pitch - pitch)
122+
val pitchDiff = other.pitch - pitch
123123

124-
val diff = hypot(yawDiff, pitchDiff)
124+
val diff = hypot(yawDiff, pitchDiff).let { if (it == 0.0) 1.0 else it }
125125

126126
val yawSpeed = abs(yawDiff / diff) * speed
127127
val pitchSpeed = abs(pitchDiff / diff) * speed
128128

129-
val yaw = wrap(yaw + yawDiff.coerceIn(-yawSpeed, yawSpeed))
130-
val pitch = wrap(pitch + pitchDiff.coerceIn(-pitchSpeed, pitchSpeed))
129+
// Apply without wrapping the absolute yaw (keep it continuous)
130+
val yaw = yaw + yawDiff.coerceIn(-yawSpeed, yawSpeed)
131+
val pitch = (pitch + pitchDiff.coerceIn(-pitchSpeed, pitchSpeed)).coerceIn(-90.0, 90.0)
131132

132133
return Rotation(yaw, pitch)
133134
}
134135

135-
fun Rotation.fixSensitivity(prev: Rotation): Rotation {
136-
val f = mc.options.mouseSensitivity.value * 0.6 + 0.2
137-
val gcd = f * f * f * 8.0 * 0.15F
138-
139-
val r1 = Vec2d(prev.yaw, prev.pitch)
140-
val r2 = Vec2d(this.yaw, this.pitch)
141-
val delta = ((r2 - r1) / gcd).roundToInt() * gcd
142-
val fixed = r1 + delta
143-
144-
return Rotation(fixed.x, fixed.y.coerceIn(-90.0, 90.0))
145-
}
146-
147136
fun Vec3d.rotationTo(vec: Vec3d): Rotation {
148137
val diffX = vec.x - x
149138
val diffY = vec.y - y
@@ -152,8 +141,9 @@ data class Rotation(val yaw: Double, val pitch: Double) {
152141
val yawRad = atan2(diffZ, diffX)
153142
val pitchRad = -atan2(diffY, hypot(diffX, diffZ))
154143

155-
val yaw = wrap(yawRad.toDegree() - 90.0)
156-
val pitch = wrap(pitchRad.toDegree())
144+
// Target yaw can be normalized; our slerp keeps absolute yaw continuous
145+
val yaw = yawRad.toDegree() - 90.0
146+
val pitch = pitchRad.toDegree().coerceIn(-90.0, 90.0)
157147

158148
return Rotation(yaw, pitch)
159149
}

0 commit comments

Comments
 (0)