package net.minecraft.server; import com.google.common.collect.Lists; import net.minecraft.server.BlockPistonExtension.EnumPistonType; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; // CraftBukkit start import java.util.AbstractList; import java.util.Collection; import java.util.Iterator; import java.util.ListIterator; import com.google.common.collect.ImmutableList; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.event.block.BlockPistonRetractEvent; import org.bukkit.event.block.BlockPistonEvent; import org.bukkit.event.block.BlockPistonExtendEvent; // CraftBukkit end public class BlockPiston extends BlockDirectional { public static final BlockStateBoolean EXTENDED = BlockStateBoolean.of("extended"); protected static final AxisAlignedBB b = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.75D, 1.0D, 1.0D); protected static final AxisAlignedBB c = new AxisAlignedBB(0.25D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D); protected static final AxisAlignedBB d = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.75D); protected static final AxisAlignedBB e = new AxisAlignedBB(0.0D, 0.0D, 0.25D, 1.0D, 1.0D, 1.0D); protected static final AxisAlignedBB f = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D); protected static final AxisAlignedBB g = new AxisAlignedBB(0.0D, 0.25D, 0.0D, 1.0D, 1.0D, 1.0D); private final boolean sticky; public BlockPiston(boolean flag) { super(Material.PISTON); this.y(this.blockStateList.getBlockData().set(BlockPiston.FACING, EnumDirection.NORTH).set(BlockPiston.EXTENDED, Boolean.valueOf(false))); this.sticky = flag; this.a(SoundEffectType.d); this.c(0.5F); this.a(CreativeModeTab.d); } @Override public boolean u(IBlockData iblockdata) { return !iblockdata.get(BlockPiston.EXTENDED).booleanValue(); } @Override public AxisAlignedBB b(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition) { if (iblockdata.get(BlockPiston.EXTENDED).booleanValue()) { switch (iblockdata.get(BlockPiston.FACING)) { case DOWN: return BlockPiston.g; case UP: default: return BlockPiston.f; case NORTH: return BlockPiston.e; case SOUTH: return BlockPiston.d; case WEST: return BlockPiston.c; case EAST: return BlockPiston.b; } } else { return BlockPiston.j; } } @Override public boolean k(IBlockData iblockdata) { return !iblockdata.get(BlockPiston.EXTENDED).booleanValue() || iblockdata.get(BlockPiston.FACING) == EnumDirection.DOWN; } @Override public void a(IBlockData iblockdata, World world, BlockPosition blockposition, AxisAlignedBB axisalignedbb, List<AxisAlignedBB> list, @Nullable Entity entity, boolean flag) { a(blockposition, axisalignedbb, list, iblockdata.d(world, blockposition)); } @Override public boolean b(IBlockData iblockdata) { return false; } @Override public void postPlace(World world, BlockPosition blockposition, IBlockData iblockdata, EntityLiving entityliving, ItemStack itemstack) { world.setTypeAndData(blockposition, iblockdata.set(BlockPiston.FACING, EnumDirection.a(blockposition, entityliving)), 2); if (!world.isClientSide) { this.e(world, blockposition, iblockdata); } } @Override public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) { if (!world.isClientSide) { this.e(world, blockposition, iblockdata); } } @Override public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) { if (!world.isClientSide && world.getTileEntity(blockposition) == null) { this.e(world, blockposition, iblockdata); } } @Override public IBlockData getPlacedState(World world, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2, int i, EntityLiving entityliving) { return this.getBlockData().set(BlockPiston.FACING, EnumDirection.a(blockposition, entityliving)).set(BlockPiston.EXTENDED, Boolean.valueOf(false)); } private void e(World world, BlockPosition blockposition, IBlockData iblockdata) { EnumDirection enumdirection = iblockdata.get(BlockPiston.FACING); boolean flag = this.a(world, blockposition, enumdirection); if (flag && !iblockdata.get(BlockPiston.EXTENDED).booleanValue()) { if ((new PistonExtendsChecker(world, blockposition, enumdirection, true)).a()) { world.playBlockAction(blockposition, this, 0, enumdirection.a()); } } else if (!flag && iblockdata.get(BlockPiston.EXTENDED).booleanValue()) { // CraftBukkit start if (!this.sticky) { org.bukkit.block.Block block = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.<org.bukkit.block.Block>of(), CraftBlock.notchToBlockFace(enumdirection)); world.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return; } } // PAIL: checkME - what happened to setTypeAndData? // CraftBukkit end world.playBlockAction(blockposition, this, 1, enumdirection.a()); } } private boolean a(World world, BlockPosition blockposition, EnumDirection enumdirection) { EnumDirection[] aenumdirection = EnumDirection.values(); int i = aenumdirection.length; int j; for (j = 0; j < i; ++j) { EnumDirection enumdirection1 = aenumdirection[j]; if (enumdirection1 != enumdirection && world.isBlockFacePowered(blockposition.shift(enumdirection1), enumdirection1)) { return true; } } if (world.isBlockFacePowered(blockposition, EnumDirection.DOWN)) { return true; } else { BlockPosition blockposition1 = blockposition.up(); EnumDirection[] aenumdirection1 = EnumDirection.values(); j = aenumdirection1.length; for (int k = 0; k < j; ++k) { EnumDirection enumdirection2 = aenumdirection1[k]; if (enumdirection2 != EnumDirection.DOWN && world.isBlockFacePowered(blockposition1.shift(enumdirection2), enumdirection2)) { return true; } } return false; } } @Override public boolean a(IBlockData iblockdata, World world, BlockPosition blockposition, int i, int j) { EnumDirection enumdirection = iblockdata.get(BlockPiston.FACING); if (!world.isClientSide) { boolean flag = this.a(world, blockposition, enumdirection); if (flag && i == 1) { world.setTypeAndData(blockposition, iblockdata.set(BlockPiston.EXTENDED, Boolean.valueOf(true)), 2); return false; } if (!flag && i == 0) { return false; } } if (i == 0) { if (!this.a(world, blockposition, enumdirection, true)) { return false; } world.setTypeAndData(blockposition, iblockdata.set(BlockPiston.EXTENDED, Boolean.valueOf(true)), 3); world.a((EntityHuman) null, blockposition, SoundEffects.ev, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.25F + 0.6F); } else if (i == 1) { TileEntity tileentity = world.getTileEntity(blockposition.shift(enumdirection)); if (tileentity instanceof TileEntityPiston) { ((TileEntityPiston) tileentity).i(); } world.setTypeAndData(blockposition, Blocks.PISTON_EXTENSION.getBlockData().set(BlockPistonMoving.FACING, enumdirection).set(BlockPistonMoving.TYPE, this.sticky ? BlockPistonExtension.EnumPistonType.STICKY : BlockPistonExtension.EnumPistonType.DEFAULT), 3); world.setTileEntity(blockposition, BlockPistonMoving.a(this.fromLegacyData(j), enumdirection, false, true)); if (this.sticky) { BlockPosition blockposition1 = blockposition.a(enumdirection.getAdjacentX() * 2, enumdirection.getAdjacentY() * 2, enumdirection.getAdjacentZ() * 2); IBlockData iblockdata1 = world.getType(blockposition1); Block block = iblockdata1.getBlock(); boolean flag1 = false; if (block == Blocks.PISTON_EXTENSION) { TileEntity tileentity1 = world.getTileEntity(blockposition1); if (tileentity1 instanceof TileEntityPiston) { TileEntityPiston tileentitypiston = (TileEntityPiston) tileentity1; if (tileentitypiston.f() == enumdirection && tileentitypiston.e()) { tileentitypiston.i(); flag1 = true; } } } if (!flag1 && a(iblockdata1, world, blockposition1, enumdirection.opposite(), false) && (iblockdata1.p() == EnumPistonReaction.NORMAL || block == Blocks.PISTON || block == Blocks.STICKY_PISTON)) { // CraftBukkit - remove 'block.getMaterial() != Material.AIR' condition this.a(world, blockposition, enumdirection, false); } } else { world.setAir(blockposition.shift(enumdirection)); } world.a((EntityHuman) null, blockposition, SoundEffects.eu, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F); } return true; } @Override public boolean c(IBlockData iblockdata) { return false; } @Nullable public static EnumDirection e(int i) { int j = i & 7; return j > 5 ? null : EnumDirection.fromType1(j); } public static boolean a(IBlockData iblockdata, World world, BlockPosition blockposition, EnumDirection enumdirection, boolean flag) { Block block = iblockdata.getBlock(); if (block == Blocks.OBSIDIAN) { return false; } else if (!world.getWorldBorder().a(blockposition)) { return false; } else if (blockposition.getY() >= 0 && (enumdirection != EnumDirection.DOWN || blockposition.getY() != 0)) { if (blockposition.getY() <= world.getHeight() - 1 && (enumdirection != EnumDirection.UP || blockposition.getY() != world.getHeight() - 1)) { if (block != Blocks.PISTON && block != Blocks.STICKY_PISTON) { if (iblockdata.b(world, blockposition) == -1.0F) { return false; } if (iblockdata.p() == EnumPistonReaction.BLOCK) { return false; } if (iblockdata.p() == EnumPistonReaction.DESTROY) { return flag; } } else if (iblockdata.get(BlockPiston.EXTENDED).booleanValue()) { return false; } return !block.isTileEntity(); } else { return false; } } else { return false; } } /** PAIL: doMove */ private boolean a(World world, BlockPosition position, EnumDirection direction, boolean extending) { if (!extending) world.setAir(position.shift(direction)); PistonExtendsChecker extendsChecker = new PistonExtendsChecker(world, position, direction, extending); if (!extendsChecker.a()) return false; // PAIL: a() -> canMove() List<BlockPosition> movedBlockPos = extendsChecker.getMovedBlocks(); ArrayList<IBlockData> movedBlocks = Lists.newArrayList(); for (int i = 0, size = movedBlockPos.size(); i < size; i++) { BlockPosition eachBlock = movedBlockPos.get(i); movedBlocks.add(world.getType(eachBlock).b((IBlockAccess) world, eachBlock)); // PAIL: b -> getActualState } List<BlockPosition> brokenBlockPos = extendsChecker.getBrokenBlocks(); int blockSize = movedBlockPos.size() + brokenBlockPos.size(); IBlockData[] blocks = new IBlockData[blockSize]; EnumDirection actualDirection = extending ? direction : direction.opposite(); // CraftBukkit start final org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()); final List<BlockPosition> moved = extendsChecker.getMovedBlocks(); final List<BlockPosition> broken = extendsChecker.getBrokenBlocks(); List<org.bukkit.block.Block> bukkitBlocks = new AbstractList<org.bukkit.block.Block>() { @Override public int size() { return moved.size() + broken.size(); } @Override public org.bukkit.block.Block get(int index) { if (index >= size() || index < 0) { throw new ArrayIndexOutOfBoundsException(index); } BlockPosition pos = index < moved.size() ? moved.get(index) : broken.get(index - moved.size()); return bukkitBlock.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); } }; BlockPistonEvent event; if (extending) { event = new BlockPistonExtendEvent(bukkitBlock, bukkitBlocks, CraftBlock.notchToBlockFace(actualDirection)); } else { event = new BlockPistonRetractEvent(bukkitBlock, bukkitBlocks, CraftBlock.notchToBlockFace(actualDirection)); } world.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { for (BlockPosition pos : broken) { world.notify(pos, Blocks.AIR.getBlockData(), world.getType(pos), 3); } for (BlockPosition pos : moved) { world.notify(pos, Blocks.AIR.getBlockData(), world.getType(pos), 3); pos = pos.shift(actualDirection); world.notify(pos, Blocks.AIR.getBlockData(), world.getType(pos), 3); } return false; } // CraftBukkit end int index; BlockPosition eachBlock; IBlockData eachType; for (index = brokenBlockPos.size() - 1; index >= 0; --index) { eachBlock = brokenBlockPos.get(index); eachType = world.getType(eachBlock); eachType.getBlock().b(world, eachBlock, eachType, 0); // PAIL: b -> dropBlock world.setTypeAndData(eachBlock, Blocks.AIR.getBlockData(), 4); blockSize--; blocks[blockSize] = eachType; } for (index = movedBlockPos.size() - 1; index >= 0; --index) { eachBlock = movedBlockPos.get(index); eachType = world.getType(eachBlock); world.setTypeAndData(eachBlock, Blocks.AIR.getBlockData(), 2); eachBlock = eachBlock.shift(actualDirection); world.setTypeAndData(eachBlock, Blocks.PISTON_EXTENSION.getBlockData().set(BlockPiston.FACING, direction), 4); world.setTileEntity(eachBlock, BlockPistonMoving.a(movedBlocks.get(index), direction, extending, false)); blockSize--; blocks[blockSize] = eachType; } BlockPosition offset = position.shift(direction); if (extending) { EnumPistonType blockpistonextension_enumpistontype = this.sticky ? EnumPistonType.STICKY : EnumPistonType.DEFAULT; eachType = Blocks.PISTON_HEAD.getBlockData().set(BlockPistonExtension.FACING, direction).set(BlockPistonExtension.TYPE, blockpistonextension_enumpistontype); IBlockData iblockdata1 = Blocks.PISTON_EXTENSION.getBlockData().set(BlockPistonMoving.FACING, direction).set(BlockPistonMoving.TYPE, this.sticky ? BlockPistonExtension.EnumPistonType.STICKY : BlockPistonExtension.EnumPistonType.DEFAULT); world.setTypeAndData(offset, iblockdata1, 4); world.setTileEntity(offset, BlockPistonMoving.a(eachType, direction, true, true)); } index = 0; for (index = brokenBlockPos.size() - 1; index >= 0; --index) { world.applyPhysics(brokenBlockPos.get(index), blocks[blockSize].getBlock(), false); } for (index = movedBlockPos.size() - 1; index >= 0; --index) { world.applyPhysics(movedBlockPos.get(index), blocks[blockSize].getBlock(), false); } if (extending) { world.applyPhysics(offset, Blocks.PISTON_HEAD, false); } return true; } @Override public IBlockData fromLegacyData(int i) { return this.getBlockData().set(BlockPiston.FACING, e(i)).set(BlockPiston.EXTENDED, Boolean.valueOf((i & 8) > 0)); } @Override public int toLegacyData(IBlockData iblockdata) { byte b0 = 0; int i = b0 | iblockdata.get(BlockPiston.FACING).a(); if (iblockdata.get(BlockPiston.EXTENDED).booleanValue()) { i |= 8; } return i; } @Override public IBlockData a(IBlockData iblockdata, EnumBlockRotation enumblockrotation) { return iblockdata.set(BlockPiston.FACING, enumblockrotation.a(iblockdata.get(BlockPiston.FACING))); } @Override public IBlockData a(IBlockData iblockdata, EnumBlockMirror enumblockmirror) { return iblockdata.a(enumblockmirror.a(iblockdata.get(BlockPiston.FACING))); } @Override protected BlockStateList getStateList() { return new BlockStateList(this, new IBlockState[] { BlockPiston.FACING, BlockPiston.EXTENDED}); } }