    001package net.minecraft.block;
    002
    003import java.util.Random;
    004import net.minecraft.block.material.Material;
    005import net.minecraft.creativetab.CreativeTabs;
    006import net.minecraft.entity.item.EntityMinecart;
    007import net.minecraft.util.AxisAlignedBB;
    008import net.minecraft.util.MovingObjectPosition;
    009import net.minecraft.util.Vec3;
    010import net.minecraft.world.IBlockAccess;
    011import net.minecraft.world.World;
    012
    013public abstract class BlockRailBase extends Block
    014{
    015    /** Power related rails have this field at true. */
    016    protected final boolean isPowered;
    017
    018    /**
    019     * Returns true if the block at the coordinates of world passed is a valid rail block (current is rail, powered or
    020     * detector).
    021     */
    022    public static final boolean isRailBlockAt(World par0World, int par1, int par2, int par3)
    023    {
    024        return isRailBlock(par0World.getBlockId(par1, par2, par3));
    025    }
    026
    027    /**
    028     * Return true if the parameter is a blockID for a valid rail block (current is rail, powered or detector).
    029     */
    030    public static final boolean isRailBlock(int par0)
    031    {
    032        return Block.blocksList[par0] instanceof BlockRailBase;
    033    }
    034
    035    protected BlockRailBase(int par1, boolean par2)
    036    {
    037        super(par1, Material.circuits);
    038        this.isPowered = par2;
    039        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
    040        this.setCreativeTab(CreativeTabs.tabTransport);
    041    }
    042
    043    /**
    044     * Returns true if the block is power related rail.
    045     */
    046    public boolean isPowered()
    047    {
    048        return this.isPowered;
    049    }
    050
    051    /**
    052     * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
    053     * cleared to be reused)
    054     */
    055    public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
    056    {
    057        return null;
    058    }
    059
    060    /**
    061     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    062     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    063     */
    064    public boolean isOpaqueCube()
    065    {
    066        return false;
    067    }
    068
    069    /**
    070     * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world,
    071     * x, y, z, startVec, endVec
    072     */
    073    public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3)
    074    {
    075        this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
    076        return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3);
    077    }
    078
    079    /**
    080     * Updates the blocks bounds based on its current state. Args: world, x, y, z
    081     */
    082    public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    083    {
    084        int l = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
    085
    086        if (l >= 2 && l <= 5)
    087        {
    088            this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F);
    089        }
    090        else
    091        {
    092            this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
    093        }
    094    }
    095
    096    /**
    097     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
    098     */
    099    public boolean renderAsNormalBlock()
    100    {
    101        return false;
    102    }
    103
    104    /**
    105     * The type of render function that is called for this block
    106     */
    107    public int getRenderType()
    108    {
    109        return renderType;
    110    }
    111
    112    /**
    113     * Returns the quantity of items to drop on block destruction.
    114     */
    115    public int quantityDropped(Random par1Random)
    116    {
    117        return 1;
    118    }
    119
    120    /**
    121     * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
    122     */
    123    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
    124    {
    125        return par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4);
    126    }
    127
    128    /**
    129     * Called whenever the block is added into the world. Args: world, x, y, z
    130     */
    131    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    132    {
    133        if (!par1World.isRemote)
    134        {
    135            this.refreshTrackShape(par1World, par2, par3, par4, true);
    136
    137            if (this.isPowered)
    138            {
    139                this.onNeighborBlockChange(par1World, par2, par3, par4, this.blockID);
    140            }
    141        }
    142    }
    143
    144    /**
    145     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
    146     * their own) Args: x, y, z, neighbor blockID
    147     */
    148    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
    149    {
    150        if (!par1World.isRemote)
    151        {
    152            int i1 = par1World.getBlockMetadata(par2, par3, par4);
    153            int j1 = i1;
    154
    155            if (this.isPowered)
    156            {
    157                j1 = i1 & 7;
    158            }
    159
    160            boolean flag = false;
    161
    162            if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4))
    163            {
    164                flag = true;
    165            }
    166
    167            if (j1 == 2 && !par1World.doesBlockHaveSolidTopSurface(par2 + 1, par3, par4))
    168            {
    169                flag = true;
    170            }
    171
    172            if (j1 == 3 && !par1World.doesBlockHaveSolidTopSurface(par2 - 1, par3, par4))
    173            {
    174                flag = true;
    175            }
    176
    177            if (j1 == 4 && !par1World.doesBlockHaveSolidTopSurface(par2, par3, par4 - 1))
    178            {
    179                flag = true;
    180            }
    181
    182            if (j1 == 5 && !par1World.doesBlockHaveSolidTopSurface(par2, par3, par4 + 1))
    183            {
    184                flag = true;
    185            }
    186
    187            if (flag)
    188            {
    189                this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
    190                par1World.setBlockToAir(par2, par3, par4);
    191            }
    192            else
    193            {
    194                this.func_94358_a(par1World, par2, par3, par4, i1, j1, par5);
    195            }
    196        }
    197    }
    198
    199    protected void func_94358_a(World par1World, int par2, int par3, int par4, int par5, int par6, int par7) {}
    200
    201    /**
    202     * Completely recalculates the track shape based on neighboring tracks
    203     */
    204    protected void refreshTrackShape(World par1World, int par2, int par3, int par4, boolean par5)
    205    {
    206        if (!par1World.isRemote)
    207        {
    208            (new BlockBaseRailLogic(this, par1World, par2, par3, par4)).func_94511_a(par1World.isBlockIndirectlyGettingPowered(par2, par3, par4), par5);
    209        }
    210    }
    211
    212    /**
    213     * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
    214     * and stop pistons
    215     */
    216    public int getMobilityFlag()
    217    {
    218        return 0;
    219    }
    220
    221    /**
    222     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
    223     */
    224    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
    225    {
    226        int j1 = par6;
    227
    228        if (this.isPowered)
    229        {
    230            j1 = par6 & 7;
    231        }
    232
    233        super.breakBlock(par1World, par2, par3, par4, par5, par6);
    234
    235        if (j1 == 2 || j1 == 3 || j1 == 4 || j1 == 5)
    236        {
    237            par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, par5);
    238        }
    239
    240        if (this.isPowered)
    241        {
    242            par1World.notifyBlocksOfNeighborChange(par2, par3, par4, par5);
    243            par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, par5);
    244        }
    245    }
    246
    247        /**
    248     * Return true if the rail can make corners.
    249     * Used by placement logic.
    250     * @param world The world.
    251     * @param x The rail X coordinate.
    252     * @param y The rail Y coordinate.
    253     * @param z The rail Z coordinate.
    254     * @return True if the rail can make corners.
    255     */
    256    public boolean isFlexibleRail(World world, int y, int x, int z)
    257    {
    258        return !isPowered;
    259    }
    260
    261    /**
    262     * Returns true if the rail can make up and down slopes.
    263     * Used by placement logic.
    264     * @param world The world.
    265     * @param x The rail X coordinate.
    266     * @param y The rail Y coordinate.
    267     * @param z The rail Z coordinate.
    268     * @return True if the rail can make slopes.
    269     */
    270    public boolean canMakeSlopes(World world, int x, int y, int z)
    271    {
    272        return true;
    273    }
    274
    275    /**
    276     * Return the rail's metadata (without the power bit if the rail uses one).
    277     * Can be used to make the cart think the rail something other than it is,
    278     * for example when making diamond junctions or switches.
    279     * The cart parameter will often be null unless it it called from EntityMinecart.
    280     *
    281     * Valid rail metadata is defined as follows:
    282     * 0x0: flat track going North-South
    283     * 0x1: flat track going West-East
    284     * 0x2: track ascending to the East
    285     * 0x3: track ascending to the West
    286     * 0x4: track ascending to the North
    287     * 0x5: track ascending to the South
    288     * 0x6: WestNorth corner (connecting East and South)
    289     * 0x7: EastNorth corner (connecting West and South)
    290     * 0x8: EastSouth corner (connecting West and North)
    291     * 0x9: WestSouth corner (connecting East and North)
    292     *
    293     * @param world The world.
    294     * @param cart The cart asking for the metadata, null if it is not called by EntityMinecart.
    295     * @param y The rail X coordinate.
    296     * @param x The rail Y coordinate.
    297     * @param z The rail Z coordinate.
    298     * @return The metadata.
    299     */
    300    public int getBasicRailMetadata(IBlockAccess world, EntityMinecart cart, int x, int y, int z)
    301    {
    302        int meta = world.getBlockMetadata(x, y, z);
    303        if(isPowered)
    304        {
    305            meta = meta & 7;
    306        }
    307        return meta;
    308    }
    309
    310    /**
    311     * Returns the max speed of the rail at the specified position.
    312     * @param world The world.
    313     * @param cart The cart on the rail, may be null.
    314     * @param x The rail X coordinate.
    315     * @param y The rail Y coordinate.
    316     * @param z The rail Z coordinate.
    317     * @return The max speed of the current rail.
    318     */
    319    public float getRailMaxSpeed(World world, EntityMinecart cart, int y, int x, int z)
    320    {
    321        return 0.4f;
    322    }
    323
    324    /**
    325     * This function is called by any minecart that passes over this rail.
    326     * It is called once per update tick that the minecart is on the rail.
    327     * @param world The world.
    328     * @param cart The cart on the rail.
    329     * @param y The rail X coordinate.
    330     * @param x The rail Y coordinate.
    331     * @param z The rail Z coordinate.
    332     */
    333    public void onMinecartPass(World world, EntityMinecart cart, int y, int x, int z)
    334    {
    335    }
    336
    337    /**
    338     * Forge: Moved render type to a field and a setter.
    339     * This allows for a mod to change the render type
    340     * for vanilla rails, and any mod rails that extend
    341     * this class.
    342     */
    343    private int renderType = 9;
    344
    345    public void setRenderType(int value)
    346    {
    347        renderType = value;
    348    }
    349}