From 56acb2b972ea5d16d46baf757382a583f699bed0 Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:49:00 -0800 Subject: [PATCH 1/3] Freecam: Rusherhack compatibility --- .../mixin/player/MixinEntityPlayerSP.java | 86 +++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java b/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java index 488b10976..929ff58e1 100644 --- a/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java +++ b/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java @@ -24,6 +24,8 @@ import net.minecraft.inventory.IInventory; import net.minecraft.network.play.client.CPacketEntityAction; import net.minecraft.network.play.client.CPacketPlayer; +import net.minecraft.util.MovementInput; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.Vec3d; import net.minecraft.world.IInteractionObject; import net.minecraft.world.World; @@ -37,6 +39,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.Objects; + @Mixin(value = EntityPlayerSP.class, priority = Integer.MAX_VALUE) public abstract class MixinEntityPlayerSP extends EntityPlayer { @Shadow @Final public NetHandlerPlayClient connection; @@ -51,6 +55,11 @@ public abstract class MixinEntityPlayerSP extends EntityPlayer { @Shadow private boolean serverSneakState; @Shadow private boolean prevOnGround; @Shadow private boolean autoJumpEnabled; + @Shadow public MovementInput movementInput; + @Shadow public float renderArmYaw; + @Shadow public float renderArmPitch; + @Shadow public float prevRenderArmYaw; + @Shadow public float prevRenderArmPitch; public MixinEntityPlayerSP(World worldIn, GameProfile gameProfileIn) { super(worldIn, gameProfileIn); @@ -123,11 +132,78 @@ public boolean modifySprinting(boolean sprinting) { } } - // We have to return true here so it would still update movement inputs from Baritone and send packets - @Inject(method = "isCurrentViewEntity", at = @At("RETURN"), cancellable = true) - protected void mixinIsCurrentViewEntity(CallbackInfoReturnable cir) { - if (Freecam.INSTANCE.isEnabled() && Freecam.INSTANCE.getCameraGuy() != null) { - cir.setReturnValue(mc.getRenderViewEntity() == Freecam.INSTANCE.getCameraGuy()); + // Cannot use an inject in isCurrentViewEntity due to rusherhack redirecting it here + @Inject(method = "onUpdateWalkingPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;isCurrentViewEntity()Z"), cancellable = true) + protected void mixinUpdateWalkingPlayerCompat(CallbackInfo ci) { + if (Freecam.INSTANCE.isEnabled() && Freecam.INSTANCE.getCameraGuy() != null && Objects.equals(this, mc.player)) { + ci.cancel(); + + // mc code copied as is + AxisAlignedBB axisalignedbb = this.getEntityBoundingBox(); + double d0 = this.posX - this.lastReportedPosX; + double d1 = axisalignedbb.minY - this.lastReportedPosY; + double d2 = this.posZ - this.lastReportedPosZ; + double d3 = (double)(this.rotationYaw - this.lastReportedYaw); + double d4 = (double)(this.rotationPitch - this.lastReportedPitch); + ++this.positionUpdateTicks; + boolean flag2 = d0 * d0 + d1 * d1 + d2 * d2 > 9.0E-4D || this.positionUpdateTicks >= 20; + boolean flag3 = d3 != 0.0D || d4 != 0.0D; + + if (this.isRiding()) + { + this.connection.sendPacket(new CPacketPlayer.PositionRotation(this.motionX, -999.0D, this.motionZ, this.rotationYaw, this.rotationPitch, this.onGround)); + flag2 = false; + } + else if (flag2 && flag3) + { + this.connection.sendPacket(new CPacketPlayer.PositionRotation(this.posX, axisalignedbb.minY, this.posZ, this.rotationYaw, this.rotationPitch, this.onGround)); + } + else if (flag2) + { + this.connection.sendPacket(new CPacketPlayer.Position(this.posX, axisalignedbb.minY, this.posZ, this.onGround)); + } + else if (flag3) + { + this.connection.sendPacket(new CPacketPlayer.Rotation(this.rotationYaw, this.rotationPitch, this.onGround)); + } + else if (this.prevOnGround != this.onGround) + { + this.connection.sendPacket(new CPacketPlayer(this.onGround)); + } + + if (flag2) + { + this.lastReportedPosX = this.posX; + this.lastReportedPosY = axisalignedbb.minY; + this.lastReportedPosZ = this.posZ; + this.positionUpdateTicks = 0; + } + + if (flag3) + { + this.lastReportedYaw = this.rotationYaw; + this.lastReportedPitch = this.rotationPitch; + } + + this.prevOnGround = this.onGround; + this.autoJumpEnabled = this.mc.gameSettings.autoJump; + } + } + + // Cannot use an inject in isCurrentViewEntity due to rusherhack redirecting it here + @Inject(method = "updateEntityActionState", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;isCurrentViewEntity()Z"), cancellable = true) + protected void mixinEntityActionState(CallbackInfo ci) { + if (Freecam.INSTANCE.isEnabled() && Freecam.INSTANCE.getCameraGuy() != null && Objects.equals(this, mc.player)) { + ci.cancel(); + + // mc code copied as is + this.moveStrafing = this.movementInput.moveStrafe; + this.moveForward = this.movementInput.moveForward; + this.isJumping = this.movementInput.jump; + this.prevRenderArmYaw = this.renderArmYaw; + this.prevRenderArmPitch = this.renderArmPitch; + this.renderArmPitch = (float)((double)this.renderArmPitch + (double)(this.rotationPitch - this.renderArmPitch) * 0.5D); + this.renderArmYaw = (float)((double)this.renderArmYaw + (double)(this.rotationYaw - this.renderArmYaw) * 0.5D); } } From 47c68ab216930917e06e00f3c2697ec274f167d3 Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Sat, 18 Feb 2023 11:53:01 -0800 Subject: [PATCH 2/3] use our paraphrased pos/rot update methods --- .../mixin/player/MixinEntityPlayerSP.java | 69 +++++-------------- 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java b/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java index 929ff58e1..49b89a968 100644 --- a/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java +++ b/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java @@ -65,9 +65,6 @@ public MixinEntityPlayerSP(World worldIn, GameProfile gameProfileIn) { super(worldIn, gameProfileIn); } - @Shadow - protected abstract boolean isCurrentViewEntity(); - @Shadow protected abstract void updateAutoJump(float p_189810_1_, float p_189810_2_); @@ -137,52 +134,24 @@ public boolean modifySprinting(boolean sprinting) { protected void mixinUpdateWalkingPlayerCompat(CallbackInfo ci) { if (Freecam.INSTANCE.isEnabled() && Freecam.INSTANCE.getCameraGuy() != null && Objects.equals(this, mc.player)) { ci.cancel(); - - // mc code copied as is - AxisAlignedBB axisalignedbb = this.getEntityBoundingBox(); - double d0 = this.posX - this.lastReportedPosX; - double d1 = axisalignedbb.minY - this.lastReportedPosY; - double d2 = this.posZ - this.lastReportedPosZ; - double d3 = (double)(this.rotationYaw - this.lastReportedYaw); - double d4 = (double)(this.rotationPitch - this.lastReportedPitch); + // we need to perform the same actions as what is in the mc method ++this.positionUpdateTicks; - boolean flag2 = d0 * d0 + d1 * d1 + d2 * d2 > 9.0E-4D || this.positionUpdateTicks >= 20; - boolean flag3 = d3 != 0.0D || d4 != 0.0D; - - if (this.isRiding()) - { - this.connection.sendPacket(new CPacketPlayer.PositionRotation(this.motionX, -999.0D, this.motionZ, this.rotationYaw, this.rotationPitch, this.onGround)); - flag2 = false; - } - else if (flag2 && flag3) - { - this.connection.sendPacket(new CPacketPlayer.PositionRotation(this.posX, axisalignedbb.minY, this.posZ, this.rotationYaw, this.rotationPitch, this.onGround)); - } - else if (flag2) - { - this.connection.sendPacket(new CPacketPlayer.Position(this.posX, axisalignedbb.minY, this.posZ, this.onGround)); - } - else if (flag3) - { - this.connection.sendPacket(new CPacketPlayer.Rotation(this.rotationYaw, this.rotationPitch, this.onGround)); - } - else if (this.prevOnGround != this.onGround) - { - this.connection.sendPacket(new CPacketPlayer(this.onGround)); - } - - if (flag2) - { - this.lastReportedPosX = this.posX; - this.lastReportedPosY = axisalignedbb.minY; - this.lastReportedPosZ = this.posZ; + final AxisAlignedBB boundingBox = this.getEntityBoundingBox(); + final Vec3d pos = new Vec3d(this.posX, boundingBox.minY, this.posZ); + final Vec2f rot = new Vec2f(this.rotationYaw, this.rotationPitch); + final boolean isMoving = isMoving(pos); + final boolean isRotating = isRotating(rot); + sendPlayerPacket(isMoving, isRotating, pos, rot); + if (isMoving) { + this.lastReportedPosX = pos.x; + this.lastReportedPosY = pos.y; + this.lastReportedPosZ = pos.z; this.positionUpdateTicks = 0; } - if (flag3) - { - this.lastReportedYaw = this.rotationYaw; - this.lastReportedPitch = this.rotationPitch; + if (isRotating) { + this.lastReportedYaw = rot.getX(); + this.lastReportedPitch = rot.getY(); } this.prevOnGround = this.onGround; @@ -196,14 +165,14 @@ protected void mixinEntityActionState(CallbackInfo ci) { if (Freecam.INSTANCE.isEnabled() && Freecam.INSTANCE.getCameraGuy() != null && Objects.equals(this, mc.player)) { ci.cancel(); - // mc code copied as is + // we need to perform the same actions as what is in the mc method this.moveStrafing = this.movementInput.moveStrafe; this.moveForward = this.movementInput.moveForward; this.isJumping = this.movementInput.jump; this.prevRenderArmYaw = this.renderArmYaw; this.prevRenderArmPitch = this.renderArmPitch; - this.renderArmPitch = (float)((double)this.renderArmPitch + (double)(this.rotationPitch - this.renderArmPitch) * 0.5D); - this.renderArmYaw = (float)((double)this.renderArmYaw + (double)(this.rotationYaw - this.renderArmYaw) * 0.5D); + this.renderArmPitch = this.renderArmPitch + (this.rotationPitch - this.renderArmPitch) * 0.5f; + this.renderArmYaw = this.renderArmYaw + (this.rotationYaw - this.renderArmYaw) * 0.5f; } } @@ -227,6 +196,8 @@ private void onUpdateInvokeOnUpdateWalkingPlayer(CallbackInfo ci) { @Inject(method = "onUpdateWalkingPlayer", at = @At("HEAD"), cancellable = true) private void onUpdateWalkingPlayerHead(CallbackInfo ci) { + if (Freecam.INSTANCE.isEnabled() && Freecam.INSTANCE.getCameraGuy() != null + && Objects.equals(this, Freecam.INSTANCE.getCameraGuy())) return; CriticalsUpdateWalkingEvent criticalsEditEvent = new CriticalsUpdateWalkingEvent(); LambdaEventBus.INSTANCE.post(criticalsEditEvent); @@ -295,8 +266,6 @@ private void sendSneakPacket() { } private void sendPlayerPacket(boolean moving, boolean rotating, Vec3d position, Vec2f rotation) { - if (!this.isCurrentViewEntity()) return; - if (this.isRiding()) { this.connection.sendPacket(new CPacketPlayer.PositionRotation(this.motionX, -999.0D, this.motionZ, rotation.getX(), rotation.getY(), onGround)); moving = false; From 31ce2da2776c0d940665e985050af76c7642ed63 Mon Sep 17 00:00:00 2001 From: Constructor Date: Sun, 19 Feb 2023 05:07:49 +0100 Subject: [PATCH 3/3] Cleanup --- .../mixin/player/MixinEntityPlayerSP.java | 127 +++++++++--------- 1 file changed, 62 insertions(+), 65 deletions(-) diff --git a/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java b/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java index 49b89a968..a7a8803f0 100644 --- a/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java +++ b/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java @@ -44,6 +44,11 @@ @Mixin(value = EntityPlayerSP.class, priority = Integer.MAX_VALUE) public abstract class MixinEntityPlayerSP extends EntityPlayer { @Shadow @Final public NetHandlerPlayClient connection; + @Shadow public MovementInput movementInput; + @Shadow public float renderArmYaw; + @Shadow public float renderArmPitch; + @Shadow public float prevRenderArmYaw; + @Shadow public float prevRenderArmPitch; @Shadow protected Minecraft mc; @Shadow private double lastReportedPosX; @Shadow private double lastReportedPosY; @@ -55,11 +60,6 @@ public abstract class MixinEntityPlayerSP extends EntityPlayer { @Shadow private boolean serverSneakState; @Shadow private boolean prevOnGround; @Shadow private boolean autoJumpEnabled; - @Shadow public MovementInput movementInput; - @Shadow public float renderArmYaw; - @Shadow public float renderArmPitch; - @Shadow public float prevRenderArmYaw; - @Shadow public float prevRenderArmPitch; public MixinEntityPlayerSP(World worldIn, GameProfile gameProfileIn) { super(worldIn, gameProfileIn); @@ -95,7 +95,7 @@ private void onPushOutOfBlocks(CallbackInfoReturnable callbackInfoRetur public void onDisplayGUIChest(IInventory chestInventory, CallbackInfo ci) { if (BeaconSelector.INSTANCE.isEnabled()) { if (chestInventory instanceof IInteractionObject && "minecraft:beacon".equals(((IInteractionObject) chestInventory).getGuiID())) { - Minecraft.getMinecraft().displayGuiScreen(new LambdaGuiBeacon(this.inventory, chestInventory)); + Minecraft.getMinecraft().displayGuiScreen(new LambdaGuiBeacon(inventory, chestInventory)); ci.cancel(); } } @@ -110,11 +110,11 @@ public void moveHead(MoverType type, double x, double y, double z, CallbackInfo LambdaEventBus.INSTANCE.post(event); if (event.isModified()) { - double prevX = this.posX; - double prevZ = this.posZ; + double prevX = posX; + double prevZ = posZ; super.move(type, event.getX(), event.getY(), event.getZ()); - this.updateAutoJump((float) (this.posX - prevX), (float) (this.posZ - prevZ)); + updateAutoJump((float) (posX - prevX), (float) (posZ - prevZ)); ci.cancel(); } @@ -135,27 +135,27 @@ protected void mixinUpdateWalkingPlayerCompat(CallbackInfo ci) { if (Freecam.INSTANCE.isEnabled() && Freecam.INSTANCE.getCameraGuy() != null && Objects.equals(this, mc.player)) { ci.cancel(); // we need to perform the same actions as what is in the mc method - ++this.positionUpdateTicks; - final AxisAlignedBB boundingBox = this.getEntityBoundingBox(); - final Vec3d pos = new Vec3d(this.posX, boundingBox.minY, this.posZ); - final Vec2f rot = new Vec2f(this.rotationYaw, this.rotationPitch); + ++positionUpdateTicks; + final AxisAlignedBB boundingBox = getEntityBoundingBox(); + final Vec3d pos = new Vec3d(posX, boundingBox.minY, posZ); + final Vec2f rot = new Vec2f(rotationYaw, rotationPitch); final boolean isMoving = isMoving(pos); final boolean isRotating = isRotating(rot); sendPlayerPacket(isMoving, isRotating, pos, rot); if (isMoving) { - this.lastReportedPosX = pos.x; - this.lastReportedPosY = pos.y; - this.lastReportedPosZ = pos.z; - this.positionUpdateTicks = 0; + lastReportedPosX = pos.x; + lastReportedPosY = pos.y; + lastReportedPosZ = pos.z; + positionUpdateTicks = 0; } if (isRotating) { - this.lastReportedYaw = rot.getX(); - this.lastReportedPitch = rot.getY(); + lastReportedYaw = rot.getX(); + lastReportedPitch = rot.getY(); } - this.prevOnGround = this.onGround; - this.autoJumpEnabled = this.mc.gameSettings.autoJump; + prevOnGround = onGround; + autoJumpEnabled = mc.gameSettings.autoJump; } } @@ -166,13 +166,13 @@ protected void mixinEntityActionState(CallbackInfo ci) { ci.cancel(); // we need to perform the same actions as what is in the mc method - this.moveStrafing = this.movementInput.moveStrafe; - this.moveForward = this.movementInput.moveForward; - this.isJumping = this.movementInput.jump; - this.prevRenderArmYaw = this.renderArmYaw; - this.prevRenderArmPitch = this.renderArmPitch; - this.renderArmPitch = this.renderArmPitch + (this.rotationPitch - this.renderArmPitch) * 0.5f; - this.renderArmYaw = this.renderArmYaw + (this.rotationYaw - this.renderArmYaw) * 0.5f; + moveStrafing = movementInput.moveStrafe; + moveForward = movementInput.moveForward; + isJumping = movementInput.jump; + prevRenderArmYaw = renderArmYaw; + prevRenderArmPitch = renderArmPitch; + renderArmPitch = renderArmPitch + (rotationPitch - renderArmPitch) * 0.5f; + renderArmYaw = renderArmYaw + (rotationYaw - renderArmYaw) * 0.5f; } } @@ -186,12 +186,12 @@ private void onUpdateInvokeOnUpdateWalkingPlayer(CallbackInfo ci) { Vec3d serverSidePos = PlayerPacketManager.INSTANCE.getServerSidePosition(); Vec2f serverSideRotation = PlayerPacketManager.INSTANCE.getPrevServerSideRotation(); - this.lastReportedPosX = serverSidePos.x; - this.lastReportedPosY = serverSidePos.y; - this.lastReportedPosZ = serverSidePos.z; + lastReportedPosX = serverSidePos.x; + lastReportedPosY = serverSidePos.y; + lastReportedPosZ = serverSidePos.z; - this.lastReportedYaw = serverSideRotation.getX(); - this.lastReportedPitch = serverSideRotation.getY(); + lastReportedYaw = serverSideRotation.getX(); + lastReportedPitch = serverSideRotation.getY(); } @Inject(method = "onUpdateWalkingPlayer", at = @At("HEAD"), cancellable = true) @@ -203,8 +203,8 @@ private void onUpdateWalkingPlayerHead(CallbackInfo ci) { LambdaEventBus.INSTANCE.post(criticalsEditEvent); // Setup flags - Vec3d position = new Vec3d(this.posX, this.getEntityBoundingBox().minY, this.posZ); - Vec2f rotation = new Vec2f(this.rotationYaw, this.rotationPitch); + Vec3d position = new Vec3d(posX, getEntityBoundingBox().minY, posZ); + Vec2f rotation = new Vec2f(rotationYaw, rotationPitch); boolean moving = isMoving(position); boolean rotating = isRotating(rotation); @@ -228,11 +228,11 @@ private void onUpdateWalkingPlayerHead(CallbackInfo ci) { sendSneakPacket(); sendPlayerPacket(moving, rotating, position, rotation); - this.prevOnGround = onGround; + prevOnGround = onGround; } - ++this.positionUpdateTicks; - this.autoJumpEnabled = this.mc.gameSettings.autoJump; + ++positionUpdateTicks; + autoJumpEnabled = mc.gameSettings.autoJump; } event = event.nextPhase(); @@ -240,62 +240,59 @@ private void onUpdateWalkingPlayerHead(CallbackInfo ci) { } private void sendSprintPacket() { - boolean sprinting = this.isSprinting(); + boolean sprinting = isSprinting(); - if (sprinting != this.serverSprintState) { + if (sprinting != serverSprintState) { if (sprinting) { - this.connection.sendPacket(new CPacketEntityAction(this, CPacketEntityAction.Action.START_SPRINTING)); + connection.sendPacket(new CPacketEntityAction(this, CPacketEntityAction.Action.START_SPRINTING)); } else { - this.connection.sendPacket(new CPacketEntityAction(this, CPacketEntityAction.Action.STOP_SPRINTING)); + connection.sendPacket(new CPacketEntityAction(this, CPacketEntityAction.Action.STOP_SPRINTING)); } - this.serverSprintState = sprinting; + serverSprintState = sprinting; } } private void sendSneakPacket() { - boolean sneaking = this.isSneaking(); + boolean sneaking = isSneaking(); - if (sneaking != this.serverSneakState) { + if (sneaking != serverSneakState) { if (sneaking) { - this.connection.sendPacket(new CPacketEntityAction(this, CPacketEntityAction.Action.START_SNEAKING)); + connection.sendPacket(new CPacketEntityAction(this, CPacketEntityAction.Action.START_SNEAKING)); } else { - this.connection.sendPacket(new CPacketEntityAction(this, CPacketEntityAction.Action.STOP_SNEAKING)); + connection.sendPacket(new CPacketEntityAction(this, CPacketEntityAction.Action.STOP_SNEAKING)); } - this.serverSneakState = sneaking; + serverSneakState = sneaking; } } private void sendPlayerPacket(boolean moving, boolean rotating, Vec3d position, Vec2f rotation) { - if (this.isRiding()) { - this.connection.sendPacket(new CPacketPlayer.PositionRotation(this.motionX, -999.0D, this.motionZ, rotation.getX(), rotation.getY(), onGround)); + if (isRiding()) { + connection.sendPacket(new CPacketPlayer.PositionRotation(motionX, -999.0D, motionZ, rotation.getX(), rotation.getY(), onGround)); moving = false; } else if (moving && rotating) { - this.connection.sendPacket(new CPacketPlayer.PositionRotation(position.x, position.y, position.z, rotation.getX(), rotation.getY(), onGround)); + connection.sendPacket(new CPacketPlayer.PositionRotation(position.x, position.y, position.z, rotation.getX(), rotation.getY(), onGround)); } else if (moving) { - this.connection.sendPacket(new CPacketPlayer.Position(position.x, position.y, position.z, onGround)); + connection.sendPacket(new CPacketPlayer.Position(position.x, position.y, position.z, onGround)); } else if (rotating) { - this.connection.sendPacket(new CPacketPlayer.Rotation(rotation.getX(), rotation.getY(), onGround)); - } else if (this.prevOnGround != onGround) { - this.connection.sendPacket(new CPacketPlayer(onGround)); + connection.sendPacket(new CPacketPlayer.Rotation(rotation.getX(), rotation.getY(), onGround)); + } else if (prevOnGround != onGround) { + connection.sendPacket(new CPacketPlayer(onGround)); } - if (moving) { - this.positionUpdateTicks = 0; - } + if (moving) positionUpdateTicks = 0; } private boolean isMoving(Vec3d position) { - double xDiff = position.x - this.lastReportedPosX; - double yDiff = position.y - this.lastReportedPosY; - double zDiff = position.z - this.lastReportedPosZ; + double xDiff = position.x - lastReportedPosX; + double yDiff = position.y - lastReportedPosY; + double zDiff = position.z - lastReportedPosZ; - return this.positionUpdateTicks >= 20 || xDiff * xDiff + yDiff * yDiff + zDiff * zDiff > 9.0E-4D; + return positionUpdateTicks >= 20 || xDiff * xDiff + yDiff * yDiff + zDiff * zDiff > 9.0E-4D; } private boolean isRotating(Vec2f rotation) { - double yawDiff = rotation.getX() - this.lastReportedYaw; - double pitchDiff = rotation.getY() - this.lastReportedPitch; - + double yawDiff = rotation.getX() - lastReportedYaw; + double pitchDiff = rotation.getY() - lastReportedPitch; return yawDiff != 0.0D || pitchDiff != 0.0D; } }