diff --git a/src/main/java/com/minelittlepony/client/HorseCam.java b/src/main/java/com/minelittlepony/client/HorseCam.java index 591f0217..5d2004d2 100644 --- a/src/main/java/com/minelittlepony/client/HorseCam.java +++ b/src/main/java/com/minelittlepony/client/HorseCam.java @@ -1,15 +1,28 @@ package com.minelittlepony.client; -import net.minecraft.block.Material; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import com.minelittlepony.api.pony.IPony; public class HorseCam { + private static float lastOriginalPitch; + private static float lastComputedPitch; + + /** + * Restores the previous camera (unadjusted) angle for the client when the server sends an update. + * This is to prevent issues caused by the server updating our pitch whenever the player leaves a portal. + */ + public static float transformIncomingServerCameraAngle(float serverPitch) { + if (MathHelper.approximatelyEquals(serverPitch, lastComputedPitch)) { + return lastOriginalPitch; + } + return serverPitch; + } + /** * Transforms the client pony's pitch to the corresponding angle for a human character. */ @@ -19,12 +32,28 @@ public class HorseCam { return pitch; } + if (pitch != 0) { + lastOriginalPitch = pitch; + lastComputedPitch = pitch; + } + PlayerEntity player = MinecraftClient.getInstance().player; + + // noop + // Only run when the player has an item in their hands. Can't check for buckets specifically since mods exist. + if (player.getMainHandStack().isEmpty() && player.getOffHandStack().isEmpty()) { + return pitch; + } + IPony pony = MineLittlePony.getInstance().getManager().getPony(player); if (!pony.getRace(false).isHuman()) { float factor = pony.getMetadata().getSize().getEyeHeightFactor(); - return rescaleCameraPitch(player.getStandingEyeHeight() / factor, pitch); + pitch = rescaleCameraPitch(player.getStandingEyeHeight() / factor, pitch); + } + + if (lastOriginalPitch != 0) { + lastComputedPitch = pitch; } return pitch; @@ -78,19 +107,19 @@ public class HorseCam { MinecraftClient client = MinecraftClient.getInstance(); PlayerEntity player = client.player; - client.gameRenderer.updateTargetedEntity(1); + client.gameRenderer.updateTargetedEntity(client.getTickDelta()); HitResult hit = client.crosshairTarget; + if (client.targetedEntity != null) { + return originalPitch; + } + // noop // Ignore misses, helps with bows, arrows, and projectiles if (hit == null || hit.getType() != HitResult.Type.BLOCK || player == null) { return originalPitch; } - if (hit instanceof BlockHitResult && player.world.getBlockState(((BlockHitResult)hit).getBlockPos()).getMaterial() == Material.PORTAL) { - return originalPitch; - } - Vec3d hitPos = hit.getPos(); Vec3d pos = player.getPos(); diff --git a/src/main/java/com/minelittlepony/client/mixin/MixinPlayerPositionLookS2CPacket.java b/src/main/java/com/minelittlepony/client/mixin/MixinPlayerPositionLookS2CPacket.java new file mode 100644 index 00000000..889afa27 --- /dev/null +++ b/src/main/java/com/minelittlepony/client/mixin/MixinPlayerPositionLookS2CPacket.java @@ -0,0 +1,30 @@ +package com.minelittlepony.client.mixin; + +import com.minelittlepony.client.HorseCam; + +import java.util.Set; + +import net.minecraft.network.*; +import net.minecraft.network.listener.ClientPlayPacketListener; +import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket.Flag; + +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PlayerPositionLookS2CPacket.class) +abstract class MixinPlayerPositionLookS2CPacket implements Packet { + @Shadow @Mutable + private @Final float pitch; + private @Final Set flags; + + @Inject(method = "apply(Lnet/minecraft/network/listener/ClientPlayPacketListener;)V", + at = @At("HEAD")) + private void onApply(ClientPlayPacketListener clientPlayPacketListener, CallbackInfo info) { + if (!flags.contains(PlayerPositionLookS2CPacket.Flag.Y_ROT)) { + pitch = HorseCam.transformIncomingServerCameraAngle(pitch); + } + } +} diff --git a/src/main/resources/minelp.mixin.json b/src/main/resources/minelp.mixin.json index aefe9d16..80cd505c 100644 --- a/src/main/resources/minelp.mixin.json +++ b/src/main/resources/minelp.mixin.json @@ -16,6 +16,7 @@ "MixinTexturedRenderLayers", "MixinSpriteIdentifier", "MixinClientPlayerEntity", - "MixinPlayerMoveC2SPacket" + "MixinPlayerMoveC2SPacket", + "MixinPlayerPositionLookS2CPacket" ] }