package net.minecraftforge.common.util;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.minecraft.block.Block;
import net.minecraft.block.BlockAnvil;
import net.minecraft.block.BlockBed;
import net.minecraft.block.BlockButton;
import net.minecraft.block.BlockChest;
import net.minecraft.block.BlockCocoa;
import net.minecraft.block.BlockDispenser;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.BlockEndPortalFrame;
import net.minecraft.block.BlockEnderChest;
import net.minecraft.block.BlockFenceGate;
import net.minecraft.block.BlockFurnace;
import net.minecraft.block.BlockHopper;
import net.minecraft.block.BlockHugeMushroom;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockLever;
import net.minecraft.block.BlockLog;
import net.minecraft.block.BlockPistonBase;
import net.minecraft.block.BlockPistonExtension;
import net.minecraft.block.BlockPumpkin;
import net.minecraft.block.BlockRail;
import net.minecraft.block.BlockRailDetector;
import net.minecraft.block.BlockRailPowered;
import net.minecraft.block.BlockRedstoneComparator;
import net.minecraft.block.BlockRedstoneRepeater;
import net.minecraft.block.BlockSkull;
import net.minecraft.block.BlockStairs;
import net.minecraft.block.BlockTorch;
import net.minecraft.block.BlockTrapDoor;
import net.minecraft.block.BlockTripWireHook;
import net.minecraft.block.BlockVine;
import net.minecraft.init.Blocks;
import net.minecraft.world.World;
import java.util.HashMap;
import java.util.Map;
import static net.minecraftforge.common.util.ForgeDirection.*;
/**
* This class is a helper function for vanilla blocks, and should not be called by Modders.
* Refer to block.rotateBlock and block.getValidRotations instead.
*
*/
public class RotationHelper {
/**
* Some blocks have the same rotation.
* The first of these blocks (sorted by itemID) should be listed as a type.
* Some of the types aren't actual blocks (helper types).
*/
private static enum BlockType {
LOG,
DISPENSER,
BED,
RAIL,
RAIL_POWERED,
RAIL_ASCENDING,
RAIL_CORNER,
TORCH,
STAIR,
CHEST,
SIGNPOST,
DOOR,
LEVER,
BUTTON,
REDSTONE_REPEATER,
TRAPDOOR,
MUSHROOM_CAP,
MUSHROOM_CAP_CORNER,
MUSHROOM_CAP_SIDE,
VINE,
SKULL,
ANVIL
}
private static final ForgeDirection[] UP_DOWN_AXES = new ForgeDirection[] { UP, DOWN };
private static final Map<BlockType, BiMap<Integer, ForgeDirection>> MAPPINGS = new HashMap<BlockType, BiMap<Integer, ForgeDirection>>();
public static ForgeDirection[] getValidVanillaBlockRotations(Block block)
{
return (block instanceof BlockBed ||
block instanceof BlockPumpkin ||
block instanceof BlockFenceGate ||
block instanceof BlockEndPortalFrame ||
block instanceof BlockTripWireHook ||
block instanceof BlockCocoa ||
block instanceof BlockRailPowered ||
block instanceof BlockRailDetector ||
block instanceof BlockStairs ||
block instanceof BlockChest ||
block instanceof BlockEnderChest ||
block instanceof BlockFurnace ||
block instanceof BlockLadder ||
block == Blocks.wall_sign ||
block == Blocks.standing_sign ||
block instanceof BlockDoor ||
block instanceof BlockRail ||
block instanceof BlockButton ||
block instanceof BlockRedstoneRepeater ||
block instanceof BlockRedstoneComparator ||
block instanceof BlockTrapDoor ||
block instanceof BlockHugeMushroom ||
block instanceof BlockVine ||
block instanceof BlockSkull ||
block instanceof BlockAnvil) ? UP_DOWN_AXES : VALID_DIRECTIONS;
}
public static boolean rotateVanillaBlock(Block block, World worldObj, int x, int y, int z, ForgeDirection axis)
{
if (worldObj.isRemote)
{
return false;
}
if (axis == UP || axis == DOWN)
{
if (block instanceof BlockBed || block instanceof BlockPumpkin || block instanceof BlockFenceGate || block instanceof BlockEndPortalFrame || block instanceof BlockTripWireHook || block instanceof BlockCocoa)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.BED);
}
if (block instanceof BlockRail)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.RAIL);
}
if (block instanceof BlockRailPowered || block instanceof BlockRailDetector)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.RAIL_POWERED);
}
if (block instanceof BlockStairs)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.STAIR);
}
if (block instanceof BlockChest || block instanceof BlockEnderChest || block instanceof BlockFurnace || block instanceof BlockLadder || block == Blocks.wall_sign)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.CHEST);
}
if (block == Blocks.standing_sign)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.SIGNPOST);
}
if (block instanceof BlockDoor)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.DOOR);
}
if (block instanceof BlockButton)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.BUTTON);
}
if (block instanceof BlockRedstoneRepeater || block instanceof BlockRedstoneComparator)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.REDSTONE_REPEATER);
}
if (block instanceof BlockTrapDoor)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.TRAPDOOR);
}
if (block instanceof BlockHugeMushroom)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.MUSHROOM_CAP);
}
if (block instanceof BlockVine)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.VINE);
}
if (block instanceof BlockSkull)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.SKULL);
}
if (block instanceof BlockAnvil)
{
return rotateBlock(worldObj, x, y, z, axis, 0x1, BlockType.ANVIL);
}
}
if (block instanceof BlockLog)
{
return rotateBlock(worldObj, x, y, z, axis, 0xC, BlockType.LOG);
}
if (block instanceof BlockDispenser || block instanceof BlockPistonBase || block instanceof BlockPistonExtension || block instanceof BlockHopper)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.DISPENSER);
}
if (block instanceof BlockTorch)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.TORCH);
}
if (block instanceof BlockLever)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.LEVER);
}
return false;
}
private static boolean rotateBlock(World worldObj, int x, int y, int z, ForgeDirection axis, int mask, BlockType blockType)
{
int rotMeta = worldObj.getBlockMetadata(x, y, z);
if (blockType == BlockType.DOOR && (rotMeta & 0x8) == 0x8)
{
return false;
}
int masked = rotMeta & ~mask;
int meta = rotateMetadata(axis, blockType, rotMeta & mask);
if (meta == -1)
{
return false;
}
worldObj.setBlockMetadataWithNotify(x, y, z, meta & mask | masked, 3);
return true;
}
private static int rotateMetadata(ForgeDirection axis, BlockType blockType, int meta)
{
if (blockType == BlockType.RAIL || blockType == BlockType.RAIL_POWERED)
{
if (meta == 0x0 || meta == 0x1)
{
return ~meta & 0x1;
}
if (meta >= 0x2 && meta <= 0x5)
{
blockType = BlockType.RAIL_ASCENDING;
}
if (meta >= 0x6 && meta <= 0x9 && blockType == BlockType.RAIL)
{
blockType = BlockType.RAIL_CORNER;
}
}
if (blockType == BlockType.SIGNPOST)
{
return (axis == UP) ? (meta + 0x4) % 0x10 : (meta + 0xC) % 0x10;
}
if (blockType == BlockType.LEVER && (axis == UP || axis == DOWN))
{
switch (meta)
{
case 0x5:
return 0x6;
case 0x6:
return 0x5;
case 0x7:
return 0x0;
case 0x0:
return 0x7;
}
}
if (blockType == BlockType.MUSHROOM_CAP)
{
if (meta % 0x2 == 0)
{
blockType = BlockType.MUSHROOM_CAP_SIDE;
}
else
{
blockType = BlockType.MUSHROOM_CAP_CORNER;
}
}
if (blockType == BlockType.VINE)
{
return ((meta << 1) | ((meta & 0x8) >> 3));
}
ForgeDirection orientation = metadataToDirection(blockType, meta);
ForgeDirection rotated = orientation.getRotation(axis);
return directionToMetadata(blockType, rotated);
}
private static ForgeDirection metadataToDirection(BlockType blockType, int meta)
{
if (blockType == BlockType.LEVER)
{
if (meta == 0x6)
{
meta = 0x5;
}
else if (meta == 0x0)
{
meta = 0x7;
}
}
if (MAPPINGS.containsKey(blockType))
{
BiMap<Integer, ForgeDirection> biMap = MAPPINGS.get(blockType);
if (biMap.containsKey(meta))
{
return biMap.get(meta);
}
}
if (blockType == BlockType.TORCH)
{
return ForgeDirection.getOrientation(6 - meta);
}
if (blockType == BlockType.STAIR)
{
return ForgeDirection.getOrientation(5 - meta);
}
if (blockType == BlockType.CHEST || blockType == BlockType.DISPENSER || blockType == BlockType.SKULL)
{
return ForgeDirection.getOrientation(meta);
}
if (blockType == BlockType.BUTTON)
{
return ForgeDirection.getOrientation(6 - meta);
}
if (blockType == BlockType.TRAPDOOR)
{
return ForgeDirection.getOrientation(meta + 2).getOpposite();
}
return ForgeDirection.UNKNOWN;
}
private static int directionToMetadata(BlockType blockType, ForgeDirection direction)
{
if ((blockType == BlockType.LOG || blockType == BlockType.ANVIL) && (direction.offsetX + direction.offsetY + direction.offsetZ) < 0)
{
direction = direction.getOpposite();
}
if (MAPPINGS.containsKey(blockType))
{
BiMap<ForgeDirection, Integer> biMap = MAPPINGS.get(blockType).inverse();
if (biMap.containsKey(direction))
{
return biMap.get(direction);
}
}
if (blockType == BlockType.TORCH)
{
if (direction.ordinal() >= 1)
{
return 6 - direction.ordinal();
}
}
if (blockType == BlockType.STAIR)
{
return 5 - direction.ordinal();
}
if (blockType == BlockType.CHEST || blockType == BlockType.DISPENSER || blockType == BlockType.SKULL)
{
return direction.ordinal();
}
if (blockType == BlockType.BUTTON)
{
if (direction.ordinal() >= 2)
{
return 6 - direction.ordinal();
}
}
if (blockType == BlockType.TRAPDOOR)
{
return direction.getOpposite().ordinal() - 2;
}
return -1;
}
static
{
BiMap<Integer, ForgeDirection> biMap;
biMap = HashBiMap.create(3);
biMap.put(0x0, UP);
biMap.put(0x4, EAST);
biMap.put(0x8, SOUTH);
MAPPINGS.put(BlockType.LOG, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x0, SOUTH);
biMap.put(0x1, WEST);
biMap.put(0x2, NORTH);
biMap.put(0x3, EAST);
MAPPINGS.put(BlockType.BED, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x2, EAST);
biMap.put(0x3, WEST);
biMap.put(0x4, NORTH);
biMap.put(0x5, SOUTH);
MAPPINGS.put(BlockType.RAIL_ASCENDING, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x6, WEST);
biMap.put(0x7, NORTH);
biMap.put(0x8, EAST);
biMap.put(0x9, SOUTH);
MAPPINGS.put(BlockType.RAIL_CORNER, biMap);
biMap = HashBiMap.create(6);
biMap.put(0x1, EAST);
biMap.put(0x2, WEST);
biMap.put(0x3, SOUTH);
biMap.put(0x4, NORTH);
biMap.put(0x5, UP);
biMap.put(0x7, DOWN);
MAPPINGS.put(BlockType.LEVER, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x0, WEST);
biMap.put(0x1, NORTH);
biMap.put(0x2, EAST);
biMap.put(0x3, SOUTH);
MAPPINGS.put(BlockType.DOOR, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x0, NORTH);
biMap.put(0x1, EAST);
biMap.put(0x2, SOUTH);
biMap.put(0x3, WEST);
MAPPINGS.put(BlockType.REDSTONE_REPEATER, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x1, EAST);
biMap.put(0x3, SOUTH);
biMap.put(0x7, NORTH);
biMap.put(0x9, WEST);
MAPPINGS.put(BlockType.MUSHROOM_CAP_CORNER, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x2, NORTH);
biMap.put(0x4, WEST);
biMap.put(0x6, EAST);
biMap.put(0x8, SOUTH);
MAPPINGS.put(BlockType.MUSHROOM_CAP_SIDE, biMap);
biMap = HashBiMap.create(2);
biMap.put(0x0, SOUTH);
biMap.put(0x1, EAST);
MAPPINGS.put(BlockType.ANVIL, biMap);
}
}