2016-06-22 23:49:47 -04:00
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
2013-04-04 17:55:35 -07:00
package net.minecraftforge.common ;
import java.util.* ;
2013-09-05 10:08:02 -04:00
2014-11-25 19:56:35 -08:00
import net.minecraftforge.fml.common.FMLLog ;
2016-04-09 18:03:46 -05:00
import net.minecraft.init.Biomes ;
2014-07-01 12:46:00 +10:00
import net.minecraft.init.Blocks ;
2016-03-03 18:07:18 +11:00
import net.minecraft.util.ResourceLocation ;
2013-04-04 17:55:35 -07:00
import net.minecraft.world.biome.* ;
2014-07-07 21:29:37 -07:00
import net.minecraftforge.common.util.EnumHelper ;
2013-09-05 10:08:02 -04:00
import net.minecraftforge.event.terraingen.DeferredBiomeDecorator ;
2013-04-04 17:55:35 -07:00
import static net.minecraftforge.common.BiomeDictionary.Type.* ;
public class BiomeDictionary
{
public enum Type
{
2014-07-01 12:46:00 +10:00
/*Temperature-based tags. Specifying neither implies a biome is temperate*/
HOT ,
COLD ,
/*Tags specifying the amount of vegetation a biome has. Specifying neither implies a biome to have moderate amounts*/
SPARSE ,
DENSE ,
/*Tags specifying how moist a biome is. Specifying neither implies the biome as having moderate humidity*/
WET ,
DRY ,
/*Tree-based tags, SAVANNA refers to dry, desert-like trees (Such as Acacia), CONIFEROUS refers to snowy trees (Such as Spruce) and JUNGLE refers to jungle trees.
* Specifying no tag implies a biome has temperate trees (Such as Oak)*/
SAVANNA ,
CONIFEROUS ,
JUNGLE ,
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
/*Tags specifying the nature of a biome*/
SPOOKY ,
DEAD ,
LUSH ,
NETHER ,
END ,
MUSHROOM ,
MAGICAL ,
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
OCEAN ,
RIVER ,
/**A general tag for all water-based biomes. Shown as present if OCEAN or RIVER are.**/
WATER ( OCEAN , RIVER ),
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
/*Generic types which a biome can be*/
MESA ,
2013-04-04 17:55:35 -07:00
FOREST ,
PLAINS ,
MOUNTAIN ,
HILLS ,
SWAMP ,
2014-07-01 12:46:00 +10:00
SANDY ,
SNOWY ,
2013-04-04 17:55:35 -07:00
WASTELAND ,
2016-03-03 18:07:18 +11:00
BEACH ;
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
private List < Type > subTags ;
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
private Type ( Type ... subTags )
{
this . subTags = Arrays . asList ( subTags );
}
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
private boolean hasSubTags ()
{
return subTags != null && ! subTags . isEmpty ();
}
2014-07-07 21:29:37 -07:00
/**
* Retrieves a Type value by name,
* if one does not exist already it creates one.
2016-03-23 17:34:48 +03:00
* This can be used as intermediate measure for modders to
* add their own category of Biome.
2014-07-07 21:29:37 -07:00
*
* There are NO naming conventions besides:
* MUST be all upper case (enforced by name.toUpper())
* NO Special characters. {Unenforced, just don't be a pain, if it becomes a issue I WILL
* make this RTE with no worry about backwards compatibility}
*
* Note: For performance sake, the return value of this function SHOULD be cached.
* Two calls with the same name SHOULD return the same value.
*
*
* @param name The name of this Type
* @return An instance of Type for this name.
*/
public static Type getType ( String name , Type ... subTypes )
{
name = name . toUpperCase ();
for ( Type t : values ())
{
if ( t . name (). equals ( name ))
return t ;
}
2014-08-14 20:33:23 -07:00
Type ret = EnumHelper . addEnum ( Type . class , name , new Class [] { Type [] . class }, new Object [] { subTypes });
if ( ret . ordinal () >= typeInfoList . length )
{
2015-06-12 17:08:19 -07:00
typeInfoList = Arrays . copyOf ( typeInfoList , ret . ordinal () + 1 );
}
2016-03-03 18:07:18 +11:00
for ( BiomeInfo bInfo : biomeInfoMap . values ())
2015-06-12 17:08:19 -07:00
{
if ( bInfo != null )
{
EnumSet < Type > oldSet = bInfo . typeList ;
bInfo . typeList = EnumSet . noneOf ( Type . class );
bInfo . typeList . addAll ( oldSet );
}
2014-08-14 20:33:23 -07:00
}
return ret ;
2014-07-07 21:29:37 -07:00
}
2013-04-04 17:55:35 -07:00
}
2016-03-03 18:07:18 +11:00
private static HashMap < ResourceLocation , BiomeInfo > biomeInfoMap = new HashMap < ResourceLocation , BiomeInfo > ();
2014-01-17 21:55:48 -08:00
@SuppressWarnings ( "unchecked" )
2016-05-18 03:29:10 -07:00
private static ArrayList < Biome >[] typeInfoList = new ArrayList [ Type . values (). length ] ;
2013-04-04 17:55:35 -07:00
private static class BiomeInfo
{
public EnumSet < Type > typeList ;
public BiomeInfo ( Type [] types )
{
typeList = EnumSet . noneOf ( Type . class );
for ( Type t : types )
{
typeList . add ( t );
}
}
}
static
{
registerVanillaBiomes ();
}
/**
* Registers a biome with a specific biome type
2014-07-07 21:29:37 -07:00
*
2013-04-04 17:55:35 -07:00
* @param biome the biome to be registered
2016-05-29 14:05:07 -07:00
* @param types the types to register the biome as
2013-04-04 17:55:35 -07:00
* @return returns true if the biome was registered successfully
*/
2016-05-18 03:29:10 -07:00
public static boolean registerBiomeType ( Biome biome , Type ... types )
2014-07-07 21:29:37 -07:00
{
2014-07-01 12:46:00 +10:00
types = listSubTags ( types );
2014-07-07 21:29:37 -07:00
2016-05-18 05:11:56 -07:00
if ( Biome . REGISTRY . getNameForObject ( biome ) != null )
2013-04-04 17:55:35 -07:00
{
for ( Type type : types )
{
if ( typeInfoList [ type . ordinal () ] == null )
{
2016-05-18 03:29:10 -07:00
typeInfoList [ type . ordinal () ] = new ArrayList < Biome > ();
2013-04-04 17:55:35 -07:00
}
typeInfoList [ type . ordinal () ] . add ( biome );
}
2016-03-03 18:07:18 +11:00
if ( ! isBiomeRegistered ( biome ))
2013-04-04 17:55:35 -07:00
{
2016-05-18 05:11:56 -07:00
ResourceLocation location = Biome . REGISTRY . getNameForObject ( biome );
2016-03-03 18:07:18 +11:00
biomeInfoMap . put ( location , new BiomeInfo ( types ));
2013-04-04 17:55:35 -07:00
}
else
{
for ( Type type : types )
{
2016-03-03 18:07:18 +11:00
getBiomeInfo ( biome ). typeList . add ( type );
2013-04-04 17:55:35 -07:00
}
}
return true ;
}
return false ;
}
/**
* Returns a list of biomes registered with a specific type
2014-07-07 21:29:37 -07:00
*
2013-04-04 17:55:35 -07:00
* @param type the Type to look for
* @return a list of biomes of the specified type, null if there are none
*/
2016-05-18 03:29:10 -07:00
public static Biome [] getBiomesForType ( Type type )
2013-04-04 17:55:35 -07:00
{
if ( typeInfoList [ type . ordinal () ] != null )
{
2016-05-18 03:29:10 -07:00
return typeInfoList [ type . ordinal () ] . toArray ( new Biome [ 0 ] );
2013-04-04 17:55:35 -07:00
}
2016-05-18 03:29:10 -07:00
return new Biome [ 0 ] ;
2013-04-04 17:55:35 -07:00
}
/**
* Gets a list of Types that a specific biome is registered with
2014-07-07 21:29:37 -07:00
*
2013-04-04 17:55:35 -07:00
* @param biome the biome to check
* @return the list of types, null if there are none
*/
2016-05-18 03:29:10 -07:00
public static Type [] getTypesForBiome ( Biome biome )
2013-04-04 17:55:35 -07:00
{
2016-05-18 03:29:10 -07:00
checkRegistration ( biome );
return getBiomeInfo ( biome ). typeList . toArray ( new Type [ 0 ] );
2013-04-04 17:55:35 -07:00
}
/**
* Checks to see if two biomes are registered as having the same type
2014-07-07 21:29:37 -07:00
*
2013-04-04 17:55:35 -07:00
* @param biomeA
* @param biomeB
* @return returns true if a common type is found, false otherwise
*/
2016-05-18 03:29:10 -07:00
public static boolean areBiomesEquivalent ( Biome biomeA , Biome biomeB )
2013-04-04 17:55:35 -07:00
{
checkRegistration ( biomeA );
checkRegistration ( biomeB );
2016-03-03 18:07:18 +11:00
for ( Type type : getTypesForBiome ( biomeA ))
2013-04-04 17:55:35 -07:00
{
2016-05-18 03:29:10 -07:00
if ( containsType ( getBiomeInfo ( biomeB ), type ))
{
return true ;
}
2013-04-04 17:55:35 -07:00
}
return false ;
}
/**
* Checks to see if the given biome is registered as being a specific type
2014-07-07 21:29:37 -07:00
*
2013-04-04 17:55:35 -07:00
* @param biome the biome to be considered
* @param type the type to check for
* @return returns true if the biome is registered as being of type type, false otherwise
*/
2016-05-18 03:29:10 -07:00
public static boolean isBiomeOfType ( Biome biome , Type type )
2013-04-04 17:55:35 -07:00
{
checkRegistration ( biome );
2016-03-03 18:07:18 +11:00
return containsType ( getBiomeInfo ( biome ), type );
2013-04-04 17:55:35 -07:00
}
/**
* Checks to see if the given biome has been registered as being of any type
* @param biome the biome to consider
* @return returns true if the biome has been registered, false otherwise
*/
2016-05-18 03:29:10 -07:00
public static boolean isBiomeRegistered ( Biome biome )
2014-07-07 21:29:37 -07:00
{
2016-05-18 05:11:56 -07:00
return biomeInfoMap . containsKey ( Biome . REGISTRY . getNameForObject ( biome ));
2013-04-04 17:55:35 -07:00
}
2013-09-05 10:08:02 -04:00
public static void registerAllBiomes ()
{
FMLLog . warning ( "Redundant call to BiomeDictionary.registerAllBiomes ignored" );
}
2013-04-04 17:55:35 -07:00
/**
* Loops through the biome list and automatically adds tags to any biome that does not have any
2013-09-05 10:08:02 -04:00
* This is called by Forge at postinit time. It will additionally dispatch any deferred decorator
* creation events.
2014-07-07 21:29:37 -07:00
*
2013-04-04 17:55:35 -07:00
* DO NOT call this during world generation
*/
2013-09-05 10:08:02 -04:00
public static void registerAllBiomesAndGenerateEvents ()
2013-04-04 17:55:35 -07:00
{
2016-05-18 05:11:56 -07:00
for ( ResourceLocation biomeResource : Biome . REGISTRY . getKeys ())
2016-05-18 03:29:10 -07:00
{
2016-05-18 05:11:56 -07:00
Biome biome = Biome . REGISTRY . getObject ( biomeResource );
2016-05-18 03:29:10 -07:00
2013-09-05 10:08:02 -04:00
if ( biome . theBiomeDecorator instanceof DeferredBiomeDecorator )
{
DeferredBiomeDecorator decorator = ( DeferredBiomeDecorator ) biome . theBiomeDecorator ;
2013-12-21 00:10:35 -08:00
decorator . fireCreateEventAndReplace ( biome );
2013-09-05 10:08:02 -04:00
}
2013-10-19 18:31:32 -07:00
checkRegistration ( biome );
2013-04-04 17:55:35 -07:00
}
}
/**
* Automatically looks for and registers a given biome with appropriate tags
* This method is called automatically if a biome has not been registered with any tags,
* And another method requests information about it
2014-07-07 21:29:37 -07:00
*
2013-04-04 17:55:35 -07:00
* @param biome the biome to be considered
*/
2016-05-18 03:29:10 -07:00
public static void makeBestGuess ( Biome biome )
2014-07-07 21:29:37 -07:00
{
2014-07-01 12:46:00 +10:00
if ( biome . theBiomeDecorator . treesPerChunk >= 3 )
2013-04-04 17:55:35 -07:00
{
2016-03-13 04:40:03 +03:00
if ( biome . isHighHumidity () && biome . getTemperature () >= 0 . 9F )
2013-04-04 17:55:35 -07:00
{
BiomeDictionary . registerBiomeType ( biome , JUNGLE );
}
2014-07-01 12:46:00 +10:00
else if ( ! biome . isHighHumidity ())
2013-04-04 17:55:35 -07:00
{
BiomeDictionary . registerBiomeType ( biome , FOREST );
2014-07-01 12:46:00 +10:00
2016-03-13 04:40:03 +03:00
if ( biome . getTemperature () <= 0 . 2f )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , CONIFEROUS );
}
2013-04-04 17:55:35 -07:00
}
}
2016-03-13 04:40:03 +03:00
else if ( biome . getHeightVariation () <= 0 . 3F && biome . getHeightVariation () >= 0 . 0F )
2013-04-04 17:55:35 -07:00
{
2016-03-13 04:40:03 +03:00
if ( ! biome . isHighHumidity () || biome . getBaseHeight () >= 0 . 0F )
2013-04-04 17:55:35 -07:00
{
BiomeDictionary . registerBiomeType ( biome , PLAINS );
}
}
2016-03-13 04:40:03 +03:00
if ( biome . getRainfall () > 0 . 85f )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , WET );
}
2016-03-13 04:40:03 +03:00
if ( biome . getRainfall () < 0 . 15f )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , DRY );
}
2016-03-13 04:40:03 +03:00
if ( biome . getTemperature () > 0 . 85f )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , HOT );
}
2016-03-13 04:40:03 +03:00
if ( biome . getTemperature () < 0 . 15f )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , COLD );
}
if ( biome . theBiomeDecorator . treesPerChunk > 0 && biome . theBiomeDecorator . treesPerChunk < 3 )
{
BiomeDictionary . registerBiomeType ( biome , SPARSE );
}
else if ( biome . theBiomeDecorator . treesPerChunk >= 10 )
{
BiomeDictionary . registerBiomeType ( biome , DENSE );
}
2016-03-13 04:40:03 +03:00
if ( biome . isHighHumidity () && biome . getBaseHeight () < 0 . 0F && ( biome . getHeightVariation () <= 0 . 3F && biome . getHeightVariation () >= 0 . 0F ))
2013-04-04 17:55:35 -07:00
{
BiomeDictionary . registerBiomeType ( biome , SWAMP );
}
2016-03-13 04:40:03 +03:00
if ( biome . getBaseHeight () <= - 0 . 5F )
2013-04-04 17:55:35 -07:00
{
2016-03-13 04:40:03 +03:00
if ( biome . getHeightVariation () == 0 . 0F )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , RIVER );
}
else
{
BiomeDictionary . registerBiomeType ( biome , OCEAN );
}
2013-04-04 17:55:35 -07:00
}
2016-03-13 04:40:03 +03:00
if ( biome . getHeightVariation () >= 0 . 4F && biome . getHeightVariation () < 1 . 5F )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , HILLS );
}
2016-03-13 04:40:03 +03:00
if ( biome . getHeightVariation () >= 1 . 5F )
2013-04-04 17:55:35 -07:00
{
BiomeDictionary . registerBiomeType ( biome , MOUNTAIN );
}
2014-07-01 12:46:00 +10:00
if ( biome . getEnableSnow ())
2013-04-04 17:55:35 -07:00
{
2014-07-01 12:46:00 +10:00
BiomeDictionary . registerBiomeType ( biome , SNOWY );
2013-04-04 17:55:35 -07:00
}
2014-07-01 12:46:00 +10:00
2016-05-18 05:11:56 -07:00
if ( biome . topBlock != Blocks . SAND && biome . getTemperature () >= 1 . 0f && biome . getRainfall () < 0 . 2f )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , SAVANNA );
}
2016-05-18 05:11:56 -07:00
if ( biome . topBlock == Blocks . SAND )
2013-04-04 17:55:35 -07:00
{
2014-07-01 12:46:00 +10:00
BiomeDictionary . registerBiomeType ( biome , SANDY );
}
2016-05-18 05:11:56 -07:00
else if ( biome . topBlock == Blocks . MYCELIUM )
2014-07-01 12:46:00 +10:00
{
BiomeDictionary . registerBiomeType ( biome , MUSHROOM );
2013-04-04 17:55:35 -07:00
}
2016-05-18 05:11:56 -07:00
if ( biome . fillerBlock == Blocks . HARDENED_CLAY )
2015-06-19 07:04:19 -07:00
{
BiomeDictionary . registerBiomeType ( biome , MESA );
}
2013-04-04 17:55:35 -07:00
}
2014-07-07 21:29:37 -07:00
//Internal implementation
2016-05-18 03:29:10 -07:00
private static BiomeInfo getBiomeInfo ( Biome biome )
2016-03-03 18:07:18 +11:00
{
2016-05-18 05:11:56 -07:00
return biomeInfoMap . get ( Biome . REGISTRY . getNameForObject ( biome ));
2016-03-03 18:07:18 +11:00
}
2016-05-18 03:29:10 -07:00
private static void checkRegistration ( Biome biome )
2013-04-04 17:55:35 -07:00
{
if ( ! isBiomeRegistered ( biome ))
{
makeBestGuess ( biome );
}
}
private static boolean containsType ( BiomeInfo info , Type type )
{
2014-07-01 12:46:00 +10:00
if ( type . hasSubTags ())
{
for ( Type remappedType : listSubTags ( type ))
{
if ( info . typeList . contains ( remappedType )) return true ;
}
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
return false ;
}
2014-07-07 21:29:37 -07:00
2013-04-04 17:55:35 -07:00
return info . typeList . contains ( type );
}
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
private static Type [] listSubTags ( Type ... types )
{
List < Type > subTags = new ArrayList < Type > ();
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
for ( Type type : types )
{
if ( type . hasSubTags ()) subTags . addAll ( type . subTags );
else subTags . add ( type );
}
2014-07-07 21:29:37 -07:00
2014-07-01 12:46:00 +10:00
return subTags . toArray ( new Type [ subTags . size () ] );
}
2013-04-04 17:55:35 -07:00
private static void registerVanillaBiomes ()
{
2016-05-18 05:11:56 -07:00
registerBiomeType ( Biomes . OCEAN , OCEAN );
registerBiomeType ( Biomes . PLAINS , PLAINS );
registerBiomeType ( Biomes . DESERT , HOT , DRY , SANDY );
registerBiomeType ( Biomes . EXTREME_HILLS , MOUNTAIN , HILLS );
registerBiomeType ( Biomes . FOREST , FOREST );
registerBiomeType ( Biomes . TAIGA , COLD , CONIFEROUS , FOREST );
registerBiomeType ( Biomes . TAIGA_HILLS , COLD , CONIFEROUS , FOREST , HILLS );
registerBiomeType ( Biomes . SWAMPLAND , WET , SWAMP );
registerBiomeType ( Biomes . RIVER , RIVER );
registerBiomeType ( Biomes . FROZEN_OCEAN , COLD , OCEAN , SNOWY );
registerBiomeType ( Biomes . FROZEN_RIVER , COLD , RIVER , SNOWY );
registerBiomeType ( Biomes . ICE_PLAINS , COLD , SNOWY , WASTELAND );
registerBiomeType ( Biomes . ICE_MOUNTAINS , COLD , SNOWY , MOUNTAIN );
registerBiomeType ( Biomes . BEACH , BEACH );
registerBiomeType ( Biomes . DESERT_HILLS , HOT , DRY , SANDY , HILLS );
registerBiomeType ( Biomes . JUNGLE , HOT , WET , DENSE , JUNGLE );
registerBiomeType ( Biomes . JUNGLE_HILLS , HOT , WET , DENSE , JUNGLE , HILLS );
registerBiomeType ( Biomes . FOREST_HILLS , FOREST , HILLS );
registerBiomeType ( Biomes . SKY , COLD , DRY , END );
registerBiomeType ( Biomes . HELL , HOT , DRY , NETHER );
registerBiomeType ( Biomes . MUSHROOM_ISLAND , MUSHROOM );
registerBiomeType ( Biomes . EXTREME_HILLS_EDGE , MOUNTAIN );
registerBiomeType ( Biomes . MUSHROOM_ISLAND_SHORE , MUSHROOM , BEACH );
registerBiomeType ( Biomes . JUNGLE_EDGE , HOT , WET , JUNGLE , FOREST );
registerBiomeType ( Biomes . DEEP_OCEAN , OCEAN );
registerBiomeType ( Biomes . STONE_BEACH , BEACH );
registerBiomeType ( Biomes . COLD_BEACH , COLD , BEACH , SNOWY );
registerBiomeType ( Biomes . BIRCH_FOREST , FOREST );
registerBiomeType ( Biomes . BIRCH_FOREST_HILLS , FOREST , HILLS );
registerBiomeType ( Biomes . ROOFED_FOREST , SPOOKY , DENSE , FOREST );
registerBiomeType ( Biomes . COLD_TAIGA , COLD , CONIFEROUS , FOREST , SNOWY );
registerBiomeType ( Biomes . COLD_TAIGA_HILLS , COLD , CONIFEROUS , FOREST , SNOWY , HILLS );
registerBiomeType ( Biomes . REDWOOD_TAIGA , COLD , CONIFEROUS , FOREST );
registerBiomeType ( Biomes . REDWOOD_TAIGA_HILLS , COLD , CONIFEROUS , FOREST , HILLS );
registerBiomeType ( Biomes . EXTREME_HILLS_WITH_TREES , MOUNTAIN , FOREST , SPARSE );
registerBiomeType ( Biomes . SAVANNA , HOT , SAVANNA , PLAINS , SPARSE );
registerBiomeType ( Biomes . SAVANNA_PLATEAU , HOT , SAVANNA , PLAINS , SPARSE );
registerBiomeType ( Biomes . MESA , MESA , SANDY );
registerBiomeType ( Biomes . MESA_ROCK , MESA , SPARSE , SANDY );
registerBiomeType ( Biomes . MESA_CLEAR_ROCK , MESA , SANDY );
2013-04-04 17:55:35 -07:00
}
2013-04-19 14:08:53 +03:00
}