45 Strafe

    From Minecraft Parkour Wiki
    Other languages:

    45° Strafe is a technique that grants more speed than regular movement.

    It can be done by strafing and turning 45° degrees (hence the name).


    45° Strafe can be performed by either:

    • Turning 45° left and Strafing right.
    • Turning 45° right and Strafing left.


    The turning must be quick (< 1tick) and precise (at least ±11.5°, the closer to ±0° the better), so it's difficult to perform consistently.

    Some jumps require the use of 45° strafe, such as 1bm 4.375b.



    Effect on Movement

    On every tick, the Player gains some acceleration depending on inputs and other factors.

    • When moving forward (without strafing), the acceleration gained is scaled by
    • When strafing, the acceleration is scaled by

    Therefore, 45° Strafe is times faster than regular movement (about 2% faster).


    Special case: 45° Sneak

    • When sneaking forward (without strafing), the acceleration gained is scaled by
    • When strafing while sneaking, the acceleration gained is scaled by (≈ 1.386)

    45° Sneak is used for no momentum jumps (example).

    Outside of parkour, it's notably used for bridging, as it's ~41% faster than regular sneaking.



    Explanation

    Below is a simplified version of the horizontal movement source code.

    /* 
     * Code from Entity and EntityLivingBase
     * Unnecessary or unrelated code is stripped out
     */
    
    public void onLivingUpdate()
    {
        /* 
         * moveStrafing and moveForward represent relative movement.
         * moveStrafing = 1.0 if moving left, -1.0 if moving right, else 0.0
         * moveForward = 1.0 if moving forward, -1.0 if moving backward, else 0.0
         *
         * Furthermore, moveStrafing and moveForward *= 0.3 if the player is sneaking.
         */
    
        this.moveStrafing *= 0.98F;
        this.moveForward *= 0.98F;
        this.moveEntityWithHeading(this.moveStrafing, this.moveForward);
    }
    
    
    
    public void moveEntityWithHeading(float strafe, float forward)
    {
        /* inertia determines how much speed is conserved onto the next tick */
        float mult = 0.91F;
        if (this.onGround)
        {
            /* Get slipperiness 1 block below the player */
            mult *= getBlockSlipperinessAt(this.posX, this.getEntityBoundingBox().minY - 1, this.posZ);
        }
    
        /* acceleration = (0.6*0.91)^3 / (slipperiness*0.91)^3) */
        float acceleration = 0.16277136F / (mult * mult * mult);
    
        float movementFactor;
        if (this.onGround)
            movementFactor = this.landMovementFactor * acceleration;
            /* base: 0.1; x1.3 if sprinting, affected by potion effects. */
    
        else
            movementFactor = this.airMovementFactor; 
            /* base: 0.02; x1.3 if sprinting */
    
        this.updateMotionXZ(strafe, forward, movementFactor); 
        this.moveEntity(this.motionX, this.motionY, this.motionZ);
    
        this.motionY -= 0.08D; /* gravity */
        this.motionY *= 0.98D; /* drag */
    
        this.motionX *= mult;
        this.motionZ *= mult;
    }
    
    
    
    public void updateMotionXZ(float strafe, float forward, float movementFactor)
    {
        /*
         * This function is responsible for the existence of 45° strafe. The geometry doesn't seem to make sense...
         * Note that:
         *     - Sprint multiplier is contained within "movementFactor"
         *     - Sneak multiplier is contained within "strafe" and "forward"
         * This is likely because Sneaking was implemented long before Sprinting
         */
        float distance = strafe * strafe + forward * forward;
    
        if (distance >= 1.0E-4F)
        {
            distance = MathHelper.sqrt_float(distance);
                
            if (distance < 1.0F)
                distance = 1.0F;
    
            distance = movementFactor / distance;
            strafe = strafe * distance;
            forward = forward * distance;
            float sinYaw = MathHelper.sin(this.rotationYaw * Math.PI / 180.0F);
            float cosYaw = MathHelper.cos(this.rotationYaw * Math.PI / 180.0F);
            this.motionX += strafe * cosYaw - forward * sinYaw;
            this.motionZ += forward * cosYaw + strafe * sinYaw;
        }
    }