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