mojira.dev
MC-114504

Opening shulker boxes move entities inside them

The bug

Opening shulker boxes move entities which are inside them. Expected would be that they only move entities which are next to them.

How to reproduce

  1. Summon an entity which is taller than two blocks

    /summon wither_skeleton ~2 ~ ~ {NoAI:1b,Invulnerable:1b}
  2. Place a shulker box at the upper block

    /setblock ~2 ~1 ~ white_shulker_box
  3. Open the shulker box
    → You will see that the entity was moved upwards

Code analysis

Based on 1.11.2 decompiled using MCP 9.35 rc1

The problem is that the method net.minecraft.tileentity.TileEntityShulkerBox.moveCollidedEntities() searches in a bounding box beginning outside the 1*1*1 cube of the shulker box instead of at the last progress and that it moves entities whose bounding box starts behind this bounding box.

The following shows a proof of concept fix which can possibly be improved performance-wise.

private AxisAlignedBB getTopBoundingBox(EnumFacing p_190588_1_)
{
    // Comment: Replaced this to return a bounding box between progressOld and progress (= area in which entities should be moved)
    // EnumFacing enumfacing = p_190588_1_.getOpposite();
    // return this.getBoundingBox(p_190588_1_).contract((double)enumfacing.getFrontOffsetX(), (double)enumfacing.getFrontOffsetY(), (double)enumfacing.getFrontOffsetZ());
    
    return new AxisAlignedBB(
            p_190588_1_.getFrontOffsetX() > 0 ? 1 + 0.5F * this.progress: 0 - (p_190588_1_.getFrontOffsetX() < 0 ? 0.5F * this.progressOld : 0),
            p_190588_1_.getFrontOffsetY() > 0 ? 1 + 0.5F * this.progress: 0 - (p_190588_1_.getFrontOffsetY() < 0 ? 0.5F * this.progressOld : 0),
            p_190588_1_.getFrontOffsetZ() > 0 ? 1 + 0.5F * this.progress: 0 - (p_190588_1_.getFrontOffsetZ() < 0 ? 0.5F * this.progressOld : 0),
            p_190588_1_.getFrontOffsetX() < 0 ? 0 - 0.5F * this.progress: 1 + (p_190588_1_.getFrontOffsetX() > 0 ? 0.5F * this.progressOld : 0),
            p_190588_1_.getFrontOffsetY() < 0 ? 0 - 0.5F * this.progress: 1 + (p_190588_1_.getFrontOffsetX() > 0 ? 0.5F * this.progressOld : 0),
            p_190588_1_.getFrontOffsetZ() < 0 ? 0 - 0.5F * this.progress: 1 + (p_190588_1_.getFrontOffsetX() > 0 ? 0.5F * this.progressOld : 0)
        );
}

private void moveCollidedEntities()
{
    IBlockState iblockstate = this.world.getBlockState(this.getPos());

    if (iblockstate.getBlock() instanceof BlockShulkerBox)
    {
        EnumFacing enumfacing = (EnumFacing)iblockstate.getValue(BlockShulkerBox.FACING);
        AxisAlignedBB axisalignedbb = this.getTopBoundingBox(enumfacing).offset(this.pos);
        List<Entity> list = this.world.getEntitiesWithinAABBExcludingEntity((Entity)null, axisalignedbb);

        if (!list.isEmpty())
        {
            for (int i = 0; i < list.size(); ++i)
            {
                Entity entity = (Entity)list.get(i);

                // Comment: Change start
                // if (entity.getPushReaction() != EnumPushReaction.IGNORE)
                boolean shouldMoveEntity = false;
                AxisAlignedBB entityBoundingBox = entity.getEntityBoundingBox();
                
                if (enumfacing.getFrontOffsetX() > 0) {
                    if (entityBoundingBox.minX >= axisalignedbb.minX) {
                        shouldMoveEntity = true;
                    }
                }
                else if (enumfacing.getFrontOffsetX() < 0) {
                    if (entityBoundingBox.minX <= axisalignedbb.minX) {
                        shouldMoveEntity = true;
                    }
                }
                else if (enumfacing.getFrontOffsetY() > 0) {
                    if (entityBoundingBox.minY >= axisalignedbb.minY) {
                        shouldMoveEntity = true;
                    }
                }
                else if (enumfacing.getFrontOffsetY() < 0) {
                    if (entityBoundingBox.minY <= axisalignedbb.minY) {
                        shouldMoveEntity = true;
                    }
                }
                else if (enumfacing.getFrontOffsetZ() > 0) {
                    if (entityBoundingBox.minZ >= axisalignedbb.minZ) {
                        shouldMoveEntity = true;
                    }
                }
                else if (enumfacing.getFrontOffsetZ() < 0) {
                    if (entityBoundingBox.minZ <= axisalignedbb.minZ) {
                        shouldMoveEntity = true;
                    }
                }
                
                if (entity.getPushReaction() != EnumPushReaction.IGNORE && shouldMoveEntity)
                // Comment: Change end
                {
                    // ...
                }
            }
        }
    }
}

Linked issues

Attachments

Comments 8

Can confirm in 21w06a.

Can confirm in 1.16.5 and 21w08b.

Can confirm in 21w17a.

Can confirm in 1.17.

Can confirm in 1.17.1.

Can confirm in 1.18.1.

Can confirm in 1.19.2 and 22w42a.

marcono1234

(Unassigned)

Confirmed

(Unassigned)

bounding-box, collision-box, entity, shulker_box

Minecraft 1.11.2, Minecraft 17w06a, Minecraft 1.12.1, Minecraft 1.12.2, Minecraft 18w22c, ..., 1.17.1, 1.18.1, 1.19.2, 22w42a, 1.21

Retrieved