Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-124195

Left hand swing animation does not perfectly mirror right hand

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • None
    • Minecraft 1.12.2, Minecraft 18w02a, Minecraft 1.13.1, Minecraft 18w50a, Minecraft 1.14.3, 1.14.4, 19w41a, 1.15 Pre-Release 2, 1.15 Pre-release 4, 1.15.1 Pre-release 1, 1.15.2, 1.16 Pre-release 2, 1.16 Pre-release 3, 1.16 Pre-release 6, 1.16.1, 20w28a, 20w29a, 20w30a, 1.16.2 Pre-release 1, 1.16.2 Pre-release 2, 1.16.2 Pre-release 3, 1.16.2 Release Candidate 1, 1.16.2 Release Candidate 2, 1.16.2, 1.16.3, 21w03a, 21w05b, 1.17.1, 1.18.1, 22w06a, 1.19 Pre-release 1, 1.19, 1.19.2, 1.19.3, 1.19.4, 1.20.1, 1.20.4
    • Confirmed
    • Mob behaviour, Player
    • Low
    • Gameplay

      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

      1. /tp @s ~ ~ ~ 0 0
      2. /effect give @p mining_fatigue 10000 15 true (to slow down the swinging animation)
      3. Go in third person to look at yourself from the front
      4. 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 little
      5. Hit 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 all

        To reproduce

      6. Summon an enderman
         /summon minecraft:enderman ~ ~ ~ {Attributes:[{Base:-10.0d,Name:"generic.movement_speed"},{Base:0.0d,Name:"generic.attack_damage"}],LeftHanded:1b} 
      7. 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;
                  }
              }
      

            Unassigned Unassigned
            onnowhere Onnowhere
            Votes:
            18 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              CHK: