The bug
When swinging with your left hand, the animation is not perfectly mirrored to swinging with your right hand. There is a very slight mismatch.
How to reproduce
/tp @s ~ ~ ~ 0 0
/effect give @p mining_fatigue 10000 15 true
(to slow down the swinging animation)Go in third person to look at yourself from the front
Hit with your right hand, notice that the corner of your hand goes past the center of your body
→ Also notice that your left hand will shake a littleHit with your left hand by switching your main hand, notice that the corner of your hand does not go past the center of your body
→ Also notice that your right hand does NOT shake at allTO REPRODUCE
Summon an enderman
/summon minecraft:enderman ~ ~ ~ {Attributes:[{Base:-10.0d,Name:"generic.movement_speed"},{Base:0.0d,Name:"generic.attack_damage"}],LeftHanded:1b}
Either attack it or look at it in the eyes
→ ❌ It's swings it's left arm in a weird way
also happens with piglin
Code analysis
The following is based on a decompiled version of Minecraft 1.12 using MCP 9.40
The reason is likely due to an oversight in net.minecraft.client.model.ModelBiped.setRotationAngles()
. In the section calculating animations based off swingProgress
, the line:
this.bipedLeftArm.rotateAngleX += this.bipedBody.rotateAngleY;
appears to add an offset to the left arm when the right arm is swinging. This line should instead subtract the value from the X angle and switch to modifying the right hand when the main hand is the left hand.
Additionally, in the same section, the line:
modelrenderer.rotateAngleZ += MathHelper.sin(this.swingProgress * (float)Math.PI) * -0.4F;
does not apply the angle correctly when on the left hand as the Z angle should be mirrored. Instead it should subtract the value from the Z angle.
Potential fix
if (this.swingProgress > 0.0F)
{
EnumHandSide enumhandside = this.getMainHand(entityIn);
ModelRenderer modelrenderer = this.getArmForSide(enumhandside);
float f1 = this.swingProgress;
this.bipedBody.rotateAngleY = MathHelper.sin(MathHelper.sqrt(f1) * ((float)Math.PI * 2F)) * 0.2F;
if (enumhandside == EnumHandSide.LEFT)
{
this.bipedBody.rotateAngleY *= -1.0F;
}
this.bipedRightArm.rotationPointZ = MathHelper.sin(this.bipedBody.rotateAngleY) * 5.0F;
this.bipedRightArm.rotationPointX = -MathHelper.cos(this.bipedBody.rotateAngleY) * 5.0F;
this.bipedLeftArm.rotationPointZ = -MathHelper.sin(this.bipedBody.rotateAngleY) * 5.0F;
this.bipedLeftArm.rotationPointX = MathHelper.cos(this.bipedBody.rotateAngleY) * 5.0F;
this.bipedRightArm.rotateAngleY += this.bipedBody.rotateAngleY;
this.bipedLeftArm.rotateAngleY += this.bipedBody.rotateAngleY;
/**
* this.bipedBody.rotateAngleY is negated when hand side is left
* thus it must be subtracted from this.bipedRightArm.rotateAngleX
* to make it positive again as X angles aren't affected by mirroring
*/
if (enumhandside == EnumHandSide.LEFT)
{
this.bipedRightArm.rotateAngleX -= this.bipedBody.rotateAngleY;
}
else
{
this.bipedLeftArm.rotateAngleX += this.bipedBody.rotateAngleY;
}
f1 = 1.0F - this.swingProgress;
f1 = f1 * f1;
f1 = f1 * f1;
f1 = 1.0F - f1;
float f2 = MathHelper.sin(f1 * (float)Math.PI);
float f3 = MathHelper.sin(this.swingProgress * (float)Math.PI) * -(this.bipedHead.rotateAngleX - 0.7F) * 0.75F;
modelrenderer.rotateAngleX = (float)((double)modelrenderer.rotateAngleX - ((double)f2 * 1.2D + (double)f3));
modelrenderer.rotateAngleY += this.bipedBody.rotateAngleY * 2.0F;
/**
* Used 0.4F instead of -0.4F here. Right hand subtracts and left hand adds
* since Z angles must apply opposite on left versus right hand to correctly mirror
*/
if (enumhandside == EnumHandSide.LEFT)
{
modelrenderer.rotateAngleZ += MathHelper.sin(this.swingProgress * (float)Math.PI) * 0.4F;
}
else
{
modelrenderer.rotateAngleZ -= MathHelper.sin(this.swingProgress * (float)Math.PI) * 0.4F;
}
}
Linked issues
is duplicated by 5
Attachments
Comments 10
See MC-156118
Can confirm for 1.18.1, if you look at the base of your torso you can tell that the animation is the same for both right and left handed players. What should happen is your torso should rotate with the punch, not against it.
Confirmed for 1.13.1.