Affects Version/s: Minecraft 1.12.1, Minecraft 1.12.2 Pre-Release 1, Minecraft 1.12.2 Pre-Release 2, Minecraft 1.12.2, Minecraft 17w43a, Minecraft 17w43b, Minecraft 17w46a, Minecraft 17w48a, Minecraft 17w50a, Minecraft 18w01a, Minecraft 18w03b, Minecraft 18w06a, Minecraft 18w09a, Minecraft 18w10d, Minecraft 18w14b, Minecraft 1.13-pre1, Minecraft 1.13-pre3, Minecraft 1.13-pre6, Minecraft 1.13-pre8, Minecraft 1.13-pre10, Minecraft 1.13, Minecraft 18w30b, Minecraft 18w31a, Minecraft 1.13.1, Minecraft 1.13.2, Minecraft 18w44a, 1.16.3, 1.16.4, 20w48a, 21w03a, 21w05b, 1.17.1
Fix Version/s: None
Category:Commands, Player Animation
/tp and /teleport forcibly wrap player rotation, which causes the first person hand/held item to rotate incorrectly.
If you rotate in circles several times, and then run /tp @p ~ ~ ~ or /teleport @p ~ ~ ~, your hand will spin in circles several times extremely quickly, even though the actual visual angle will not change.
If, after running /tp @p ~ ~ ~ 0 ~ to ensure consistency, you run /tp @p ~ ~ ~ ~90 ~, your hand will make 3 small rotations from the left and then one big rotation from the right, even though in each case you've been making small rotations from the left. The inverse happens with /tp @p ~ ~ ~ ~-90 ~.
The hand rotation interpolates between Entity.prevRotationYaw and Entity.rotationYaw. This would normally be fine, but these values are wrapped differently. rotationYaw is modulo'd by 360 within setRotation, while prevRotationYaw is left unwrapped by setPositionAndRotation (the one that the player position packet handler uses) except for a +/- 360 change based off of the difference from the old value.
This can be hack-fixed by simply removing both cases of angle wrapping:
in Entity.setPositionAndRotation (Entity.a(DDDFF)V) should be removed completely (without wrapping it doesn't make sense).
The % 360 should be removed from setRotation.
The problem with this fix is that now there is no limit to the angle. That isn't too big of a problem (as clientside there already is no limit - F3 displays the wrapped version), but it could be mitigated by calling MathHelper.wrapDegrees when reading/writing the entity from/to NBT (as there won't be any previous rotations to worry about there).
See this video. This video was recorded in my MCP test install, and there are some things that are non-standard, but this bug has been tested in vanilla. Of important note is the unwrapped angle in F3, displayed in red. This is the exact value of rotationYaw, without calling wrapDegrees. The game was also slowed down to .25x the normal speed using cheat engine, again for visibility.