package speedytools.common.utilities;
import net.minecraft.block.Block;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.EnumFacing;
import java.util.HashMap;
import java.util.Map;
/**
* Utility class for rotating / flipping blocks
* Authored by TheGreyGhost 17 Mar 2015
*/
public final class BlockRotateFlipHelper
{
public enum FlipDirection
{
NORTH_SOUTH,
WEST_EAST,
}
private BlockRotateFlipHelper() {
}
/**
* Rotate a block by 90 degrees clockwise(north->east->south->west->north);
* Works by manipulating the block's FACING property. Blocks without FACING are unaffected.
* @param iBlockState the starting blockstate
* @return the rotated blockstate
*/
public static IBlockState rotate90(IBlockState iBlockState)
{
PropertyDirection propertyDirection = getPropertyDirection(iBlockState);
if (propertyDirection == null) return iBlockState; // block doesn't have this property
EnumFacing currentFacing = (EnumFacing)iBlockState.getValue(propertyDirection);
int currentHorizontalIndex = currentFacing.getHorizontalIndex();
if (currentHorizontalIndex < 0) return iBlockState; // points up or down
int newHorizontalIndex = (currentHorizontalIndex + 1) & 3;
EnumFacing newFacing = EnumFacing.getHorizontal(newHorizontalIndex);
return iBlockState.withProperty(propertyDirection, newFacing);
}
/**
* Rotate a block by 90 degrees clockwise(north->east->south->west->north);
* Works by manipulating the block's FACING property. Blocks without FACING are unaffected.
* @param blockID the internal ID for this block
* @param metadata the metadata value for this block
* @return the rotated metadata value
*/
public static int rotate90(int blockID, int metadata)
{
Boolean hasPropertyDirection = hasPropertyDirectionCache.get(blockID);
if (hasPropertyDirection == null) {
hasPropertyDirection = setPropertyDirectionCache(blockID, metadata);
}
if (!hasPropertyDirection) {
return metadata;
}
Block block = Block.getBlockById(blockID);
IBlockState iBlockState = block.getStateFromMeta(metadata);
iBlockState = rotate90(iBlockState);
return block.getMetaFromState(iBlockState);
}
/**
* Mirror image a block
* Can't do this perfectly because blocks only have a facing, not a left/right mirror image.
* Make the assumption that a block typically has left/right symmetry in the direction it is facing
* eg steps when facing EAST are north/south symmetrical but not east-west symmetrical.
* Hence, if the steps are facing east or west, and you flip in the EAST_WEST direction, it is the same as rotating
* the steps twice by 90 degrees.
* If the steps are facing north or south, and you flip in the EAST_WEST direction, then nothing happens.
* @param blockID the internal ID of this block
* @param metadata the starting metadata of the block
* @param flipDirection the axis of flipping - eg EAST_WEST means that the east becomes west
* @return the flipped blockstate
*/
public static int flip(int blockID, int metadata, FlipDirection flipDirection)
{
Boolean hasPropertyDirection = hasPropertyDirectionCache.get(blockID);
if (hasPropertyDirection == null) {
hasPropertyDirection = setPropertyDirectionCache(blockID, metadata);
}
if (!hasPropertyDirection) {
return metadata;
}
Block block = Block.getBlockById(blockID);
IBlockState iBlockState = block.getStateFromMeta(metadata);
iBlockState = flip(iBlockState, flipDirection);
return block.getMetaFromState(iBlockState);
}
/**
* Mirror image a block
* Can't do this perfectly because blocks only have a facing, not a left/right mirror image.
* Make the assumption that a block typically has left/right symmetry in the direction it is facing
* eg steps when facing EAST are north/south symmetrical but not east-west symmetrical.
* Hence, if the steps are facing east or west, and you flip in the EAST_WEST direction, it is the same as rotating
* the steps twice by 90 degrees.
* If the steps are facing north or south, and you flip in the EAST_WEST direction, then nothing happens.
* @param iBlockState the starting blockstate
* @param flipDirection the axis of flipping - eg EAST_WEST means that the east becomes west
* @return the flipped blockstate
*/
public static IBlockState flip(IBlockState iBlockState, FlipDirection flipDirection)
{
PropertyDirection propertyDirection = getPropertyDirection(iBlockState);
if (propertyDirection == null) return iBlockState; // block doesn't have this property
EnumFacing currentFacing = (EnumFacing)iBlockState.getValue(propertyDirection);
if ( flipDirection == FlipDirection.WEST_EAST && (currentFacing == EnumFacing.EAST || currentFacing == EnumFacing.WEST)
|| flipDirection == FlipDirection.NORTH_SOUTH && (currentFacing == EnumFacing.SOUTH || currentFacing == EnumFacing.NORTH )) {
return rotate90(rotate90(iBlockState));
} else {
return iBlockState;
}
}
// retrieves the PropertyDirection for the given block, or null if it doesn't have one.
// uses caching
private static PropertyDirection getPropertyDirection(IBlockState iBlockState) {
PropertyDirection propertyDirection = null;
if (!propertyDirectionCache.containsKey(iBlockState.getBlock())) {
for (Object property : iBlockState.getProperties().keySet()) {
if (property instanceof PropertyDirection) {
propertyDirection = (PropertyDirection) property;
break;
}
}
propertyDirectionCache.put(iBlockState.getBlock(), propertyDirection);
} else {
propertyDirection = propertyDirectionCache.get(iBlockState.getBlock());
}
return propertyDirection;
}
// caches whether this blockID has a property direction or not
private static boolean setPropertyDirectionCache(int blockID, int metadata)
{
Block block = Block.getBlockById(blockID);
IBlockState iBlockState = block.getStateFromMeta(metadata);
boolean hasPropertyDirection = false;
for (Object property : iBlockState.getProperties().keySet()) {
if (property instanceof PropertyDirection) {
hasPropertyDirection = true;
break;
}
}
hasPropertyDirectionCache.put(blockID, hasPropertyDirection);
return hasPropertyDirection;
}
private static Map<Block, PropertyDirection> propertyDirectionCache = new HashMap<Block, PropertyDirection>();
// cache of the direction property for each block; null = block has none
private static Map<Integer, Boolean> hasPropertyDirectionCache = new HashMap<Integer, Boolean>();
}