From 4a1369d3c94d88db1b9bf788956dc59b104421de Mon Sep 17 00:00:00 2001 From: Gingerbeard <68350259+Gingerbeard5773@users.noreply.github.com> Date: Fri, 6 Nov 2026 23:29:05 -0500 Subject: [PATCH 1/7] Rotations rewrite * Rewrites the entire rotations manager for the purpose of implementing movefix. * Movefix can be enabled or disabled in meteor's config. * Adds a new TickEvent to help with synchronizing module calculations to rotations. --- .../meteorclient/events/world/TickEvent.java | 8 + .../meteorclient/mixin/EntityMixin.java | 10 + .../meteorclient/mixin/LocalPlayerMixin.java | 12 + .../meteorclient/systems/config/Config.java | 9 +- .../meteorclient/utils/player/Rotations.java | 280 +++++++++++------- src/main/resources/meteor-client.classtweaker | 3 + 6 files changed, 212 insertions(+), 110 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/events/world/TickEvent.java b/src/main/java/meteordevelopment/meteorclient/events/world/TickEvent.java index 72f5b510394..ff90cec8eb9 100644 --- a/src/main/java/meteordevelopment/meteorclient/events/world/TickEvent.java +++ b/src/main/java/meteordevelopment/meteorclient/events/world/TickEvent.java @@ -21,4 +21,12 @@ public static Post get() { return INSTANCE; } } + + public static class Rotate extends TickEvent { + private static final Rotate INSTANCE = new Rotate(); + + public static Rotate get() { + return INSTANCE; + } + } } diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/EntityMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/EntityMixin.java index fc772cb46bd..c29d6c4bae1 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/EntityMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/EntityMixin.java @@ -23,6 +23,7 @@ import meteordevelopment.meteorclient.systems.modules.world.HighwayBuilder; import meteordevelopment.meteorclient.utils.Utils; import meteordevelopment.meteorclient.utils.entity.fakeplayer.FakePlayerEntity; +import meteordevelopment.meteorclient.utils.player.Rotations; import net.minecraft.client.Camera; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.MoverType; @@ -107,6 +108,15 @@ private void onMove(MoverType moverType, Vec3 delta, CallbackInfo ci) { } } + @ModifyExpressionValue(method = "moveRelative", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getYRot()F")) + private float moveRelativeYaw(float original) { + if ((Object) this == mc.player && Rotations.shouldCorrectPlayerInput()) { + return Rotations.serverYaw; + } + + return original; + } + @ModifyExpressionValue(method = "getBlockSpeedFactor", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;getBlock()Lnet/minecraft/world/level/block/Block;")) private Block modifyBlockSpeedFactor(Block original) { if ((Object) this != mc.player) return original; diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/LocalPlayerMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/LocalPlayerMixin.java index cebbd842957..b67f30fe04f 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/LocalPlayerMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/LocalPlayerMixin.java @@ -8,6 +8,8 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import com.mojang.authlib.GameProfile; import meteordevelopment.meteorclient.MeteorClient; @@ -20,6 +22,7 @@ import meteordevelopment.meteorclient.systems.modules.player.Portals; import meteordevelopment.meteorclient.systems.modules.render.NoRender; import meteordevelopment.meteorclient.utils.entity.fakeplayer.FakePlayerEntity; +import meteordevelopment.meteorclient.utils.player.Rotations; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.AbstractClientPlayer; @@ -103,6 +106,15 @@ private void preAiStep(CallbackInfo ci) { MeteorClient.EVENT_BUS.post(PlayerTickMovementEvent.get()); } + @WrapOperation(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/ClientInput;tick()V")) + private void wrapTick(ClientInput input, Operation original) { + original.call(input); + + if (Rotations.shouldCorrectPlayerInput()) { + Rotations.setCorrectedPlayerInput(input); + } + } + @ModifyReturnValue(method = "getJumpRidingScale", at = @At("RETURN")) private float modifyJumpRidingScale(float original) { if (Modules.get().get(EntityControl.class).maxJump()) return 1f; diff --git a/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java b/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java index ba0d7db1543..0e3d1f42215 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java @@ -183,7 +183,14 @@ public class Config extends System { public final Setting rotationHoldTicks = sgMisc.add(new IntSetting.Builder() .name("rotation-hold") .description("Hold long to hold server side rotation when not sending any packets.") - .defaultValue(4) + .defaultValue(2) + .build() + ); + + public final Setting rotationMovementCorrection = sgMisc.add(new BoolSetting.Builder() + .name("rotation-movement-correction") + .description("Adjust player movement inputs depending on server side rotation (Grim movefix).") + .defaultValue(true) .build() ); diff --git a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java index fd562c33c0e..cde07bb5b28 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java @@ -11,12 +11,15 @@ import meteordevelopment.meteorclient.systems.config.Config; import meteordevelopment.meteorclient.utils.PreInit; import meteordevelopment.meteorclient.utils.entity.Target; -import meteordevelopment.meteorclient.utils.misc.Pool; import meteordevelopment.orbit.EventHandler; +import meteordevelopment.orbit.EventPriority; +import net.minecraft.client.player.ClientInput; import net.minecraft.core.BlockPos; import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Input; +import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import java.util.ArrayList; @@ -25,17 +28,14 @@ import static meteordevelopment.meteorclient.MeteorClient.mc; public class Rotations { - private static final Pool rotationPool = new Pool<>(Rotation::new); + private static final List queue = new ArrayList<>(); private static final List rotations = new ArrayList<>(); - public static float serverYaw; - public static float serverPitch; - public static int rotationTimer; private static float preYaw, prePitch; - private static int i = 0; + public static float serverYaw, serverPitch; private static Rotation lastRotation; private static int lastRotationTimer; - private static boolean sentLastRotation; + public static boolean rotating = false; private Rotations() { @@ -47,139 +47,154 @@ public static void init() { } public static void rotate(double yaw, double pitch, int priority, boolean clientSide, Runnable callback) { - Rotation rotation = rotationPool.get(); - rotation.set(yaw, pitch, priority, clientSide, callback); + Rotation rotation = new Rotation(yaw, pitch, priority, clientSide, callback); int i = 0; - for (; i < rotations.size(); i++) { - if (priority > rotations.get(i).priority) break; + for (; i < queue.size(); i++) { + if (priority > queue.get(i).priority) break; } - rotations.add(i, rotation); + queue.add(i, rotation); } public static void rotate(double yaw, double pitch, int priority, Runnable callback) { - rotate(yaw, pitch, priority, false, callback); + rotate(yaw, pitch, priority, true, callback); } public static void rotate(double yaw, double pitch, Runnable callback) { - rotate(yaw, pitch, 0, callback); + rotate(yaw, pitch, 0, true, callback); } public static void rotate(double yaw, double pitch, int priority) { - rotate(yaw, pitch, priority, null); + rotate(yaw, pitch, priority, true, null); } public static void rotate(double yaw, double pitch) { - rotate(yaw, pitch, 0, null); + rotate(yaw, pitch, 0, true, null); } - private static void resetLastRotation() { - if (lastRotation != null) { - rotationPool.free(lastRotation); + private static void setPreRotation() { + preYaw = mc.player.getYRot(); + prePitch = mc.player.getXRot(); + } - lastRotation = null; - lastRotationTimer = 0; - } + private static void setClientRotation(float yaw, float pitch) { + mc.player.setYRot(yaw); + mc.player.setXRot(pitch); } - @EventHandler - private static void onSendMovementPacketsPre(SendMovementPacketsEvent.Pre event) { - if (mc.getCameraEntity() != mc.player) return; - sentLastRotation = false; + private static void setServerRotation(float yaw, float pitch) { + serverYaw = yaw; + serverPitch = pitch; + } - if (!rotations.isEmpty()) { - rotating = true; - resetLastRotation(); + private static void queueRotations() { + MeteorClient.EVENT_BUS.post(TickEvent.Rotate.get()); - Rotation rotation = rotations.get(i); - setupMovementPacketRotation(rotation); + rotating = false; - if (rotations.size() > 1) rotationPool.free(rotation); + if (lastRotation != null) { + if (lastRotationTimer++ >= Config.get().rotationHoldTicks.get()) { + lastRotation = null; + lastRotationTimer = 0; + } else if (queue.isEmpty()) { + queue.add(lastRotation); + } + } - i++; - } else if (lastRotation != null) { - if (lastRotationTimer >= Config.get().rotationHoldTicks.get()) { - resetLastRotation(); - rotating = false; - } else { - setupMovementPacketRotation(lastRotation); - sentLastRotation = true; + if (!queue.isEmpty()) { + rotating = true; - lastRotationTimer++; + for (Rotation rotation : queue) { + setServerRotation(rotation.yaw, rotation.pitch); + rotations.add(rotation); } + + queue.clear(); } } - private static void setupMovementPacketRotation(Rotation rotation) { - setClientRotation(rotation); - setCamRotation(rotation.yaw, rotation.pitch); + @EventHandler(priority = EventPriority.LOWEST - 700) + private static void onTickQueue(TickEvent.Pre event) { + if (Config.get().rotationMovementCorrection.get()) { + queueRotations(); + } } - private static void setClientRotation(Rotation rotation) { - preYaw = mc.player.getYRot(); - prePitch = mc.player.getXRot(); + @EventHandler + private static void onSendMovementPacketsPre(SendMovementPacketsEvent.Pre event) { + if (!Config.get().rotationMovementCorrection.get()) { + queueRotations(); + } + + if (rotations.isEmpty()) return; - mc.player.setYRot((float) rotation.yaw); - mc.player.setXRot((float) rotation.pitch); + // The first rotation is sent within our normal movement packets + Rotation first = rotations.get(0); + setPreRotation(); + setServerRotation(first.yaw, first.pitch); + setClientRotation(first.yaw, first.pitch); } @EventHandler private static void onSendMovementPacketsPost(SendMovementPacketsEvent.Post event) { - if (!rotations.isEmpty()) { - if (mc.getCameraEntity() == mc.player) { - rotations.get(i - 1).runCallback(); + if (rotations.isEmpty()) return; - if (rotations.size() == 1) lastRotation = rotations.get(i - 1); + setClientRotation(preYaw, prePitch); - resetPreRotation(); - } - - for (; i < rotations.size(); i++) { - Rotation rotation = rotations.get(i); + // First rotation packet was already sent to server last tick naturally + Rotation first = rotations.get(0); + if (first.clientSide) setClientRotation(first.yaw, first.pitch); + first.runCallback(); - setCamRotation(rotation.yaw, rotation.pitch); - if (rotation.clientSide) setClientRotation(rotation); - rotation.sendPacket(); - if (rotation.clientSide) resetPreRotation(); + // All subsequent rotations require a packet sent + for (int i = 1; i < rotations.size(); i++) { + Rotation rotation = rotations.get(i); + setServerRotation(rotation.yaw, rotation.pitch); + if (rotation.clientSide) setClientRotation(rotation.yaw, rotation.pitch); + rotation.sendPacket(); + rotation.runCallback(); + } - if (i == rotations.size() - 1) lastRotation = rotation; - else rotationPool.free(rotation); - } + setClientRotation(preYaw, prePitch); - rotations.clear(); - i = 0; - } else if (sentLastRotation) { - resetPreRotation(); + Rotation lastIndexRotation = rotations.get(rotations.size() - 1); + if (lastIndexRotation != lastRotation) { + lastRotation = lastIndexRotation; + lastRotation.callback = null; + lastRotationTimer = 0; + rotating = Config.get().rotationHoldTicks.get() > 0; } - } - private static void resetPreRotation() { - mc.player.setYRot(preYaw); - mc.player.setXRot(prePitch); + rotations.clear(); } - @EventHandler - private static void onTick(TickEvent.Pre event) { - rotationTimer++; + // Utilities + + public static double getYaw(double x, double z) { + return Mth.wrapDegrees((float) Math.toDegrees(Math.atan2(z - mc.player.getZ(), x - mc.player.getX())) - 90f); } - public static double getYaw(Entity entity) { - return mc.player.getYRot() + Mth.wrapDegrees((float) Math.toDegrees(Math.atan2(entity.getZ() - mc.player.getZ(), entity.getX() - mc.player.getX())) - 90f - mc.player.getYRot()); + public static double getPitch(double x, double y, double z) { + double diffX = x - mc.player.getX(); + double diffY = y - mc.player.getEyeY(); + double diffZ = z - mc.player.getZ(); + + double diffXZ = Math.hypot(diffX, diffZ); + + return Mth.wrapDegrees((float) -Math.toDegrees(Math.atan2(diffY, diffXZ))); } public static double getYaw(Vec3 pos) { - return mc.player.getYRot() + Mth.wrapDegrees((float) Math.toDegrees(Math.atan2(pos.z() - mc.player.getZ(), pos.x() - mc.player.getX())) - 90f - mc.player.getYRot()); + return getYaw(pos.x(), pos.z()); } public static double getPitch(Vec3 pos) { - double diffX = pos.x() - mc.player.getX(); - double diffY = pos.y() - (mc.player.getY() + mc.player.getEyeHeight(mc.player.getPose())); - double diffZ = pos.z() - mc.player.getZ(); - - double diffXZ = Math.sqrt(diffX * diffX + diffZ * diffZ); + return getPitch(pos.x(), pos.y(), pos.z()); + } - return mc.player.getXRot() + Mth.wrapDegrees((float) -Math.toDegrees(Math.atan2(diffY, diffXZ)) - mc.player.getXRot()); + public static double getYaw(Entity entity) { + return getYaw(entity.getX(), entity.getZ()); } public static double getPitch(Entity entity, Target target) { @@ -188,14 +203,8 @@ public static double getPitch(Entity entity, Target target) { case Body -> entity.getY() + entity.getBbHeight() / 2; case Feet -> entity.getY(); }; - - double diffX = entity.getX() - mc.player.getX(); - double diffY = y - (mc.player.getY() + mc.player.getEyeHeight(mc.player.getPose())); - double diffZ = entity.getZ() - mc.player.getZ(); - - double diffXZ = Math.sqrt(diffX * diffX + diffZ * diffZ); - - return mc.player.getXRot() + Mth.wrapDegrees((float) -Math.toDegrees(Math.atan2(diffY, diffXZ)) - mc.player.getXRot()); + + return getPitch(entity.getX(), y, entity.getZ()); } public static double getPitch(Entity entity) { @@ -203,42 +212,95 @@ public static double getPitch(Entity entity) { } public static double getYaw(BlockPos pos) { - return mc.player.getYRot() + Mth.wrapDegrees((float) Math.toDegrees(Math.atan2(pos.getZ() + 0.5 - mc.player.getZ(), pos.getX() + 0.5 - mc.player.getX())) - 90f - mc.player.getYRot()); + return getYaw(pos.getX() + 0.5, pos.getZ() + 0.5); } public static double getPitch(BlockPos pos) { - double diffX = pos.getX() + 0.5 - mc.player.getX(); - double diffY = pos.getY() + 0.5 - (mc.player.getY() + mc.player.getEyeHeight(mc.player.getPose())); - double diffZ = pos.getZ() + 0.5 - mc.player.getZ(); + return getPitch(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); + } + + /** + * setCorrectedPlayerInput & getInputFromRelativeYaw are derived from Lambda Client. + * @see https://github.com/lambda-client/lambda/blob/1.21.11/src/main/kotlin/com/lambda/util/player/RotationUtils.kt + * + * @author dinosaurwizard + * @date 2026-10-10 + * + * Implementation of Grim movefix logic. + **/ + + public static boolean shouldCorrectPlayerInput() { + return rotating && Config.get().rotationMovementCorrection.get(); + } - double diffXZ = Math.sqrt(diffX * diffX + diffZ * diffZ); + public static void setCorrectedPlayerInput(ClientInput input) { + input.keyPresses = getInputFromRelativeYaw(input.keyPresses); - return mc.player.getXRot() + Mth.wrapDegrees((float) -Math.toDegrees(Math.atan2(diffY, diffXZ)) - mc.player.getXRot()); + int x = (input.keyPresses.left() ? 1 : 0) - (input.keyPresses.right() ? 1 : 0); + int y = (input.keyPresses.forward() ? 1 : 0) - (input.keyPresses.backward() ? 1 : 0); + input.moveVector = new Vec2(x, y).normalized(); } - public static void setCamRotation(double yaw, double pitch) { - serverYaw = (float) yaw; - serverPitch = (float) pitch; - rotationTimer = 0; + private static Input getInputFromRelativeYaw(Input input) { + int strafe = (input.left() ? 1 : 0) - (input.right() ? 1 : 0); + int forward = (input.forward() ? 1 : 0) - (input.backward() ? 1 : 0); + if (strafe == 0 && forward == 0) return input; + + double deltaYawRad = Math.toRadians(mc.player.getYRot() - serverYaw); + double cos = Math.cos(deltaYawRad); + double sin = Math.sin(deltaYawRad); + double newStrafe = strafe * cos - forward * sin; + double newForward = strafe * sin + forward * cos; + double angle = Math.atan2(newStrafe, newForward); + double sector = Math.PI / 4.0; + double boundary = Math.PI / 8.0; + + boolean pressForward = false; + boolean pressBackward = false; + boolean pressLeft = false; + boolean pressRight = false; + + if (angle > -boundary && angle <= boundary) { + pressForward = true; + } else if (angle > boundary && angle <= boundary + sector) { + pressForward = true; + pressLeft = true; + } else if (angle > boundary + sector && angle <= boundary + 2 * sector) { + pressLeft = true; + } else if (angle > boundary + 2 * sector && angle <= boundary + 3 * sector) { + pressBackward = true; + pressLeft = true; + } else if (angle > boundary + 3 * sector || angle <= -(boundary + 3 * sector)) { + pressBackward = true; + } else if (angle > -(boundary + 3 * sector) && angle <= -(boundary + 2 * sector)) { + pressBackward = true; + pressRight = true; + } else if (angle > -(boundary + 2 * sector) && angle <= -(boundary + sector)) { + pressRight = true; + } else if (angle > -(boundary + sector) && angle <= -boundary) { + pressForward = true; + pressRight = true; + } + + return new Input(pressForward, pressBackward, pressLeft, pressRight, input.jump(), input.shift(), input.sprint()); } private static class Rotation { - public double yaw, pitch; + public float yaw, pitch; public int priority; public boolean clientSide; public Runnable callback; - public void set(double yaw, double pitch, int priority, boolean clientSide, Runnable callback) { - this.yaw = yaw; - this.pitch = pitch; + public Rotation(double yaw, double pitch, int priority, boolean clientSide, Runnable callback) { + this.yaw = (float) yaw; + this.pitch = (float) pitch; this.priority = priority; this.clientSide = clientSide; this.callback = callback; } public void sendPacket() { - mc.getConnection().send(new ServerboundMovePlayerPacket.Rot((float) yaw, (float) pitch, mc.player.onGround(), mc.player.horizontalCollision)); - runCallback(); + mc.getConnection().send(new ServerboundMovePlayerPacket.Rot(yaw, pitch, mc.player.onGround(), mc.player.horizontalCollision)); } public void runCallback() { diff --git a/src/main/resources/meteor-client.classtweaker b/src/main/resources/meteor-client.classtweaker index 66a57a1d0bc..890905d8af7 100644 --- a/src/main/resources/meteor-client.classtweaker +++ b/src/main/resources/meteor-client.classtweaker @@ -43,3 +43,6 @@ accessible method com/mojang/renderpearl/api/pipeline/RenderPipeline$Builder Date: Fri, 6 Nov 2026 23:39:56 -0500 Subject: [PATCH 2/7] Fix Kill Aura Rotations Kill Aura now handles rotations correctly. Previously, it was not accounting for the desync between module calculation and rotation. --- .../systems/modules/combat/KillAura.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java index aeea4ad28f7..f90de2779f9 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java @@ -283,7 +283,7 @@ public void onDeactivate() { } @EventHandler - private void onTick(TickEvent.Pre event) { + private void onTick(TickEvent.Rotate event) { if (!mc.player.isAlive() || PlayerUtils.getGameMode() == GameType.SPECTATOR) { stopAttacking(); return; @@ -350,14 +350,17 @@ private void onTick(TickEvent.Pre event) { } attacking = true; - if (rotation.get() == RotationMode.Always) - Rotations.rotate(Rotations.getYaw(primary), Rotations.getPitch(primary, Target.Body)); + if (pauseOnCombat.get() && PathManagers.get().isPathing() && !wasPathing) { PathManagers.get().pause(); wasPathing = true; } - if (delayCheck()) targets.forEach(this::attack); + if (rotation.get() == RotationMode.Always) { + Rotations.rotate(Rotations.getYaw(primary), Rotations.getPitch(primary, Target.Body), () -> attackTargets()); + } else { + attackTargets(); + } } @EventHandler @@ -456,11 +459,20 @@ private boolean delayCheck() { } else return true; } else return mc.player.getAttackStrengthScale(delay) >= 1; } + + private void attackTargets() { + if (!delayCheck()) return; - private void attack(Entity target) { - if (rotation.get() == RotationMode.OnHit) - Rotations.rotate(Rotations.getYaw(target), Rotations.getPitch(target, Target.Body)); + for (Entity target : targets) { + if (rotation.get() == RotationMode.OnHit) { + Rotations.rotate(Rotations.getYaw(target), Rotations.getPitch(target, Target.Body), () -> attack(target)); + } else { + attack(target); + } + } + } + private void attack(Entity target) { mc.gameMode.attack(mc.player, target); SwingMode.Both.attackSwing(InteractionHand.MAIN_HAND); From 2039f3ccf3895ba15fbbeba5595be82b20e322f7 Mon Sep 17 00:00:00 2001 From: Gingerbeard <68350259+Gingerbeard5773@users.noreply.github.com> Date: Sat, 7 Nov 2026 00:08:40 -0500 Subject: [PATCH 3/7] Commenting --- .../meteorclient/utils/player/Rotations.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java index cde07bb5b28..0f65726e081 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java @@ -89,6 +89,8 @@ private static void setServerRotation(float yaw, float pitch) { } private static void queueRotations() { + // Post a TickEvent.Rotate event, which is used for synchronizing a module's calculation to its rotation. + // Using TickEvent.Rotate in modules instead of TickEvent.Pre allows for more accurate rotations (when the player is not using movefix). MeteorClient.EVENT_BUS.post(TickEvent.Rotate.get()); rotating = false; @@ -105,10 +107,11 @@ private static void queueRotations() { if (!queue.isEmpty()) { rotating = true; - for (Rotation rotation : queue) { - setServerRotation(rotation.yaw, rotation.pitch); - rotations.add(rotation); - } + rotations.addAll(queue); + + // Set the server rotation early so movefix inputs compensate. + Rotation last = queue.get(queue.size() - 1); + setServerRotation(last.yaw, last.pitch); queue.clear(); } @@ -142,7 +145,7 @@ private static void onSendMovementPacketsPost(SendMovementPacketsEvent.Post even setClientRotation(preYaw, prePitch); - // First rotation packet was already sent to server last tick naturally + // First rotation packet was already sent to server naturally Rotation first = rotations.get(0); if (first.clientSide) setClientRotation(first.yaw, first.pitch); first.runCallback(); @@ -236,6 +239,7 @@ public static boolean shouldCorrectPlayerInput() { public static void setCorrectedPlayerInput(ClientInput input) { input.keyPresses = getInputFromRelativeYaw(input.keyPresses); + // The movement vector must be adjusted according to the new input int x = (input.keyPresses.left() ? 1 : 0) - (input.keyPresses.right() ? 1 : 0); int y = (input.keyPresses.forward() ? 1 : 0) - (input.keyPresses.backward() ? 1 : 0); input.moveVector = new Vec2(x, y).normalized(); From 813d4c825ebf98f9eec87e526312eadcfd2bd298 Mon Sep 17 00:00:00 2001 From: Gingerbeard <68350259+Gingerbeard5773@users.noreply.github.com> Date: Sat, 7 Nov 2026 03:05:39 -0500 Subject: [PATCH 4/7] Warns --- .../meteorclient/utils/player/Rotations.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java index 0f65726e081..aa902701f81 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java @@ -223,11 +223,9 @@ public static double getPitch(BlockPos pos) { } /** - * setCorrectedPlayerInput & getInputFromRelativeYaw are derived from Lambda Client. + * setCorrectedPlayerInput and getInputFromRelativeYaw are derived from Lambda Client. * @see https://github.com/lambda-client/lambda/blob/1.21.11/src/main/kotlin/com/lambda/util/player/RotationUtils.kt - * * @author dinosaurwizard - * @date 2026-10-10 * * Implementation of Grim movefix logic. **/ From fc899c319c7cfa52e9bc1d4b15f3410cf5f8b5e4 Mon Sep 17 00:00:00 2001 From: Gingerbeard <68350259+Gingerbeard5773@users.noreply.github.com> Date: Sun, 8 Nov 2026 01:27:29 -0500 Subject: [PATCH 5/7] Undo 'rotation correctness' fix Reverting this as it is precarious code and methods. It works but I just don't like it or trust it fully. May redo in the future. --- .../meteorclient/events/world/TickEvent.java | 8 -------- .../systems/modules/combat/KillAura.java | 2 +- .../meteorclient/utils/player/Rotations.java | 18 ++---------------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/events/world/TickEvent.java b/src/main/java/meteordevelopment/meteorclient/events/world/TickEvent.java index ff90cec8eb9..72f5b510394 100644 --- a/src/main/java/meteordevelopment/meteorclient/events/world/TickEvent.java +++ b/src/main/java/meteordevelopment/meteorclient/events/world/TickEvent.java @@ -21,12 +21,4 @@ public static Post get() { return INSTANCE; } } - - public static class Rotate extends TickEvent { - private static final Rotate INSTANCE = new Rotate(); - - public static Rotate get() { - return INSTANCE; - } - } } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java index f90de2779f9..8f9b0cd7ae9 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java @@ -283,7 +283,7 @@ public void onDeactivate() { } @EventHandler - private void onTick(TickEvent.Rotate event) { + private void onTick(TickEvent.Pre event) { if (!mc.player.isAlive() || PlayerUtils.getGameMode() == GameType.SPECTATOR) { stopAttacking(); return; diff --git a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java index aa902701f81..7303e9a0434 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java @@ -88,11 +88,8 @@ private static void setServerRotation(float yaw, float pitch) { serverPitch = pitch; } - private static void queueRotations() { - // Post a TickEvent.Rotate event, which is used for synchronizing a module's calculation to its rotation. - // Using TickEvent.Rotate in modules instead of TickEvent.Pre allows for more accurate rotations (when the player is not using movefix). - MeteorClient.EVENT_BUS.post(TickEvent.Rotate.get()); - + @EventHandler(priority = EventPriority.LOWEST - 700) + private static void onTickPre(TickEvent.Pre event) { rotating = false; if (lastRotation != null) { @@ -117,19 +114,8 @@ private static void queueRotations() { } } - @EventHandler(priority = EventPriority.LOWEST - 700) - private static void onTickQueue(TickEvent.Pre event) { - if (Config.get().rotationMovementCorrection.get()) { - queueRotations(); - } - } - @EventHandler private static void onSendMovementPacketsPre(SendMovementPacketsEvent.Pre event) { - if (!Config.get().rotationMovementCorrection.get()) { - queueRotations(); - } - if (rotations.isEmpty()) return; // The first rotation is sent within our normal movement packets From 9b864fcca39aedf59a7767cae75d4cd2a37882eb Mon Sep 17 00:00:00 2001 From: marc3d Date: Sun, 8 Nov 2026 23:22:20 +0100 Subject: [PATCH 6/7] fix MoveFix --- .../mixin/FireworkRocketEntityMixin.java | 15 +++++++++++++++ .../meteorclient/mixin/ItemMixin.java | 14 ++++++++++++++ .../meteorclient/mixin/LivingEntityMixin.java | 15 +++++++++++++++ .../mixin/MultiPlayerGameModeMixin.java | 9 +++++++++ .../meteorclient/mixin/PlayerMixin.java | 8 ++++++++ .../meteorclient/systems/config/Config.java | 2 +- .../meteorclient/utils/player/Rotations.java | 10 +++++++--- 7 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/FireworkRocketEntityMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/FireworkRocketEntityMixin.java index 7edab1947cd..d393fca3810 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/FireworkRocketEntityMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/FireworkRocketEntityMixin.java @@ -5,17 +5,23 @@ package meteordevelopment.meteorclient.mixin; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.systems.modules.movement.ElytraBoost; +import meteordevelopment.meteorclient.utils.player.Rotations; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.projectile.FireworkRocketEntity; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.Vec3; 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 static meteordevelopment.meteorclient.MeteorClient.mc; + @Mixin(FireworkRocketEntity.class) public abstract class FireworkRocketEntityMixin { @Shadow @@ -24,6 +30,15 @@ public abstract class FireworkRocketEntityMixin { @Shadow private int lifetime; + @Shadow + private LivingEntity attachedToEntity; + + @ModifyExpressionValue(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getLookAngle()Lnet/minecraft/world/phys/Vec3;")) + private Vec3 fixRocketBoostDirection(Vec3 original) { + if (attachedToEntity == mc.player && mc.player != null && Rotations.shouldCorrectPlayerInput()) return Rotations.getServerDirection(); + return original; + } + @Inject(method = "tick", at = @At("TAIL")) private void onTick(CallbackInfo ci) { FireworkRocketEntity firework = ((FireworkRocketEntity) (Object) this); diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/ItemMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/ItemMixin.java index 31f45980051..551cf745709 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/ItemMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/ItemMixin.java @@ -5,11 +5,17 @@ package meteordevelopment.meteorclient.mixin; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.events.render.TooltipDataEvent; +import meteordevelopment.meteorclient.utils.player.Rotations; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -17,6 +23,8 @@ import java.util.Optional; +import static meteordevelopment.meteorclient.MeteorClient.mc; + @Mixin(Item.class) public abstract class ItemMixin { @Inject(method = "getTooltipImage", at = @At("HEAD"), cancellable = true) @@ -26,4 +34,10 @@ private void onTooltipData(ItemStack itemStack, CallbackInfoReturnable effect) { @ModifyExpressionValue(method = "jumpFromGround", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getYRot()F")) private float modifyGetYaw(float original) { if ((Object) this != mc.player) return original; + if (Rotations.shouldCorrectPlayerInput()) original = Rotations.serverYaw; if (!Modules.get().get(Sprint.class).rageSprint()) return original; float forward = Math.signum(mc.player.zza); @@ -141,4 +144,16 @@ private void onDropItem(ItemStack itemStack, boolean thrownFromHand, Prediction if (MeteorClient.EVENT_BUS.post(DropItemsEvent.get(itemStack)).isCancelled()) cir.setReturnValue(null); } } + + @ModifyExpressionValue(method = "updateFallFlyingMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getLookAngle()Lnet/minecraft/world/phys/Vec3;")) + private Vec3 fixFallFlyingLookAngle(Vec3 original) { + if ((Object) this == mc.player && Rotations.shouldCorrectPlayerInput()) return Rotations.getServerDirection(); + return original; + } + + @ModifyExpressionValue(method = "updateFallFlyingMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getXRot()F")) + private float fixFallFlyingPitch(float original) { + if ((Object) this == mc.player && Rotations.shouldCorrectPlayerInput()) return Rotations.serverPitch; + return original; + } } diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/MultiPlayerGameModeMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/MultiPlayerGameModeMixin.java index c2014ac42d3..8270171a677 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/MultiPlayerGameModeMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/MultiPlayerGameModeMixin.java @@ -8,6 +8,7 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.events.entity.DropItemsEvent; import meteordevelopment.meteorclient.events.entity.player.*; @@ -15,6 +16,7 @@ import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.systems.modules.player.BreakDelay; import meteordevelopment.meteorclient.systems.modules.player.SpeedMine; +import meteordevelopment.meteorclient.utils.player.Rotations; import meteordevelopment.meteorclient.utils.world.BlockUtils; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.MultiPlayerGameMode; @@ -23,6 +25,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.protocol.game.ServerboundUseItemPacket; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; @@ -153,6 +156,12 @@ private void onUseItem(Player player, InteractionHand hand, CallbackInfoReturnab if (event.toReturn != null) cir.setReturnValue(event.toReturn); } + @WrapOperation(method = "lambda$useItem$0", at = @At(value = "NEW", target = "(Lnet/minecraft/world/InteractionHand;IFF)Lnet/minecraft/network/protocol/game/ServerboundUseItemPacket;")) + private ServerboundUseItemPacket fixItemRotation(InteractionHand hand, int sequence, float yaw, float pitch, Operation original, @Local(argsOnly = true) Player player) { + if (player == mc.player && Rotations.rotating) return original.call(hand, sequence, Rotations.serverYaw, Rotations.serverPitch); + return original.call(hand, sequence, yaw, pitch); + } + @Inject(method = "stopDestroyBlock", at = @At("HEAD"), cancellable = true) private void onStopDestroyBlock(CallbackInfo ci) { if (BlockUtils.breaking) ci.cancel(); diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/PlayerMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/PlayerMixin.java index 8ac78b5cb0c..268f907288c 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/PlayerMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/PlayerMixin.java @@ -5,6 +5,7 @@ package meteordevelopment.meteorclient.mixin; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import meteordevelopment.meteorclient.MeteorClient; @@ -15,6 +16,7 @@ import meteordevelopment.meteorclient.systems.modules.movement.Sprint; import meteordevelopment.meteorclient.systems.modules.player.Reach; import meteordevelopment.meteorclient.systems.modules.player.SpeedMine; +import meteordevelopment.meteorclient.utils.player.Rotations; import meteordevelopment.meteorclient.utils.world.BlockUtils; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.EntityType; @@ -115,6 +117,12 @@ private void onGetFlyingSpeed(CallbackInfoReturnable cir) { return Modules.get().get(Sprint.class).stopSprinting(); } + @ModifyExpressionValue(method = {"causeExtraKnockback", "doSweepAttack"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getYRot()F")) + private float fixAttackYaw(float original) { + if ((Object) this == mc.player && Rotations.shouldCorrectPlayerInput()) return Rotations.serverYaw; + return original; + } + @ModifyReturnValue(method = "blockInteractionRange", at = @At("RETURN")) private double modifyBlockInteractionRange(double original) { return Math.max(0, original + Modules.get().get(Reach.class).blockReach()); diff --git a/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java b/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java index 0e3d1f42215..0bef7fe70f7 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/config/Config.java @@ -189,7 +189,7 @@ public class Config extends System { public final Setting rotationMovementCorrection = sgMisc.add(new BoolSetting.Builder() .name("rotation-movement-correction") - .description("Adjust player movement inputs depending on server side rotation (Grim movefix).") + .description("Adjust player movement depending on server side rotation (Grim movefix).") .defaultValue(true) .build() ); diff --git a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java index 7303e9a0434..ce5ad64dafb 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java @@ -192,7 +192,7 @@ public static double getPitch(Entity entity, Target target) { case Body -> entity.getY() + entity.getBbHeight() / 2; case Feet -> entity.getY(); }; - + return getPitch(entity.getX(), y, entity.getZ()); } @@ -212,14 +212,18 @@ public static double getPitch(BlockPos pos) { * setCorrectedPlayerInput and getInputFromRelativeYaw are derived from Lambda Client. * @see https://github.com/lambda-client/lambda/blob/1.21.11/src/main/kotlin/com/lambda/util/player/RotationUtils.kt * @author dinosaurwizard - * + * * Implementation of Grim movefix logic. **/ - + public static boolean shouldCorrectPlayerInput() { return rotating && Config.get().rotationMovementCorrection.get(); } + public static Vec3 getServerDirection() { + return Vec3.directionFromRotation(serverPitch, serverYaw); + } + public static void setCorrectedPlayerInput(ClientInput input) { input.keyPresses = getInputFromRelativeYaw(input.keyPresses); From e49d2a6bb9bd321e20ec6a68281e4cd9a2f23fdd Mon Sep 17 00:00:00 2001 From: Gingerbeard <68350259+Gingerbeard5773@users.noreply.github.com> Date: Mon, 9 Nov 2026 01:31:10 -0500 Subject: [PATCH 7/7] Rotation accuracy supplier * Adds in a new way to ensure accurate rotations. Devs will have to opt into it via the new api. * Deprecate 'clientSide' boolean. --- .../meteorclient/mixin/EntityMixin.java | 5 +- .../meteorclient/mixin/LocalPlayerMixin.java | 5 +- .../systems/modules/combat/KillAura.java | 10 +- .../systems/modules/movement/NoFall.java | 2 +- .../meteorclient/utils/player/Rotations.java | 97 +++++++++++++++---- 5 files changed, 86 insertions(+), 33 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/EntityMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/EntityMixin.java index c29d6c4bae1..f4d26e96d1f 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/EntityMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/EntityMixin.java @@ -110,10 +110,7 @@ private void onMove(MoverType moverType, Vec3 delta, CallbackInfo ci) { @ModifyExpressionValue(method = "moveRelative", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getYRot()F")) private float moveRelativeYaw(float original) { - if ((Object) this == mc.player && Rotations.shouldCorrectPlayerInput()) { - return Rotations.serverYaw; - } - + if ((Object) this == mc.player && Rotations.shouldCorrectPlayerInput()) return Rotations.serverYaw; return original; } diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/LocalPlayerMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/LocalPlayerMixin.java index b67f30fe04f..b52722338ba 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/LocalPlayerMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/LocalPlayerMixin.java @@ -109,10 +109,7 @@ private void preAiStep(CallbackInfo ci) { @WrapOperation(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/ClientInput;tick()V")) private void wrapTick(ClientInput input, Operation original) { original.call(input); - - if (Rotations.shouldCorrectPlayerInput()) { - Rotations.setCorrectedPlayerInput(input); - } + if (Rotations.shouldCorrectPlayerInput()) Rotations.setCorrectedPlayerInput(input); } @ModifyReturnValue(method = "getJumpRidingScale", at = @At("RETURN")) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java index 8f9b0cd7ae9..c6aca2fddb8 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/KillAura.java @@ -68,7 +68,7 @@ public class KillAura extends Module { .build() ); - private final Setting rotation = sgGeneral.add(new EnumSetting.Builder() + private final Setting rotate = sgGeneral.add(new EnumSetting.Builder() .name("rotate") .description("Determines when you should rotate towards the target.") .defaultValue(RotationMode.Always) @@ -356,8 +356,8 @@ private void onTick(TickEvent.Pre event) { wasPathing = true; } - if (rotation.get() == RotationMode.Always) { - Rotations.rotate(Rotations.getYaw(primary), Rotations.getPitch(primary, Target.Body), () -> attackTargets()); + if (rotate.get() == RotationMode.Always) { + Rotations.rotate(primary, 30, () -> attackTargets()); } else { attackTargets(); } @@ -464,8 +464,8 @@ private void attackTargets() { if (!delayCheck()) return; for (Entity target : targets) { - if (rotation.get() == RotationMode.OnHit) { - Rotations.rotate(Rotations.getYaw(target), Rotations.getPitch(target, Target.Body), () -> attack(target)); + if (rotate.get() == RotationMode.OnHit) { + Rotations.rotate(target, 30, () -> attack(target)); } else { attack(target); } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/movement/NoFall.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/movement/NoFall.java index dad0eb93fae..981642b8015 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/movement/NoFall.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/movement/NoFall.java @@ -427,7 +427,7 @@ private void queueBucketUse(FindItemResult item, BlockHitResult hit, PlacedItem boolean useNow = pickup || isWithinPlaceReach(hit.getLocation()); Vec3 aim = pickup ? Vec3.atCenterOf(hit.getBlockPos()) : hit.getLocation(); if (rotate.get()) Rotations.rotate(Rotations.getYaw(aim), Rotations.getPitch(aim), - Integer.MAX_VALUE, true, useNow ? null : use); + Integer.MAX_VALUE, useNow ? null : use); else if (!useNow) pendingBucketUse = use; if (useNow) use.run(); } diff --git a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java index ce5ad64dafb..2e879be423c 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/player/Rotations.java @@ -23,6 +23,7 @@ import net.minecraft.world.phys.Vec3; import java.util.ArrayList; +import java.util.function.Supplier; import java.util.List; import static meteordevelopment.meteorclient.MeteorClient.mc; @@ -46,33 +47,68 @@ public static void init() { MeteorClient.EVENT_BUS.subscribe(Rotations.class); } - public static void rotate(double yaw, double pitch, int priority, boolean clientSide, Runnable callback) { - Rotation rotation = new Rotation(yaw, pitch, priority, clientSide, callback); - + // Rotation Setup + + private static void rotate(Rotation rotation) { int i = 0; for (; i < queue.size(); i++) { - if (priority > queue.get(i).priority) break; + if (rotation.priority > queue.get(i).priority) break; } queue.add(i, rotation); } + @Deprecated // clientSide boolean is no longer used. + public static void rotate(double yaw, double pitch, int priority, boolean clientSide, Runnable callback) { + rotate(new Rotation(yaw, pitch, priority, callback)); + } + public static void rotate(double yaw, double pitch, int priority, Runnable callback) { - rotate(yaw, pitch, priority, true, callback); + rotate(new Rotation(yaw, pitch, priority, callback)); } public static void rotate(double yaw, double pitch, Runnable callback) { - rotate(yaw, pitch, 0, true, callback); + rotate(new Rotation(yaw, pitch, 0, callback)); } public static void rotate(double yaw, double pitch, int priority) { - rotate(yaw, pitch, priority, true, null); + rotate(new Rotation(yaw, pitch, priority, null)); } public static void rotate(double yaw, double pitch) { - rotate(yaw, pitch, 0, true, null); + rotate(new Rotation(yaw, pitch, 0, null)); + } + + public static void rotate(Entity entity, int priority, Runnable callback) { + rotate(new Rotation(entity, priority, callback)); + } + + public static void rotate(Entity entity, Runnable callback) { + rotate(new Rotation(entity, 0, callback)); + } + + public static void rotate(Vec3 position, int priority, Runnable callback) { + rotate(new Rotation(position, priority, callback)); + } + + public static void rotate(Vec3 position, Runnable callback) { + rotate(new Rotation(position, 0, callback)); + } + + public static void rotate(int priority, Supplier calculate, Runnable callback) { + rotate(new Rotation(priority, calculate, callback)); + } + + public static void rotate(Supplier calculate, Runnable callback) { + rotate(new Rotation(0, calculate, callback)); + } + + public static void rotate(Supplier calculate) { + rotate(new Rotation(0, calculate, null)); } + // Rotation Execution + private static void setPreRotation() { preYaw = mc.player.getYRot(); prePitch = mc.player.getXRot(); @@ -104,12 +140,11 @@ private static void onTickPre(TickEvent.Pre event) { if (!queue.isEmpty()) { rotating = true; - rotations.addAll(queue); - // Set the server rotation early so movefix inputs compensate. Rotation last = queue.get(queue.size() - 1); setServerRotation(last.yaw, last.pitch); + rotations.addAll(queue); queue.clear(); } } @@ -118,6 +153,11 @@ private static void onTickPre(TickEvent.Pre event) { private static void onSendMovementPacketsPre(SendMovementPacketsEvent.Pre event) { if (rotations.isEmpty()) return; + // Recalculate yaw and pitch due to entities moving around. + if (!Config.get().rotationMovementCorrection.get()) { + rotations.forEach(Rotation::recalculate); + } + // The first rotation is sent within our normal movement packets Rotation first = rotations.get(0); setPreRotation(); @@ -129,18 +169,16 @@ private static void onSendMovementPacketsPre(SendMovementPacketsEvent.Pre event) private static void onSendMovementPacketsPost(SendMovementPacketsEvent.Post event) { if (rotations.isEmpty()) return; - setClientRotation(preYaw, prePitch); - - // First rotation packet was already sent to server naturally + // First rotation packet was already sent to server naturally. Rotation first = rotations.get(0); - if (first.clientSide) setClientRotation(first.yaw, first.pitch); + setClientRotation(first.yaw, first.pitch); first.runCallback(); // All subsequent rotations require a packet sent for (int i = 1; i < rotations.size(); i++) { Rotation rotation = rotations.get(i); setServerRotation(rotation.yaw, rotation.pitch); - if (rotation.clientSide) setClientRotation(rotation.yaw, rotation.pitch); + setClientRotation(rotation.yaw, rotation.pitch); rotation.sendPacket(); rotation.runCallback(); } @@ -227,7 +265,7 @@ public static Vec3 getServerDirection() { public static void setCorrectedPlayerInput(ClientInput input) { input.keyPresses = getInputFromRelativeYaw(input.keyPresses); - // The movement vector must be adjusted according to the new input + // The movement vector must be adjusted according to the new input. int x = (input.keyPresses.left() ? 1 : 0) - (input.keyPresses.right() ? 1 : 0); int y = (input.keyPresses.forward() ? 1 : 0) - (input.keyPresses.backward() ? 1 : 0); input.moveVector = new Vec2(x, y).normalized(); @@ -280,17 +318,38 @@ private static Input getInputFromRelativeYaw(Input input) { private static class Rotation { public float yaw, pitch; public int priority; - public boolean clientSide; public Runnable callback; + public Supplier calculate; - public Rotation(double yaw, double pitch, int priority, boolean clientSide, Runnable callback) { + public Rotation(double yaw, double pitch, int priority, Runnable callback) { this.yaw = (float) yaw; this.pitch = (float) pitch; this.priority = priority; - this.clientSide = clientSide; this.callback = callback; } + public Rotation(int priority, Supplier calculate, Runnable callback) { + this(0, 0, priority, callback); + this.calculate = calculate; + recalculate(); + } + + public Rotation(Vec3 position, int priority, Runnable callback) { + this(priority, () -> new Vec2((float) getYaw(position), (float) getPitch(position)), callback); + } + + public Rotation(Entity entity, int priority, Runnable callback) { + this(priority, () -> new Vec2((float) getYaw(entity), (float) getPitch(entity)), callback); + } + + public void recalculate() { + if (calculate != null) { + Vec2 result = calculate.get(); + this.yaw = result.x; + this.pitch = result.y; + } + } + public void sendPacket() { mc.getConnection().send(new ServerboundMovePlayerPacket.Rot(yaw, pitch, mc.player.onGround(), mc.player.horizontalCollision)); }