    001    package net.minecraft.src;
    002
    003    import java.util.Random;
    004
    005    import net.minecraftforge.common.ForgeDirection;
    006    import static net.minecraftforge.common.ForgeDirection.*;
    007
    008    public class BlockRail extends Block
    009    {
    010        /** Power related rails have this field at true. */
    011        private final boolean isPowered;
    012
    013        /**
    014         * Forge: Moved render type to a field and a setter.
    015         * This allows for a mod to change the render type
    016         * for vanilla rails, and any mod rails that extend
    017         * this class.
    018         */
    019        private int renderType = 9;
    020
    021        public void setRenderType(int value)
    022        {
    023            renderType = value;
    024        }
    025
    026        /**
    027         * Returns true if the block at the coordinates of world passed is a valid rail block (current is rail, powered or
    028         * detector).
    029         */
    030        public static final boolean isRailBlockAt(World par0World, int par1, int par2, int par3)
    031        {
    032            int var4 = par0World.getBlockId(par1, par2, par3);
    033            return isRailBlock(var4);
    034        }
    035
    036        /**
    037         * Return true if the parameter is a blockID for a valid rail block (current is rail, powered or detector).
    038         */
    039        public static final boolean isRailBlock(int par0)
    040        {
    041            return Block.blocksList[par0] instanceof BlockRail;
    042        }
    043
    044        protected BlockRail(int par1, int par2, boolean par3)
    045        {
    046            super(par1, par2, Material.circuits);
    047            this.isPowered = par3;
    048            this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
    049            this.setCreativeTab(CreativeTabs.tabTransport);
    050        }
    051
    052        /**
    053         * Returns true if the block is power related rail.
    054         */
    055        public boolean isPowered()
    056        {
    057            return this.isPowered;
    058        }
    059
    060        /**
    061         * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
    062         * cleared to be reused)
    063         */
    064        public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
    065        {
    066            return null;
    067        }
    068
    069        /**
    070         * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    071         * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    072         */
    073        public boolean isOpaqueCube()
    074        {
    075            return false;
    076        }
    077
    078        /**
    079         * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world,
    080         * x, y, z, startVec, endVec
    081         */
    082        public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3)
    083        {
    084            this.setBlockBoundsBasedOnState(par1World, par2, par3, par4);
    085            return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3);
    086        }
    087
    088        /**
    089         * Updates the blocks bounds based on its current state. Args: world, x, y, z
    090         */
    091        public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    092        {
    093            int var5 = par1IBlockAccess.getBlockMetadata(par2, par3, par4);
    094
    095            if (var5 >= 2 && var5 <= 5)
    096            {
    097                this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F);
    098            }
    099            else
    100            {
    101                this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
    102            }
    103        }
    104
    105        /**
    106         * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
    107         */
    108        public int getBlockTextureFromSideAndMetadata(int par1, int par2)
    109        {
    110            if (this.isPowered)
    111            {
    112                if (this.blockID == Block.railPowered.blockID && (par2 & 8) == 0)
    113                {
    114                    return this.blockIndexInTexture - 16;
    115                }
    116            }
    117            else if (par2 >= 6)
    118            {
    119                return this.blockIndexInTexture - 16;
    120            }
    121
    122            return this.blockIndexInTexture;
    123        }
    124
    125        /**
    126         * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
    127         */
    128        public boolean renderAsNormalBlock()
    129        {
    130            return false;
    131        }
    132
    133        /**
    134         * The type of render function that is called for this block
    135         */
    136        public int getRenderType()
    137        {
    138            return renderType;
    139        }
    140
    141        /**
    142         * Returns the quantity of items to drop on block destruction.
    143         */
    144        public int quantityDropped(Random par1Random)
    145        {
    146            return 1;
    147        }
    148
    149        /**
    150         * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
    151         */
    152        public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
    153        {
    154            return par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP);
    155        }
    156
    157        /**
    158         * Called whenever the block is added into the world. Args: world, x, y, z
    159         */
    160        public void onBlockAdded(World par1World, int par2, int par3, int par4)
    161        {
    162            if (!par1World.isRemote)
    163            {
    164                this.refreshTrackShape(par1World, par2, par3, par4, true);
    165
    166                if (this.blockID == Block.railPowered.blockID)
    167                {
    168                    this.onNeighborBlockChange(par1World, par2, par3, par4, this.blockID);
    169                }
    170            }
    171        }
    172
    173        /**
    174         * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
    175         * their own) Args: x, y, z, neighbor blockID
    176         */
    177        public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
    178        {
    179            if (!par1World.isRemote)
    180            {
    181                int var6 = par1World.getBlockMetadata(par2, par3, par4);
    182                int var7 = var6;
    183
    184                if (this.isPowered)
    185                {
    186                    var7 = var6 & 7;
    187                }
    188
    189                boolean var8 = false;
    190
    191                if (!par1World.isBlockSolidOnSide(par2, par3 - 1, par4, UP))
    192                {
    193                    var8 = true;
    194                }
    195
    196                if (var7 == 2 && !par1World.isBlockSolidOnSide(par2 + 1, par3, par4, UP))
    197                {
    198                    var8 = true;
    199                }
    200
    201                if (var7 == 3 && !par1World.isBlockSolidOnSide(par2 - 1, par3, par4, UP))
    202                {
    203                    var8 = true;
    204                }
    205
    206                if (var7 == 4 && !par1World.isBlockSolidOnSide(par2, par3, par4 - 1, UP))
    207                {
    208                    var8 = true;
    209                }
    210
    211                if (var7 == 5 && !par1World.isBlockSolidOnSide(par2, par3, par4 + 1, UP))
    212                {
    213                    var8 = true;
    214                }
    215
    216                if (var8)
    217                {
    218                    this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
    219                    par1World.setBlockWithNotify(par2, par3, par4, 0);
    220                }
    221                else if (this.blockID == Block.railPowered.blockID)
    222                {
    223                    boolean var9 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4);
    224                    var9 = var9 || this.isNeighborRailPowered(par1World, par2, par3, par4, var6, true, 0) || this.isNeighborRailPowered(par1World, par2, par3, par4, var6, false, 0);
    225                    boolean var10 = false;
    226
    227                    if (var9 && (var6 & 8) == 0)
    228                    {
    229                        par1World.setBlockMetadataWithNotify(par2, par3, par4, var7 | 8);
    230                        var10 = true;
    231                    }
    232                    else if (!var9 && (var6 & 8) != 0)
    233                    {
    234                        par1World.setBlockMetadataWithNotify(par2, par3, par4, var7);
    235                        var10 = true;
    236                    }
    237
    238                    if (var10)
    239                    {
    240                        par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
    241
    242                        if (var7 == 2 || var7 == 3 || var7 == 4 || var7 == 5)
    243                        {
    244                            par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
    245                        }
    246                    }
    247                }
    248                else if (par5 > 0 && Block.blocksList[par5].canProvidePower() && !this.isPowered && RailLogic.getAdjacentTracks(new RailLogic(this, par1World, par2, par3, par4)) == 3)
    249                {
    250                    this.refreshTrackShape(par1World, par2, par3, par4, false);
    251                }
    252            }
    253        }
    254
    255        /**
    256         * Completely recalculates the track shape based on neighboring tracks
    257         */
    258        private void refreshTrackShape(World par1World, int par2, int par3, int par4, boolean par5)
    259        {
    260            if (!par1World.isRemote)
    261            {
    262                (new RailLogic(this, par1World, par2, par3, par4)).refreshTrackShape(par1World.isBlockIndirectlyGettingPowered(par2, par3, par4), par5);
    263            }
    264        }
    265
    266        /**
    267         * Powered minecart rail is conductive like wire, so check for powered neighbors
    268         */
    269        private boolean isNeighborRailPowered(World par1World, int par2, int par3, int par4, int par5, boolean par6, int par7)
    270        {
    271            if (par7 >= 8)
    272            {
    273                return false;
    274            }
    275            else
    276            {
    277                int var8 = par5 & 7;
    278                boolean var9 = true;
    279
    280                switch (var8)
    281                {
    282                    case 0:
    283                        if (par6)
    284                        {
    285                            ++par4;
    286                        }
    287                        else
    288                        {
    289                            --par4;
    290                        }
    291
    292                        break;
    293                    case 1:
    294                        if (par6)
    295                        {
    296                            --par2;
    297                        }
    298                        else
    299                        {
    300                            ++par2;
    301                        }
    302
    303                        break;
    304                    case 2:
    305                        if (par6)
    306                        {
    307                            --par2;
    308                        }
    309                        else
    310                        {
    311                            ++par2;
    312                            ++par3;
    313                            var9 = false;
    314                        }
    315
    316                        var8 = 1;
    317                        break;
    318                    case 3:
    319                        if (par6)
    320                        {
    321                            --par2;
    322                            ++par3;
    323                            var9 = false;
    324                        }
    325                        else
    326                        {
    327                            ++par2;
    328                        }
    329
    330                        var8 = 1;
    331                        break;
    332                    case 4:
    333                        if (par6)
    334                        {
    335                            ++par4;
    336                        }
    337                        else
    338                        {
    339                            --par4;
    340                            ++par3;
    341                            var9 = false;
    342                        }
    343
    344                        var8 = 0;
    345                        break;
    346                    case 5:
    347                        if (par6)
    348                        {
    349                            ++par4;
    350                            ++par3;
    351                            var9 = false;
    352                        }
    353                        else
    354                        {
    355                            --par4;
    356                        }
    357
    358                        var8 = 0;
    359                }
    360
    361                return this.isRailPassingPower(par1World, par2, par3, par4, par6, par7, var8) ? true : var9 && this.isRailPassingPower(par1World, par2, par3 - 1, par4, par6, par7, var8);
    362            }
    363        }
    364
    365        /**
    366         * Returns true if the specified rail is passing power to its neighbor
    367         */
    368        private boolean isRailPassingPower(World par1World, int par2, int par3, int par4, boolean par5, int par6, int par7)
    369        {
    370            int var8 = par1World.getBlockId(par2, par3, par4);
    371
    372            if (var8 == Block.railPowered.blockID)
    373            {
    374                int var9 = par1World.getBlockMetadata(par2, par3, par4);
    375                int var10 = var9 & 7;
    376
    377                if (par7 == 1 && (var10 == 0 || var10 == 4 || var10 == 5))
    378                {
    379                    return false;
    380                }
    381
    382                if (par7 == 0 && (var10 == 1 || var10 == 2 || var10 == 3))
    383                {
    384                    return false;
    385                }
    386
    387                if ((var9 & 8) != 0)
    388                {
    389                    if (par1World.isBlockIndirectlyGettingPowered(par2, par3, par4))
    390                    {
    391                        return true;
    392                    }
    393
    394                    return this.isNeighborRailPowered(par1World, par2, par3, par4, var9, par5, par6 + 1);
    395                }
    396            }
    397
    398            return false;
    399        }
    400
    401        /**
    402         * Returns the mobility information of the block, 0 = free, 1 = can't push but can move over, 2 = total immobility
    403         * and stop pistons
    404         */
    405        public int getMobilityFlag()
    406        {
    407            return 0;
    408        }
    409
    410        /**
    411         * Return true if the blocks passed is a power related rail.
    412         * @deprecated
    413         * This function is no longer called by Minecraft
    414         */
    415        @Deprecated
    416        static boolean isPoweredBlockRail(BlockRail par0BlockRail)
    417        {
    418            return par0BlockRail.isPowered;
    419        }
    420
    421        /**
    422         * Return true if the rail can make corners.
    423         * Used by placement logic.
    424         * @param world The world.
    425         * @param x The rail X coordinate.
    426         * @param y The rail Y coordinate.
    427         * @param z The rail Z coordinate.
    428         * @return True if the rail can make corners.
    429         */
    430        public boolean isFlexibleRail(World world, int y, int x, int z)
    431        {
    432            return !isPowered;
    433        }
    434
    435        /**
    436         * Returns true if the rail can make up and down slopes.
    437         * Used by placement logic.
    438         * @param world The world.
    439         * @param x The rail X coordinate.
    440         * @param y The rail Y coordinate.
    441         * @param z The rail Z coordinate.
    442         * @return True if the rail can make slopes.
    443         */
    444        public boolean canMakeSlopes(World world, int x, int y, int z)
    445        {
    446            return true;
    447        }
    448
    449        /**
    450         * Return the rails metadata (without the power bit if the rail uses one).
    451         * Can be used to make the cart think the rail something other than it is,
    452         * for example when making diamond junctions or switches.
    453         * The cart parameter will often be null unless it it called from EntityMinecart.
    454         *
    455         * Valid rail metadata is defined as follows:
    456         * 0x0: flat track going North-South
    457         * 0x1: flat track going West-East
    458         * 0x2: track ascending to the East
    459         * 0x3: track ascending to the West
    460         * 0x4: track ascending to the North
    461         * 0x5: track ascending to the South
    462         * 0x6: WestNorth corner (connecting East and South)
    463         * 0x7: EastNorth corner (connecting West and South)
    464         * 0x8: EastSouth corner (connecting West and North)
    465         * 0x9: WestSouth corner (connecting East and North)
    466         *
    467         * All directions are Notch defined.
    468         * In MC Beta 1.8.3 the Sun rises in the North.
    469         * In MC 1.0.0 the Sun rises in the East.
    470         *
    471         * @param world The world.
    472         * @param cart The cart asking for the metadata, null if it is not called by EntityMinecart.
    473         * @param y The rail X coordinate.
    474         * @param x The rail Y coordinate.
    475         * @param z The rail Z coordinate.
    476         * @return The metadata.
    477         */
    478        public int getBasicRailMetadata(IBlockAccess world, EntityMinecart cart, int x, int y, int z)
    479        {
    480            int meta = world.getBlockMetadata(x, y, z);
    481            if(isPowered)
    482            {
    483                meta = meta & 7;
    484            }
    485            return meta;
    486        }
    487
    488        /**
    489         * Returns the max speed of the rail at the specified position.
    490         * @param world The world.
    491         * @param cart The cart on the rail, may be null.
    492         * @param x The rail X coordinate.
    493         * @param y The rail Y coordinate.
    494         * @param z The rail Z coordinate.
    495         * @return The max speed of the current rail.
    496         */
    497        public float getRailMaxSpeed(World world, EntityMinecart cart, int y, int x, int z)
    498        {
    499            return 0.4f;
    500        }
    501
    502        /**
    503         * This function is called by any minecart that passes over this rail.
    504         * It is called once per update tick that the minecart is on the rail.
    505         * @param world The world.
    506         * @param cart The cart on the rail.
    507         * @param y The rail X coordinate.
    508         * @param x The rail Y coordinate.
    509         * @param z The rail Z coordinate.
    510         */
    511        public void onMinecartPass(World world, EntityMinecart cart, int y, int x, int z)
    512        {
    513        }
    514
    515        /**
    516         * Return true if this rail uses the 4th bit as a power bit.
    517         * Avoid using this function when getBasicRailMetadata() can be used instead.
    518         * The only reason to use this function is if you wish to change the rails metadata.
    519         * @param world The world.
    520         * @param x The rail X coordinate.
    521         * @param y The rail Y coordinate.
    522         * @param z The rail Z coordinate.
    523         * @return True if the 4th bit is a power bit.
    524         */
    525        public boolean hasPowerBit(World world, int x, int y, int z)
    526        {
    527            return isPowered;
    528        }
    529    }