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 }