001 package net.minecraft.src; 002 003 import java.util.Random; 004 005 public class WorldGenBigTree extends WorldGenerator 006 { 007 /** 008 * Contains three sets of two values that provide complimentary indices for a given 'major' index - 1 and 2 for 0, 0 009 * and 2 for 1, and 0 and 1 for 2. 010 */ 011 static final byte[] otherCoordPairs = new byte[] {(byte)2, (byte)0, (byte)0, (byte)1, (byte)2, (byte)1}; 012 013 /** random seed for GenBigTree */ 014 Random rand = new Random(); 015 016 /** Reference to the World object. */ 017 World worldObj; 018 int[] basePos = new int[] {0, 0, 0}; 019 int heightLimit = 0; 020 int height; 021 double heightAttenuation = 0.618D; 022 double branchDensity = 1.0D; 023 double branchSlope = 0.381D; 024 double scaleWidth = 1.0D; 025 double leafDensity = 1.0D; 026 027 /** 028 * Currently always 1, can be set to 2 in the class constructor to generate a double-sized tree trunk for big trees. 029 */ 030 int trunkSize = 1; 031 032 /** 033 * Sets the limit of the random value used to initialize the height limit. 034 */ 035 int heightLimitLimit = 12; 036 037 /** 038 * Sets the distance limit for how far away the generator will populate leaves from the base leaf node. 039 */ 040 int leafDistanceLimit = 4; 041 042 /** Contains a list of a points at which to generate groups of leaves. */ 043 int[][] leafNodes; 044 045 public WorldGenBigTree(boolean par1) 046 { 047 super(par1); 048 } 049 050 /** 051 * Generates a list of leaf nodes for the tree, to be populated by generateLeaves. 052 */ 053 void generateLeafNodeList() 054 { 055 this.height = (int)((double)this.heightLimit * this.heightAttenuation); 056 057 if (this.height >= this.heightLimit) 058 { 059 this.height = this.heightLimit - 1; 060 } 061 062 int var1 = (int)(1.382D + Math.pow(this.leafDensity * (double)this.heightLimit / 13.0D, 2.0D)); 063 064 if (var1 < 1) 065 { 066 var1 = 1; 067 } 068 069 int[][] var2 = new int[var1 * this.heightLimit][4]; 070 int var3 = this.basePos[1] + this.heightLimit - this.leafDistanceLimit; 071 int var4 = 1; 072 int var5 = this.basePos[1] + this.height; 073 int var6 = var3 - this.basePos[1]; 074 var2[0][0] = this.basePos[0]; 075 var2[0][1] = var3; 076 var2[0][2] = this.basePos[2]; 077 var2[0][3] = var5; 078 --var3; 079 080 while (var6 >= 0) 081 { 082 int var7 = 0; 083 float var8 = this.layerSize(var6); 084 085 if (var8 < 0.0F) 086 { 087 --var3; 088 --var6; 089 } 090 else 091 { 092 for (double var9 = 0.5D; var7 < var1; ++var7) 093 { 094 double var11 = this.scaleWidth * (double)var8 * ((double)this.rand.nextFloat() + 0.328D); 095 double var13 = (double)this.rand.nextFloat() * 2.0D * Math.PI; 096 int var15 = MathHelper.floor_double(var11 * Math.sin(var13) + (double)this.basePos[0] + var9); 097 int var16 = MathHelper.floor_double(var11 * Math.cos(var13) + (double)this.basePos[2] + var9); 098 int[] var17 = new int[] {var15, var3, var16}; 099 int[] var18 = new int[] {var15, var3 + this.leafDistanceLimit, var16}; 100 101 if (this.checkBlockLine(var17, var18) == -1) 102 { 103 int[] var19 = new int[] {this.basePos[0], this.basePos[1], this.basePos[2]}; 104 double var20 = Math.sqrt(Math.pow((double)Math.abs(this.basePos[0] - var17[0]), 2.0D) + Math.pow((double)Math.abs(this.basePos[2] - var17[2]), 2.0D)); 105 double var22 = var20 * this.branchSlope; 106 107 if ((double)var17[1] - var22 > (double)var5) 108 { 109 var19[1] = var5; 110 } 111 else 112 { 113 var19[1] = (int)((double)var17[1] - var22); 114 } 115 116 if (this.checkBlockLine(var19, var17) == -1) 117 { 118 var2[var4][0] = var15; 119 var2[var4][1] = var3; 120 var2[var4][2] = var16; 121 var2[var4][3] = var19[1]; 122 ++var4; 123 } 124 } 125 } 126 127 --var3; 128 --var6; 129 } 130 } 131 132 this.leafNodes = new int[var4][4]; 133 System.arraycopy(var2, 0, this.leafNodes, 0, var4); 134 } 135 136 void genTreeLayer(int par1, int par2, int par3, float par4, byte par5, int par6) 137 { 138 int var7 = (int)((double)par4 + 0.618D); 139 byte var8 = otherCoordPairs[par5]; 140 byte var9 = otherCoordPairs[par5 + 3]; 141 int[] var10 = new int[] {par1, par2, par3}; 142 int[] var11 = new int[] {0, 0, 0}; 143 int var12 = -var7; 144 int var13 = -var7; 145 146 for (var11[par5] = var10[par5]; var12 <= var7; ++var12) 147 { 148 var11[var8] = var10[var8] + var12; 149 var13 = -var7; 150 151 while (var13 <= var7) 152 { 153 double var15 = Math.pow((double)Math.abs(var12) + 0.5D, 2.0D) + Math.pow((double)Math.abs(var13) + 0.5D, 2.0D); 154 155 if (var15 > (double)(par4 * par4)) 156 { 157 ++var13; 158 } 159 else 160 { 161 var11[var9] = var10[var9] + var13; 162 int var14 = this.worldObj.getBlockId(var11[0], var11[1], var11[2]); 163 164 if (var14 != 0 && var14 != Block.leaves.blockID) 165 { 166 ++var13; 167 } 168 else 169 { 170 this.setBlockAndMetadata(this.worldObj, var11[0], var11[1], var11[2], par6, 0); 171 ++var13; 172 } 173 } 174 } 175 } 176 } 177 178 /** 179 * Gets the rough size of a layer of the tree. 180 */ 181 float layerSize(int par1) 182 { 183 if ((double)par1 < (double)((float)this.heightLimit) * 0.3D) 184 { 185 return -1.618F; 186 } 187 else 188 { 189 float var2 = (float)this.heightLimit / 2.0F; 190 float var3 = (float)this.heightLimit / 2.0F - (float)par1; 191 float var4; 192 193 if (var3 == 0.0F) 194 { 195 var4 = var2; 196 } 197 else if (Math.abs(var3) >= var2) 198 { 199 var4 = 0.0F; 200 } 201 else 202 { 203 var4 = (float)Math.sqrt(Math.pow((double)Math.abs(var2), 2.0D) - Math.pow((double)Math.abs(var3), 2.0D)); 204 } 205 206 var4 *= 0.5F; 207 return var4; 208 } 209 } 210 211 float leafSize(int par1) 212 { 213 return par1 >= 0 && par1 < this.leafDistanceLimit ? (par1 != 0 && par1 != this.leafDistanceLimit - 1 ? 3.0F : 2.0F) : -1.0F; 214 } 215 216 /** 217 * Generates the leaves surrounding an individual entry in the leafNodes list. 218 */ 219 void generateLeafNode(int par1, int par2, int par3) 220 { 221 int var4 = par2; 222 223 for (int var5 = par2 + this.leafDistanceLimit; var4 < var5; ++var4) 224 { 225 float var6 = this.leafSize(var4 - par2); 226 this.genTreeLayer(par1, var4, par3, var6, (byte)1, Block.leaves.blockID); 227 } 228 } 229 230 /** 231 * Places a line of the specified block ID into the world from the first coordinate triplet to the second. 232 */ 233 void placeBlockLine(int[] par1ArrayOfInteger, int[] par2ArrayOfInteger, int par3) 234 { 235 int[] var4 = new int[] {0, 0, 0}; 236 byte var5 = 0; 237 byte var6; 238 239 for (var6 = 0; var5 < 3; ++var5) 240 { 241 var4[var5] = par2ArrayOfInteger[var5] - par1ArrayOfInteger[var5]; 242 243 if (Math.abs(var4[var5]) > Math.abs(var4[var6])) 244 { 245 var6 = var5; 246 } 247 } 248 249 if (var4[var6] != 0) 250 { 251 byte var7 = otherCoordPairs[var6]; 252 byte var8 = otherCoordPairs[var6 + 3]; 253 byte var9; 254 255 if (var4[var6] > 0) 256 { 257 var9 = 1; 258 } 259 else 260 { 261 var9 = -1; 262 } 263 264 double var10 = (double)var4[var7] / (double)var4[var6]; 265 double var12 = (double)var4[var8] / (double)var4[var6]; 266 int[] var14 = new int[] {0, 0, 0}; 267 int var15 = 0; 268 269 for (int var16 = var4[var6] + var9; var15 != var16; var15 += var9) 270 { 271 var14[var6] = MathHelper.floor_double((double)(par1ArrayOfInteger[var6] + var15) + 0.5D); 272 var14[var7] = MathHelper.floor_double((double)par1ArrayOfInteger[var7] + (double)var15 * var10 + 0.5D); 273 var14[var8] = MathHelper.floor_double((double)par1ArrayOfInteger[var8] + (double)var15 * var12 + 0.5D); 274 byte var17 = 0; 275 int var18 = Math.abs(var14[0] - par1ArrayOfInteger[0]); 276 int var19 = Math.abs(var14[2] - par1ArrayOfInteger[2]); 277 int var20 = Math.max(var18, var19); 278 279 if (var20 > 0) 280 { 281 if (var18 == var20) 282 { 283 var17 = 4; 284 } 285 else if (var19 == var20) 286 { 287 var17 = 8; 288 } 289 } 290 291 this.setBlockAndMetadata(this.worldObj, var14[0], var14[1], var14[2], par3, var17); 292 } 293 } 294 } 295 296 /** 297 * Generates the leaf portion of the tree as specified by the leafNodes list. 298 */ 299 void generateLeaves() 300 { 301 int var1 = 0; 302 303 for (int var2 = this.leafNodes.length; var1 < var2; ++var1) 304 { 305 int var3 = this.leafNodes[var1][0]; 306 int var4 = this.leafNodes[var1][1]; 307 int var5 = this.leafNodes[var1][2]; 308 this.generateLeafNode(var3, var4, var5); 309 } 310 } 311 312 /** 313 * Indicates whether or not a leaf node requires additional wood to be added to preserve integrity. 314 */ 315 boolean leafNodeNeedsBase(int par1) 316 { 317 return (double)par1 >= (double)this.heightLimit * 0.2D; 318 } 319 320 /** 321 * Places the trunk for the big tree that is being generated. Able to generate double-sized trunks by changing a 322 * field that is always 1 to 2. 323 */ 324 void generateTrunk() 325 { 326 int var1 = this.basePos[0]; 327 int var2 = this.basePos[1]; 328 int var3 = this.basePos[1] + this.height; 329 int var4 = this.basePos[2]; 330 int[] var5 = new int[] {var1, var2, var4}; 331 int[] var6 = new int[] {var1, var3, var4}; 332 this.placeBlockLine(var5, var6, Block.wood.blockID); 333 334 if (this.trunkSize == 2) 335 { 336 ++var5[0]; 337 ++var6[0]; 338 this.placeBlockLine(var5, var6, Block.wood.blockID); 339 ++var5[2]; 340 ++var6[2]; 341 this.placeBlockLine(var5, var6, Block.wood.blockID); 342 var5[0] += -1; 343 var6[0] += -1; 344 this.placeBlockLine(var5, var6, Block.wood.blockID); 345 } 346 } 347 348 /** 349 * Generates additional wood blocks to fill out the bases of different leaf nodes that would otherwise degrade. 350 */ 351 void generateLeafNodeBases() 352 { 353 int var1 = 0; 354 int var2 = this.leafNodes.length; 355 356 for (int[] var3 = new int[] {this.basePos[0], this.basePos[1], this.basePos[2]}; var1 < var2; ++var1) 357 { 358 int[] var4 = this.leafNodes[var1]; 359 int[] var5 = new int[] {var4[0], var4[1], var4[2]}; 360 var3[1] = var4[3]; 361 int var6 = var3[1] - this.basePos[1]; 362 363 if (this.leafNodeNeedsBase(var6)) 364 { 365 this.placeBlockLine(var3, var5, (byte)Block.wood.blockID); 366 } 367 } 368 } 369 370 /** 371 * Checks a line of blocks in the world from the first coordinate to triplet to the second, returning the distance 372 * (in blocks) before a non-air, non-leaf block is encountered and/or the end is encountered. 373 */ 374 int checkBlockLine(int[] par1ArrayOfInteger, int[] par2ArrayOfInteger) 375 { 376 int[] var3 = new int[] {0, 0, 0}; 377 byte var4 = 0; 378 byte var5; 379 380 for (var5 = 0; var4 < 3; ++var4) 381 { 382 var3[var4] = par2ArrayOfInteger[var4] - par1ArrayOfInteger[var4]; 383 384 if (Math.abs(var3[var4]) > Math.abs(var3[var5])) 385 { 386 var5 = var4; 387 } 388 } 389 390 if (var3[var5] == 0) 391 { 392 return -1; 393 } 394 else 395 { 396 byte var6 = otherCoordPairs[var5]; 397 byte var7 = otherCoordPairs[var5 + 3]; 398 byte var8; 399 400 if (var3[var5] > 0) 401 { 402 var8 = 1; 403 } 404 else 405 { 406 var8 = -1; 407 } 408 409 double var9 = (double)var3[var6] / (double)var3[var5]; 410 double var11 = (double)var3[var7] / (double)var3[var5]; 411 int[] var13 = new int[] {0, 0, 0}; 412 int var14 = 0; 413 int var15; 414 415 for (var15 = var3[var5] + var8; var14 != var15; var14 += var8) 416 { 417 var13[var5] = par1ArrayOfInteger[var5] + var14; 418 var13[var6] = MathHelper.floor_double((double)par1ArrayOfInteger[var6] + (double)var14 * var9); 419 var13[var7] = MathHelper.floor_double((double)par1ArrayOfInteger[var7] + (double)var14 * var11); 420 int var16 = this.worldObj.getBlockId(var13[0], var13[1], var13[2]); 421 422 if (var16 != 0 && var16 != Block.leaves.blockID) 423 { 424 break; 425 } 426 } 427 428 return var14 == var15 ? -1 : Math.abs(var14); 429 } 430 } 431 432 /** 433 * Returns a boolean indicating whether or not the current location for the tree, spanning basePos to to the height 434 * limit, is valid. 435 */ 436 boolean validTreeLocation() 437 { 438 int[] var1 = new int[] {this.basePos[0], this.basePos[1], this.basePos[2]}; 439 int[] var2 = new int[] {this.basePos[0], this.basePos[1] + this.heightLimit - 1, this.basePos[2]}; 440 int var3 = this.worldObj.getBlockId(this.basePos[0], this.basePos[1] - 1, this.basePos[2]); 441 442 if (var3 != 2 && var3 != 3) 443 { 444 return false; 445 } 446 else 447 { 448 int var4 = this.checkBlockLine(var1, var2); 449 450 if (var4 == -1) 451 { 452 return true; 453 } 454 else if (var4 < 6) 455 { 456 return false; 457 } 458 else 459 { 460 this.heightLimit = var4; 461 return true; 462 } 463 } 464 } 465 466 /** 467 * Rescales the generator settings, only used in WorldGenBigTree 468 */ 469 public void setScale(double par1, double par3, double par5) 470 { 471 this.heightLimitLimit = (int)(par1 * 12.0D); 472 473 if (par1 > 0.5D) 474 { 475 this.leafDistanceLimit = 5; 476 } 477 478 this.scaleWidth = par3; 479 this.leafDensity = par5; 480 } 481 482 public boolean generate(World par1World, Random par2Random, int par3, int par4, int par5) 483 { 484 this.worldObj = par1World; 485 long var6 = par2Random.nextLong(); 486 this.rand.setSeed(var6); 487 this.basePos[0] = par3; 488 this.basePos[1] = par4; 489 this.basePos[2] = par5; 490 491 if (this.heightLimit == 0) 492 { 493 this.heightLimit = 5 + this.rand.nextInt(this.heightLimitLimit); 494 } 495 496 if (!this.validTreeLocation()) 497 { 498 return false; 499 } 500 else 501 { 502 this.generateLeafNodeList(); 503 this.generateLeaves(); 504 this.generateTrunk(); 505 this.generateLeafNodeBases(); 506 return true; 507 } 508 } 509 }