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