    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 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}