package net.minecraft.block;
import java.util.Random;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.item.EntityMinecart;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import static net.minecraftforge.common.ForgeDirection.*;
public class BlockRail extends Block
{
/** Power related rails have this field at true. */
private final boolean isPowered;
/**
* Returns true if the block at the coordinates of world passed is a valid rail block (current is rail, powered or
* detector).
*/
public static final boolean isRailBlockAt(World par0World, int par1, int par2, int par3)
{
int var4 = par0World.getBlockId(par1, par2, par3);
return isRailBlock(var4);
}
/**
* Return true if the parameter is a blockID for a valid rail block (current is rail, powered or detector).
*/
public static final boolean isRailBlock(int par0)
{
return Block.blocksList[par0] instanceof BlockRail;
}
protected BlockRail(int par1, int par2, boolean par3)
{
super(par1, par2, Material.circuits);
this.isPowered = par3;
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
this.setCreativeTab(CreativeTabs.tabTransport);
}
/**
* Returns true if the block is power related rail.
*/
public boolean isPowered()
{
return this.isPowered;
}
/**
* Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
* cleared to be reused)
*/
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
return null;
}
/**
* Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
* adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
*/
public boolean isOpaqueCube()
{
return false;
}
/**
* Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world,
* x, y, z, startVec, endVec
*/
public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3)
{
this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3);
}
/**
* Updates the blocks bounds based on its current state. Args: world, x, y, z
*/
public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
{
int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
if (var5 >= 2 && var5 <= 5)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F);
}
else
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
}
}
/**
* From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
*/
public int getBlockTextureFromSideAndMetadata(int par1, int par2)
{
if (this.isPowered)
{
if (this.blockID == Block.railPowered.blockID && (par2 & 8) == 0)
{
return this.blockIndexInTexture - 16;
}
}
else if (par2 >= 6)
{
return this.blockIndexInTexture - 16;
}
return this.blockIndexInTexture;
}
/**
* If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
*/
public boolean renderAsNormalBlock()
{
return false;
}
/**
* The type of render function that is called for this block
*/
public int getRenderType()
{
return renderType;
}
/**
* Returns the quantity of items to drop on block destruction.
*/
public int quantityDropped(Random par1Random)
{
return 1;
}
/**
* Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
*/
public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
{
return par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP);
}
/**
* Called whenever the block is added into the world. Args: world, x, y, z
*/
public void onBlockAdded(World par1World, int par2, int par3, int par4)
{
if (!par1World.isRemote)
{
this.refreshTrackShape(par1World, par2, par3, par4, true);
if (this.blockID == Block.railPowered.blockID)
{
this.onNeighborBlockChange(par1World, par2, par3, par4, this.blockID);
}
}
}
/**
* Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
* their own) Args: x, y, z, neighbor blockID
*/
public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
{
if (!par1World.isRemote)
{
int var6 = par1World.getBlockMetadata(par2, par3, par4);
int var7 = var6;
if (this.isPowered)
{
var7 = var6 & 7;
}
boolean var8 = false;
if (!par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP))
{
var8 = true;
}
if (var7 == 2 && !par1World.isBlockSolidOnSide(par2 + 1, par3, par4, UP))
{
var8 = true;
}
if (var7 == 3 && !par1World.isBlockSolidOnSide(par2 - 1, par3, par4, UP))
{
var8 = true;
}
if (var7 == 4 && !par1World.isBlockSolidOnSide(par2, par3, par4 - 1, UP))
{
var8 = true;
}
if (var7 == 5 && !par1World.isBlockSolidOnSide(par2, par3, par4 + 1, UP))
{
var8 = true;
}
if (var8)
{
this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
par1World.setBlockWithNotify(par2, par3, par4, 0);
}
else if (this.blockID == Block.railPowered.blockID)
{
boolean var9 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4);
var9 = var9 || this.isNeighborRailPowered(par1World, par2, par3, par4, var6, true, 0) || this.isNeighborRailPowered(par1World, par2, par3, par4, var6, false, 0);
boolean var10 = false;
if (var9 && (var6 & 8) == 0)
{
par1World.setBlockMetadataWithNotify(par2, par3, par4, var7 | 8);
var10 = true;
}
else if (!var9 && (var6 & 8) != 0)
{
par1World.setBlockMetadataWithNotify(par2, par3, par4, var7);
var10 = true;
}
if (var10)
{
par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
if (var7 == 2 || var7 == 3 || var7 == 4 || var7 == 5)
{
par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
}
}
}
else if (par5 > 0 && Block.blocksList[par5].canProvidePower() && !this.isPowered && RailLogic.getAdjacentTrackCount(new RailLogic(this, par1World, par2, par3, par4)) == 3)
{
this.refreshTrackShape(par1World, par2, par3, par4, false);
}
}
}
/**
* Completely recalculates the track shape based on neighboring tracks
*/
private void refreshTrackShape(World par1World, int par2, int par3, int par4, boolean par5)
{
if (!par1World.isRemote)
{
(new RailLogic(this, par1World, par2, par3, par4)).refreshTrackShape(par1World.isBlockIndirectlyGettingPowered(par2, par3, par4), par5);
}
}
/**
* Powered minecart rail is conductive like wire, so check for powered neighbors
*/
private boolean isNeighborRailPowered(World par1World, int par2, int par3, int par4, int par5, boolean par6, int par7)
{
if (par7 >= 8)
{
return false;
}
else
{
int var8 = par5 & 7;
boolean var9 = true;
switch (var8)
{
case 0:
if (par6)
{
++par4;
}
else
{
--par4;
}
break;
case 1:
if (par6)
{
--par2;
}
else
{
++par2;
}
break;
case 2:
if (par6)
{
--par2;
}
else
{
++par2;
++par3;
var9 = false;
}
var8 = 1;
break;
case 3:
if (par6)
{
--par2;
++par3;
var9 = false;
}
else
{
++par2;
}
var8 = 1;
break;
case 4:
if (par6)
{
++par4;
}
else
{
--par4;
++par3;
var9 = false;
}
var8 = 0;
break;
case 5:
if (par6)
{
++par4;
++par3;
var9 = false;
}
else
{
--par4;
}
var8 = 0;
}
return this.isRailPassingPower(par1World, par2, par3, par4, par6, par7, var8) ? true : var9 && this.isRailPassingPower(par1World, par2, par3 - 1, par4, par6, par7, var8);
}
}
/**
* Returns true if the specified rail is passing power to its neighbor
*/
private boolean isRailPassingPower(World par1World, int par2, int par3, int par4, boolean par5, int par6, int par7)
{
int var8 = par1World.getBlockId(par2, par3, par4);
if (var8 == Block.railPowered.blockID)
{
int var9 = par1World.getBlockMetadata(par2, par3, par4);
int var10 = var9 & 7;
if (par7 == 1 && (var10 == 0 || var10 == 4 || var10 == 5))
{
return false;
}
if (par7 == 0 && (var10 == 1 || var10 == 2 || var10 == 3))
{
return false;
}
if ((var9 & 8) != 0)
{
if (par1World.isBlockIndirectlyGettingPowered(par2, par3, par4))
{
return true;
}
return this.isNeighborRailPowered(par1World, par2, par3, par4, var9, par5, par6 + 1);
}
}
return false;
}
/**
* Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
* and stop pistons
*/
public int getMobilityFlag()
{
return 0;
}
/**
* Return true if the blocks passed is a power related rail.
* @deprecated
* This function is no longer called by Minecraft
*/
@Deprecated
static boolean isPoweredBlockRail(BlockRail par0BlockRail)
{
return par0BlockRail.isPowered;
}
/**
* Return true if the rail can make corners.
* Used by placement logic.
* @param world The world.
* @param x The rail X coordinate.
* @param y The rail Y coordinate.
* @param z The rail Z coordinate.
* @return True if the rail can make corners.
*/
public boolean isFlexibleRail(World world, int y, int x, int z)
{
return !isPowered;
}
/**
* Returns true if the rail can make up and down slopes.
* Used by placement logic.
* @param world The world.
* @param x The rail X coordinate.
* @param y The rail Y coordinate.
* @param z The rail Z coordinate.
* @return True if the rail can make slopes.
*/
public boolean canMakeSlopes(World world, int x, int y, int z)
{
return true;
}
/**
* Return the rails metadata (without the power bit if the rail uses one).
* Can be used to make the cart think the rail something other than it is,
* for example when making diamond junctions or switches.
* The cart parameter will often be null unless it it called from EntityMinecart.
*
* Valid rail metadata is defined as follows:
* 0x0: flat track going North-South
* 0x1: flat track going West-East
* 0x2: track ascending to the East
* 0x3: track ascending to the West
* 0x4: track ascending to the North
* 0x5: track ascending to the South
* 0x6: WestNorth corner (connecting East and South)
* 0x7: EastNorth corner (connecting West and South)
* 0x8: EastSouth corner (connecting West and North)
* 0x9: WestSouth corner (connecting East and North)
*
* All directions are Notch defined.
* In MC Beta 1.8.3 the Sun rises in the North.
* In MC 1.0.0 the Sun rises in the East.
*
* @param world The world.
* @param cart The cart asking for the metadata, null if it is not called by EntityMinecart.
* @param y The rail X coordinate.
* @param x The rail Y coordinate.
* @param z The rail Z coordinate.
* @return The metadata.
*/
public int getBasicRailMetadata(IBlockAccess world, EntityMinecart cart, int x, int y, int z)
{
int meta = world.getBlockMetadata(x, y, z);
if(isPowered)
{
meta = meta & 7;
}
return meta;
}
/**
* Returns the max speed of the rail at the specified position.
* @param world The world.
* @param cart The cart on the rail, may be null.
* @param x The rail X coordinate.
* @param y The rail Y coordinate.
* @param z The rail Z coordinate.
* @return The max speed of the current rail.
*/
public float getRailMaxSpeed(World world, EntityMinecart cart, int y, int x, int z)
{
return 0.4f;
}
/**
* This function is called by any minecart that passes over this rail.
* It is called once per update tick that the minecart is on the rail.
* @param world The world.
* @param cart The cart on the rail.
* @param y The rail X coordinate.
* @param x The rail Y coordinate.
* @param z The rail Z coordinate.
*/
public void onMinecartPass(World world, EntityMinecart cart, int y, int x, int z)
{
}
/**
* Return true if this rail uses the 4th bit as a power bit.
* Avoid using this function when getBasicRailMetadata() can be used instead.
* The only reason to use this function is if you wish to change the rails metadata.
* @param world The world.
* @param x The rail X coordinate.
* @param y The rail Y coordinate.
* @param z The rail Z coordinate.
* @return True if the 4th bit is a power bit.
*/
public boolean hasPowerBit(World world, int x, int y, int z)
{
return isPowered;
}
/**
* Forge: Moved render type to a field and a setter.
* This allows for a mod to change the render type
* for vanilla rails, and any mod rails that extend
* this class.
*/
private int renderType = 9;
public void setRenderType(int value)
{
renderType = value;
}
}