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