Java tutorial
package com.builtbroken.assemblyline.content.rail.powered; import com.builtbroken.assemblyline.AssemblyLine; import com.builtbroken.assemblyline.content.parts.ALParts; import com.builtbroken.assemblyline.content.rail.BlockRail; import com.builtbroken.jlib.type.Pair; import com.builtbroken.mc.api.rails.*; import com.builtbroken.mc.api.tile.node.IExternalInventory; import com.builtbroken.mc.core.Engine; import com.builtbroken.mc.core.content.parts.CraftingParts; import com.builtbroken.mc.core.network.IPacketIDReceiver; import com.builtbroken.mc.core.registry.implement.IRecipeContainer; import com.builtbroken.mc.lib.helper.recipe.OreNames; import com.builtbroken.mc.lib.helper.recipe.UniversalRecipe; import com.builtbroken.mc.imp.transform.region.Cube; import com.builtbroken.mc.imp.transform.vector.Pos; import com.builtbroken.mc.prefab.inventory.InventoryUtility; import com.builtbroken.mc.api.IInventoryFilter; import com.builtbroken.mc.prefab.tile.Tile; import com.builtbroken.mc.prefab.tile.TileModuleMachineBase; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChatComponentText; import net.minecraftforge.common.util.ForgeDirection; import java.util.List; /** * Handles different functions * <p> * A) Handles rotation of the block on any axis. * <p> * B) Handles pushing the carts forward * <p> * B is the lower tech version of A only pushing the carts and can not actually move the carts. While A can also push and rotate * the carts allowing it to be used in place of a B type rail. * <p> * C) handles directing the cart from one direction * into another direction. So long as the direction does not change facing side of the block. * Example North side moving into the block, redirect upwards, still on the north side of the block but moving up instead of forwards. * <p> * D) stops the cart from moving, should be redstone controllable with no redstone being off by default * * @see <a href="https://github.com/BuiltBrokenModding/VoltzEngine/blob/development/license.md">License</a> for what you can and can't do with the code. * Created by Dark(DarkGuardsman, Robert) on 10/29/2016. */ public class TilePowerRail extends TileModuleMachineBase implements ITransportRail, IPacketIDReceiver, IRecipeContainer { //TODO C type rails need to show a stair case symbol to show it moving up or down //TODO D type needs to have a redstone upgrade /** What type of rail are we */ protected PoweredRails railType = PoweredRails.POWERED; //////////////ROTATION RAIL STUFF /** How much to rotate */ protected int rotateYaw = 90; /** Are we rotating to an angle or just rotating by an angle */ protected boolean rotateToAngle = true; /** Are we rotating clockwise, not used if setting angle */ protected boolean rotateClockwise = true; /////////////STOP RAIL STUFF /** Should we stop carts */ protected boolean stopCarts = true; /** Should we use restone to override stopping of carts */ protected boolean useRedstoneToInvertStop = true; /////////////LOADER UNLOADER STUFF /** Direction to load/unload cargo */ protected ForgeDirection loadDirection; /** Should we trigger connected stop rails when we have cargo or no cargo */ protected boolean triggerStopRails = true; /** Should we emmit redstone when we have cargo or no cargo */ protected boolean doRedstoneOnLoad = true; /** Side of the block we are attached to */ private ForgeDirection attachedSide; /** Direction the rail is pointing towards */ private ForgeDirection facingDirection = ForgeDirection.NORTH; //Collision/Render/Selection boxes private static final Cube COLLISION_BOX_DOWN = new Cube(0, .6, 0, 1, 1, 1); private static final Cube COLLISION_BOX_NORTH = new Cube(0, 0, .6, 1, 1, 1); private static final Cube COLLISION_BOX_SOUTH = new Cube(0, 0, 0, 1, 1, .4); private static final Cube COLLISION_BOX_EAST = new Cube(0, 0, 0, .4, 1, 1); private static final Cube COLLISION_BOX_WEST = new Cube(.6, 0, 0, 1, 1, 1); public TilePowerRail() { super("cartPowerRail", Material.iron); this.bounds = new Cube(0, 0, 0, 1, .4, 1); this.itemBlock = ItemBlockPowerRail.class; } @Override public void genRecipes(List<IRecipe> recipes) { recipes.add(newShapedRecipe(new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.POWERED.ordinal()), "RPR", "MLM", "PCP", 'R', OreNames.ROD_IRON, 'M', CraftingParts.MOTOR.toStack(), 'C', UniversalRecipe.CIRCUIT_T1.get(), 'L', AssemblyLine.blockRail, 'P', OreNames.PLATE_IRON)); recipes.add(newShapedRecipe(new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.ROTATION.ordinal()), "RPR", "RMR", "WLW", 'R', OreNames.ROD_IRON, 'M', CraftingParts.STEPPER_MOTOR.toStack(), 'L', new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.POWERED.ordinal()), 'P', OreNames.PLATE_IRON, 'W', OreNames.WIRE_COPPER)); recipes.add(newShapedRecipe(new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.STOP.ordinal()), "RPR", "QCQ", "WLW", 'R', ALParts.ROBOTIC_HAND.toStack(), 'L', new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.POWERED.ordinal()), 'Q', OreNames.QUARTZ, 'C', UniversalRecipe.CIRCUIT_T1.get(), 'P', Blocks.stone_pressure_plate, 'W', OreNames.REDSTONE)); recipes.add(newShapedRecipe(new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.LOADER.ordinal()), "RPR", "TCT", "WLW", 'R', AssemblyLine.blockInserter, 'L', new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.STOP.ordinal()), 'T', UniversalRecipe.CIRCUIT_T2.get(), 'C', UniversalRecipe.CIRCUIT_T3.get(), 'P', OreNames.PLATE_IRON, 'W', OreNames.REDSTONE)); recipes.add( newShapelessRecipe(new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.UNLOADER.ordinal()), new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.LOADER.ordinal()))); recipes.add(newShapelessRecipe(new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.LOADER.ordinal()), new ItemStack(AssemblyLine.blockPowerRail, 1, PoweredRails.UNLOADER.ordinal()))); } @Override public Tile newTile() { return new TilePowerRail(); } @Override public boolean canUpdate() { return false; } @Override public void onNeighborChanged(Block block) { super.onNeighborChanged(block); if (useRedstoneToInvertStop) { //TODO move to neighbor block change boolean prevRed = stopCarts; stopCarts = !isIndirectlyPowered(); if (prevRed != stopCarts) { sendDescPacket(); } } } @Override public void tickRailFromCart(ITransportCart cart) { if (isRotationRail()) { //TODO lerp rotation to provide a transition if (rotateToAngle) { cart.setCartRotation(rotateYaw, 0); } else if (rotateClockwise) { cart.setCartRotation(rotateYaw + rotateYaw, 0); } else { cart.setCartRotation(rotateYaw - rotateYaw, 0); } handlePush(cart); } else if (isPoweredRail()) { handlePush(cart); } else if (isOrientationRail()) { //TODO implements } else if (isStopRail()) { if (ticks % 5 == 0) { final Pos delta = new Pos((TileEntity) this).add(0.5).sub(cart.x(), cart.y(), cart.z()); boolean stop = true; // Moving negative <--- -0.5 -0.4 -0.3 -0.2 -0.1 [0] 0.1 0.2 0.3 0.4 0.5 <- coming into station // Moving positive <--- 0.5 0.4 0.3 0.2 0.1 [0] -0.1 -0.2 -0.3 -0.4 -0.5 <- coming into station switch (getFacingDirection()) { case DOWN: stop = delta.y() > -0.05; break; case UP: stop = delta.y() < 0.05; break; case NORTH: stop = delta.z() > -0.05; break; case SOUTH: stop = delta.z() < 0.05; break; case EAST: stop = delta.x() < 0.05; break; case WEST: stop = delta.x() > -0.05; break; } if (stopCarts) { if (stop) { cart.setCartMotion(0, 0, 0); cart.recenterCartOnRail(this, true); } } else { handlePush(cart); cart.recenterCartOnRail(this, false); } } } else if (isLoaderRail()) { //TODO implement max item movement per tick //Large inventory if (cart instanceof ITransportCartHasCargo) { IExternalInventory inventory = ((ITransportCartHasCargo) cart).getInventory(); if (inventory != null && !inventory.isFull()) { cart.setCartMotion(0, 0, 0); cart.recenterCartOnRail(this, true); if (!worldObj.isRemote) { final Pair<ItemStack, Integer> slotData = takeItemFromTile((ITransportCartCargo) cart); if (slotData != null && slotData.left() != null && slotData.left().stackSize >= 0) { TileEntity tile = getLoadTile(); if (tile instanceof IInventory) { ItemStack left = InventoryUtility.putStackInInventory(inventory, slotData.left(), false); if (left == null || left.stackSize <= 0) { ((IInventory) tile).setInventorySlotContents(slotData.right(), null); } else { ((IInventory) tile).setInventorySlotContents(slotData.right(), left); } } } } } else { //TODO trigger redstone 3 ticks handlePush(cart); cart.recenterCartOnRail(this, false); return; } } //Single item inventory else if (cart instanceof ITransportCartHasItem) { if (((ITransportCartHasItem) cart).getTransportedItem() == null) { cart.setCartMotion(0, 0, 0); cart.recenterCartOnRail(this, true); if (!worldObj.isRemote) { final Pair<ItemStack, Integer> slotData = takeItemFromTile((ITransportCartHasItem) cart); if (slotData != null && slotData.left() != null && slotData.left().stackSize >= 0) { TileEntity tile = getLoadTile(); if (tile instanceof IInventory) { ItemStack left = ((ITransportCartHasItem) cart).setTransportedItem(slotData.left()); if (left == null || left.stackSize <= 0) { ((IInventory) tile).setInventorySlotContents(slotData.right(), null); } else { ((IInventory) tile).setInventorySlotContents(slotData.right(), left); } } } } //Else nothing happened } else { //TODO trigger redstone 3 ticks handlePush(cart); cart.recenterCartOnRail(this, false); return; } } } else if (isUnloadRail()) { //Large cargo cart if (cart instanceof ITransportCartHasCargo) { IExternalInventory inventory = ((ITransportCartHasCargo) cart).getInventory(); if (inventory != null && !inventory.isEmpty()) { //Get slots with items List<Integer> slotsWithItems = inventory.getFilledSlots(); //Only stop cart if it is not empty if (!slotsWithItems.isEmpty()) { cart.setCartMotion(0, 0, 0); cart.recenterCartOnRail(this, true); //TODO add a movement per tick limit if (!worldObj.isRemote) { for (int slot : slotsWithItems) { final ItemStack prev = inventory.getStackInSlot(slot).copy(); ItemStack stack = storeItemInTile(inventory.getStackInSlot(slot).copy()); if (stack == null || stack.stackSize <= 0) { inventory.setInventorySlotContents(slot, null); } else if (!InventoryUtility.stacksMatchExact(prev, stack)) { inventory.setInventorySlotContents(slot, stack); } } } } } else { //TODO trigger redstone 3 ticks handlePush(cart); cart.recenterCartOnRail(this, false); return; } } //Single item cart else if (cart instanceof ITransportCartHasItem) { if (((ITransportCartHasItem) cart).getTransportedItem() != null) { cart.setCartMotion(0, 0, 0); cart.recenterCartOnRail(this, true); if (!worldObj.isRemote) { final ItemStack prev = ((ITransportCartHasItem) cart).getTransportedItem().copy(); ItemStack stack = storeItemInTile( ((ITransportCartHasItem) cart).getTransportedItem().copy()); if (stack == null || stack.stackSize <= 0) { ((ITransportCartHasItem) cart).setTransportedItem(null); } else if (!InventoryUtility.stacksMatchExact(prev, stack)) { ((ITransportCartHasItem) cart).setTransportedItem(stack); } } //Else nothing happened } else { //TODO trigger redstone 3 ticks handlePush(cart); cart.recenterCartOnRail(this, false); return; } } } } /** * Stores the item in the first open slot * <p> * Consumes the item and places into the inventory * * @param stack - input stack * @return what is left of the stack */ public ItemStack storeItemInTile(ItemStack stack) { final TileEntity tile = getLoadTile(); if (tile instanceof IRailInventoryTile) { //Check if we can globally store the item if (((IRailInventoryTile) tile).canStore(stack, getLoadingDirection().getOpposite())) { final int[] slots = ((IRailInventoryTile) tile).getSlotsToLoad(stack, getLoadingDirection().getOpposite()); final int stackLimit = ((IRailInventoryTile) tile).getInventory().getInventoryStackLimit(); final IInventory inventory = ((IRailInventoryTile) tile).getInventory(); for (int index = 0; index < slots.length; index++) { final int slot = slots[index]; //Check if we can store the exact item if (((IRailInventoryTile) tile).canStore(stack, slot, getLoadingDirection().getOpposite())) { final ItemStack slotStack = inventory.getStackInSlot(slot); if (slotStack == null) { if (stack.stackSize > stackLimit) { ItemStack copyStack = stack.copy(); copyStack.stackSize = stackLimit; inventory.setInventorySlotContents(slot, copyStack); stack.stackSize -= copyStack.stackSize; } else { inventory.setInventorySlotContents(slot, stack); return null; } } else if (InventoryUtility.stacksMatch(slotStack, stack)) { final int roomLeft = stackLimit - slotStack.stackSize; if (roomLeft > 0) { slotStack.stackSize += roomLeft; inventory.setInventorySlotContents(slot, slotStack); stack.stackSize -= roomLeft; } } } } } } else if (tile instanceof IInventory) { return InventoryUtility.putStackInInventory((IInventory) tile, stack, getLoadingDirection().getOpposite().ordinal(), false); } return stack; } /** * Takes the first stack the matches the requirements. * <p> * Does not actually consume the item * * @return the item */ public Pair<ItemStack, Integer> takeItemFromTile(ITransportCartCargo cart) { final TileEntity tile = getLoadTile(); if (tile instanceof IRailInventoryTile) { int[] slots = ((IRailInventoryTile) tile).getSlotsToUnload(getLoadingDirection().getOpposite()); final IInventory inventory = ((IRailInventoryTile) tile).getInventory(); for (int index = 0; index < slots.length; index++) { final int slot = slots[index]; final ItemStack slotStack = inventory.getStackInSlot(slot); if (slotStack != null && ((IRailInventoryTile) tile).canRemove(slotStack, getLoadingDirection().getOpposite())) { if (cart.canAcceptItemForTransport(slotStack)) { return new Pair(slotStack, slot); } } } } else if (tile instanceof IInventory) { return InventoryUtility.findFirstItemInInventory((IInventory) tile, getLoadingDirection().getOpposite().ordinal(), 64, cart.getInventoryFilter()); } return null; } /** * Modified version of the above method designed for cargo carts that * require items per slot. * * @param filter - slot based filter, used to filter global and per slot * @return item & slot pair */ public Pair<ItemStack, Integer> takeItemFromTile(IInventoryFilter filter) { final TileEntity tile = getLoadTile(); if (tile instanceof IRailInventoryTile) { int[] slots = ((IRailInventoryTile) tile).getSlotsToUnload(getLoadingDirection().getOpposite()); final IInventory inventory = ((IRailInventoryTile) tile).getInventory(); for (int index = 0; index < slots.length; index++) { final int slot = slots[index]; final ItemStack slotStack = inventory.getStackInSlot(slot); if (slotStack != null && ((IRailInventoryTile) tile).canRemove(slotStack, getLoadingDirection().getOpposite())) { if (filter.isStackInFilter(slotStack)) { return new Pair(slotStack, slot); } } } } else if (tile instanceof IInventory) { return InventoryUtility.findFirstItemInInventory((IInventory) tile, getLoadingDirection().getOpposite().ordinal(), 64, filter); } return null; } /** * Gets the tile that will be used to load or unload * into * * @return */ public TileEntity getLoadTile() { return toLocation().add(getLoadingDirection()).getTileEntity(); } @Override public boolean isUsableRail() { return !isLoaderExtendTrack(); } /** * Pushs the cart * * @return */ public boolean isPoweredRail() { return railType == PoweredRails.POWERED; } /** * Rotates the cart * * @return */ public boolean isRotationRail() { return railType == PoweredRails.ROTATION; } /** * Changes the side of a tile the cart is on * * @return */ public boolean isOrientationRail() { return railType == PoweredRails.ORIENTATION; } /** * Stops a cart * * @return */ public boolean isStopRail() { return railType == PoweredRails.STOP; } /** * Loads cargo from carts from a tile * * @return */ public boolean isLoaderRail() { return railType == PoweredRails.LOADER; } /** * Unloads cargo from carts into a tile * * @return */ public boolean isUnloadRail() { return railType == PoweredRails.UNLOADER; } /** * Two way splitter rail * Sends cart left or right * * @return */ public boolean isSplitterRail() { return railType == PoweredRails.SPLITTER; } /** * Extender tracks allow tiles to be connected to * loaders and unloads a little distance from the * track itself * * @return */ public boolean isLoaderExtendTrack() { return railType == PoweredRails.EXTENDER; } /** * Calculates that direction to access tiles * for loading and unloading. */ protected void setupLoadingDirection() { switch (getFacingDirection()) { case UP: switch (getAttachedDirection()) { case NORTH: loadDirection = ForgeDirection.WEST; break; case SOUTH: loadDirection = ForgeDirection.EAST; break; case EAST: loadDirection = ForgeDirection.NORTH; break; case WEST: loadDirection = ForgeDirection.SOUTH; break; } break; case DOWN: switch (getAttachedDirection()) { case NORTH: loadDirection = ForgeDirection.EAST; break; case SOUTH: loadDirection = ForgeDirection.WEST; break; case EAST: loadDirection = ForgeDirection.SOUTH; break; case WEST: loadDirection = ForgeDirection.NORTH; break; } break; case NORTH: switch (getAttachedDirection()) { case EAST: loadDirection = ForgeDirection.DOWN; break; case WEST: loadDirection = ForgeDirection.UP; break; default: loadDirection = ForgeDirection.EAST; } break; case SOUTH: switch (getAttachedDirection()) { case EAST: loadDirection = ForgeDirection.UP; break; case WEST: loadDirection = ForgeDirection.DOWN; break; default: loadDirection = ForgeDirection.WEST; } break; case WEST: switch (getAttachedDirection()) { case NORTH: loadDirection = ForgeDirection.DOWN; break; case SOUTH: loadDirection = ForgeDirection.UP; break; default: loadDirection = ForgeDirection.NORTH; } break; case EAST: switch (getAttachedDirection()) { case NORTH: loadDirection = ForgeDirection.UP; break; case SOUTH: loadDirection = ForgeDirection.DOWN; break; default: loadDirection = ForgeDirection.SOUTH; } break; } if (!rotateClockwise) { loadDirection = loadDirection.getOpposite(); } } /** * Sets the loading direction for accessing tiles * * @param direction */ public void setLoadingDirection(ForgeDirection direction) { this.loadDirection = direction; } /** * Direction to load/unload items from tiles * * @return direction */ public ForgeDirection getLoadingDirection() { if (loadDirection == null) { setupLoadingDirection(); } return loadDirection; } @Override public ForgeDirection getAttachedDirection() { if (attachedSide == null) { attachedSide = ForgeDirection.getOrientation(getMetadata()); } return attachedSide; } public void setFacingDirection(ForgeDirection facingDirection) { this.facingDirection = facingDirection; if (oldWorld() != null && isServer()) { sendDescPacket(); } } /** Direction we are facing */ @Override public ForgeDirection getFacingDirection() { return facingDirection; } @Override public float getRailHeight() { return BlockRail.RAIL_HEIGHT; } protected void handlePush(ITransportCart cart) { if (isServer()) { cart.recenterCartOnRail(this, false); Pos pos = new Pos(facingDirection).multiply(cart.getDesiredPushVelocity()); cart.setCartMotion(pos.x(), pos.y(), pos.z()); } } @Override protected boolean onPlayerRightClick(EntityPlayer player, int side, Pos hit) { if (Engine.runningAsDev) { if (player.getHeldItem() != null && player.getHeldItem().getItem() == Items.stick) { if (isServer()) { player.addChatMessage(new ChatComponentText( "A: " + getAttachedDirection() + " F:" + getFacingDirection() + " T:" + railType)); if (isUnloadRail() || isLoaderRail()) { setupLoadingDirection(); player.addChatMessage( new ChatComponentText("L: " + loadDirection + " C: " + rotateClockwise)); } } return true; } } return false; } @Override protected boolean onPlayerRightClickWrench(EntityPlayer player, int side, Pos hit) { if (player.isSneaking()) { if (isRotationRail() || isUnloadRail() || isLoaderRail()) { rotateClockwise = !rotateClockwise; setupLoadingDirection(); if (isServer()) { sendDescPacket(); } else { oldWorld().markBlockRangeForRenderUpdate(xi(), yi(), zi(), xi(), yi(), zi()); } } } else { if (side == 0 || side == 1) { boolean high = hit.z() >= 0.7; boolean low = hit.z() <= 0.3; //Left & right are inverted for South boolean left = hit.x() <= 0.3; boolean right = hit.x() >= 0.7; if (!left && !right) { if (high) { setFacingDirection(ForgeDirection.SOUTH); } else if (low) { setFacingDirection(ForgeDirection.NORTH); } } else { if (left) { setFacingDirection(side == 0 ? ForgeDirection.EAST : ForgeDirection.WEST); } else if (right) { setFacingDirection(side == 0 ? ForgeDirection.WEST : ForgeDirection.EAST); } } } //North South else if (side == 2 || side == 3) { boolean high = hit.y() >= 0.7; boolean low = hit.y() <= 0.3; //Left & right are inverted for South boolean left = hit.x() <= 0.3; boolean right = hit.x() >= 0.7; if (!left && !right) { if (high) { setFacingDirection(ForgeDirection.UP); } else if (low) { setFacingDirection(ForgeDirection.DOWN); } } else { if (left) { setFacingDirection(ForgeDirection.WEST); } else if (right) { setFacingDirection(ForgeDirection.EAST); } } } //West East else if (side == 4 || side == 5) { boolean high = hit.y() >= 0.7; boolean low = hit.y() <= 0.3; //Left & right are inverted for East boolean left = hit.z() <= 0.3; boolean right = hit.z() >= 0.7; if (!left && !right) { if (high) { setFacingDirection(ForgeDirection.UP); } else if (low) { setFacingDirection(ForgeDirection.DOWN); } } else { if (left) { setFacingDirection(ForgeDirection.NORTH); } else if (right) { setFacingDirection(ForgeDirection.SOUTH); } } } oldWorld().markBlockRangeForRenderUpdate(xi(), yi(), zi(), xi(), yi(), zi()); } return true; } @Override public void writeDescPacket(ByteBuf buf) { buf.writeInt(railType.ordinal()); buf.writeInt(getFacingDirection().ordinal()); if (isRotationRail()) { buf.writeBoolean(rotateToAngle); buf.writeBoolean(rotateClockwise); buf.writeInt(rotateYaw); } else if (isStopRail()) { buf.writeBoolean(stopCarts); } else if (isLoaderRail() || isUnloadRail()) { buf.writeBoolean(rotateClockwise); } } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); if (nbt.hasKey("facingDirection")) { setFacingDirection(ForgeDirection.getOrientation(nbt.getInteger("facingDirection"))); } railType = PoweredRails.get(nbt.getInteger("railType")); rotateClockwise = nbt.getBoolean("rotateClockwise"); if (isRotationRail()) { if (nbt.hasKey("rotateToAngle")) { rotateToAngle = nbt.getBoolean("rotateToAngle"); } if (nbt.hasKey("rotationYaw")) { rotateYaw = nbt.getInteger("rotationYaw"); } } } @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); nbt.setInteger("facingDirection", getFacingDirection().ordinal()); nbt.setInteger("railType", railType.ordinal()); nbt.setBoolean("rotateClockwise", rotateClockwise); if (isRotationRail()) { nbt.setBoolean("rotateToAngle", rotateToAngle); nbt.setInteger("rotationYaw", rotateYaw); } } @Override public Cube getCollisionBounds() { if (oldWorld() != null) { final int meta = oldWorld().getBlockMetadata(xi(), yi(), zi()); final ForgeDirection dir = ForgeDirection.getOrientation(meta); switch (dir) { case DOWN: return COLLISION_BOX_DOWN; case NORTH: return COLLISION_BOX_NORTH; case SOUTH: return COLLISION_BOX_SOUTH; case EAST: return COLLISION_BOX_EAST; case WEST: return COLLISION_BOX_WEST; } } return bounds; } @Override public void getSubBlocks(Item item, CreativeTabs creativeTabs, List list) { for (PoweredRails rails : PoweredRails.values()) { list.add(new ItemStack(item, 1, rails.ordinal())); } } }