content: package thebetweenlands.common.block.structure;
  
  import java.util.List;
  
  import javax.annotation.Nullable;
  
  import net.minecraft.block.Block;
  import net.minecraft.block.BlockFence;
  import net.minecraft.block.BlockFenceGate;
  import net.minecraft.block.properties.IProperty;
  import net.minecraft.block.properties.PropertyBool;
  import net.minecraft.block.state.BlockFaceShape;
  import net.minecraft.block.state.BlockStateContainer;
  import net.minecraft.block.state.IBlockState;
  import net.minecraft.entity.Entity;
  import net.minecraft.entity.player.EntityPlayer;
  import net.minecraft.init.Blocks;
  import net.minecraft.init.Items;
  import net.minecraft.item.ItemLead;
  import net.minecraft.item.ItemStack;
  import net.minecraft.util.EnumFacing;
  import net.minecraft.util.EnumHand;
  import net.minecraft.util.Mirror;
  import net.minecraft.util.Rotation;
  import net.minecraft.util.math.AxisAlignedBB;
  import net.minecraft.util.math.BlockPos;
  import net.minecraft.world.IBlockAccess;
  import net.minecraft.world.World;
  import net.minecraftforge.fml.relauncher.Side;
  import net.minecraftforge.fml.relauncher.SideOnly;
  import thebetweenlands.client.tab.BLCreativeTabs;
  
  /**
   * Just a vanilla C&P because it's not extensible...
   */
  public class BlockFenceBetweenlands extends Block {
  
  	/** Whether this fence connects in the northern direction */
  	public static final PropertyBool NORTH = PropertyBool.create("north");
  	/** Whether this fence connects in the eastern direction */
  	public static final PropertyBool EAST = PropertyBool.create("east");
  	/** Whether this fence connects in the southern direction */
  	public static final PropertyBool SOUTH = PropertyBool.create("south");
  	/** Whether this fence connects in the western direction */
  	public static final PropertyBool WEST = PropertyBool.create("west");
  	protected static final AxisAlignedBB[] BOUNDING_BOXES = new AxisAlignedBB[] {new AxisAlignedBB(0.375D, 0.0D, 0.375D, 0.625D, 1.0D, 0.625D), new AxisAlignedBB(0.375D, 0.0D, 0.375D, 0.625D, 1.0D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.375D, 0.625D, 1.0D, 0.625D), new AxisAlignedBB(0.0D, 0.0D, 0.375D, 0.625D, 1.0D, 1.0D), new AxisAlignedBB(0.375D, 0.0D, 0.0D, 0.625D, 1.0D, 0.625D), new AxisAlignedBB(0.375D, 0.0D, 0.0D, 0.625D, 1.0D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.625D, 1.0D, 0.625D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.625D, 1.0D, 1.0D), new AxisAlignedBB(0.375D, 0.0D, 0.375D, 1.0D, 1.0D, 0.625D), new AxisAlignedBB(0.375D, 0.0D, 0.375D, 1.0D, 1.0D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.375D, 1.0D, 1.0D, 0.625D), new AxisAlignedBB(0.0D, 0.0D, 0.375D, 1.0D, 1.0D, 1.0D), new AxisAlignedBB(0.375D, 0.0D, 0.0D, 1.0D, 1.0D, 0.625D), new AxisAlignedBB(0.375D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.625D), new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D)};
  	public static final AxisAlignedBB PILLAR_AABB = new AxisAlignedBB(0.375D, 0.0D, 0.375D, 0.625D, 1.5D, 0.625D);
  	public static final AxisAlignedBB SOUTH_AABB = new AxisAlignedBB(0.375D, 0.0D, 0.625D, 0.625D, 1.5D, 1.0D);
  	public static final AxisAlignedBB WEST_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.375D, 0.375D, 1.5D, 0.625D);
  	public static final AxisAlignedBB NORTH_AABB = new AxisAlignedBB(0.375D, 0.0D, 0.0D, 0.625D, 1.5D, 0.375D);
  	public static final AxisAlignedBB EAST_AABB = new AxisAlignedBB(0.625D, 0.0D, 0.375D, 1.0D, 1.5D, 0.625D);
  
  	public BlockFenceBetweenlands(IBlockState state) {
  		super(state.getMaterial(), state.getMaterial().getMaterialMapColor());
  		setSoundType(state.getBlock().getSoundType());
  		setHardness(2.0F);
  		setResistance(5.0F);
  		setDefaultState(this.blockState.getBaseState().withProperty(NORTH, Boolean.FALSE).withProperty(EAST, Boolean.FALSE).withProperty(SOUTH, Boolean.FALSE).withProperty(WEST, Boolean.FALSE));
  		setCreativeTab(BLCreativeTabs.BLOCKS);
  	}
  
  	@Override
  	public void addCollisionBoxToList(IBlockState state, World worldIn, BlockPos pos, AxisAlignedBB entityBox, List<AxisAlignedBB> collidingBoxes, @Nullable Entity entityIn, boolean p_185477_7_) {
  		state = state.getActualState(worldIn, pos);
  		addCollisionBoxToList(pos, entityBox, collidingBoxes, PILLAR_AABB);
  
  		if (state.getValue(NORTH)) {
  			addCollisionBoxToList(pos, entityBox, collidingBoxes, NORTH_AABB);
  		}
  
  		if (state.getValue(EAST)) {
  			addCollisionBoxToList(pos, entityBox, collidingBoxes, EAST_AABB);
  		}
  
  		if (state.getValue(SOUTH)) {
  			addCollisionBoxToList(pos, entityBox, collidingBoxes, SOUTH_AABB);
  		}
  
  		if (state.getValue(WEST)) {
  			addCollisionBoxToList(pos, entityBox, collidingBoxes, WEST_AABB);
  		}
  	}
  
  	@Override
  	public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos)
  	{
  		state = this.getActualState(state, source, pos);
  		return BOUNDING_BOXES[getBoundingBoxIdx(state)];
  	}
  
  	/**
  	 * Returns the correct index into boundingBoxes, based on what the fence is connected to.
  	 */
  	private static int getBoundingBoxIdx(IBlockState state) {
  		int i = 0;
  
  		if (state.getValue(NORTH)) {
  			i |= 1 << EnumFacing.NORTH.getHorizontalIndex();
  		}
  
  		if (state.getValue(EAST)) {
  			i |= 1 << EnumFacing.EAST.getHorizontalIndex();
  		}
  
  		if (state.getValue(SOUTH)) {
  			i |= 1 << EnumFacing.SOUTH.getHorizontalIndex();
  		}
  
  		if (state.getValue(WEST)) {
  			i |= 1 << EnumFacing.WEST.getHorizontalIndex();
  		}
  
  		return i;
  	}
  
  	/**
  	 * Used to determine ambient occlusion and culling when rebuilding chunks for render
  	 */
  	@Override
  	public boolean isOpaqueCube(IBlockState state)
  	{
  		return false;
  	}
  
  	@Override
  	public boolean isFullCube(IBlockState state)
  	{
  		return false;
  	}
  
  	@Override
  	public boolean isPassable(IBlockAccess worldIn, BlockPos pos)
  	{
  		return false;
  	}
  
  	public boolean canConnectTo(IBlockAccess worldIn, BlockPos pos, EnumFacing facing) {
  		IBlockState iblockstate = worldIn.getBlockState(pos);
  		BlockFaceShape blockfaceshape = iblockstate.getBlockFaceShape(worldIn, pos, facing);
  		Block block = iblockstate.getBlock();
  		boolean flag = blockfaceshape == BlockFaceShape.MIDDLE_POLE && (iblockstate.getMaterial() == this.material || (block instanceof BlockFenceGate || block instanceof BlockFenceGateBetweenlands));
  		return !isExcepBlockForAttachWithPiston(block) && blockfaceshape == BlockFaceShape.SOLID || flag;
  	}
  
  	protected static boolean isExcepBlockForAttachWithPiston(Block block) {
  		return Block.isExceptBlockForAttachWithPiston(block) || block == Blocks.BARRIER || block == Blocks.MELON_BLOCK || block == Blocks.PUMPKIN || block == Blocks.LIT_PUMPKIN;
  	}
  
  	@Override
  	@SideOnly(Side.CLIENT)
  	public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) {
  		return true;
  	}
  
  	@Override
  	public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
  		if (!worldIn.isRemote) {
  			return ItemLead.attachToFence(playerIn, worldIn, pos);
  		} else {
  			ItemStack itemstack = playerIn.getHeldItem(hand);
  			return itemstack.getItem() == Items.LEAD || itemstack.isEmpty();
  		}
  	}
  
  	/**
  	 * Convert the BlockState into the correct metadata value
  	 */
  	@Override
  	public int getMetaFromState(IBlockState state)
  	{
  		return 0;
  	}
  
  	/**
  	 * Get the actual Block state of this Block at the given position. This applies properties not visible in the
  	 * metadata, such as fence connections.
  	 */
  	@Override
  	public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) {
  		return state.withProperty(NORTH, canFenceConnectTo(worldIn, pos, EnumFacing.NORTH))
  					.withProperty(EAST,  canFenceConnectTo(worldIn, pos, EnumFacing.EAST))
  					.withProperty(SOUTH, canFenceConnectTo(worldIn, pos, EnumFacing.SOUTH))
  					.withProperty(WEST,  canFenceConnectTo(worldIn, pos, EnumFacing.WEST));
  	}
  
  	/**
  	 * Returns the blockstate with the given rotation from the passed blockstate. If inapplicable, returns the passed
  	 * blockstate.
  	 */
  	@Override
  	public IBlockState withRotation(IBlockState state, Rotation rot) {
  		switch (rot) {
  			case CLOCKWISE_180:
  				return state.withProperty(NORTH, state.getValue(SOUTH)).withProperty(EAST, state.getValue(WEST)).withProperty(SOUTH, state.getValue(NORTH)).withProperty(WEST, state.getValue(EAST));
  			case COUNTERCLOCKWISE_90:
  				return state.withProperty(NORTH, state.getValue(EAST)).withProperty(EAST, state.getValue(SOUTH)).withProperty(SOUTH, state.getValue(WEST)).withProperty(WEST, state.getValue(NORTH));
  			case CLOCKWISE_90:
  				return state.withProperty(NORTH, state.getValue(WEST)).withProperty(EAST, state.getValue(NORTH)).withProperty(SOUTH, state.getValue(EAST)).withProperty(WEST, state.getValue(SOUTH));
  			default:
  				return state;
  		}
  	}
  
  	/**
  	 * Returns the blockstate with the given mirror of the passed blockstate. If inapplicable, returns the passed
  	 * blockstate.
  	 */
  	@SuppressWarnings("deprecation")
  	@Override
  	public IBlockState withMirror(IBlockState state, Mirror mirrorIn) {
  		switch (mirrorIn) {
  			case LEFT_RIGHT:
  				return state.withProperty(NORTH, state.getValue(SOUTH)).withProperty(SOUTH, state.getValue(NORTH));
  			case FRONT_BACK:
  				return state.withProperty(EAST, state.getValue(WEST)).withProperty(WEST, state.getValue(EAST));
  			default:
  				return super.withMirror(state, mirrorIn);
  		}
  	}
  
  	@Override
  	protected BlockStateContainer createBlockState() {
  		return new BlockStateContainer(this, new IProperty[] {NORTH, EAST, WEST, SOUTH});
  	}
  
  	@Override
  	public boolean canPlaceTorchOnTop(IBlockState state, IBlockAccess world, BlockPos pos) {
  		return true;
      }
  
      /* ======================================== FORGE START ======================================== */
  
  	@Override
  	public boolean canBeConnectedTo(IBlockAccess world, BlockPos pos, EnumFacing facing) {
  		Block connector = world.getBlockState(pos.offset(facing)).getBlock();
  
  		if(connector instanceof BlockFence || connector instanceof BlockFenceBetweenlands) {
  			return connector != Blocks.NETHER_BRICK_FENCE;
  		}
  		return false;
  	}
  
  	private boolean canFenceConnectTo(IBlockAccess world, BlockPos pos, EnumFacing facing) {
  		BlockPos other = pos.offset(facing);
  		Block block = world.getBlockState(other).getBlock();
  		return block.canBeConnectedTo(world, other, facing.getOpposite()) || canConnectTo(world, other, facing.getOpposite());
  	}
  
      /* ======================================== FORGE END ======================================== */
  
      @Override
  	public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing facing) {
  		return facing != EnumFacing.UP && facing != EnumFacing.DOWN ? BlockFaceShape.MIDDLE_POLE : BlockFaceShape.CENTER;
  	}
  }
  