mojira.dev
MC-124718

Hardcoded limit of pistons pushing entities

The bug

There is a hardcoded limit imposed by the game to restrict entities being pushed by 0.51 blocks per direction per gametick. It's an arbitrary restriction that is unintuitive when multiple pistons attempt to push an entity in the same tick, especially when it involves mobs "stepping up" (0.5m for most mobs, 1m for player/llama/horse), and becomes glitched inside blocks (example

[media]

).

Code analysis

Originally by Myren Eario
Based on 1.12.2 decompiled using MCP 9.40

net.minecraft.entity.Entity.move(MoverType, double, double, double) uses the attribute pistonDeltasGameTime to store the offset by which an entity has been moved by pistons in a tick.

Entity.move(MoverType, double, double, double)

...

if (type == MoverType.PISTON)
{
    long i = this.world.getTotalWorldTime();

    if (i != this.pistonDeltasGameTime)
    {
        Arrays.fill(this.pistonDeltas, 0.0D);
        this.pistonDeltasGameTime = i;
    }

    if (x != 0.0D)
    {
        int j = EnumFacing.Axis.X.ordinal();
        double d0 = MathHelper.clamp(x + this.pistonDeltas[j], -0.51D, 0.51D);
        x = d0 - this.pistonDeltas[j];
        this.pistonDeltas[j] = d0;

        if (Math.abs(x) <= 9.999999747378752E-6D)
        {
            return;
        }
    }
    else if (y != 0.0D)
    {
        int l4 = EnumFacing.Axis.Y.ordinal();
        double d12 = MathHelper.clamp(y + this.pistonDeltas[l4], -0.51D, 0.51D);
        y = d12 - this.pistonDeltas[l4];
        this.pistonDeltas[l4] = d12;

        if (Math.abs(y) <= 9.999999747378752E-6D)
        {
            return;
        }
    }
    else
    {
        if (z == 0.0D)
        {
            return;
        }

        int i5 = EnumFacing.Axis.Z.ordinal();
        double d13 = MathHelper.clamp(z + this.pistonDeltas[i5], -0.51D, 0.51D);
        z = d13 - this.pistonDeltas[i5];
        this.pistonDeltas[i5] = d13;

        if (Math.abs(z) <= 9.999999747378752E-6D)
        {
            return;
        }
    }
}

...

Attachments

Comments 2

Here´s a less obfuscated version of the relevant part of the code. It´s the beginning of the moveEntity() method in the Entity class in 1.12 MCP, except that I renamed some variables.

public void moveEntity(MoverType moverType, double amtXIn, double amtYIn, double amtZIn)
    {
        if (this.noClip)
        {
            this.setEntityBoundingBox(this.getEntityBoundingBox().offset(amtXIn, amtYIn, amtZIn));
            this.resetPositionToBB();
        }
        else
        {
            if (moverType == MoverType.PISTON)
            {
                long i = this.world.getTotalWorldTime();

                if (i != this.lastTimePushedByPistons)
                {
                    Arrays.fill(this.distanceMovedByPistonsInThisGtick, 0.0D);
                    this.lastTimePushedByPistons = i;
                }

                if (amtXIn != 0.0D)
                {
                    int j = EnumFacing.Axis.X.ordinal();
                    double d0 = MathHelper.clamp(amtXIn + this.distanceMovedByPistonsInThisGtick[j], -0.51D, 0.51D);
                    amtXIn = d0 - this.distanceMovedByPistonsInThisGtick[j];
                    this.distanceMovedByPistonsInThisGtick[j] = d0;

                    if (Math.abs(amtXIn) <= 9.999999747378752E-6D)
                    {
                        return;
                    }
                }
                else if (amtYIn != 0.0D)
                {
                    int l4 = EnumFacing.Axis.Y.ordinal();
                    double d12 = MathHelper.clamp(amtYIn + this.distanceMovedByPistonsInThisGtick[l4], -0.51D, 0.51D);
                    amtYIn = d12 - this.distanceMovedByPistonsInThisGtick[l4];
                    this.distanceMovedByPistonsInThisGtick[l4] = d12;

                    if (Math.abs(amtYIn) <= 9.999999747378752E-6D)
                    {
                        return;
                    }
                }
                else
                {
                    if (amtZIn == 0.0D)
                    {
                        return;
                    }

                    int i5 = EnumFacing.Axis.Z.ordinal();
                    double d13 = MathHelper.clamp(amtZIn + this.distanceMovedByPistonsInThisGtick[i5], -0.51D, 0.51D);
                    amtZIn = d13 - this.distanceMovedByPistonsInThisGtick[i5];
                    this.distanceMovedByPistonsInThisGtick[i5] = d13;

                    if (Math.abs(amtZIn) <= 9.999999747378752E-6D)
                    {
                        return;
                    }
                }
            }

and then there´s the rest of the moveEntity method.

While I don´t like this behavior, it looks intentional, so I don´t think this bug report will go very far.

Sorry, missed your comment (had the report still open without reloading it). I hope the changes I made reflect the problem well enough.

Eta740

(Unassigned)

Confirmed

(Unassigned)

piston

Minecraft 1.12.2, Minecraft 1.13, 1.15.2, 20w18a

Retrieved