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 map = this.field_82699_e.getWorldFeatures();
047
048            if (map.containsKey("village"))
049            {
050                Map map1 = (Map)map.get("village");
051
052                if (!map1.containsKey("size"))
053                {
054                    map1.put("size", "1");
055                }
056
057                this.structureGenerators.add(new MapGenVillage(map1));
058            }
059
060            if (map.containsKey("biome_1"))
061            {
062                this.structureGenerators.add(new MapGenScatteredFeature((Map)map.get("biome_1")));
063            }
064
065            if (map.containsKey("mineshaft"))
066            {
067                this.structureGenerators.add(new MapGenMineshaft((Map)map.get("mineshaft")));
068            }
069
070            if (map.containsKey("stronghold"))
071            {
072                this.structureGenerators.add(new MapGenStronghold((Map)map.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 iterator = this.field_82699_e.getFlatLayers().iterator();
090
091        while (iterator.hasNext())
092        {
093            FlatLayerInfo flatlayerinfo = (FlatLayerInfo)iterator.next();
094
095            for (int j = flatlayerinfo.getMinY(); j < flatlayerinfo.getMinY() + flatlayerinfo.getLayerCount(); ++j)
096            {
097                this.field_82700_c[j] = (byte)(flatlayerinfo.getFillBlock() & 255);
098                this.field_82698_d[j] = (byte)flatlayerinfo.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 chunk = new Chunk(this.worldObj, par1, par2);
118
119        for (int k = 0; k < this.field_82700_c.length; ++k)
120        {
121            int l = k >> 4;
122            ExtendedBlockStorage extendedblockstorage = chunk.getBlockStorageArray()[l];
123
124            if (extendedblockstorage == null)
125            {
126                extendedblockstorage = new ExtendedBlockStorage(k, !this.worldObj.provider.hasNoSky);
127                chunk.getBlockStorageArray()[l] = extendedblockstorage;
128            }
129
130            for (int i1 = 0; i1 < 16; ++i1)
131            {
132                for (int j1 = 0; j1 < 16; ++j1)
133                {
134                    extendedblockstorage.setExtBlockID(i1, k & 15, j1, this.field_82700_c[k] & 255);
135                    extendedblockstorage.setExtBlockMetadata(i1, k & 15, j1, this.field_82698_d[k]);
136                }
137            }
138        }
139
140        chunk.generateSkylightMap();
141        BiomeGenBase[] abiomegenbase = this.worldObj.getWorldChunkManager().loadBlockGeneratorData((BiomeGenBase[])null, par1 * 16, par2 * 16, 16, 16);
142        byte[] abyte = chunk.getBiomeArray();
143
144        for (int k1 = 0; k1 < abyte.length; ++k1)
145        {
146            abyte[k1] = (byte)abiomegenbase[k1].biomeID;
147        }
148
149        Iterator iterator = this.structureGenerators.iterator();
150
151        while (iterator.hasNext())
152        {
153            MapGenStructure mapgenstructure = (MapGenStructure)iterator.next();
154            mapgenstructure.generate(this, this.worldObj, par1, par2, (byte[])null);
155        }
156
157        chunk.generateSkylightMap();
158        return chunk;
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 k = par2 * 16;
175        int l = par3 * 16;
176        BiomeGenBase biomegenbase = this.worldObj.getBiomeGenForCoords(k + 16, l + 16);
177        boolean flag = false;
178        this.random.setSeed(this.worldObj.getSeed());
179        long i1 = this.random.nextLong() / 2L * 2L + 1L;
180        long j1 = this.random.nextLong() / 2L * 2L + 1L;
181        this.random.setSeed((long)par2 * i1 + (long)par3 * j1 ^ this.worldObj.getSeed());
182        Iterator iterator = this.structureGenerators.iterator();
183
184        while (iterator.hasNext())
185        {
186            MapGenStructure mapgenstructure = (MapGenStructure)iterator.next();
187            boolean flag1 = mapgenstructure.generateStructuresInChunk(this.worldObj, this.random, par2, par3);
188
189            if (mapgenstructure instanceof MapGenVillage)
190            {
191                flag |= flag1;
192            }
193        }
194
195        int k1;
196        int l1;
197        int i2;
198
199        if (this.waterLakeGenerator != null && !flag && this.random.nextInt(4) == 0)
200        {
201            l1 = k + this.random.nextInt(16) + 8;
202            k1 = this.random.nextInt(128);
203            i2 = l + this.random.nextInt(16) + 8;
204            this.waterLakeGenerator.generate(this.worldObj, this.random, l1, k1, i2);
205        }
206
207        if (this.lavaLakeGenerator != null && !flag && this.random.nextInt(8) == 0)
208        {
209            l1 = k + this.random.nextInt(16) + 8;
210            k1 = this.random.nextInt(this.random.nextInt(120) + 8);
211            i2 = l + this.random.nextInt(16) + 8;
212
213            if (k1 < 63 || this.random.nextInt(10) == 0)
214            {
215                this.lavaLakeGenerator.generate(this.worldObj, this.random, l1, k1, i2);
216            }
217        }
218
219        if (this.field_82702_h)
220        {
221            for (l1 = 0; l1 < 8; ++l1)
222            {
223                k1 = k + this.random.nextInt(16) + 8;
224                i2 = this.random.nextInt(128);
225                int j2 = l + this.random.nextInt(16) + 8;
226                (new WorldGenDungeons()).generate(this.worldObj, this.random, k1, i2, j2);
227            }
228        }
229
230        if (this.field_82697_g)
231        {
232            biomegenbase.decorate(this.worldObj, this.random, k, l);
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 chunks that are marked to be unloaded. This is not guaranteed to unload every such chunk.
247     */
248    public boolean unloadQueuedChunks()
249    {
250        return false;
251    }
252
253    /**
254     * Returns if the IChunkProvider supports saving.
255     */
256    public boolean canSave()
257    {
258        return true;
259    }
260
261    /**
262     * Converts the instance data to a readable string.
263     */
264    public String makeString()
265    {
266        return "FlatLevelSource";
267    }
268
269    /**
270     * Returns a list of creatures of the specified type that can spawn at the given location.
271     */
272    public List getPossibleCreatures(EnumCreatureType par1EnumCreatureType, int par2, int par3, int par4)
273    {
274        BiomeGenBase biomegenbase = this.worldObj.getBiomeGenForCoords(par2, par4);
275        return biomegenbase == null ? null : biomegenbase.getSpawnableList(par1EnumCreatureType);
276    }
277
278    /**
279     * Returns the location of the closest structure of the specified type. If not found returns null.
280     */
281    public ChunkPosition findClosestStructure(World par1World, String par2Str, int par3, int par4, int par5)
282    {
283        if ("Stronghold".equals(par2Str))
284        {
285            Iterator iterator = this.structureGenerators.iterator();
286
287            while (iterator.hasNext())
288            {
289                MapGenStructure mapgenstructure = (MapGenStructure)iterator.next();
290
291                if (mapgenstructure instanceof MapGenStronghold)
292                {
293                    return mapgenstructure.getNearestInstance(par1World, par3, par4, par5);
294                }
295            }
296        }
297
298        return null;
299    }
300
301    public int getLoadedChunkCount()
302    {
303        return 0;
304    }
305
306    public void recreateStructures(int par1, int par2)
307    {
308        Iterator iterator = this.structureGenerators.iterator();
309
310        while (iterator.hasNext())
311        {
312            MapGenStructure mapgenstructure = (MapGenStructure)iterator.next();
313            mapgenstructure.generate(this, this.worldObj, par1, par2, (byte[])null);
314        }
315    }
316}