    001    package net.minecraft.block;
    002
    003    import java.util.Random;
    004    import net.minecraft.block.material.Material;
    005    import net.minecraft.world.IBlockAccess;
    006    import net.minecraft.world.World;
    007
    008    public class BlockFlowing extends BlockFluid
    009    {
    010        /**
    011         * Number of horizontally adjacent liquid source blocks. Diagonal doesn't count. Only source blocks of the same
    012         * liquid as the block using the field are counted.
    013         */
    014        int numAdjacentSources = 0;
    015
    016        /**
    017         * Indicates whether the flow direction is optimal. Each array index corresponds to one of the four cardinal
    018         * directions.
    019         */
    020        boolean[] isOptimalFlowDirection = new boolean[4];
    021
    022        /**
    023         * The estimated cost to flow in a given direction from the current point. Each array index corresponds to one of
    024         * the four cardinal directions.
    025         */
    026        int[] flowCost = new int[4];
    027
    028        protected BlockFlowing(int par1, Material par2Material)
    029        {
    030            super(par1, par2Material);
    031        }
    032
    033        /**
    034         * Updates the flow for the BlockFlowing object.
    035         */
    036        private void updateFlow(World par1World, int par2, int par3, int par4)
    037        {
    038            int var5 = par1World.getBlockMetadata(par2, par3, par4);
    039            par1World.setBlockAndMetadata(par2, par3, par4, this.blockID + 1, var5);
    040            par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4);
    041        }
    042
    043        public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    044        {
    045            return this.blockMaterial != Material.lava;
    046        }
    047
    048        /**
    049         * Ticks the block if it's been scheduled
    050         */
    051        public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
    052        {
    053            int var6 = this.getFlowDecay(par1World, par2, par3, par4);
    054            byte var7 = 1;
    055
    056            if (this.blockMaterial == Material.lava && !par1World.provider.isHellWorld)
    057            {
    058                var7 = 2;
    059            }
    060
    061            boolean var8 = true;
    062            int var10;
    063
    064            if (var6 > 0)
    065            {
    066                byte var9 = -100;
    067                this.numAdjacentSources = 0;
    068                int var12 = this.getSmallestFlowDecay(par1World, par2 - 1, par3, par4, var9);
    069                var12 = this.getSmallestFlowDecay(par1World, par2 + 1, par3, par4, var12);
    070                var12 = this.getSmallestFlowDecay(par1World, par2, par3, par4 - 1, var12);
    071                var12 = this.getSmallestFlowDecay(par1World, par2, par3, par4 + 1, var12);
    072                var10 = var12 + var7;
    073
    074                if (var10 >= 8 || var12 < 0)
    075                {
    076                    var10 = -1;
    077                }
    078
    079                if (this.getFlowDecay(par1World, par2, par3 + 1, par4) >= 0)
    080                {
    081                    int var11 = this.getFlowDecay(par1World, par2, par3 + 1, par4);
    082
    083                    if (var11 >= 8)
    084                    {
    085                        var10 = var11;
    086                    }
    087                    else
    088                    {
    089                        var10 = var11 + 8;
    090                    }
    091                }
    092
    093                if (this.numAdjacentSources >= 2 && this.blockMaterial == Material.water)
    094                {
    095                    if (par1World.getBlockMaterial(par2, par3 - 1, par4).isSolid())
    096                    {
    097                        var10 = 0;
    098                    }
    099                    else if (par1World.getBlockMaterial(par2, par3 - 1, par4) == this.blockMaterial && par1World.getBlockMetadata(par2, par3, par4) == 0)
    100                    {
    101                        var10 = 0;
    102                    }
    103                }
    104
    105                if (this.blockMaterial == Material.lava && var6 < 8 && var10 < 8 && var10 > var6 && par5Random.nextInt(4) != 0)
    106                {
    107                    var10 = var6;
    108                    var8 = false;
    109                }
    110
    111                if (var10 == var6)
    112                {
    113                    if (var8)
    114                    {
    115                        this.updateFlow(par1World, par2, par3, par4);
    116                    }
    117                }
    118                else
    119                {
    120                    var6 = var10;
    121
    122                    if (var10 < 0)
    123                    {
    124                        par1World.setBlockWithNotify(par2, par3, par4, 0);
    125                    }
    126                    else
    127                    {
    128                        par1World.setBlockMetadataWithNotify(par2, par3, par4, var10);
    129                        par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate());
    130                        par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID);
    131                    }
    132                }
    133            }
    134            else
    135            {
    136                this.updateFlow(par1World, par2, par3, par4);
    137            }
    138
    139            if (this.liquidCanDisplaceBlock(par1World, par2, par3 - 1, par4))
    140            {
    141                if (this.blockMaterial == Material.lava && par1World.getBlockMaterial(par2, par3 - 1, par4) == Material.water)
    142                {
    143                    par1World.setBlockWithNotify(par2, par3 - 1, par4, Block.stone.blockID);
    144                    this.triggerLavaMixEffects(par1World, par2, par3 - 1, par4);
    145                    return;
    146                }
    147
    148                if (var6 >= 8)
    149                {
    150                    this.flowIntoBlock(par1World, par2, par3 - 1, par4, var6);
    151                }
    152                else
    153                {
    154                    this.flowIntoBlock(par1World, par2, par3 - 1, par4, var6 + 8);
    155                }
    156            }
    157            else if (var6 >= 0 && (var6 == 0 || this.blockBlocksFlow(par1World, par2, par3 - 1, par4)))
    158            {
    159                boolean[] var13 = this.getOptimalFlowDirections(par1World, par2, par3, par4);
    160                var10 = var6 + var7;
    161
    162                if (var6 >= 8)
    163                {
    164                    var10 = 1;
    165                }
    166
    167                if (var10 >= 8)
    168                {
    169                    return;
    170                }
    171
    172                if (var13[0])
    173                {
    174                    this.flowIntoBlock(par1World, par2 - 1, par3, par4, var10);
    175                }
    176
    177                if (var13[1])
    178                {
    179                    this.flowIntoBlock(par1World, par2 + 1, par3, par4, var10);
    180                }
    181
    182                if (var13[2])
    183                {
    184                    this.flowIntoBlock(par1World, par2, par3, par4 - 1, var10);
    185                }
    186
    187                if (var13[3])
    188                {
    189                    this.flowIntoBlock(par1World, par2, par3, par4 + 1, var10);
    190                }
    191            }
    192        }
    193
    194        /**
    195         * flowIntoBlock(World world, int x, int y, int z, int newFlowDecay) - Flows into the block at the coordinates and
    196         * changes the block type to the liquid.
    197         */
    198        private void flowIntoBlock(World par1World, int par2, int par3, int par4, int par5)
    199        {
    200            if (this.liquidCanDisplaceBlock(par1World, par2, par3, par4))
    201            {
    202                int var6 = par1World.getBlockId(par2, par3, par4);
    203
    204                if (var6 > 0)
    205                {
    206                    if (this.blockMaterial == Material.lava)
    207                    {
    208                        this.triggerLavaMixEffects(par1World, par2, par3, par4);
    209                    }
    210                    else
    211                    {
    212                        Block.blocksList[var6].dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
    213                    }
    214                }
    215
    216                par1World.setBlockAndMetadataWithNotify(par2, par3, par4, this.blockID, par5);
    217            }
    218        }
    219
    220        /**
    221         * calculateFlowCost(World world, int x, int y, int z, int accumulatedCost, int previousDirectionOfFlow) - Used to
    222         * determine the path of least resistance, this method returns the lowest possible flow cost for the direction of
    223         * flow indicated. Each necessary horizontal flow adds to the flow cost.
    224         */
    225        private int calculateFlowCost(World par1World, int par2, int par3, int par4, int par5, int par6)
    226        {
    227            int var7 = 1000;
    228
    229            for (int var8 = 0; var8 < 4; ++var8)
    230            {
    231                if ((var8 != 0 || par6 != 1) && (var8 != 1 || par6 != 0) && (var8 != 2 || par6 != 3) && (var8 != 3 || par6 != 2))
    232                {
    233                    int var9 = par2;
    234                    int var11 = par4;
    235
    236                    if (var8 == 0)
    237                    {
    238                        var9 = par2 - 1;
    239                    }
    240
    241                    if (var8 == 1)
    242                    {
    243                        ++var9;
    244                    }
    245
    246                    if (var8 == 2)
    247                    {
    248                        var11 = par4 - 1;
    249                    }
    250
    251                    if (var8 == 3)
    252                    {
    253                        ++var11;
    254                    }
    255
    256                    if (!this.blockBlocksFlow(par1World, var9, par3, var11) && (par1World.getBlockMaterial(var9, par3, var11) != this.blockMaterial || par1World.getBlockMetadata(var9, par3, var11) != 0))
    257                    {
    258                        if (!this.blockBlocksFlow(par1World, var9, par3 - 1, var11))
    259                        {
    260                            return par5;
    261                        }
    262
    263                        if (par5 < 4)
    264                        {
    265                            int var12 = this.calculateFlowCost(par1World, var9, par3, var11, par5 + 1, var8);
    266
    267                            if (var12 < var7)
    268                            {
    269                                var7 = var12;
    270                            }
    271                        }
    272                    }
    273                }
    274            }
    275
    276            return var7;
    277        }
    278
    279        /**
    280         * Returns a boolean array indicating which flow directions are optimal based on each direction's calculated flow
    281         * cost. Each array index corresponds to one of the four cardinal directions. A value of true indicates the
    282         * direction is optimal.
    283         */
    284        private boolean[] getOptimalFlowDirections(World par1World, int par2, int par3, int par4)
    285        {
    286            int var5;
    287            int var6;
    288
    289            for (var5 = 0; var5 < 4; ++var5)
    290            {
    291                this.flowCost[var5] = 1000;
    292                var6 = par2;
    293                int var8 = par4;
    294
    295                if (var5 == 0)
    296                {
    297                    var6 = par2 - 1;
    298                }
    299
    300                if (var5 == 1)
    301                {
    302                    ++var6;
    303                }
    304
    305                if (var5 == 2)
    306                {
    307                    var8 = par4 - 1;
    308                }
    309
    310                if (var5 == 3)
    311                {
    312                    ++var8;
    313                }
    314
    315                if (!this.blockBlocksFlow(par1World, var6, par3, var8) && (par1World.getBlockMaterial(var6, par3, var8) != this.blockMaterial || par1World.getBlockMetadata(var6, par3, var8) != 0))
    316                {
    317                    if (this.blockBlocksFlow(par1World, var6, par3 - 1, var8))
    318                    {
    319                        this.flowCost[var5] = this.calculateFlowCost(par1World, var6, par3, var8, 1, var5);
    320                    }
    321                    else
    322                    {
    323                        this.flowCost[var5] = 0;
    324                    }
    325                }
    326            }
    327
    328            var5 = this.flowCost[0];
    329
    330            for (var6 = 1; var6 < 4; ++var6)
    331            {
    332                if (this.flowCost[var6] < var5)
    333                {
    334                    var5 = this.flowCost[var6];
    335                }
    336            }
    337
    338            for (var6 = 0; var6 < 4; ++var6)
    339            {
    340                this.isOptimalFlowDirection[var6] = this.flowCost[var6] == var5;
    341            }
    342
    343            return this.isOptimalFlowDirection;
    344        }
    345
    346        /**
    347         * Returns true if block at coords blocks fluids
    348         */
    349        private boolean blockBlocksFlow(World par1World, int par2, int par3, int par4)
    350        {
    351            int var5 = par1World.getBlockId(par2, par3, par4);
    352
    353            if (var5 != Block.doorWood.blockID && var5 != Block.doorSteel.blockID && var5 != Block.signPost.blockID && var5 != Block.ladder.blockID && var5 != Block.reed.blockID)
    354            {
    355                if (var5 == 0)
    356                {
    357                    return false;
    358                }
    359                else
    360                {
    361                    Material var6 = Block.blocksList[var5].blockMaterial;
    362                    return var6 == Material.portal ? true : var6.blocksMovement();
    363                }
    364            }
    365            else
    366            {
    367                return true;
    368            }
    369        }
    370
    371        /**
    372         * getSmallestFlowDecay(World world, intx, int y, int z, int currentSmallestFlowDecay) - Looks up the flow decay at
    373         * the coordinates given and returns the smaller of this value or the provided currentSmallestFlowDecay. If one
    374         * value is valid and the other isn't, the valid value will be returned. Valid values are >= 0. Flow decay is the
    375         * amount that a liquid has dissipated. 0 indicates a source block.
    376         */
    377        protected int getSmallestFlowDecay(World par1World, int par2, int par3, int par4, int par5)
    378        {
    379            int var6 = this.getFlowDecay(par1World, par2, par3, par4);
    380
    381            if (var6 < 0)
    382            {
    383                return par5;
    384            }
    385            else
    386            {
    387                if (var6 == 0)
    388                {
    389                    ++this.numAdjacentSources;
    390                }
    391
    392                if (var6 >= 8)
    393                {
    394                    var6 = 0;
    395                }
    396
    397                return par5 >= 0 && var6 >= par5 ? par5 : var6;
    398            }
    399        }
    400
    401        /**
    402         * Returns true if the block at the coordinates can be displaced by the liquid.
    403         */
    404        private boolean liquidCanDisplaceBlock(World par1World, int par2, int par3, int par4)
    405        {
    406            Material var5 = par1World.getBlockMaterial(par2, par3, par4);
    407            return var5 == this.blockMaterial ? false : (var5 == Material.lava ? false : !this.blockBlocksFlow(par1World, par2, par3, par4));
    408        }
    409
    410        /**
    411         * Called whenever the block is added into the world. Args: world, x, y, z
    412         */
    413        public void onBlockAdded(World par1World, int par2, int par3, int par4)
    414        {
    415            super.onBlockAdded(par1World, par2, par3, par4);
    416
    417            if (par1World.getBlockId(par2, par3, par4) == this.blockID)
    418            {
    419                par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate());
    420            }
    421        }
    422
    423        public boolean func_82506_l()
    424        {
    425            return false;
    426        }
    427    }