001package net.minecraftforge.common;
002
003import java.util.*;
004import net.minecraft.world.biome.*;
005import static net.minecraft.world.biome.BiomeGenBase.*;
006import static net.minecraftforge.common.BiomeDictionary.Type.*;
007
008public class BiomeDictionary
009{
010    public enum Type
011    {
012        FOREST,
013        PLAINS,
014        MOUNTAIN,
015        HILLS,
016        SWAMP,
017        WATER,
018        DESERT,
019        FROZEN,
020        JUNGLE,
021        WASTELAND,
022        BEACH,
023        NETHER,
024        END,
025        MUSHROOM,
026        MAGICAL;
027    }
028
029    private static final int BIOME_LIST_SIZE = 256;
030    private static BiomeInfo[] biomeList = new BiomeInfo[BIOME_LIST_SIZE];
031    private static ArrayList<BiomeGenBase>[] typeInfoList = new ArrayList[Type.values().length];
032
033    private static class BiomeInfo
034    {
035        public EnumSet<Type> typeList;
036
037        public BiomeInfo(Type[] types)
038        {
039            typeList = EnumSet.noneOf(Type.class);
040            for(Type t : types)
041            {
042                typeList.add(t);
043            }
044        }
045    }
046
047    static
048    {
049        registerVanillaBiomes();
050    }
051
052    /**
053     * Registers a biome with a specific biome type
054     * 
055     * @param biome the biome to be registered
056     * @param type the type to register the biome as
057     * @return returns true if the biome was registered successfully
058     */
059    public static boolean registerBiomeType(BiomeGenBase biome, Type ... types)
060    {   
061        if(BiomeGenBase.biomeList[biome.biomeID] != null)
062        {
063            for(Type type : types)
064            {
065                if(typeInfoList[type.ordinal()] == null)
066                {
067                    typeInfoList[type.ordinal()] = new ArrayList<BiomeGenBase>();
068                }
069
070                typeInfoList[type.ordinal()].add(biome);
071            }
072
073            if(biomeList[biome.biomeID] == null)
074            {
075                biomeList[biome.biomeID] = new BiomeInfo(types);
076            }
077            else
078            {
079                for(Type type : types)
080                {
081                    biomeList[biome.biomeID].typeList.add(type);
082                }
083            }
084
085            return true;
086        }
087
088        return false;
089    }
090
091    /**
092     * Returns a list of biomes registered with a specific type
093     * 
094     * @param type the Type to look for
095     * @return a list of biomes of the specified type, null if there are none
096     */
097    public static BiomeGenBase[] getBiomesForType(Type type)
098    {
099        if(typeInfoList[type.ordinal()] != null)
100        {
101            return (BiomeGenBase[])typeInfoList[type.ordinal()].toArray(new BiomeGenBase[0]);
102        }
103
104        return new BiomeGenBase[0];
105    }
106
107    /**
108     * Gets a list of Types that a specific biome is registered with
109     * 
110     * @param biome the biome to check
111     * @return the list of types, null if there are none
112     */
113    public static Type[] getTypesForBiome(BiomeGenBase biome)
114    {
115        checkRegistration(biome);
116
117        if(biomeList[biome.biomeID] != null)
118        {
119            return (Type[])biomeList[biome.biomeID].typeList.toArray(new Type[0]);
120        }
121
122        return new Type[0];
123    }
124
125    /**
126     * Checks to see if two biomes are registered as having the same type
127     * 
128     * @param biomeA
129     * @param biomeB
130     * @return returns true if a common type is found, false otherwise
131     */
132    public static boolean areBiomesEquivalent(BiomeGenBase biomeA, BiomeGenBase biomeB)
133    {
134        int a = biomeA.biomeID;
135        int b = biomeB.biomeID;
136
137        checkRegistration(biomeA);
138        checkRegistration(biomeB);
139
140        if(biomeList[a] != null && biomeList[b] != null)
141        {
142            for(Type type : biomeList[a].typeList)
143            {
144                if(containsType(biomeList[b], type))
145                {
146                    return true;
147                }
148            }
149        }
150
151        return false;
152    }
153
154    /**
155     * Checks to see if the given biome is registered as being a specific type
156     * 
157     * @param biome the biome to be considered
158     * @param type the type to check for
159     * @return returns true if the biome is registered as being of type type, false otherwise
160     */
161    public static boolean isBiomeOfType(BiomeGenBase biome, Type type)
162    {
163        checkRegistration(biome);
164
165        if(biomeList[biome.biomeID] != null)
166        {
167            return containsType(biomeList[biome.biomeID], type);
168        }
169
170        return false;
171    }
172
173    /**
174     * Checks to see if the given biome has been registered as being of any type
175     * @param biome the biome to consider
176     * @return returns true if the biome has been registered, false otherwise
177     */
178    public static boolean isBiomeRegistered(BiomeGenBase biome)
179    {    
180        return biomeList[biome.biomeID] != null;
181    }
182
183    public static boolean isBiomeRegistered(int biomeID)
184    {
185        return biomeList[biomeID] != null;
186    }
187
188    /**
189     * Loops through the biome list and automatically adds tags to any biome that does not have any
190     * This should be called in postInit to make sure all biomes have been registered
191     * 
192     * DO NOT call this during world generation
193     */
194    public static void registerAllBiomes()
195    {
196        for(int i = 0; i < BIOME_LIST_SIZE; i++)
197        {
198            if(BiomeGenBase.biomeList[i] != null)
199            {
200                checkRegistration(BiomeGenBase.biomeList[i]);
201            }
202        }
203    }
204
205    /**
206     * Automatically looks for and registers a given biome with appropriate tags
207     * This method is called automatically if a biome has not been registered with any tags,
208     * And another method requests information about it
209     * 
210     * NOTE: You can opt out of having your biome registered by registering it as type NULL
211     * 
212     * @param biome the biome to be considered
213     */
214    public static void makeBestGuess(BiomeGenBase biome)
215    {    
216        if(biome.theBiomeDecorator.treesPerChunk >= 3)
217        {
218            if(biome.isHighHumidity() && biome.temperature >= 1.0F)
219            {
220                BiomeDictionary.registerBiomeType(biome, JUNGLE);
221            }
222            else if(!biome.isHighHumidity())
223            {
224                BiomeDictionary.registerBiomeType(biome, FOREST);
225            }
226        }
227        else if(biome.maxHeight <= 0.3F && biome.maxHeight >= 0.0F)
228        {
229            if(!biome.isHighHumidity() || biome.minHeight >= 0.0F)
230            {
231                BiomeDictionary.registerBiomeType(biome, PLAINS);
232            }
233        }
234
235        if(biome.isHighHumidity() && biome.minHeight < 0.0F && (biome.maxHeight <= 0.3F && biome.maxHeight >= 0.0F))
236        {
237            BiomeDictionary.registerBiomeType(biome, SWAMP);
238        }
239
240        if(biome.minHeight <= -0.5F)
241        {
242            BiomeDictionary.registerBiomeType(biome, WATER);
243        }
244
245        if(biome.maxHeight >= 1.5F)
246        {
247            BiomeDictionary.registerBiomeType(biome, MOUNTAIN);
248        }
249        
250        if(biome.getEnableSnow() || biome.temperature < 0.2F)
251        {
252            BiomeDictionary.registerBiomeType(biome, FROZEN);
253        }
254        
255        if(!biome.isHighHumidity() && biome.temperature >= 1.0F)
256        {
257            BiomeDictionary.registerBiomeType(biome, DESERT);
258        }
259    }
260
261    //Internal implementation    
262    private static void checkRegistration(BiomeGenBase biome)
263    {
264        if(!isBiomeRegistered(biome))
265        {
266            makeBestGuess(biome);
267        }
268    }
269
270    private static boolean containsType(BiomeInfo info, Type type)
271    {
272        return info.typeList.contains(type);
273    }
274
275    private static void registerVanillaBiomes()
276    {
277        registerBiomeType(ocean,               WATER          );
278        registerBiomeType(plains,              PLAINS         );
279        registerBiomeType(desert,              DESERT         );
280        registerBiomeType(extremeHills,        MOUNTAIN       );
281        registerBiomeType(forest,              FOREST         );
282        registerBiomeType(taiga,               FOREST,  FROZEN);
283        registerBiomeType(taigaHills,          FOREST,  FROZEN);
284        registerBiomeType(swampland,           SWAMP          );
285        registerBiomeType(river,               WATER          );
286        registerBiomeType(frozenOcean,         WATER,   FROZEN);
287        registerBiomeType(frozenRiver,         WATER,   FROZEN);
288        registerBiomeType(icePlains,           FROZEN         );
289        registerBiomeType(iceMountains,        FROZEN         );
290        registerBiomeType(beach,               BEACH          );
291        registerBiomeType(desertHills,         DESERT         );
292        registerBiomeType(jungle,              JUNGLE         );
293        registerBiomeType(jungleHills,         JUNGLE         );
294        registerBiomeType(forestHills,         FOREST         );
295        registerBiomeType(sky,                 END            );
296        registerBiomeType(hell,                NETHER         );
297        registerBiomeType(mushroomIsland,      MUSHROOM       );
298        registerBiomeType(extremeHillsEdge,    MOUNTAIN       );
299        registerBiomeType(mushroomIslandShore, MUSHROOM, BEACH);
300    }
301}