The Bug:
Players that are swimming render outside of their hitboxes when looking up or down.
Steps to Reproduce:
Enter a deep body of water and enable entity hitboxes by pressing "F3 + B".
Begin swimming upwards or downwards and look at your hitbox and your model.
Take note as to whether or not players that are swimming render outside of their hitboxes when looking up or down.
Observed Behavior:
Players render outside of their hitboxes.
Expected Behavior:
Players would not render outside of their hitboxes.
Code Analysis:
The following is based on a decompiled version of Minecraft 26.3 Snapshot 4 using Mojang mappings.
net.minecraft.client.renderer.entity.player.AvatarRenderer.java
} else if (swimAmount > 0.0F) {
super.setupRotations(state, poseStack, bodyRot, entityScale);
float targetXRot = state.isInWater ? -90.0F - xRot : -90.0F;
float xAngle = Mth.lerp(swimAmount, 0.0F, targetXRot);
poseStack.mulPose(Axis.XP.rotationDegrees(xAngle));
if (state.isVisuallySwimming) {
poseStack.translate(0.0F, -1.0F, 0.3F);
}
}If we look at the above class, we can see that the model is turned by an angle that depends on where the player is looking, and is then moved by a fixed amount to put it back onto the hitbox. The problem is that the move happens after the turn, so it is measured along the turned model rather than along the world, and it turns with it.
The two numbers are doing different jobs that only line up at one angle. The 0.3 is half the height of the swimming hitbox, so it is the lift needed to reach the middle of that hitbox, and it is written on the Z axis only because at level swimming the turn happens to point Z upwards. The 1.0 is roughly half the length of the model, which moves its middle onto the point being turned around.
The result is that the middle of the model travels in a circle around the player's feet as they look up and down, instead of staying on the hitbox. Measured against the middle of the hitbox it is 0.06 blocks out when swimming level, but 0.38 out when looking straight down and 0.47 out when looking straight up. The hitbox is only 0.6 across, so at that point the middle of the model has left it completely.
It is worth noting that the model is around 1.875 blocks long and the swimming hitbox is a 0.6 cube, so the model cannot be contained by it at any angle. What can be corrected is the model sliding off the hitbox, so that it stays centred on it and extends evenly instead.
Fixed Code:
net.minecraft.client.renderer.entity.player.AvatarRenderer.java
} else if (swimAmount > 0.0F) {
super.setupRotations(state, poseStack, bodyRot, entityScale);
float targetXRot = state.isInWater ? -90.0F - xRot : -90.0F;
float xAngle = Mth.lerp(swimAmount, 0.0F, targetXRot);
if (state.isVisuallySwimming) {
poseStack.translate(0.0F, Avatar.SWIMMING_BB_HEIGHT / 2.0F, 0.0F);
poseStack.mulPose(Axis.XP.rotationDegrees(xAngle));
poseStack.translate(0.0F, -1.0F, 0.0F);
} else {
poseStack.mulPose(Axis.XP.rotationDegrees(xAngle));
}
}The above lifts the model to the middle of the hitbox before turning it, and steps back along the model's own length afterwards. The model is then turned around its own middle while that middle stays on the hitbox, so it no longer slides off as the player looks up or down.
Level swimming and crawling are unchanged. Both use an angle of -90 degrees, and at that angle the new steps come to exactly the same position as the existing ones, so the pose that is currently correct stays exactly as it is.
This change was applied to a modified client and tested against the steps above, and the model now stays centred on its hitbox at every angle.
Linked issues
relates to 3
Attachments
Comments 2
Just to clarify, this ticket (MC-262805) is not about the hitboxes of swimming players being too small or being positioned at their feet; it's about the player model not being centered inside the player hitbox.
Can confirm that this is the case.