001package net.minecraft.world.gen;
002
003import java.util.ArrayList;
004import java.util.Iterator;
005import java.util.List;
006import java.util.Map;
007import java.util.Random;
008import net.minecraft.block.Block;
009import net.minecraft.entity.EnumCreatureType;
010import net.minecraft.util.IProgressUpdate;
011import net.minecraft.world.ChunkPosition;
012import net.minecraft.world.World;
013import net.minecraft.world.biome.BiomeGenBase;
014import net.minecraft.world.chunk.Chunk;
015import net.minecraft.world.chunk.IChunkProvider;
016import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
017import net.minecraft.world.gen.feature.MapGenScatteredFeature;
018import net.minecraft.world.gen.feature.WorldGenDungeons;
019import net.minecraft.world.gen.feature.WorldGenLakes;
020import net.minecraft.world.gen.structure.MapGenMineshaft;
021import net.minecraft.world.gen.structure.MapGenStronghold;
022import net.minecraft.world.gen.structure.MapGenStructure;
023import net.minecraft.world.gen.structure.MapGenVillage;
024
025public class ChunkProviderFlat implements IChunkProvider
026{
027    private World worldObj;
028    private Random random;
029    private final byte[] field_82700_c = new byte[256];
030    private final byte[] field_82698_d = new byte[256];
031    private final FlatGeneratorInfo field_82699_e;
032    private final List structureGenerators = new ArrayList();
033    private final boolean field_82697_g;
034    private final boolean field_82702_h;
035    private WorldGenLakes waterLakeGenerator;
036    private WorldGenLakes lavaLakeGenerator;
037
038    public ChunkProviderFlat(World par1World, long par2, boolean par4, String par5Str)
039    {
040        this.worldObj = par1World;
041        this.random = new Random(par2);
042        this.field_82699_e = FlatGeneratorInfo.createFlatGeneratorFromString(par5Str);
043
044        if (par4)
045        {
046            Map var6 = this.field_82699_e.getWorldFeatures();
047
048            if (var6.containsKey("village"))
049            {
050                Map var7 = (Map)var6.get("village");
051
052                if (!var7.containsKey("size"))
053                {
054                    var7.put("size", "1");
055                }
056
057                this.structureGenerators.add(new MapGenVillage(var7));
058            }
059
060            if (var6.containsKey("biome_1"))
061            {
062                this.structureGenerators.add(new MapGenScatteredFeature((Map)var6.get("biome_1")));
063            }
064
065            if (var6.containsKey("mineshaft"))
066            {
067                this.structureGenerators.add(new MapGenMineshaft((Map)var6.get("mineshaft")));
068            }
069
070            if (var6.containsKey("stronghold"))
071            {
072                this.structureGenerators.add(new MapGenStronghold((Map)var6.get("stronghold")));
073            }
074        }
075
076        this.field_82697_g = this.field_82699_e.getWorldFeatures().containsKey("decoration");
077
078        if (this.field_82699_e.getWorldFeatures().containsKey("lake"))
079        {
080            this.waterLakeGenerator = new WorldGenLakes(Block.waterStill.blockID);
081        }
082
083        if (this.field_82699_e.getWorldFeatures().containsKey("lava_lake"))
084        {
085            this.lavaLakeGenerator = new WorldGenLakes(Block.lavaStill.blockID);
086        }
087
088        this.field_82702_h = this.field_82699_e.getWorldFeatures().containsKey("dungeon");
089        Iterator var9 = this.field_82699_e.getFlatLayers().iterator();
090
091        while (var9.hasNext())
092        {
093            FlatLayerInfo var10 = (FlatLayerInfo)var9.next();
094
095            for (int var8 = var10.getMinY(); var8 < var10.getMinY() + var10.getLayerCount(); ++var8)
096            {
097                this.field_82700_c[var8] = (byte)(var10.getFillBlock() & 255);
098                this.field_82698_d[var8] = (byte)var10.getFillBlockMeta();
099            }
100        }
101    }
102
103    /**
104     * loads or generates the chunk at the chunk location specified
105     */
106    public Chunk loadChunk(int par1, int par2)
107    {
108        return this.provideChunk(par1, par2);
109    }
110
111    /**
112     * Will return back a chunk, if it doesn't exist and its not a MP client it will generates all the blocks for the
113     * specified chunk from the map seed and chunk seed
114     */
115    public Chunk provideChunk(int par1, int par2)
116    {
117        Chunk var3 = new Chunk(this.worldObj, par1, par2);
118
119        for (int var4 = 0; var4 < this.field_82700_c.length; ++var4)
120        {
121            int var5 = var4 >> 4;
122            ExtendedBlockStorage var6 = var3.getBlockStorageArray()[var5];
123
124            if (var6 == null)
125            {
126                var6 = new ExtendedBlockStorage(var4, !this.worldObj.provider.hasNoSky);
127                var3.getBlockStorageArray()[var5] = var6;
128            }
129
130            for (int var7 = 0; var7 < 16; ++var7)
131            {
132                for (int var8 = 0; var8 < 16; ++var8)
133                {
134                    var6.setExtBlockID(var7, var4 & 15, var8, this.field_82700_c[var4] & 255);
135                    var6.setExtBlockMetadata(var7, var4 & 15, var8, this.field_82698_d[var4]);
136                }
137            }
138        }
139
140        var3.generateSkylightMap();
141        BiomeGenBase[] var9 = this.worldObj.getWorldChunkManager().loadBlockGeneratorData((BiomeGenBase[])null, par1 * 16, par2 * 16, 16, 16);
142        byte[] var10 = var3.getBiomeArray();
143
144        for (int var11 = 0; var11 < var10.length; ++var11)
145        {
146            var10[var11] = (byte)var9[var11].biomeID;
147        }
148
149        Iterator var12 = this.structureGenerators.iterator();
150
151        while (var12.hasNext())
152        {
153            MapGenStructure var13 = (MapGenStructure)var12.next();
154            var13.generate(this, this.worldObj, par1, par2, (byte[])null);
155        }
156
157        var3.generateSkylightMap();
158        return var3;
159    }
160
161    /**
162     * Checks to see if a chunk exists at x, y
163     */
164    public boolean chunkExists(int par1, int par2)
165    {
166        return true;
167    }
168
169    /**
170     * Populates chunk with ores etc etc
171     */
172    public void populate(IChunkProvider par1IChunkProvider, int par2, int par3)
173    {
174        int var4 = par2 * 16;
175        int var5 = par3 * 16;
176        BiomeGenBase var6 = this.worldObj.getBiomeGenForCoords(var4 + 16, var5 + 16);
177        boolean var7 = false;
178        this.random.setSeed(this.worldObj.getSeed());
179        long var8 = this.random.nextLong() / 2L * 2L + 1L;
180        long var10 = this.random.nextLong() / 2L * 2L + 1L;
181        this.random.setSeed((long)par2 * var8 + (long)par3 * var10 ^ this.worldObj.getSeed());
182        Iterator var12 = this.structureGenerators.iterator();
183
184        while (var12.hasNext())
185        {
186            MapGenStructure var13 = (MapGenStructure)var12.next();
187            boolean var14 = var13.generateStructuresInChunk(this.worldObj, this.random, par2, par3);
188
189            if (var13 instanceof MapGenVillage)
190            {
191                var7 |= var14;
192            }
193        }
194
195        int var17;
196        int var16;
197        int var18;
198
199        if (this.waterLakeGenerator != null && !var7 && this.random.nextInt(4) == 0)
200        {
201            var16 = var4 + this.random.nextInt(16) + 8;
202            var17 = this.random.nextInt(128);
203            var18 = var5 + this.random.nextInt(16) + 8;
204            this.waterLakeGenerator.generate(this.worldObj, this.random, var16, var17, var18);
205        }
206
207        if (this.lavaLakeGenerator != null && !var7 && this.random.nextInt(8) == 0)
208        {
209            var16 = var4 + this.random.nextInt(16) + 8;
210            var17 = this.random.nextInt(this.random.nextInt(120) + 8);
211            var18 = var5 + this.random.nextInt(16) + 8;
212
213            if (var17 < 63 || this.random.nextInt(10) == 0)
214            {
215                this.lavaLakeGenerator.generate(this.worldObj, this.random, var16, var17, var18);
216            }
217        }
218
219        if (this.field_82702_h)
220        {
221            for (var16 = 0; var16 < 8; ++var16)
222            {
223                var17 = var4 + this.random.nextInt(16) + 8;
224                var18 = this.random.nextInt(128);
225                int var15 = var5 + this.random.nextInt(16) + 8;
226                (new WorldGenDungeons()).generate(this.worldObj, this.random, var17, var18, var15);
227            }
228        }
229
230        if (this.field_82697_g)
231        {
232            var6.decorate(this.worldObj, this.random, var4, var5);
233        }
234    }
235
236    /**
237     * Two modes of operation: if passed true, save all Chunks in one go.  If passed false, save up to two chunks.
238     * Return true if all chunks have been saved.
239     */
240    public boolean saveChunks(boolean par1, IProgressUpdate par2IProgressUpdate)
241    {
242        return true;
243    }
244
245    /**
246     * Unloads the 100 oldest chunks from memory, due to a bug with chunkSet.add() never being called it thinks the list
247     * is always empty and will not remove any chunks.
248     */
249    public boolean unload100OldestChunks()
250    {
251        return false;
252    }
253
254    /**
255     * Returns if the IChunkProvider supports saving.
256     */
257    public boolean canSave()
258    {
259        return true;
260    }
261
262    /**
263     * Converts the instance data to a readable string.
264     */
265    public String makeString()
266    {
267        return "FlatLevelSource";
268    }
269
270    /**
271     * Returns a list of creatures of the specified type that can spawn at the given location.
272     */
273    public List getPossibleCreatures(EnumCreatureType par1EnumCreatureType, int par2, int par3, int par4)
274    {
275        BiomeGenBase var5 = this.worldObj.getBiomeGenForCoords(par2, par4);
276        return var5 == null ? null : var5.getSpawnableList(par1EnumCreatureType);
277    }
278
279    /**
280     * Returns the location of the closest structure of the specified type. If not found returns null.
281     */
282    public ChunkPosition findClosestStructure(World par1World, String par2Str, int par3, int par4, int par5)
283    {
284        if ("Stronghold".equals(par2Str))
285        {
286            Iterator var6 = this.structureGenerators.iterator();
287
288            while (var6.hasNext())
289            {
290                MapGenStructure var7 = (MapGenStructure)var6.next();
291
292                if (var7 instanceof MapGenStronghold)
293                {
294                    return var7.getNearestInstance(par1World, par3, par4, par5);
295                }
296            }
297        }
298
299        return null;
300    }
301
302    public int getLoadedChunkCount()
303    {
304        return 0;
305    }
306
307    public void recreateStructures(int par1, int par2)
308    {
309        Iterator var3 = this.structureGenerators.iterator();
310
311        while (var3.hasNext())
312        {
313            MapGenStructure var4 = (MapGenStructure)var3.next();
314            var4.generate(this, this.worldObj, par1, par2, (byte[])null);
315        }
316    }
317}