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.setBlock(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.setBlockToAir(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.setBlock(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.setBlock(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.doorIron.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}