I was looking to differentiate between Ocean and Deep Ocean by assigning a new biome Type to BiomeGenBase.deepOcean by using the following code snippet:
Type deepOcean = BiomeDictionary.Type.getType("DEEP OCEAN");
BiomeDictionary.registerBiomeType(BiomeGenBase.deepOcean, deepOcean);
However, I get this error:
java.lang.ArrayIndexOutOfBoundsException: 31
at net.minecraftforge.common.BiomeDictionary.registerBiomeType(BiomeDictionary.java:152)
...
It's like array to store the biome types isn't being resized. Anyone know the way to do this?
So apparently, if I'm reading the code correctly, you can not add new BiomeDictionary.Type's as there is a private list whose length is set.
private static ArrayList[] typeInfoList = new ArrayList[Type.values().length];
That length is not updated when calling registerBiomeType.
public static boolean registerBiomeType(BiomeGenBase biome, Type ... types)
{
types = listSubTags(types);
if(BiomeGenBase.getBiomeGenArray()[biome.biomeID] != null)
{
for(Type type : types)
{
if(typeInfoList[type.ordinal()] == null)
{
typeInfoList[type.ordinal()] = new ArrayList();
}
typeInfoList[type.ordinal()].add(biome);
}
if(biomeList[biome.biomeID] == null)
{
biomeList[biome.biomeID] = new BiomeInfo(types);
}
else
{
for(Type type : types)
{
biomeList[biome.biomeID].typeList.add(type);
}
}
return true;
}
return false;
}
My code in the first post fails at: typeInfoList[type.ordinal()].add(biome);
So, my thought was to extend the BiomeDictionary and override this method to work properly, but I didn't know if it then would still work with other mods that register new biomes?
For anyone who has this same issue, I had to create my own BiomeDictionary - basically duplication the Forge one, with some modifications. (removed all the subtype stuff and changed the registerBiomeType(). So, in short, you still add your custom Types to the Forge BiomeDictionary but you need to check both dictionary's if a biome is of a certain Type.
/**
*
* @author Mark Gottschling on Dec 29, 2014
*
*/
public class TreasureBiomeDictionary {
// the length of all the biomes
private static final int BIOME_LIST_SIZE = BiomeGenBase.getBiomeGenArray().length;
private static BiomeInfo[] biomeList = new BiomeInfo[BIOME_LIST_SIZE];
@SuppressWarnings("unchecked")
// array of arraylists for each biome.
private static ArrayList<BiomeGenBase>[] typeInfoList = new ArrayList[1];
// index of typeInfoList
private static int index = 0;
private static class BiomeInfo
{
public EnumSet<Type> typeList;
public BiomeInfo(Type[] types)
{
typeList = EnumSet.noneOf(Type.class);
for(Type t : types)
{
typeList.add(t);
}
}
}
/**
* Registers a biome with a specific biome type
*
* @param biome the biome to be registered
* @param type the type to register the biome as
* @return returns true if the biome was registered successfully
*/
public static boolean registerBiomeType(BiomeGenBase biome, Type ... types) {
if(BiomeGenBase.getBiomeGenArray()[biome.biomeID] != null) {
for(Type type : types) {
if(typeInfoList[index] == null) {
typeInfoList[index] = new ArrayList<BiomeGenBase>();
}
// add the biome
typeInfoList[index].add(biome);
// increment the index
index++;
// resize the typeInfoList array
typeInfoList = Arrays.copyOf(typeInfoList, index);
}
/**
* Returns a list of biomes registered with a specific type
*
* @param type the Type to look for
* @return a list of biomes of the specified type, null if there are none
*/
public static BiomeGenBase[] getBiomesForType(Type type) {
if(typeInfoList[type.ordinal()] != null) {
return (BiomeGenBase[])typeInfoList[type.ordinal()].toArray(new BiomeGenBase[0]);
}
return new BiomeGenBase[0];
}
/**
* Gets a list of Types that a specific biome is registered with
*
* @param biome the biome to check
* @return the list of types, null if there are none
*/
public static Type[] getTypesForBiome(BiomeGenBase biome) {
if(biomeList[biome.biomeID] != null) {
return (Type[])biomeList[biome.biomeID].typeList.toArray(new Type[0]);
}
return new Type[0];
}
/**
* Checks to see if two biomes are registered as having the same type
*
* @param biomeA
* @param biomeB
* @return returns true if a common type is found, false otherwise
*/
public static boolean areBiomesEquivalent(BiomeGenBase biomeA, BiomeGenBase biomeB) {
int a = biomeA.biomeID;
int b = biomeB.biomeID;
/**
* Checks to see if the given biome is registered as being a specific type
*
* @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
*/
public static boolean isBiomeOfType(BiomeGenBase biome, Type type) {
if(biomeList[biome.biomeID] != null) {
return containsType(biomeList[biome.biomeID], type);
}
return false;
}
/**
* 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
*/
public static boolean isBiomeRegistered(BiomeGenBase biome)
{
return biomeList[biome.biomeID] != null;
}
/**
*
*/
public static void registerAllBiomes() {
FMLLog.warning("Redundant call to TreasureBiomeDictionary.registerAllBiomes ignored");
}
/**
* Loops through the biome list and automatically adds tags to any biome that does not have any
* This is called by Forge at postinit time. It will additionally dispatch any deferred decorator
* creation events.
*
* DO NOT call this during world generation
*/
public static void registerAllBiomesAndGenerateEvents()
{
for(int i = 0; i < BiomeGenBase.getBiomeGenArray().length; i++)
{
BiomeGenBase biome = BiomeGenBase.getBiomeGenArray()[i];
However, I get this error:
It's like array to store the biome types isn't being resized. Anyone know the way to do this?
That length is not updated when calling registerBiomeType.
My code in the first post fails at: typeInfoList[type.ordinal()].add(biome);
So, my thought was to extend the BiomeDictionary and override this method to work properly, but I didn't know if it then would still work with other mods that register new biomes?
Known issue.
Publish a pull request if you are interested enough.
TreasureBiomeDictionary:
package com.someguyssoftware.treasure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraftforge.common.BiomeDictionary.Type;
import net.minecraftforge.event.terraingen.DeferredBiomeDecorator;
import cpw.mods.fml.common.FMLLog;
/**
*
* @author Mark Gottschling on Dec 29, 2014
*
*/
public class TreasureBiomeDictionary {
// the length of all the biomes
private static final int BIOME_LIST_SIZE = BiomeGenBase.getBiomeGenArray().length;
private static BiomeInfo[] biomeList = new BiomeInfo[BIOME_LIST_SIZE];
@SuppressWarnings("unchecked")
// array of arraylists for each biome.
private static ArrayList<BiomeGenBase>[] typeInfoList = new ArrayList[1];
// index of typeInfoList
private static int index = 0;
private static class BiomeInfo
{
public EnumSet<Type> typeList;
public BiomeInfo(Type[] types)
{
typeList = EnumSet.noneOf(Type.class);
for(Type t : types)
{
typeList.add(t);
}
}
}
/**
* Registers a biome with a specific biome type
*
* @param biome the biome to be registered
* @param type the type to register the biome as
* @return returns true if the biome was registered successfully
*/
public static boolean registerBiomeType(BiomeGenBase biome, Type ... types) {
if(BiomeGenBase.getBiomeGenArray()[biome.biomeID] != null) {
for(Type type : types) {
if(typeInfoList[index] == null) {
typeInfoList[index] = new ArrayList<BiomeGenBase>();
}
// add the biome
typeInfoList[index].add(biome);
// increment the index
index++;
// resize the typeInfoList array
typeInfoList = Arrays.copyOf(typeInfoList, index);
}
if(biomeList[biome.biomeID] == null) {
biomeList[biome.biomeID] = new BiomeInfo(types);
}
else {
for(Type type : types) {
biomeList[biome.biomeID].typeList.add(type);
}
}
return true;
}
return false;
}
/**
* Returns a list of biomes registered with a specific type
*
* @param type the Type to look for
* @return a list of biomes of the specified type, null if there are none
*/
public static BiomeGenBase[] getBiomesForType(Type type) {
if(typeInfoList[type.ordinal()] != null) {
return (BiomeGenBase[])typeInfoList[type.ordinal()].toArray(new BiomeGenBase[0]);
}
return new BiomeGenBase[0];
}
/**
* Gets a list of Types that a specific biome is registered with
*
* @param biome the biome to check
* @return the list of types, null if there are none
*/
public static Type[] getTypesForBiome(BiomeGenBase biome) {
if(biomeList[biome.biomeID] != null) {
return (Type[])biomeList[biome.biomeID].typeList.toArray(new Type[0]);
}
return new Type[0];
}
/**
* Checks to see if two biomes are registered as having the same type
*
* @param biomeA
* @param biomeB
* @return returns true if a common type is found, false otherwise
*/
public static boolean areBiomesEquivalent(BiomeGenBase biomeA, BiomeGenBase biomeB) {
int a = biomeA.biomeID;
int b = biomeB.biomeID;
if(biomeList[a] != null && biomeList[b] != null)
{
for(Type type : biomeList[a].typeList)
{
if(containsType(biomeList[b], type))
{
return true;
}
}
}
return false;
}
/**
* Checks to see if the given biome is registered as being a specific type
*
* @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
*/
public static boolean isBiomeOfType(BiomeGenBase biome, Type type) {
if(biomeList[biome.biomeID] != null) {
return containsType(biomeList[biome.biomeID], type);
}
return false;
}
/**
* 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
*/
public static boolean isBiomeRegistered(BiomeGenBase biome)
{
return biomeList[biome.biomeID] != null;
}
/**
*
* @param biomeID
* @return
*/
public static boolean isBiomeRegistered(int biomeID) {
return biomeList[biomeID] != null;
}
/**
*
*/
public static void registerAllBiomes() {
FMLLog.warning("Redundant call to TreasureBiomeDictionary.registerAllBiomes ignored");
}
/**
* Loops through the biome list and automatically adds tags to any biome that does not have any
* This is called by Forge at postinit time. It will additionally dispatch any deferred decorator
* creation events.
*
* DO NOT call this during world generation
*/
public static void registerAllBiomesAndGenerateEvents()
{
for(int i = 0; i < BiomeGenBase.getBiomeGenArray().length; i++)
{
BiomeGenBase biome = BiomeGenBase.getBiomeGenArray()[i];
if(biome == null)
{
continue;
}
if (biome.theBiomeDecorator instanceof DeferredBiomeDecorator)
{
DeferredBiomeDecorator decorator = (DeferredBiomeDecorator) biome.theBiomeDecorator;
decorator.fireCreateEventAndReplace(biome);
}
}
}
/**
*
* @param info
* @param type
* @return
*/
private static boolean containsType(BiomeInfo info, Type type) {
return info.typeList.contains(type);
}
}