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 }