001 package net.minecraft.world.gen;
002
003 import java.util.List;
004 import java.util.Random;
005 import net.minecraft.block.Block;
006 import net.minecraft.block.BlockSand;
007 import net.minecraft.entity.EnumCreatureType;
008 import net.minecraft.util.IProgressUpdate;
009 import net.minecraft.world.ChunkPosition;
010 import net.minecraft.world.World;
011 import net.minecraft.world.biome.BiomeGenBase;
012 import net.minecraft.world.chunk.Chunk;
013 import net.minecraft.world.chunk.IChunkProvider;
014 import net.minecraft.world.gen.feature.WorldGenFire;
015 import net.minecraft.world.gen.feature.WorldGenFlowers;
016 import net.minecraft.world.gen.feature.WorldGenGlowStone1;
017 import net.minecraft.world.gen.feature.WorldGenGlowStone2;
018 import net.minecraft.world.gen.feature.WorldGenHellLava;
019 import net.minecraft.world.gen.structure.MapGenNetherBridge;
020
021 import static net.minecraftforge.event.terraingen.DecorateBiomeEvent.Decorate.EventType.*;
022 import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.*;
023 import static net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.*;
024 import net.minecraftforge.common.*;
025 import net.minecraftforge.event.Event.*;
026 import net.minecraftforge.event.terraingen.*;
027
028 public class ChunkProviderHell implements IChunkProvider
029 {
030 private Random hellRNG;
031
032 /** A NoiseGeneratorOctaves used in generating nether terrain */
033 private NoiseGeneratorOctaves netherNoiseGen1;
034 private NoiseGeneratorOctaves netherNoiseGen2;
035 private NoiseGeneratorOctaves netherNoiseGen3;
036
037 /** Determines whether slowsand or gravel can be generated at a location */
038 private NoiseGeneratorOctaves slowsandGravelNoiseGen;
039
040 /**
041 * Determines whether something other than nettherack can be generated at a location
042 */
043 private NoiseGeneratorOctaves netherrackExculsivityNoiseGen;
044 public NoiseGeneratorOctaves netherNoiseGen6;
045 public NoiseGeneratorOctaves netherNoiseGen7;
046
047 /** Is the world that the nether is getting generated. */
048 private World worldObj;
049 private double[] noiseField;
050 public MapGenNetherBridge genNetherBridge = new MapGenNetherBridge();
051
052 /**
053 * Holds the noise used to determine whether slowsand can be generated at a location
054 */
055 private double[] slowsandNoise = new double[256];
056 private double[] gravelNoise = new double[256];
057
058 /**
059 * Holds the noise used to determine whether something other than netherrack can be generated at a location
060 */
061 private double[] netherrackExclusivityNoise = new double[256];
062 private MapGenBase netherCaveGenerator = new MapGenCavesHell();
063 double[] noiseData1;
064 double[] noiseData2;
065 double[] noiseData3;
066 double[] noiseData4;
067 double[] noiseData5;
068
069 {
070 genNetherBridge = (MapGenNetherBridge) TerrainGen.getModdedMapGen(genNetherBridge, NETHER_BRIDGE);
071 netherCaveGenerator = TerrainGen.getModdedMapGen(netherCaveGenerator, NETHER_CAVE);
072 }
073
074 public ChunkProviderHell(World par1World, long par2)
075 {
076 this.worldObj = par1World;
077 this.hellRNG = new Random(par2);
078 this.netherNoiseGen1 = new NoiseGeneratorOctaves(this.hellRNG, 16);
079 this.netherNoiseGen2 = new NoiseGeneratorOctaves(this.hellRNG, 16);
080 this.netherNoiseGen3 = new NoiseGeneratorOctaves(this.hellRNG, 8);
081 this.slowsandGravelNoiseGen = new NoiseGeneratorOctaves(this.hellRNG, 4);
082 this.netherrackExculsivityNoiseGen = new NoiseGeneratorOctaves(this.hellRNG, 4);
083 this.netherNoiseGen6 = new NoiseGeneratorOctaves(this.hellRNG, 10);
084 this.netherNoiseGen7 = new NoiseGeneratorOctaves(this.hellRNG, 16);
085
086 NoiseGeneratorOctaves[] noiseGens = {netherNoiseGen1, netherNoiseGen2, netherNoiseGen3, slowsandGravelNoiseGen, netherrackExculsivityNoiseGen, netherNoiseGen6, netherNoiseGen7};
087 noiseGens = TerrainGen.getModdedNoiseGenerators(par1World, this.hellRNG, noiseGens);
088 this.netherNoiseGen1 = noiseGens[0];
089 this.netherNoiseGen2 = noiseGens[1];
090 this.netherNoiseGen3 = noiseGens[2];
091 this.slowsandGravelNoiseGen = noiseGens[3];
092 this.netherrackExculsivityNoiseGen = noiseGens[4];
093 this.netherNoiseGen6 = noiseGens[5];
094 this.netherNoiseGen7 = noiseGens[6];
095 }
096
097 /**
098 * Generates the shape of the terrain in the nether.
099 */
100 public void generateNetherTerrain(int par1, int par2, byte[] par3ArrayOfByte)
101 {
102 byte var4 = 4;
103 byte var5 = 32;
104 int var6 = var4 + 1;
105 byte var7 = 17;
106 int var8 = var4 + 1;
107 this.noiseField = this.initializeNoiseField(this.noiseField, par1 * var4, 0, par2 * var4, var6, var7, var8);
108
109 for (int var9 = 0; var9 < var4; ++var9)
110 {
111 for (int var10 = 0; var10 < var4; ++var10)
112 {
113 for (int var11 = 0; var11 < 16; ++var11)
114 {
115 double var12 = 0.125D;
116 double var14 = this.noiseField[((var9 + 0) * var8 + var10 + 0) * var7 + var11 + 0];
117 double var16 = this.noiseField[((var9 + 0) * var8 + var10 + 1) * var7 + var11 + 0];
118 double var18 = this.noiseField[((var9 + 1) * var8 + var10 + 0) * var7 + var11 + 0];
119 double var20 = this.noiseField[((var9 + 1) * var8 + var10 + 1) * var7 + var11 + 0];
120 double var22 = (this.noiseField[((var9 + 0) * var8 + var10 + 0) * var7 + var11 + 1] - var14) * var12;
121 double var24 = (this.noiseField[((var9 + 0) * var8 + var10 + 1) * var7 + var11 + 1] - var16) * var12;
122 double var26 = (this.noiseField[((var9 + 1) * var8 + var10 + 0) * var7 + var11 + 1] - var18) * var12;
123 double var28 = (this.noiseField[((var9 + 1) * var8 + var10 + 1) * var7 + var11 + 1] - var20) * var12;
124
125 for (int var30 = 0; var30 < 8; ++var30)
126 {
127 double var31 = 0.25D;
128 double var33 = var14;
129 double var35 = var16;
130 double var37 = (var18 - var14) * var31;
131 double var39 = (var20 - var16) * var31;
132
133 for (int var41 = 0; var41 < 4; ++var41)
134 {
135 int var42 = var41 + var9 * 4 << 11 | 0 + var10 * 4 << 7 | var11 * 8 + var30;
136 short var43 = 128;
137 double var44 = 0.25D;
138 double var46 = var33;
139 double var48 = (var35 - var33) * var44;
140
141 for (int var50 = 0; var50 < 4; ++var50)
142 {
143 int var51 = 0;
144
145 if (var11 * 8 + var30 < var5)
146 {
147 var51 = Block.lavaStill.blockID;
148 }
149
150 if (var46 > 0.0D)
151 {
152 var51 = Block.netherrack.blockID;
153 }
154
155 par3ArrayOfByte[var42] = (byte)var51;
156 var42 += var43;
157 var46 += var48;
158 }
159
160 var33 += var37;
161 var35 += var39;
162 }
163
164 var14 += var22;
165 var16 += var24;
166 var18 += var26;
167 var20 += var28;
168 }
169 }
170 }
171 }
172 }
173
174 /**
175 * name based on ChunkProviderGenerate
176 */
177 public void replaceBlocksForBiome(int par1, int par2, byte[] par3ArrayOfByte)
178 {
179 ChunkProviderEvent.ReplaceBiomeBlocks event = new ChunkProviderEvent.ReplaceBiomeBlocks(this, par1, par2, par3ArrayOfByte, null);
180 MinecraftForge.EVENT_BUS.post(event);
181 if (event.getResult() == Result.DENY) return;
182
183 byte var4 = 64;
184 double var5 = 0.03125D;
185 this.slowsandNoise = this.slowsandGravelNoiseGen.generateNoiseOctaves(this.slowsandNoise, par1 * 16, par2 * 16, 0, 16, 16, 1, var5, var5, 1.0D);
186 this.gravelNoise = this.slowsandGravelNoiseGen.generateNoiseOctaves(this.gravelNoise, par1 * 16, 109, par2 * 16, 16, 1, 16, var5, 1.0D, var5);
187 this.netherrackExclusivityNoise = this.netherrackExculsivityNoiseGen.generateNoiseOctaves(this.netherrackExclusivityNoise, par1 * 16, par2 * 16, 0, 16, 16, 1, var5 * 2.0D, var5 * 2.0D, var5 * 2.0D);
188
189 for (int var7 = 0; var7 < 16; ++var7)
190 {
191 for (int var8 = 0; var8 < 16; ++var8)
192 {
193 boolean var9 = this.slowsandNoise[var7 + var8 * 16] + this.hellRNG.nextDouble() * 0.2D > 0.0D;
194 boolean var10 = this.gravelNoise[var7 + var8 * 16] + this.hellRNG.nextDouble() * 0.2D > 0.0D;
195 int var11 = (int)(this.netherrackExclusivityNoise[var7 + var8 * 16] / 3.0D + 3.0D + this.hellRNG.nextDouble() * 0.25D);
196 int var12 = -1;
197 byte var13 = (byte)Block.netherrack.blockID;
198 byte var14 = (byte)Block.netherrack.blockID;
199
200 for (int var15 = 127; var15 >= 0; --var15)
201 {
202 int var16 = (var8 * 16 + var7) * 128 + var15;
203
204 if (var15 < 127 - this.hellRNG.nextInt(5) && var15 > 0 + this.hellRNG.nextInt(5))
205 {
206 byte var17 = par3ArrayOfByte[var16];
207
208 if (var17 == 0)
209 {
210 var12 = -1;
211 }
212 else if (var17 == Block.netherrack.blockID)
213 {
214 if (var12 == -1)
215 {
216 if (var11 <= 0)
217 {
218 var13 = 0;
219 var14 = (byte)Block.netherrack.blockID;
220 }
221 else if (var15 >= var4 - 4 && var15 <= var4 + 1)
222 {
223 var13 = (byte)Block.netherrack.blockID;
224 var14 = (byte)Block.netherrack.blockID;
225
226 if (var10)
227 {
228 var13 = (byte)Block.gravel.blockID;
229 }
230
231 if (var10)
232 {
233 var14 = (byte)Block.netherrack.blockID;
234 }
235
236 if (var9)
237 {
238 var13 = (byte)Block.slowSand.blockID;
239 }
240
241 if (var9)
242 {
243 var14 = (byte)Block.slowSand.blockID;
244 }
245 }
246
247 if (var15 < var4 && var13 == 0)
248 {
249 var13 = (byte)Block.lavaStill.blockID;
250 }
251
252 var12 = var11;
253
254 if (var15 >= var4 - 1)
255 {
256 par3ArrayOfByte[var16] = var13;
257 }
258 else
259 {
260 par3ArrayOfByte[var16] = var14;
261 }
262 }
263 else if (var12 > 0)
264 {
265 --var12;
266 par3ArrayOfByte[var16] = var14;
267 }
268 }
269 }
270 else
271 {
272 par3ArrayOfByte[var16] = (byte)Block.bedrock.blockID;
273 }
274 }
275 }
276 }
277 }
278
279 /**
280 * loads or generates the chunk at the chunk location specified
281 */
282 public Chunk loadChunk(int par1, int par2)
283 {
284 return this.provideChunk(par1, par2);
285 }
286
287 /**
288 * Will return back a chunk, if it doesn't exist and its not a MP client it will generates all the blocks for the
289 * specified chunk from the map seed and chunk seed
290 */
291 public Chunk provideChunk(int par1, int par2)
292 {
293 this.hellRNG.setSeed((long)par1 * 341873128712L + (long)par2 * 132897987541L);
294 byte[] var3 = new byte[32768];
295 this.generateNetherTerrain(par1, par2, var3);
296 this.replaceBlocksForBiome(par1, par2, var3);
297 this.netherCaveGenerator.generate(this, this.worldObj, par1, par2, var3);
298 this.genNetherBridge.generate(this, this.worldObj, par1, par2, var3);
299 Chunk var4 = new Chunk(this.worldObj, var3, par1, par2);
300 BiomeGenBase[] var5 = this.worldObj.getWorldChunkManager().loadBlockGeneratorData((BiomeGenBase[])null, par1 * 16, par2 * 16, 16, 16);
301 byte[] var6 = var4.getBiomeArray();
302
303 for (int var7 = 0; var7 < var6.length; ++var7)
304 {
305 var6[var7] = (byte)var5[var7].biomeID;
306 }
307
308 var4.resetRelightChecks();
309 return var4;
310 }
311
312 /**
313 * generates a subset of the level's terrain data. Takes 7 arguments: the [empty] noise array, the position, and the
314 * size.
315 */
316 private double[] initializeNoiseField(double[] par1ArrayOfDouble, int par2, int par3, int par4, int par5, int par6, int par7)
317 {
318 ChunkProviderEvent.InitNoiseField event = new ChunkProviderEvent.InitNoiseField(this, par1ArrayOfDouble, par2, par3, par4, par5, par6, par7);
319 MinecraftForge.EVENT_BUS.post(event);
320 if (event.getResult() == Result.DENY) return event.noisefield;
321 if (par1ArrayOfDouble == null)
322 {
323 par1ArrayOfDouble = new double[par5 * par6 * par7];
324 }
325
326 double var8 = 684.412D;
327 double var10 = 2053.236D;
328 this.noiseData4 = this.netherNoiseGen6.generateNoiseOctaves(this.noiseData4, par2, par3, par4, par5, 1, par7, 1.0D, 0.0D, 1.0D);
329 this.noiseData5 = this.netherNoiseGen7.generateNoiseOctaves(this.noiseData5, par2, par3, par4, par5, 1, par7, 100.0D, 0.0D, 100.0D);
330 this.noiseData1 = this.netherNoiseGen3.generateNoiseOctaves(this.noiseData1, par2, par3, par4, par5, par6, par7, var8 / 80.0D, var10 / 60.0D, var8 / 80.0D);
331 this.noiseData2 = this.netherNoiseGen1.generateNoiseOctaves(this.noiseData2, par2, par3, par4, par5, par6, par7, var8, var10, var8);
332 this.noiseData3 = this.netherNoiseGen2.generateNoiseOctaves(this.noiseData3, par2, par3, par4, par5, par6, par7, var8, var10, var8);
333 int var12 = 0;
334 int var13 = 0;
335 double[] var14 = new double[par6];
336 int var15;
337
338 for (var15 = 0; var15 < par6; ++var15)
339 {
340 var14[var15] = Math.cos((double)var15 * Math.PI * 6.0D / (double)par6) * 2.0D;
341 double var16 = (double)var15;
342
343 if (var15 > par6 / 2)
344 {
345 var16 = (double)(par6 - 1 - var15);
346 }
347
348 if (var16 < 4.0D)
349 {
350 var16 = 4.0D - var16;
351 var14[var15] -= var16 * var16 * var16 * 10.0D;
352 }
353 }
354
355 for (var15 = 0; var15 < par5; ++var15)
356 {
357 for (int var36 = 0; var36 < par7; ++var36)
358 {
359 double var17 = (this.noiseData4[var13] + 256.0D) / 512.0D;
360
361 if (var17 > 1.0D)
362 {
363 var17 = 1.0D;
364 }
365
366 double var19 = 0.0D;
367 double var21 = this.noiseData5[var13] / 8000.0D;
368
369 if (var21 < 0.0D)
370 {
371 var21 = -var21;
372 }
373
374 var21 = var21 * 3.0D - 3.0D;
375
376 if (var21 < 0.0D)
377 {
378 var21 /= 2.0D;
379
380 if (var21 < -1.0D)
381 {
382 var21 = -1.0D;
383 }
384
385 var21 /= 1.4D;
386 var21 /= 2.0D;
387 var17 = 0.0D;
388 }
389 else
390 {
391 if (var21 > 1.0D)
392 {
393 var21 = 1.0D;
394 }
395
396 var21 /= 6.0D;
397 }
398
399 var17 += 0.5D;
400 var21 = var21 * (double)par6 / 16.0D;
401 ++var13;
402
403 for (int var23 = 0; var23 < par6; ++var23)
404 {
405 double var24 = 0.0D;
406 double var26 = var14[var23];
407 double var28 = this.noiseData2[var12] / 512.0D;
408 double var30 = this.noiseData3[var12] / 512.0D;
409 double var32 = (this.noiseData1[var12] / 10.0D + 1.0D) / 2.0D;
410
411 if (var32 < 0.0D)
412 {
413 var24 = var28;
414 }
415 else if (var32 > 1.0D)
416 {
417 var24 = var30;
418 }
419 else
420 {
421 var24 = var28 + (var30 - var28) * var32;
422 }
423
424 var24 -= var26;
425 double var34;
426
427 if (var23 > par6 - 4)
428 {
429 var34 = (double)((float)(var23 - (par6 - 4)) / 3.0F);
430 var24 = var24 * (1.0D - var34) + -10.0D * var34;
431 }
432
433 if ((double)var23 < var19)
434 {
435 var34 = (var19 - (double)var23) / 4.0D;
436
437 if (var34 < 0.0D)
438 {
439 var34 = 0.0D;
440 }
441
442 if (var34 > 1.0D)
443 {
444 var34 = 1.0D;
445 }
446
447 var24 = var24 * (1.0D - var34) + -10.0D * var34;
448 }
449
450 par1ArrayOfDouble[var12] = var24;
451 ++var12;
452 }
453 }
454 }
455
456 return par1ArrayOfDouble;
457 }
458
459 /**
460 * Checks to see if a chunk exists at x, y
461 */
462 public boolean chunkExists(int par1, int par2)
463 {
464 return true;
465 }
466
467 /**
468 * Populates chunk with ores etc etc
469 */
470 public void populate(IChunkProvider par1IChunkProvider, int par2, int par3)
471 {
472 BlockSand.fallInstantly = true;
473
474 MinecraftForge.EVENT_BUS.post(new PopulateChunkEvent.Pre(par1IChunkProvider, worldObj, hellRNG, par2, par3, false));
475
476 int var4 = par2 * 16;
477 int var5 = par3 * 16;
478 this.genNetherBridge.generateStructuresInChunk(this.worldObj, this.hellRNG, par2, par3);
479 int var6;
480 int var7;
481 int var8;
482 int var9;
483
484 boolean doGen = TerrainGen.populate(par1IChunkProvider, worldObj, hellRNG, par2, par3, false, NETHER_LAVA);
485 for (var6 = 0; doGen && var6 < 8; ++var6)
486 {
487 var7 = var4 + this.hellRNG.nextInt(16) + 8;
488 var8 = this.hellRNG.nextInt(120) + 4;
489 var9 = var5 + this.hellRNG.nextInt(16) + 8;
490 (new WorldGenHellLava(Block.lavaMoving.blockID)).generate(this.worldObj, this.hellRNG, var7, var8, var9);
491 }
492
493 var6 = this.hellRNG.nextInt(this.hellRNG.nextInt(10) + 1) + 1;
494 int var10;
495
496 doGen = TerrainGen.populate(par1IChunkProvider, worldObj, hellRNG, par2, par3, false, FIRE);
497 for (var7 = 0; doGen && var7 < var6; ++var7)
498 {
499 var8 = var4 + this.hellRNG.nextInt(16) + 8;
500 var9 = this.hellRNG.nextInt(120) + 4;
501 var10 = var5 + this.hellRNG.nextInt(16) + 8;
502 (new WorldGenFire()).generate(this.worldObj, this.hellRNG, var8, var9, var10);
503 }
504
505 var6 = this.hellRNG.nextInt(this.hellRNG.nextInt(10) + 1);
506
507 doGen = TerrainGen.populate(par1IChunkProvider, worldObj, hellRNG, par2, par3, false, GLOWSTONE);
508 for (var7 = 0; doGen && var7 < var6; ++var7)
509 {
510 var8 = var4 + this.hellRNG.nextInt(16) + 8;
511 var9 = this.hellRNG.nextInt(120) + 4;
512 var10 = var5 + this.hellRNG.nextInt(16) + 8;
513 (new WorldGenGlowStone1()).generate(this.worldObj, this.hellRNG, var8, var9, var10);
514 }
515
516 for (var7 = 0; doGen && var7 < 10; ++var7)
517 {
518 var8 = var4 + this.hellRNG.nextInt(16) + 8;
519 var9 = this.hellRNG.nextInt(128);
520 var10 = var5 + this.hellRNG.nextInt(16) + 8;
521 (new WorldGenGlowStone2()).generate(this.worldObj, this.hellRNG, var8, var9, var10);
522 }
523
524 MinecraftForge.EVENT_BUS.post(new DecorateBiomeEvent.Pre(worldObj, hellRNG, var4, var5));
525
526 doGen = TerrainGen.decorate(worldObj, hellRNG, var4, var5, SHROOM);
527 if (doGen && this.hellRNG.nextInt(1) == 0)
528 {
529 var7 = var4 + this.hellRNG.nextInt(16) + 8;
530 var8 = this.hellRNG.nextInt(128);
531 var9 = var5 + this.hellRNG.nextInt(16) + 8;
532 (new WorldGenFlowers(Block.mushroomBrown.blockID)).generate(this.worldObj, this.hellRNG, var7, var8, var9);
533 }
534
535 if (doGen && this.hellRNG.nextInt(1) == 0)
536 {
537 var7 = var4 + this.hellRNG.nextInt(16) + 8;
538 var8 = this.hellRNG.nextInt(128);
539 var9 = var5 + this.hellRNG.nextInt(16) + 8;
540 (new WorldGenFlowers(Block.mushroomRed.blockID)).generate(this.worldObj, this.hellRNG, var7, var8, var9);
541 }
542
543 MinecraftForge.EVENT_BUS.post(new DecorateBiomeEvent.Post(worldObj, hellRNG, var4, var5));
544 MinecraftForge.EVENT_BUS.post(new PopulateChunkEvent.Post(par1IChunkProvider, worldObj, hellRNG, par2, par3, false));
545
546 BlockSand.fallInstantly = false;
547 }
548
549 /**
550 * Two modes of operation: if passed true, save all Chunks in one go. If passed false, save up to two chunks.
551 * Return true if all chunks have been saved.
552 */
553 public boolean saveChunks(boolean par1, IProgressUpdate par2IProgressUpdate)
554 {
555 return true;
556 }
557
558 /**
559 * Unloads the 100 oldest chunks from memory, due to a bug with chunkSet.add() never being called it thinks the list
560 * is always empty and will not remove any chunks.
561 */
562 public boolean unload100OldestChunks()
563 {
564 return false;
565 }
566
567 /**
568 * Returns if the IChunkProvider supports saving.
569 */
570 public boolean canSave()
571 {
572 return true;
573 }
574
575 /**
576 * Converts the instance data to a readable string.
577 */
578 public String makeString()
579 {
580 return "HellRandomLevelSource";
581 }
582
583 /**
584 * Returns a list of creatures of the specified type that can spawn at the given location.
585 */
586 public List getPossibleCreatures(EnumCreatureType par1EnumCreatureType, int par2, int par3, int par4)
587 {
588 if (par1EnumCreatureType == EnumCreatureType.monster && this.genNetherBridge.hasStructureAt(par2, par3, par4))
589 {
590 return this.genNetherBridge.getSpawnList();
591 }
592 else
593 {
594 BiomeGenBase var5 = this.worldObj.getBiomeGenForCoords(par2, par4);
595 return var5 == null ? null : var5.getSpawnableList(par1EnumCreatureType);
596 }
597 }
598
599 /**
600 * Returns the location of the closest structure of the specified type. If not found returns null.
601 */
602 public ChunkPosition findClosestStructure(World par1World, String par2Str, int par3, int par4, int par5)
603 {
604 return null;
605 }
606
607 public int getLoadedChunkCount()
608 {
609 return 0;
610 }
611
612 public void recreateStructures(int par1, int par2)
613 {
614 this.genNetherBridge.generate(this, this.worldObj, par1, par2, (byte[])null);
615 }
616 }