package com.vanhal.progressiveautomation.util; import net.minecraft.block.Block; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; /** * Contains various helper functions to assist with {@link Block} and Block-related manipulation and interaction. * * @url https://github.com/CoFH/CoFHLib/blob/master/src/main/java/cofh/util/BlockHelper.java * @author King Lemming * */ public final class BlockHelper { private BlockHelper() { } public static byte[] rotateType = new byte[4096]; public static final int[][] SIDE_COORD_MOD = { { 0, -1, 0 }, { 0, 1, 0 }, { 0, 0, -1 }, { 0, 0, 1 }, { -1, 0, 0 }, { 1, 0, 0 } }; public static float[][] SIDE_COORD_AABB = { { 1, -2, 1 }, { 1, 2, 1 }, { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 1 }, { 2, 1, 1 } }; public static final byte[] SIDE_LEFT = { 4, 5, 5, 4, 2, 3 }; public static final byte[] SIDE_RIGHT = { 5, 4, 4, 5, 3, 2 }; public static final byte[] SIDE_OPPOSITE = { 1, 0, 3, 2, 5, 4 }; public static final byte[] SIDE_ABOVE = { 3, 2, 1, 1, 1, 1 }; public static final byte[] SIDE_BELOW = { 2, 3, 0, 0, 0, 0 }; // These assume facing is towards negative - looking AT side 1, 3, or 5. public static final byte[] ROTATE_CLOCK_Y = { 0, 1, 4, 5, 3, 2 }; public static final byte[] ROTATE_CLOCK_Z = { 5, 4, 2, 3, 0, 1 }; public static final byte[] ROTATE_CLOCK_X = { 2, 3, 1, 0, 4, 5 }; public static final byte[] ROTATE_COUNTER_Y = { 0, 1, 5, 4, 2, 3 }; public static final byte[] ROTATE_COUNTER_Z = { 4, 5, 2, 3, 1, 0 }; public static final byte[] ROTATE_COUNTER_X = { 3, 2, 0, 1, 4, 5 }; public static final byte[] INVERT_AROUND_Y = { 0, 1, 3, 2, 5, 4 }; public static final byte[] INVERT_AROUND_Z = { 1, 0, 2, 3, 5, 4 }; public static final byte[] INVERT_AROUND_X = { 1, 0, 3, 2, 4, 5 }; // Map which gives relative Icon to use on a block which can be placed on any side. public static final byte[][] ICON_ROTATION_MAP = new byte[6][]; static { ICON_ROTATION_MAP[0] = new byte[] { 0, 1, 2, 3, 4, 5 }; ICON_ROTATION_MAP[1] = new byte[] { 1, 0, 2, 3, 4, 5 }; ICON_ROTATION_MAP[2] = new byte[] { 3, 2, 0, 1, 4, 5 }; ICON_ROTATION_MAP[3] = new byte[] { 3, 2, 1, 0, 5, 4 }; ICON_ROTATION_MAP[4] = new byte[] { 3, 2, 5, 4, 0, 1 }; ICON_ROTATION_MAP[5] = new byte[] { 3, 2, 4, 5, 1, 0 }; } public static final class RotationType { public static final int PREVENT = -1; public static final int FOUR_WAY = 1; public static final int SIX_WAY = 2; public static final int RAIL = 3; public static final int PUMPKIN = 4; public static final int STAIRS = 5; public static final int REDSTONE = 6; public static final int LOG = 7; public static final int SLAB = 8; public static final int CHEST = 9; public static final int LEVER = 10; public static final int SIGN = 11; } /*static { // TODO: review which of these can be removed in favor of the vanilla handler rotateType[Block.getIdFromBlock(Blocks.bed)] = RotationType.PREVENT; rotateType[Block.getIdFromBlock(Blocks.stone_slab)] = RotationType.SLAB; rotateType[Block.getIdFromBlock(Blocks.wooden_slab)] = RotationType.SLAB; rotateType[Block.getIdFromBlock(Blocks.rail)] = RotationType.RAIL; rotateType[Block.getIdFromBlock(Blocks.golden_rail)] = RotationType.RAIL; rotateType[Block.getIdFromBlock(Blocks.detector_rail)] = RotationType.RAIL; rotateType[Block.getIdFromBlock(Blocks.activator_rail)] = RotationType.RAIL; rotateType[Block.getIdFromBlock(Blocks.pumpkin)] = RotationType.PUMPKIN; rotateType[Block.getIdFromBlock(Blocks.lit_pumpkin)] = RotationType.PUMPKIN; rotateType[Block.getIdFromBlock(Blocks.furnace)] = RotationType.FOUR_WAY; rotateType[Block.getIdFromBlock(Blocks.lit_furnace)] = RotationType.FOUR_WAY; rotateType[Block.getIdFromBlock(Blocks.ender_chest)] = RotationType.FOUR_WAY; rotateType[Block.getIdFromBlock(Blocks.trapped_chest)] = RotationType.CHEST; rotateType[Block.getIdFromBlock(Blocks.chest)] = RotationType.CHEST; rotateType[Block.getIdFromBlock(Blocks.dispenser)] = RotationType.SIX_WAY; rotateType[Block.getIdFromBlock(Blocks.sticky_piston)] = RotationType.SIX_WAY; rotateType[Block.getIdFromBlock(Blocks.piston)] = RotationType.SIX_WAY; rotateType[Block.getIdFromBlock(Blocks.hopper)] = RotationType.SIX_WAY; rotateType[Block.getIdFromBlock(Blocks.dropper)] = RotationType.SIX_WAY; rotateType[Block.getIdFromBlock(Blocks.unpowered_repeater)] = RotationType.REDSTONE; rotateType[Block.getIdFromBlock(Blocks.unpowered_comparator)] = RotationType.REDSTONE; rotateType[Block.getIdFromBlock(Blocks.powered_repeater)] = RotationType.REDSTONE; rotateType[Block.getIdFromBlock(Blocks.powered_comparator)] = RotationType.REDSTONE; rotateType[Block.getIdFromBlock(Blocks.lever)] = RotationType.LEVER; rotateType[Block.getIdFromBlock(Blocks.standing_sign)] = RotationType.SIGN; rotateType[Block.getIdFromBlock(Blocks.oak_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.stone_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.brick_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.stone_brick_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.nether_brick_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.sandstone_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.spruce_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.birch_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.jungle_stairs)] = RotationType.STAIRS; rotateType[Block.getIdFromBlock(Blocks.quartz_stairs)] = RotationType.STAIRS; }*/ /*public static MovingObjectPosition getCurrentMovingObjectPosition(EntityPlayer player, double distance) { Vec3 posVec = Vec3.createVectorHelper(player.posX, player.posY, player.posZ); Vec3 lookVec = player.getLook(1); posVec.yCoord += player.getEyeHeight(); lookVec = posVec.addVector(lookVec.xCoord * distance, lookVec.yCoord * distance, lookVec.zCoord * distance); return player.worldObj.rayTraceBlocks(posVec, lookVec); } public static MovingObjectPosition getCurrentMovingObjectPosition(EntityPlayer player) { return getCurrentMovingObjectPosition(player, player.capabilities.isCreativeMode ? 5.0F : 4.5F); } public static int getCurrentMousedOverSide(EntityPlayer player) { MovingObjectPosition mouseOver = getCurrentMovingObjectPosition(player); return mouseOver == null ? 0 : mouseOver.subHit; }*/ public static int determineXZPlaceFacing(EntityLivingBase living) { int quadrant = MathHelper.floor_double(living.rotationYaw * 4.0F / 360.0F + 0.5D) & 3; switch (quadrant) { case 0: return 2; case 1: return 5; case 2: return 3; case 3: return 4; } return 3; } public static boolean isEqual(Block blockA, Block blockB) { if (blockA == blockB) { return true; } if (blockA == null | blockB == null) { return false; } return blockA.equals(blockB) || blockA.isAssociatedBlock(blockB); } /* Safe Tile Entity Retrieval */ public static TileEntity getAdjacentTileEntity(World world, int x, int y, int z, EnumFacing dir) { return world == null ? null : world.getTileEntity(new BlockPos(x + dir.getFrontOffsetX(), y + dir.getFrontOffsetY(), z + dir.getFrontOffsetZ())); } public static TileEntity getAdjacentTileEntity(World world, int x, int y, int z, int side) { return world == null ? null : getAdjacentTileEntity(world, x, y, z, EnumFacing.values()[side]); } public static TileEntity getAdjacentTileEntity(TileEntity refTile, EnumFacing dir) { return refTile == null ? null : getAdjacentTileEntity(refTile.getWorld(), refTile.getPos().getX(), refTile.getPos().getY(), refTile.getPos().getZ(), dir); } public static TileEntity getAdjacentTileEntity(TileEntity refTile, int side) { return refTile == null ? null : getAdjacentTileEntity(refTile.getWorld(), refTile.getPos().getX(), refTile.getPos().getY(), refTile.getPos().getZ(), EnumFacing.values()[side]); } public static int determineAdjacentSide(TileEntity refTile, int x, int y, int z) { return y > refTile.getPos().getY() ? 1 : y < refTile.getPos().getY() ? 0 : z > refTile.getPos().getZ() ? 3 : z < refTile.getPos().getZ() ? 2 : x > refTile.getPos().getX() ? 5 : 4; } /* COORDINATE TRANSFORM */ /*public static int[] getAdjacentCoordinatesForSide(MovingObjectPosition pos) { return getAdjacentCoordinatesForSide(pos.blockX, pos.blockY, pos.blockZ, pos.sideHit); }*/ public static int[] getAdjacentCoordinatesForSide(int x, int y, int z, int side) { return new int[] { x + SIDE_COORD_MOD[side][0], y + SIDE_COORD_MOD[side][1], z + SIDE_COORD_MOD[side][2] }; } public static int getLeftSide(int side) { return SIDE_LEFT[side]; } public static int getRightSide(int side) { return SIDE_RIGHT[side]; } public static int getOppositeSide(int side) { return SIDE_OPPOSITE[side]; } public static int getAboveSide(int side) { return SIDE_ABOVE[side]; } public static int getBelowSide(int side) { return SIDE_BELOW[side]; } /* BLOCK ROTATION */ public static boolean canRotate(Block block) { return rotateType[Block.getIdFromBlock(block)] != 0; } public static int rotateVanillaBlock(World world, Block block, int x, int y, int z) { int bId = Block.getIdFromBlock(block), bMeta = world.getBlockState(new BlockPos(x, y, z)).getBlock().getMetaFromState(world.getBlockState(new BlockPos(x, y, z))); switch (rotateType[bId]) { case RotationType.FOUR_WAY: return SIDE_LEFT[bMeta]; case RotationType.SIX_WAY: if (bMeta < 6) { return ++bMeta % 6; } return bMeta; case RotationType.RAIL: if (bMeta < 2) { return ++bMeta % 2; } return bMeta; case RotationType.PUMPKIN: return ++bMeta % 4; case RotationType.STAIRS: return ++bMeta % 8; case RotationType.REDSTONE: int upper = bMeta & 0xC; int lower = bMeta & 0x3; return upper + ++lower % 4; case RotationType.LOG: return (bMeta + 4) % 12; case RotationType.SLAB: return (bMeta + 8) % 16; /* case RotationType.CHEST: int coords[] = new int[3]; for (int i = 2; i < 6; i++) { coords = getAdjacentCoordinatesForSide(x, y, z, i); if (isEqual(world.getbl.getBlock(coords[0], coords[1], coords[2]), block)) { world.setBlockMetadataWithNotify(coords[0], coords[1], coords[2], SIDE_OPPOSITE[bMeta], 1); return SIDE_OPPOSITE[bMeta]; } } return SIDE_LEFT[bMeta];*/ case RotationType.LEVER: int shift = 0; if (bMeta > 7) { bMeta -= 8; shift = 8; } if (bMeta == 5) { return 6 + shift; } else if (bMeta == 6) { return 5 + shift; } else if (bMeta == 7) { return 0 + shift; } else if (bMeta == 0) { return 7 + shift; } return bMeta + shift; case RotationType.SIGN: return ++bMeta % 16; case RotationType.PREVENT: default: return bMeta; } } public static int rotateVanillaBlockAlt(World world, Block block, int x, int y, int z) { int bId = Block.getIdFromBlock(block), bMeta = world.getBlockState(new BlockPos(x, y, z)).getBlock().getMetaFromState(world.getBlockState(new BlockPos(x, y, z))); switch (rotateType[bId]) { case RotationType.FOUR_WAY: return SIDE_RIGHT[bMeta]; case RotationType.SIX_WAY: if (bMeta < 6) { return (bMeta + 5) % 6; } return bMeta; case RotationType.RAIL: if (bMeta < 2) { return ++bMeta % 2; } return bMeta; case RotationType.PUMPKIN: return (bMeta + 3) % 4; case RotationType.STAIRS: return (bMeta + 7) % 8; case RotationType.REDSTONE: int upper = bMeta & 0xC; int lower = bMeta & 0x3; return upper + (lower + 3) % 4; case RotationType.LOG: return (bMeta + 8) % 12; case RotationType.SLAB: return (bMeta + 8) % 16; /* case RotationType.CHEST: int coords[] = new int[3]; for (int i = 2; i < 6; i++) { coords = getAdjacentCoordinatesForSide(x, y, z, i); if (isEqual(world.getBlock(coords[0], coords[1], coords[2]), block)) { world.setBlockMetadataWithNotify(coords[0], coords[1], coords[2], SIDE_OPPOSITE[bMeta], 1); return SIDE_OPPOSITE[bMeta]; } } return SIDE_RIGHT[bMeta];*/ case RotationType.LEVER: int shift = 0; if (bMeta > 7) { bMeta -= 8; shift = 8; } if (bMeta == 5) { return 6 + shift; } else if (bMeta == 6) { return 5 + shift; } else if (bMeta == 7) { return 0 + shift; } else if (bMeta == 0) { return 7 + shift; } case RotationType.SIGN: return ++bMeta % 16; case RotationType.PREVENT: default: return bMeta; } } /* public static List<ItemStack> breakBlock(World worldObj, int x, int y, int z, Block block, int fortune, boolean doBreak, boolean silkTouch) { if (block.getBlockHardness(worldObj, x, y, z) == -1) { return new LinkedList<ItemStack>(); } int meta = worldObj.getBlockMetadata(x, y, z); List<ItemStack> stacks = null; if (silkTouch && block.canSilkHarvest(worldObj, null, x, y, z, meta)) { stacks = new LinkedList<ItemStack>(); stacks.add(createStackedBlock(block, meta)); } else { stacks = block.getDrops(worldObj, x, y, z, meta, fortune); } if (!doBreak) { return stacks; } worldObj.playAuxSFXAtEntity(null, 2001, new BlockPos(x, y, z), Block.getIdFromBlock(block) + (meta << 12)); worldObj.setBlockToAir(BlockPos(x, y, z)); List<EntityItem> result = worldObj.getEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getBoundingBox(x - 2, y - 2, z - 2, x + 3, y + 3, z + 3)); for (int i = 0; i < result.size(); i++) { EntityItem entity = result.get(i); if (entity.isDead || entity.getEntityItem().stackSize <= 0) { continue; } stacks.add(entity.getEntityItem()); entity.worldObj.removeEntity(entity); } return stacks; }*/ public static ItemStack createStackedBlock(Block block, int bMeta) { Item item = Item.getItemFromBlock(block); if (item.getHasSubtypes()) { return new ItemStack(item, 1, bMeta); } return new ItemStack(item, 1, 0); } }