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.util.MathHelper;
010    import net.minecraft.world.ChunkPosition;
011    import net.minecraft.world.SpawnerAnimals;
012    import net.minecraft.world.World;
013    import net.minecraft.world.biome.BiomeGenBase;
014    import net.minecraft.world.chunk.Chunk;
015    import net.minecraft.world.chunk.IChunkProvider;
016    import net.minecraft.world.gen.feature.MapGenScatteredFeature;
017    import net.minecraft.world.gen.feature.WorldGenDungeons;
018    import net.minecraft.world.gen.feature.WorldGenLakes;
019    import net.minecraft.world.gen.structure.MapGenMineshaft;
020    import net.minecraft.world.gen.structure.MapGenStronghold;
021    import net.minecraft.world.gen.structure.MapGenVillage;
022    
023    import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.*;
024    import static net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.*;
025    import net.minecraftforge.common.*;
026    import net.minecraftforge.event.Event.*;
027    import net.minecraftforge.event.terraingen.*;
028    
029    public class ChunkProviderGenerate implements IChunkProvider
030    {
031        /** RNG. */
032        private Random rand;
033    
034        /** A NoiseGeneratorOctaves used in generating terrain */
035        private NoiseGeneratorOctaves noiseGen1;
036    
037        /** A NoiseGeneratorOctaves used in generating terrain */
038        private NoiseGeneratorOctaves noiseGen2;
039    
040        /** A NoiseGeneratorOctaves used in generating terrain */
041        private NoiseGeneratorOctaves noiseGen3;
042    
043        /** A NoiseGeneratorOctaves used in generating terrain */
044        private NoiseGeneratorOctaves noiseGen4;
045    
046        /** A NoiseGeneratorOctaves used in generating terrain */
047        public NoiseGeneratorOctaves noiseGen5;
048    
049        /** A NoiseGeneratorOctaves used in generating terrain */
050        public NoiseGeneratorOctaves noiseGen6;
051        public NoiseGeneratorOctaves mobSpawnerNoise;
052    
053        /** Reference to the World object. */
054        private World worldObj;
055    
056        /** are map structures going to be generated (e.g. strongholds) */
057        private final boolean mapFeaturesEnabled;
058    
059        /** Holds the overall noise array used in chunk generation */
060        private double[] noiseArray;
061        private double[] stoneNoise = new double[256];
062        private MapGenBase caveGenerator = new MapGenCaves();
063    
064        /** Holds Stronghold Generator */
065        private MapGenStronghold strongholdGenerator = new MapGenStronghold();
066    
067        /** Holds Village Generator */
068        private MapGenVillage villageGenerator = new MapGenVillage();
069    
070        /** Holds Mineshaft Generator */
071        private MapGenMineshaft mineshaftGenerator = new MapGenMineshaft();
072        private MapGenScatteredFeature scatteredFeatureGenerator = new MapGenScatteredFeature();
073    
074        /** Holds ravine generator */
075        private MapGenBase ravineGenerator = new MapGenRavine();
076    
077        /** The biomes that are used to generate the chunk */
078        private BiomeGenBase[] biomesForGeneration;
079    
080        /** A double array that hold terrain noise from noiseGen3 */
081        double[] noise3;
082    
083        /** A double array that hold terrain noise */
084        double[] noise1;
085    
086        /** A double array that hold terrain noise from noiseGen2 */
087        double[] noise2;
088    
089        /** A double array that hold terrain noise from noiseGen5 */
090        double[] noise5;
091    
092        /** A double array that holds terrain noise from noiseGen6 */
093        double[] noise6;
094    
095        /**
096         * Used to store the 5x5 parabolic field that is used during terrain generation.
097         */
098        float[] parabolicField;
099        int[][] field_73219_j = new int[32][32];
100    
101        {
102            caveGenerator = TerrainGen.getModdedMapGen(caveGenerator, CAVE);
103            strongholdGenerator = (MapGenStronghold) TerrainGen.getModdedMapGen(strongholdGenerator, STRONGHOLD);
104            villageGenerator = (MapGenVillage) TerrainGen.getModdedMapGen(villageGenerator, VILLAGE);
105            mineshaftGenerator = (MapGenMineshaft) TerrainGen.getModdedMapGen(mineshaftGenerator, MINESHAFT);
106            scatteredFeatureGenerator = (MapGenScatteredFeature) TerrainGen.getModdedMapGen(scatteredFeatureGenerator, SCATTERED_FEATURE);
107            ravineGenerator = TerrainGen.getModdedMapGen(ravineGenerator, RAVINE);
108        }
109    
110        public ChunkProviderGenerate(World par1World, long par2, boolean par4)
111        {
112            this.worldObj = par1World;
113            this.mapFeaturesEnabled = par4;
114            this.rand = new Random(par2);
115            this.noiseGen1 = new NoiseGeneratorOctaves(this.rand, 16);
116            this.noiseGen2 = new NoiseGeneratorOctaves(this.rand, 16);
117            this.noiseGen3 = new NoiseGeneratorOctaves(this.rand, 8);
118            this.noiseGen4 = new NoiseGeneratorOctaves(this.rand, 4);
119            this.noiseGen5 = new NoiseGeneratorOctaves(this.rand, 10);
120            this.noiseGen6 = new NoiseGeneratorOctaves(this.rand, 16);
121            this.mobSpawnerNoise = new NoiseGeneratorOctaves(this.rand, 8);
122    
123            NoiseGeneratorOctaves[] noiseGens = {noiseGen1, noiseGen2, noiseGen3, noiseGen4, noiseGen5, noiseGen6, mobSpawnerNoise};
124            noiseGens = TerrainGen.getModdedNoiseGenerators(par1World, this.rand, noiseGens);
125            this.noiseGen1 = noiseGens[0];
126            this.noiseGen2 = noiseGens[1];
127            this.noiseGen3 = noiseGens[2];
128            this.noiseGen4 = noiseGens[3];
129            this.noiseGen5 = noiseGens[4];
130            this.noiseGen6 = noiseGens[5];
131            this.mobSpawnerNoise = noiseGens[6];
132        }
133    
134        /**
135         * Generates the shape of the terrain for the chunk though its all stone though the water is frozen if the
136         * temperature is low enough
137         */
138        public void generateTerrain(int par1, int par2, byte[] par3ArrayOfByte)
139        {
140            byte var4 = 4;
141            byte var5 = 16;
142            byte var6 = 63;
143            int var7 = var4 + 1;
144            byte var8 = 17;
145            int var9 = var4 + 1;
146            this.biomesForGeneration = this.worldObj.getWorldChunkManager().getBiomesForGeneration(this.biomesForGeneration, par1 * 4 - 2, par2 * 4 - 2, var7 + 5, var9 + 5);
147            this.noiseArray = this.initializeNoiseField(this.noiseArray, par1 * var4, 0, par2 * var4, var7, var8, var9);
148    
149            for (int var10 = 0; var10 < var4; ++var10)
150            {
151                for (int var11 = 0; var11 < var4; ++var11)
152                {
153                    for (int var12 = 0; var12 < var5; ++var12)
154                    {
155                        double var13 = 0.125D;
156                        double var15 = this.noiseArray[((var10 + 0) * var9 + var11 + 0) * var8 + var12 + 0];
157                        double var17 = this.noiseArray[((var10 + 0) * var9 + var11 + 1) * var8 + var12 + 0];
158                        double var19 = this.noiseArray[((var10 + 1) * var9 + var11 + 0) * var8 + var12 + 0];
159                        double var21 = this.noiseArray[((var10 + 1) * var9 + var11 + 1) * var8 + var12 + 0];
160                        double var23 = (this.noiseArray[((var10 + 0) * var9 + var11 + 0) * var8 + var12 + 1] - var15) * var13;
161                        double var25 = (this.noiseArray[((var10 + 0) * var9 + var11 + 1) * var8 + var12 + 1] - var17) * var13;
162                        double var27 = (this.noiseArray[((var10 + 1) * var9 + var11 + 0) * var8 + var12 + 1] - var19) * var13;
163                        double var29 = (this.noiseArray[((var10 + 1) * var9 + var11 + 1) * var8 + var12 + 1] - var21) * var13;
164    
165                        for (int var31 = 0; var31 < 8; ++var31)
166                        {
167                            double var32 = 0.25D;
168                            double var34 = var15;
169                            double var36 = var17;
170                            double var38 = (var19 - var15) * var32;
171                            double var40 = (var21 - var17) * var32;
172    
173                            for (int var42 = 0; var42 < 4; ++var42)
174                            {
175                                int var43 = var42 + var10 * 4 << 11 | 0 + var11 * 4 << 7 | var12 * 8 + var31;
176                                short var44 = 128;
177                                var43 -= var44;
178                                double var45 = 0.25D;
179                                double var49 = (var36 - var34) * var45;
180                                double var47 = var34 - var49;
181    
182                                for (int var51 = 0; var51 < 4; ++var51)
183                                {
184                                    if ((var47 += var49) > 0.0D)
185                                    {
186                                        par3ArrayOfByte[var43 += var44] = (byte)Block.stone.blockID;
187                                    }
188                                    else if (var12 * 8 + var31 < var6)
189                                    {
190                                        par3ArrayOfByte[var43 += var44] = (byte)Block.waterStill.blockID;
191                                    }
192                                    else
193                                    {
194                                        par3ArrayOfByte[var43 += var44] = 0;
195                                    }
196                                }
197    
198                                var34 += var38;
199                                var36 += var40;
200                            }
201    
202                            var15 += var23;
203                            var17 += var25;
204                            var19 += var27;
205                            var21 += var29;
206                        }
207                    }
208                }
209            }
210        }
211    
212        /**
213         * Replaces the stone that was placed in with blocks that match the biome
214         */
215        public void replaceBlocksForBiome(int par1, int par2, byte[] par3ArrayOfByte, BiomeGenBase[] par4ArrayOfBiomeGenBase)
216        {
217            ChunkProviderEvent.ReplaceBiomeBlocks event = new ChunkProviderEvent.ReplaceBiomeBlocks(this, par1, par2, par3ArrayOfByte, par4ArrayOfBiomeGenBase);
218            MinecraftForge.EVENT_BUS.post(event);
219            if (event.getResult() == Result.DENY) return;
220    
221            byte var5 = 63;
222            double var6 = 0.03125D;
223            this.stoneNoise = this.noiseGen4.generateNoiseOctaves(this.stoneNoise, par1 * 16, par2 * 16, 0, 16, 16, 1, var6 * 2.0D, var6 * 2.0D, var6 * 2.0D);
224    
225            for (int var8 = 0; var8 < 16; ++var8)
226            {
227                for (int var9 = 0; var9 < 16; ++var9)
228                {
229                    BiomeGenBase var10 = par4ArrayOfBiomeGenBase[var9 + var8 * 16];
230                    float var11 = var10.getFloatTemperature();
231                    int var12 = (int)(this.stoneNoise[var8 + var9 * 16] / 3.0D + 3.0D + this.rand.nextDouble() * 0.25D);
232                    int var13 = -1;
233                    byte var14 = var10.topBlock;
234                    byte var15 = var10.fillerBlock;
235    
236                    for (int var16 = 127; var16 >= 0; --var16)
237                    {
238                        int var17 = (var9 * 16 + var8) * 128 + var16;
239    
240                        if (var16 <= 0 + this.rand.nextInt(5))
241                        {
242                            par3ArrayOfByte[var17] = (byte)Block.bedrock.blockID;
243                        }
244                        else
245                        {
246                            byte var18 = par3ArrayOfByte[var17];
247    
248                            if (var18 == 0)
249                            {
250                                var13 = -1;
251                            }
252                            else if (var18 == Block.stone.blockID)
253                            {
254                                if (var13 == -1)
255                                {
256                                    if (var12 <= 0)
257                                    {
258                                        var14 = 0;
259                                        var15 = (byte)Block.stone.blockID;
260                                    }
261                                    else if (var16 >= var5 - 4 && var16 <= var5 + 1)
262                                    {
263                                        var14 = var10.topBlock;
264                                        var15 = var10.fillerBlock;
265                                    }
266    
267                                    if (var16 < var5 && var14 == 0)
268                                    {
269                                        if (var11 < 0.15F)
270                                        {
271                                            var14 = (byte)Block.ice.blockID;
272                                        }
273                                        else
274                                        {
275                                            var14 = (byte)Block.waterStill.blockID;
276                                        }
277                                    }
278    
279                                    var13 = var12;
280    
281                                    if (var16 >= var5 - 1)
282                                    {
283                                        par3ArrayOfByte[var17] = var14;
284                                    }
285                                    else
286                                    {
287                                        par3ArrayOfByte[var17] = var15;
288                                    }
289                                }
290                                else if (var13 > 0)
291                                {
292                                    --var13;
293                                    par3ArrayOfByte[var17] = var15;
294    
295                                    if (var13 == 0 && var15 == Block.sand.blockID)
296                                    {
297                                        var13 = this.rand.nextInt(4);
298                                        var15 = (byte)Block.sandStone.blockID;
299                                    }
300                                }
301                            }
302                        }
303                    }
304                }
305            }
306        }
307    
308        /**
309         * loads or generates the chunk at the chunk location specified
310         */
311        public Chunk loadChunk(int par1, int par2)
312        {
313            return this.provideChunk(par1, par2);
314        }
315    
316        /**
317         * Will return back a chunk, if it doesn't exist and its not a MP client it will generates all the blocks for the
318         * specified chunk from the map seed and chunk seed
319         */
320        public Chunk provideChunk(int par1, int par2)
321        {
322            this.rand.setSeed((long)par1 * 341873128712L + (long)par2 * 132897987541L);
323            byte[] var3 = new byte[32768];
324            this.generateTerrain(par1, par2, var3);
325            this.biomesForGeneration = this.worldObj.getWorldChunkManager().loadBlockGeneratorData(this.biomesForGeneration, par1 * 16, par2 * 16, 16, 16);
326            this.replaceBlocksForBiome(par1, par2, var3, this.biomesForGeneration);
327            this.caveGenerator.generate(this, this.worldObj, par1, par2, var3);
328            this.ravineGenerator.generate(this, this.worldObj, par1, par2, var3);
329    
330            if (this.mapFeaturesEnabled)
331            {
332                this.mineshaftGenerator.generate(this, this.worldObj, par1, par2, var3);
333                this.villageGenerator.generate(this, this.worldObj, par1, par2, var3);
334                this.strongholdGenerator.generate(this, this.worldObj, par1, par2, var3);
335                this.scatteredFeatureGenerator.generate(this, this.worldObj, par1, par2, var3);
336            }
337    
338            Chunk var4 = new Chunk(this.worldObj, var3, par1, par2);
339            byte[] var5 = var4.getBiomeArray();
340    
341            for (int var6 = 0; var6 < var5.length; ++var6)
342            {
343                var5[var6] = (byte)this.biomesForGeneration[var6].biomeID;
344            }
345    
346            var4.generateSkylightMap();
347            return var4;
348        }
349    
350        /**
351         * generates a subset of the level's terrain data. Takes 7 arguments: the [empty] noise array, the position, and the
352         * size.
353         */
354        private double[] initializeNoiseField(double[] par1ArrayOfDouble, int par2, int par3, int par4, int par5, int par6, int par7)
355        {
356            ChunkProviderEvent.InitNoiseField event = new ChunkProviderEvent.InitNoiseField(this, par1ArrayOfDouble, par2, par3, par4, par5, par6, par7);
357            MinecraftForge.EVENT_BUS.post(event);
358            if (event.getResult() == Result.DENY) return event.noisefield;
359    
360            if (par1ArrayOfDouble == null)
361            {
362                par1ArrayOfDouble = new double[par5 * par6 * par7];
363            }
364    
365            if (this.parabolicField == null)
366            {
367                this.parabolicField = new float[25];
368    
369                for (int var8 = -2; var8 <= 2; ++var8)
370                {
371                    for (int var9 = -2; var9 <= 2; ++var9)
372                    {
373                        float var10 = 10.0F / MathHelper.sqrt_float((float)(var8 * var8 + var9 * var9) + 0.2F);
374                        this.parabolicField[var8 + 2 + (var9 + 2) * 5] = var10;
375                    }
376                }
377            }
378    
379            double var44 = 684.412D;
380            double var45 = 684.412D;
381            this.noise5 = this.noiseGen5.generateNoiseOctaves(this.noise5, par2, par4, par5, par7, 1.121D, 1.121D, 0.5D);
382            this.noise6 = this.noiseGen6.generateNoiseOctaves(this.noise6, par2, par4, par5, par7, 200.0D, 200.0D, 0.5D);
383            this.noise3 = this.noiseGen3.generateNoiseOctaves(this.noise3, par2, par3, par4, par5, par6, par7, var44 / 80.0D, var45 / 160.0D, var44 / 80.0D);
384            this.noise1 = this.noiseGen1.generateNoiseOctaves(this.noise1, par2, par3, par4, par5, par6, par7, var44, var45, var44);
385            this.noise2 = this.noiseGen2.generateNoiseOctaves(this.noise2, par2, par3, par4, par5, par6, par7, var44, var45, var44);
386            boolean var43 = false;
387            boolean var42 = false;
388            int var12 = 0;
389            int var13 = 0;
390    
391            for (int var14 = 0; var14 < par5; ++var14)
392            {
393                for (int var15 = 0; var15 < par7; ++var15)
394                {
395                    float var16 = 0.0F;
396                    float var17 = 0.0F;
397                    float var18 = 0.0F;
398                    byte var19 = 2;
399                    BiomeGenBase var20 = this.biomesForGeneration[var14 + 2 + (var15 + 2) * (par5 + 5)];
400    
401                    for (int var21 = -var19; var21 <= var19; ++var21)
402                    {
403                        for (int var22 = -var19; var22 <= var19; ++var22)
404                        {
405                            BiomeGenBase var23 = this.biomesForGeneration[var14 + var21 + 2 + (var15 + var22 + 2) * (par5 + 5)];
406                            float var24 = this.parabolicField[var21 + 2 + (var22 + 2) * 5] / (var23.minHeight + 2.0F);
407    
408                            if (var23.minHeight > var20.minHeight)
409                            {
410                                var24 /= 2.0F;
411                            }
412    
413                            var16 += var23.maxHeight * var24;
414                            var17 += var23.minHeight * var24;
415                            var18 += var24;
416                        }
417                    }
418    
419                    var16 /= var18;
420                    var17 /= var18;
421                    var16 = var16 * 0.9F + 0.1F;
422                    var17 = (var17 * 4.0F - 1.0F) / 8.0F;
423                    double var47 = this.noise6[var13] / 8000.0D;
424    
425                    if (var47 < 0.0D)
426                    {
427                        var47 = -var47 * 0.3D;
428                    }
429    
430                    var47 = var47 * 3.0D - 2.0D;
431    
432                    if (var47 < 0.0D)
433                    {
434                        var47 /= 2.0D;
435    
436                        if (var47 < -1.0D)
437                        {
438                            var47 = -1.0D;
439                        }
440    
441                        var47 /= 1.4D;
442                        var47 /= 2.0D;
443                    }
444                    else
445                    {
446                        if (var47 > 1.0D)
447                        {
448                            var47 = 1.0D;
449                        }
450    
451                        var47 /= 8.0D;
452                    }
453    
454                    ++var13;
455    
456                    for (int var46 = 0; var46 < par6; ++var46)
457                    {
458                        double var48 = (double)var17;
459                        double var26 = (double)var16;
460                        var48 += var47 * 0.2D;
461                        var48 = var48 * (double)par6 / 16.0D;
462                        double var28 = (double)par6 / 2.0D + var48 * 4.0D;
463                        double var30 = 0.0D;
464                        double var32 = ((double)var46 - var28) * 12.0D * 128.0D / 128.0D / var26;
465    
466                        if (var32 < 0.0D)
467                        {
468                            var32 *= 4.0D;
469                        }
470    
471                        double var34 = this.noise1[var12] / 512.0D;
472                        double var36 = this.noise2[var12] / 512.0D;
473                        double var38 = (this.noise3[var12] / 10.0D + 1.0D) / 2.0D;
474    
475                        if (var38 < 0.0D)
476                        {
477                            var30 = var34;
478                        }
479                        else if (var38 > 1.0D)
480                        {
481                            var30 = var36;
482                        }
483                        else
484                        {
485                            var30 = var34 + (var36 - var34) * var38;
486                        }
487    
488                        var30 -= var32;
489    
490                        if (var46 > par6 - 4)
491                        {
492                            double var40 = (double)((float)(var46 - (par6 - 4)) / 3.0F);
493                            var30 = var30 * (1.0D - var40) + -10.0D * var40;
494                        }
495    
496                        par1ArrayOfDouble[var12] = var30;
497                        ++var12;
498                    }
499                }
500            }
501    
502            return par1ArrayOfDouble;
503        }
504    
505        /**
506         * Checks to see if a chunk exists at x, y
507         */
508        public boolean chunkExists(int par1, int par2)
509        {
510            return true;
511        }
512    
513        /**
514         * Populates chunk with ores etc etc
515         */
516        public void populate(IChunkProvider par1IChunkProvider, int par2, int par3)
517        {
518            BlockSand.fallInstantly = true;
519            int var4 = par2 * 16;
520            int var5 = par3 * 16;
521            BiomeGenBase var6 = this.worldObj.getBiomeGenForCoords(var4 + 16, var5 + 16);
522            this.rand.setSeed(this.worldObj.getSeed());
523            long var7 = this.rand.nextLong() / 2L * 2L + 1L;
524            long var9 = this.rand.nextLong() / 2L * 2L + 1L;
525            this.rand.setSeed((long)par2 * var7 + (long)par3 * var9 ^ this.worldObj.getSeed());
526            boolean var11 = false;
527    
528            MinecraftForge.EVENT_BUS.post(new PopulateChunkEvent.Pre(par1IChunkProvider, worldObj, rand, par2, par3, var11));
529    
530            if (this.mapFeaturesEnabled)
531            {
532                this.mineshaftGenerator.generateStructuresInChunk(this.worldObj, this.rand, par2, par3);
533                var11 = this.villageGenerator.generateStructuresInChunk(this.worldObj, this.rand, par2, par3);
534                this.strongholdGenerator.generateStructuresInChunk(this.worldObj, this.rand, par2, par3);
535                this.scatteredFeatureGenerator.generateStructuresInChunk(this.worldObj, this.rand, par2, par3);
536            }
537    
538            int var12;
539            int var13;
540            int var14;
541    
542            if (TerrainGen.populate(par1IChunkProvider, worldObj, rand, par2, par3, var11, LAKE) && 
543                    !var11 && this.rand.nextInt(4) == 0)
544            {
545                var12 = var4 + this.rand.nextInt(16) + 8;
546                var13 = this.rand.nextInt(128);
547                var14 = var5 + this.rand.nextInt(16) + 8;
548                (new WorldGenLakes(Block.waterStill.blockID)).generate(this.worldObj, this.rand, var12, var13, var14);
549            }
550    
551            if (TerrainGen.populate(par1IChunkProvider, worldObj, rand, par2, par3, var11, LAVA) &&
552                    !var11 && this.rand.nextInt(8) == 0)
553            {
554                var12 = var4 + this.rand.nextInt(16) + 8;
555                var13 = this.rand.nextInt(this.rand.nextInt(120) + 8);
556                var14 = var5 + this.rand.nextInt(16) + 8;
557    
558                if (var13 < 63 || this.rand.nextInt(10) == 0)
559                {
560                    (new WorldGenLakes(Block.lavaStill.blockID)).generate(this.worldObj, this.rand, var12, var13, var14);
561                }
562            }
563    
564            boolean doGen = TerrainGen.populate(par1IChunkProvider, worldObj, rand, par2, par3, var11, DUNGEON);
565            for (var12 = 0; doGen && var12 < 8; ++var12)
566            {
567                var13 = var4 + this.rand.nextInt(16) + 8;
568                var14 = this.rand.nextInt(128);
569                int var15 = var5 + this.rand.nextInt(16) + 8;
570    
571                if ((new WorldGenDungeons()).generate(this.worldObj, this.rand, var13, var14, var15))
572                {
573                    ;
574                }
575            }
576    
577            var6.decorate(this.worldObj, this.rand, var4, var5);
578            SpawnerAnimals.performWorldGenSpawning(this.worldObj, var6, var4 + 8, var5 + 8, 16, 16, this.rand);
579            var4 += 8;
580            var5 += 8;
581    
582            doGen = TerrainGen.populate(par1IChunkProvider, worldObj, rand, par2, par3, var11, ICE);
583            for (var12 = 0; doGen && var12 < 16; ++var12)
584            {
585                for (var13 = 0; var13 < 16; ++var13)
586                {
587                    var14 = this.worldObj.getPrecipitationHeight(var4 + var12, var5 + var13);
588    
589                    if (this.worldObj.isBlockFreezable(var12 + var4, var14 - 1, var13 + var5))
590                    {
591                        this.worldObj.setBlockWithNotify(var12 + var4, var14 - 1, var13 + var5, Block.ice.blockID);
592                    }
593    
594                    if (this.worldObj.canSnowAt(var12 + var4, var14, var13 + var5))
595                    {
596                        this.worldObj.setBlockWithNotify(var12 + var4, var14, var13 + var5, Block.snow.blockID);
597                    }
598                }
599            }
600    
601            MinecraftForge.EVENT_BUS.post(new PopulateChunkEvent.Post(par1IChunkProvider, worldObj, rand, par2, par3, var11));
602    
603            BlockSand.fallInstantly = false;
604        }
605    
606        /**
607         * Two modes of operation: if passed true, save all Chunks in one go.  If passed false, save up to two chunks.
608         * Return true if all chunks have been saved.
609         */
610        public boolean saveChunks(boolean par1, IProgressUpdate par2IProgressUpdate)
611        {
612            return true;
613        }
614    
615        /**
616         * Unloads the 100 oldest chunks from memory, due to a bug with chunkSet.add() never being called it thinks the list
617         * is always empty and will not remove any chunks.
618         */
619        public boolean unload100OldestChunks()
620        {
621            return false;
622        }
623    
624        /**
625         * Returns if the IChunkProvider supports saving.
626         */
627        public boolean canSave()
628        {
629            return true;
630        }
631    
632        /**
633         * Converts the instance data to a readable string.
634         */
635        public String makeString()
636        {
637            return "RandomLevelSource";
638        }
639    
640        /**
641         * Returns a list of creatures of the specified type that can spawn at the given location.
642         */
643        public List getPossibleCreatures(EnumCreatureType par1EnumCreatureType, int par2, int par3, int par4)
644        {
645            BiomeGenBase var5 = this.worldObj.getBiomeGenForCoords(par2, par4);
646            return var5 == null ? null : (var5 == BiomeGenBase.swampland && par1EnumCreatureType == EnumCreatureType.monster && this.scatteredFeatureGenerator.hasStructureAt(par2, par3, par4) ? this.scatteredFeatureGenerator.getScatteredFeatureSpawnList() : var5.getSpawnableList(par1EnumCreatureType));
647        }
648    
649        /**
650         * Returns the location of the closest structure of the specified type. If not found returns null.
651         */
652        public ChunkPosition findClosestStructure(World par1World, String par2Str, int par3, int par4, int par5)
653        {
654            return "Stronghold".equals(par2Str) && this.strongholdGenerator != null ? this.strongholdGenerator.getNearestInstance(par1World, par3, par4, par5) : null;
655        }
656    
657        public int getLoadedChunkCount()
658        {
659            return 0;
660        }
661    
662        public void recreateStructures(int par1, int par2)
663        {
664            if (this.mapFeaturesEnabled)
665            {
666                this.mineshaftGenerator.generate(this, this.worldObj, par1, par2, (byte[])null);
667                this.villageGenerator.generate(this, this.worldObj, par1, par2, (byte[])null);
668                this.strongholdGenerator.generate(this, this.worldObj, par1, par2, (byte[])null);
669                this.scatteredFeatureGenerator.generate(this, this.worldObj, par1, par2, (byte[])null);
670            }
671        }
672    }