package common.dimension;

import java.util.List;
import java.util.Map;
import common.biome.Biome;
import common.biome.IBiome;
import common.block.foliage.LeavesType;
import common.collect.Lists;
import common.collect.Maps;
import common.init.BlockRegistry;
import common.init.Blocks;
import common.init.MetalType;
import common.init.UniverseRegistry;
import common.tags.TagObject;
import common.util.ExtMath;
import common.util.Vec3;
import common.world.State;
import common.world.Weather;

public abstract class Dimension extends Nameable implements Comparable<Dimension> {
	public class GeneratorSettings {
	    public float coordinateScale = 684.412F;
	    public float heightScale = 684.412F;
	    public float upperLimitScale = 512.0F;
	    public float lowerLimitScale = 512.0F;
	    public float depthNoiseScaleX = 200.0F;
	    public float depthNoiseScaleZ = 200.0F;
	    public float amplification = 0.0F;
	    public float mainNoiseScaleX = 80.0F;
	    public float mainNoiseScaleY = 160.0F;
	    public float mainNoiseScaleZ = 80.0F;
	    public float baseSize = 8.5F;
	    public float stretchY = 12.0F;
	    public float biomeDepthWeight = 1.0F;
	    public float biomeDepthOffset = 0.0F;
	    public float biomeScaleWeight = 1.0F;
	    public float biomeScaleOffset = 0.0F;
	}
	
	public static enum GeneratorType {
		FLAT("flat"), PERLIN("perlin"), SIMPLE("simple"), ISLAND("island"), CAVERN("cavern"), DESTROYED("destroyed");
		
		private static final Map<String, GeneratorType> LOOKUP = Maps.newHashMap();
		
		private final String name;
		
		private GeneratorType(String name) {
			this.name = name;
		}
		
		public String getName() {
			return this.name;
		}
		
		public static GeneratorType getByName(String name) {
			GeneratorType type = LOOKUP.get(name.toLowerCase());
			return type == null ? PERLIN : type;
		}
		
		static {
			for(GeneratorType type : values()) {
				LOOKUP.put(type.name, type);
			}
		}
	}
	
	public static enum ReplacerType {
		NONE("none"), BIOMES("biomes"), SIMPLE("simple"), ALTERNATE("alternate"), TOPLAYER("toplayer");
		
		private static final Map<String, ReplacerType> LOOKUP = Maps.newHashMap();
		
		private final String name;
		
		private ReplacerType(String name) {
			this.name = name;
		}
		
		public String getName() {
			return this.name;
		}
		
		public static ReplacerType getByName(String name) {
			ReplacerType type = LOOKUP.get(name.toLowerCase());
			return type == null ? BIOMES : type;
		}
		
		static {
			for(ReplacerType type : values()) {
				LOOKUP.put(type.name, type);
			}
		}
	}
	
	public static interface ColorGenerator {
		int getColor(long time);
	}

	private static class SingleColorGen implements ColorGenerator {
		private final int color;
		
		public SingleColorGen(int color) {
			this.color = color;
		}
		
		public int getColor(long time) {
			return this.color;
		}
	}

	private static class SinusColorGen implements ColorGenerator {
		private final float period, det, dist;
		private final float rn, gn, bn;
		private final int detChn, distChn, color;
		
		public SinusColorGen(float period, float det, float dist, int color, int detChn, int distChn) {
			this.period = period;
			this.det = det;
			this.dist = dist;
			this.detChn = detChn;
			this.distChn = distChn;
			this.color = color;
			Vec3 vec = new Vec3(color);
			this.rn = (float)vec.xCoord;
			this.gn = (float)vec.yCoord;
			this.bn = (float)vec.zCoord;
		}
		
		public int getColor(long time) {
			float f = ExtMath.sin((float)time / this.period) * 0.5f + 0.5f;
			float c1 = (1.0f - this.det) + f * this.det;
			float c2 = (1.0f - f) * this.dist;
			float r = this.rn * ((this.detChn & 1) > 0 ? c1 : 1.0f) * ((this.distChn & 1) > 0 ? c2 : 1.0f);
			float g = this.gn * ((this.detChn & 2) > 0 ? c1 : 1.0f) * ((this.distChn & 2) > 0 ? c2 : 1.0f);
			float b = this.bn * ((this.detChn & 4) > 0 ? c1 : 1.0f) * ((this.distChn & 4) > 0 ? c2 : 1.0f);
			return ((int)(r * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | (int)(b * 255.0f);
		}
	}
	
	private static final int[] METAL_SIZES =   new int[] {13, 11, 11,  9,  9,  7,  6,  5,  4,  3};
	private static final int[] METAL_COUNTS =  new int[] {20, 12,  8,  5,  3,  1, -2, -4, -6, -8};
	private static final int[] METAL_OFFSETS = new int[] { 0, -12, -32, -48, -64, -72, -96, -112, -142, -168};
	private static final int[] METAL_HEIGHTS = new int[] {64, 32, 12, -10, -32, -48, -68, -84, -102, -136};
	
	private final int id;
	private final String name;
	
	private final GeneratorSettings noiseGen = new GeneratorSettings(); // g.perlin

	// client
	private boolean denseFog = false;
	private float cloudHeight = 192.0f;
	private int skyColor = 0x000000;
	private int fogColor = 0x000000;
	private int cloudColor = 0x000000;
	private float starBrightness = 0.0f;
	private float deepstarBrightness = 0.0f;
	private CloudType cloudTexture = CloudType.NORMAL;
	private SkyboxType skyboxTexture = null;
	private ColorGenerator starColorFunc = null;
	private ColorGenerator deepstarColorFunc = null;
	private String fullName; // synced only

	// common
	private float gravity = 1.0f;
	private float temperature = 2.7f;
	private float orbitOffset = 0.0f;
	private long orbitalPeriod = 1L;
	private long rotationPeriod = 1L;
	private int timeQualifier = 9;
	private int brightness = 0;
	
	// server / gen
	private Weather defaultWeather = Weather.CLEAR;
	private LeavesType defaultLeaves = LeavesType.SPRING;
	
	private GeneratorType generatorType = GeneratorType.FLAT;
	private ReplacerType replacerType = ReplacerType.NONE;

	private boolean populated = true;
	private boolean mobs = false; // mobgen+spawn
	private boolean snow = false; // snowgen+update
	private boolean caves = false;
	private boolean ravines = false;
	private boolean strideCaves = false;
	private boolean useStrongholds = false;
	private boolean useVillages = false;
	private boolean useMineshafts = false;
	private boolean useScattered = false;
	private boolean useFortresses = false;
	private boolean semiFixed = false; // b.layered
	
	private int dungeons = 0; // dungeon
	private int biomeSize = 0; // b.layered
	private int riverSize = 4; // b.layered
	private int snowRarity = 6; // b.layered
	private int seaRarity = 50; // b.layered
	private int addRarity = 50; // b.layered
	private int seaLevel = 0; // g.perlin, g.cavern, g.simple, g.destroyed, lake (r), r.biome, r.simple, r.alternate, ...
	
	private Biome defaultBiome = Biome.NONE; // biomegen
	
	private State filler = Blocks.air.getState(); // caves+rav, liquid, ore, g.perlin, g.cavern, g.island, 
			// g.simple, g.flat (sealevel), r.biome, r.simple, r.alternate, r.toplayer
	private State top = Blocks.air.getState(); // caves+rav, lake
	private State surface = Blocks.air.getState(); // caves+rav, r.toplayer
	private State alt1 = Blocks.air.getState(); // cavebase, r.biome, r.simple, r.alternate
	private State alt2 = Blocks.air.getState(); // r.simple, r.alternate
	private State liquid = Blocks.air.getState(); // g.perlin, g.cavern, g.simple, r.biome, r.simple, r.alternate
	private boolean ceiling = false; // chunk
	private State caveFiller = Blocks.air.getState(); // cavebase, ravine
	private State[] layers = null; // g.flat
	private Biome[] frostBiomes = null; // b.layered
	private Biome[] coldBiomes = null; // b.layered
	private Biome[] mediumBiomes = null; // b.layered
	private Biome[] hotBiomes = null; // b.layered
	private Biome[] addBiomes = null; // b.layered
	
	private final List<Ore> ores = Lists.newArrayList();
	private final List<Lake> lakes = Lists.newArrayList();
	private final List<Liquid> liquids = Lists.newArrayList();
	
	private long seed = 0L;
	
	public static void writeState(TagObject tag, String name, State state) {
		if(state != null)
			tag.setString(name, state.getId());
	}
	
	public static void writeState(TagObject tag, State state) {
		writeState(tag, "Block", state);
	}

	public static State readState(TagObject tag, String name, State def) {
		return tag.hasString(name) ? State.getState(tag.getString(name), def) : def;
	}

	public static State readState(TagObject tag, State def) {
		return readState(tag, "Block", def);
	}

	public Dimension(int id, String name) {
		this.id = id;
		this.name = name;
	}

	public abstract DimType getType();
	
	
	public final void setFullName(String name) {
		this.fullName = name;
	}
	
	public final void setSeed(long seed) {
		this.seed = seed;
	}
	
	
//	public final Dimension setLayers(List<FlatSettings> layers) {
//		this.seaLevel = 0;
//		for(FlatSettings layer : layers) {
//			this.seaLevel += layer.height;
//		}
//		this.layers = new IBlockState[this.seaLevel];
//		int pos = 0;
//		for(FlatSettings layer : layers) {
//			for(int z = 0; z < layer.height; z++) {
//				this.layers[pos++] = layer.state;
//			}
//		}
//		this.generatorType = GeneratorType.FLAT;
//		return this;
//	}
//	
//	public final List<FlatSettings> getLayerList() {
//		if(this.layers == null)
//			return Lists.newArrayList(new FlatSettings(this.filler));
//		List<FlatSettings> list = Lists.newArrayList();
//		IBlockState last = null;
//		FlatSettings current = null;
//		for(IBlockState state : this.layers) {
//			if(state != last)
//				list.add(current = new FlatSettings(state));
//			else
//				current.height += 1;
//		}
//		return list;
//	}
	
//	public final Dimension setOres(List<OreSettings> ores) {
//		this.ores.clear();
//		for(OreSettings ore : ores) {
//			this.ores.add(ore.createGenerator());
//		}
//		return this;
//	}
	
	public final Dimension setFlatGen(State state, int height) {
		this.layers = null;
		this.filler = this.top = this.surface = this.alt1 = state;
		this.seaLevel = height;
		this.generatorType = GeneratorType.FLAT;
		return this;
	}
	
	public final Dimension setFlatGen(State main, Object ... data) {
		List<State> states = Lists.newArrayList();
		int height = 1;
		for(Object obj : data) {
			if(obj instanceof Integer)
				height = (Integer)obj;
			else if(obj instanceof State) {
				for(int z = 0; z < height; z++) {
					states.add((State)obj);
				}
				height = 1;
			}
			else 
				throw new IllegalArgumentException("Argument muss Integer oder IBlockState sein");
		}
		if(states.size() > 512)
			throw new IllegalArgumentException("Es können höchstens 512 Schichten definiert werden");
		this.layers = states.toArray(new State[states.size()]);
		this.filler = this.top = this.surface = this.alt1 = main;
		this.seaLevel = this.layers.length;
		this.generatorType = GeneratorType.FLAT;
		return this;
	}
	
	public final Dimension setIslandGen(State filler) {
		this.filler = this.top = this.surface = this.alt1 = filler;
		this.seaLevel = 0;
		this.generatorType = GeneratorType.ISLAND;
		return this;
	}
	
	public final Dimension setCavernGen(State filler, State liquid, int seaLevel) {
		this.filler = this.top = this.surface = this.alt1 = filler;
		this.liquid = liquid;
		this.seaLevel = seaLevel;
		this.generatorType = GeneratorType.CAVERN;
		return this;
	}
	
	public final Dimension setSimpleGen(State filler, State liquid, int seaLevel) {
		this.filler = this.top = this.surface = this.alt1 = filler;
		this.liquid = liquid;
		this.seaLevel = seaLevel;
		this.generatorType = GeneratorType.SIMPLE;
		return this;
	}
	
	public final Dimension setPerlinGen(State filler, State liquid, int seaLevel) {
		this.filler = this.top = this.surface = this.alt1 = filler;
		this.liquid = liquid;
		this.seaLevel = seaLevel;
		this.generatorType = GeneratorType.PERLIN;
		return this;
	}
	
	public final Dimension setBiomeReplacer(State alt1) {
		this.alt1 = alt1;
		this.replacerType = ReplacerType.BIOMES;
		return this;
	}
	
	public final Dimension setSimpleReplacer(State alt1, State alt2) {
		this.alt1 = alt1;
		this.alt2 = alt2;
		this.replacerType = ReplacerType.SIMPLE;
		return this;
	}
	
	public final Dimension setSurfaceReplacer(State alt1, State alt2) {
		this.alt1 = alt1;
		this.alt2 = alt2;
		this.replacerType = ReplacerType.ALTERNATE;
		return this;
	}
	
	public final Dimension setTopReplacer(State surface) {
		this.surface = surface;
		this.replacerType = ReplacerType.TOPLAYER;
		return this;
	}

	public final Dimension setBiomeGen(Biome mainBiome, boolean semiFixed, int biomeSize, int riverSize, int snowRarity, int seaRarity) {
		return this.setBiomeGen(mainBiome, semiFixed, biomeSize, riverSize, snowRarity, seaRarity, 1);
	}

	public final Dimension setBiomeGen(Biome mainBiome, boolean semiFixed, int biomeSize, int riverSize, int snowRarity, int seaRarity, 
			int addRarity, Biome ... add) {
		this.defaultBiome = mainBiome;
		IBiome biome = IBiome.getBiome(mainBiome);
		this.top = biome.getFiller();
		this.surface = biome.getTop();
		this.semiFixed = semiFixed;
		this.biomeSize = biomeSize;
		this.riverSize = riverSize;
		this.snowRarity = snowRarity;
		this.seaRarity = seaRarity;
		this.addRarity = addRarity;
		this.addBiomes = add;
		return this;
	}

	public final Dimension setFrostBiomes(Biome ... biomes) {
		this.frostBiomes = biomes;
		return this;
	}

	public final Dimension setColdBiomes(Biome ... biomes) {
		this.coldBiomes = biomes;
		return this;
	}

	public final Dimension setMediumBiomes(Biome ... biomes) {
		this.mediumBiomes = biomes;
		return this;
	}

	public final Dimension setHotBiomes(Biome ... biomes) {
		this.hotBiomes = biomes;
		return this;
	}
	
	public final Dimension setBiome(Biome value) {
		this.defaultBiome = value;
		IBiome biome = IBiome.getBiome(value);
		this.top = biome.getFiller();
		this.surface = biome.getTop();
		return this;
	}

	public final Dimension enableMobs() {
		this.mobs = true;
		return this;
	}

	public final Dimension enableSnow() {
		this.snow = true;
		return this;
	}

	public final Dimension enableCaves(State filler) {
		this.caves = true;
		this.caveFiller = filler;
		return this;
	}

	public final Dimension enableRavines(State filler) {
		this.ravines = true;
		this.caveFiller = filler;
		return this;
	}

	public final Dimension enableCavesRavines(State filler) {
		this.caves = this.ravines = true;
		this.caveFiller = filler;
		return this;
	}

	public final Dimension enableLongCaves() {
		this.strideCaves = true;
		return this;
	}

	public final Dimension setDungeons(int value) {
		this.dungeons = value;
		return this;
	}
	
	public final Dimension enableWorldCeiling() {
		this.ceiling = true;
		return this;
	}
	
	public final Dimension enableStrongholds() {
		this.useStrongholds = true;
		return this;
	}

	public final Dimension enableVillages() {
		this.useVillages = true;
		return this;
	}

	public final Dimension enableMineshafts() {
		this.useMineshafts = true;
		return this;
	}

	public final Dimension enableScattered() {
		this.useScattered = true;
		return this;
	}

	public final Dimension enableFortresses() {
		this.useFortresses = true;
		return this;
	}

	public final Dimension setLeavesType(LeavesType value) {
		this.defaultLeaves = value;
		return this;
	}
	
	public final Dimension addLake(State state, State filler, State top, int chance, int minHeight, int maxHeight, 
    		boolean ratiod) {
		this.lakes.add(new Lake(state, filler, top, chance, minHeight, maxHeight, ratiod));
		return this;
	}
	
	public final Dimension addLiquid(State state, int chance, int minHeight, int maxHeight, boolean lower) {
		this.liquids.add(new Liquid(state, chance, minHeight, maxHeight, lower));
		return this;
	}
	
	public final Dimension addOre(State state, int count, int more, int size, int minHeight, int maxHeight, boolean distrib) {
		this.ores.add(new Ore(state, count, more, size, minHeight, maxHeight, distrib));
		return this;
	}
	
	public final Dimension addMetalOres(MetalType ... metals) {
		for(MetalType metal : metals) {
			int count = METAL_COUNTS[metal.rarity];
			this.ores.add(new Ore(BlockRegistry.getRegisteredBlock(metal.name + "_ore").getState(), 
					count < 0 ? 0 : count, count < 0 ? (-count) : 0, METAL_SIZES[metal.rarity], METAL_OFFSETS[metal.rarity], METAL_HEIGHTS[metal.rarity], false));
		}
		return this;
	}
	
	
	
	protected final Dimension setPhysics(long orbitalPeriod, long rotationPeriod, float orbitOffset, float gravity, float temperature, 
			int brightness) {
		this.orbitalPeriod = orbitalPeriod;
		this.rotationPeriod = rotationPeriod;
		this.orbitOffset = orbitOffset;
		this.gravity = gravity;
		this.temperature = temperature;
		this.brightness = brightness;
		return this;
	}

	protected final Dimension setSkyColor(int value) {
		this.skyColor = value;
		return this;
	}

	protected final Dimension setFogColor(int value) {
		this.fogColor = value;
		return this;
	}

	protected final Dimension setCloudColor(int value) {
		this.cloudColor = value;
		return this;
	}


	public final Dimension setTimeQualifier(int value) {
		this.timeQualifier = value;
		return this;
	}

	public final Dimension setWeather(Weather value) {
		this.defaultWeather = value;
		return this;
	}

	public final Dimension setCloudHeight(float value) {
		this.cloudHeight = value;
		return this;
	}

	public final Dimension setStarBrightness(float value) {
		this.starBrightness = value;
		return this;
	}

	public final Dimension setDeepStarBrightness(float value) {
		this.deepstarBrightness = value;
		return this;
	}

	public final Dimension setStarColor(int color) {
		this.starColorFunc = new SingleColorGen(color);
		return this;
	}

	public final Dimension setStarColorSin(float period, float det, float dist, int color, int detChn, int distChn) {
		this.starColorFunc = new SinusColorGen(period, det, dist, color, detChn, distChn);
		return this;
	}

	public final Dimension setStarColorFunc(ColorGenerator func) {
		this.starColorFunc = func;
		return this;
	}

	public final Dimension setDeepStarColor(int color) {
		this.deepstarColorFunc = new SingleColorGen(color);
		return this;
	}

	public final Dimension setDeepStarColorSin(float period, float det, float dist, int color, int detChn, int distChn) {
		this.deepstarColorFunc = new SinusColorGen(period, det, dist, color, detChn, distChn);
		return this;
	}

	public final Dimension setDeepStarColorFunc(ColorGenerator func) {
		this.deepstarColorFunc = func;
		return this;
	}

	public final Dimension setCloudTexture(CloudType value) {
		this.cloudTexture = value;
		return this;
	}

	public final Dimension setSkyBoxTexture(SkyboxType value) {
		this.skyboxTexture = value;
		return this;
	}

	public final Dimension enableDenseFog() {
		this.denseFog = true;
		return this;
	}
	
	
	public final long getSeed() {
		return this.seed;
	}
	
    
	public final long getOrbitalPeriod() {
		return this.orbitalPeriod;
	}
	
	public final long getRotationalPeriod() {
		return this.rotationPeriod;
	}
	
	public final float getOrbitOffset() {
		return this.orbitOffset;
	}
	
	public final float getTemperature() {
		return this.temperature;
	}
	
	public final float getGravity() {
		return this.gravity;
	}
	
    

	public final String getDimensionName() {
		return this.name;
	}
	
	public final int getDimensionId() {
		return this.id;
	}
	
	public final int getTimeQualifier() {
		return this.timeQualifier;
	}
	
//	public final String getCustomName() {
//		return this.customName;
//	}
	
	
	public final Weather getWeather() {
		return this.defaultWeather;
	}


	public final int getBrightness() {
		return this.brightness;
	}
	
	public final int getSkyColor() {
		return this.skyColor;
	}
	
	public final float getCloudHeight() {
		return this.cloudHeight;
	}

	public final float getStarBrightness() {
		return this.starBrightness;
	}

	public final float getDeepStarBrightness() {
		return this.deepstarBrightness;
	}

	public final int getStarColor(long time) {
		return this.starColorFunc == null ? 0xffffffff : this.starColorFunc.getColor(time);
	}

	public final int getDeepStarColor(long time) {
		return this.deepstarColorFunc == null ? 0xffffffff : this.deepstarColorFunc.getColor(time);
	}

	public final int getFogColor() {
		return this.fogColor;
	}

	public final int getCloudColor() {
		return this.cloudColor;
	}
	
	public final String getCloudTexture() {
		return "textures/world/" + this.cloudTexture.getTexture() + ".png";
	}
	
	public final String getSkyBoxTexture() {
		return this.skyboxTexture == null ? null : ("textures/world/" + this.skyboxTexture.getTexture() + ".png");
	}

	public final boolean hasDenseFog() {
		return this.denseFog;
	}
	
	
	public final State getFiller() {
		return this.filler;
	}
	
	public final State getTop() {
		return this.top;
	}
	
	public final State getAltFiller1() {
		return this.alt1;
	}
	
	public final State getLiquid() {
		return this.liquid;
	}

	public final LeavesType getLeavesType() {
		return this.defaultLeaves;
	}

	public final boolean hasMobs() {
		return this.mobs;
	}

	public final boolean hasSnow() {
		return this.snow;
	}
	
	public final boolean hasWorldCeiling() {
		return this.ceiling;
	}

	public final int getSeaLevel() {
		return this.seaLevel;
	}

	public final boolean hasStrongholds() {
		return this.useStrongholds;
	}

	public final boolean hasVillages() {
		return this.useVillages;
	}

	public final boolean hasMineshafts() {
		return this.useMineshafts;
	}

	public final boolean hasScattered() {
		return this.useScattered;
	}

	public final boolean hasFortresses() {
		return this.useFortresses;
	}

	public final boolean hasPopulator() {
		return this.populated;
	}


	public final boolean hasNoLight() {
		return !this.getType().days;
	}
	
    public final String getFormattedName(boolean full) {
    	return full && this.fullName != null ? this.fullName : UniverseRegistry.getFormattedName(this, full);
    }
    
//    public final Text getUnformattedName(boolean full) {
//    	return full && this.fullName != null ? this.fullName : UniverseRegistry.getUnformattedName(this, full);
//    }
    
    
    public final boolean equals(Object other) {
    	return other instanceof Dimension && ((Dimension)other).id == this.id;
    }
    
    public final int hashCode() {
    	return this.id;
    }

	public final String toString() {
		return this.getDimensionName();
	}
	
	public final int compareTo(Dimension other) {
		return other == null ? -1 : this.name.compareTo(other.name);
	}
    
    public static Dimension getByTag(TagObject tag) {
    	return getByTag(tag, true, false, false, false);
    }
    
    public static Dimension getByTag(TagObject tag, boolean generator) {
    	return getByTag(tag, false, generator, !generator, false);
    }
    
    private static Dimension getByTag(TagObject tag, boolean mapOnly, boolean generator, boolean partialGen, boolean all) {
    	Dimension dim;
    	DimType type = DimType.getByName(tag.getString("Type"));
    	int id = tag.getInt("ID");
    	String name = tag.getString("Name");
    	switch(type) {
    	case STAR:
    		dim = new Star(id, name);
    		break;
    	case PLANET:
    	default:
    		dim = new Planet(id, name);
    		break;
    	case MOON:
    		dim = new Moon(id, name);
    		break;
    	case AREA:
    		dim = new Area(id, name);
    		break;
    	case SEMI:
    		dim = new Semi(id, name);
    		break;
    	case SPACE:
    		dim = Space.INSTANCE;
    	}
    	if(!mapOnly)
    		dim.fromTags(tag, generator, partialGen, all);
    	return dim;
    }
    
    public final Dimension copy() {
    	Dimension dim = getByTag(this.toTags(true, false, true), false, true, false, true);
    	dim.setCustomName(this.getCustomName());
    	return dim;
    }
    
    public final Dimension copy(int id, String name) {
    	TagObject tag = this.toTags(true, false, true);
    	tag.setInt("ID", id);
    	tag.setString("Name", name);
    	return getByTag(tag, false, true, false, true);
    }
    
    public final void fromTags(TagObject tag) {
    	this.fromTags(tag, true, false, false);
    }
    
    private final void fromTags(TagObject tag, boolean generator, boolean partialGen, boolean all) {
    	if(this == Space.INSTANCE) {
    		if(generator || partialGen)
    			this.seed = tag.getLong("Seed");
    		return;
    	}
    	if(generator || partialGen) {
	    	this.seed = tag.getLong("Seed");
    		if(partialGen || all || this.id >= UniverseRegistry.MORE_DIM_ID) {
		    	this.seaLevel = tag.getInt("SeaLevel");
		    	this.filler = readState(tag, "FillerBlock", Blocks.stone.getState());
		    	this.liquid = readState(tag, "LiquidBlock", Blocks.water.getState());
    		}
    	}
    	if(generator) {
    		if(all || this.id >= UniverseRegistry.MORE_DIM_ID) {
		    	this.noiseGen.coordinateScale = tag.getFloat("CoordScale");
		    	this.noiseGen.heightScale = tag.getFloat("HeightScale");
		    	this.noiseGen.upperLimitScale = tag.getFloat("UpperLmtScale");
		    	this.noiseGen.lowerLimitScale = tag.getFloat("LowerLmtScale");
		    	this.noiseGen.depthNoiseScaleX = tag.getFloat("DepthScaleX");
		    	this.noiseGen.depthNoiseScaleZ = tag.getFloat("DepthScaleZ");
		    	this.noiseGen.amplification = tag.getFloat("Amplification");
		    	this.noiseGen.mainNoiseScaleX = tag.getFloat("ScaleX");
		    	this.noiseGen.mainNoiseScaleY = tag.getFloat("ScaleY");
		    	this.noiseGen.mainNoiseScaleZ = tag.getFloat("ScaleZ");
		    	this.noiseGen.baseSize = tag.getFloat("BaseSize");
		    	this.noiseGen.stretchY = tag.getFloat("Stretch");
		    	this.noiseGen.biomeDepthWeight = tag.getFloat("BDepthWeight");
		    	this.noiseGen.biomeDepthOffset = tag.getFloat("BDepthOffset");
		    	this.noiseGen.biomeScaleWeight = tag.getFloat("BScaleWeight");
		    	this.noiseGen.biomeScaleOffset = tag.getFloat("BScaleOffset");
		    	this.generatorType = GeneratorType.getByName(tag.getString("Generator"));
		    	this.replacerType = ReplacerType.getByName(tag.getString("Replacer"));
		    	this.mobs = tag.getBool("MobGen");
		    	this.snow = tag.getBool("SnowGen");
		    	this.ceiling = tag.getBool("Ceiling");
		    	this.caves = tag.getBool("Caves");
		    	this.ravines = tag.getBool("Ravines");
		    	this.strideCaves = tag.getBool("AltCaves");
		    	this.useStrongholds = tag.getBool("Strongholds");
		    	this.useVillages = tag.getBool("Villages");
		    	this.useMineshafts = tag.getBool("Mineshafts");
		    	this.useScattered = tag.getBool("Scattered");
		    	this.useFortresses = tag.getBool("Fortresses");
		    	this.dungeons = tag.getInt("Dungeons");
		    	this.biomeSize = tag.getInt("BiomeSize");
		    	this.riverSize = tag.getInt("RiverSize");
		    	this.snowRarity = tag.getInt("SnowRarity");
		    	this.seaRarity = tag.getInt("SeaRarity");
		    	this.addRarity = tag.getInt("AddRarity");
	//	    	this.biomeRarity = tag.getInteger("BiomeRarity");
		    	this.defaultBiome = Biome.findByName(tag.getString("DefaultBiome"));
		    	this.semiFixed = tag.getBool("SemiFixed");
		    	this.defaultWeather = Weather.getByName(tag.getString("DefaultWeather"));
		    	this.defaultWeather = this.defaultWeather == null ? Weather.CLEAR : this.defaultWeather;
		    	this.defaultLeaves = LeavesType.getByName(tag.getString("DefaultLeaves"));
		    	this.defaultLeaves = this.defaultLeaves == null ? LeavesType.SPRING : this.defaultLeaves;
		    	this.top = readState(tag, "TopBlock", Blocks.dirt.getState());
		    	this.surface = readState(tag, "SurfaceBlock", Blocks.grass.getState());
		    	this.alt1 = readState(tag, "AltBlock1", Blocks.gravel.getState());
		    	this.alt2 = readState(tag, "AltBlock2", Blocks.sand.getState());
		    	this.caveFiller = readState(tag, "CaveFillBlock", Blocks.lava.getState());
		    	if(tag.hasStringArray("Layers")) {
		    		String[] list = tag.getStringArray("Layers");
			    	this.layers = new State[list.length];
			    	for(int z = 0; z < this.layers.length; z++) {
			    		this.layers[z] = State.getState(list[z], Blocks.air.getState());
			    	}
		    	}
		    	else {
		    		this.layers = null;
		    	}
		    	if(tag.hasStringArray("AddBiomes")) {
		    		String[] list = tag.getStringArray("AddBiomes");
			    	if(list.length == 0) {
			    		this.addBiomes = null;
			    	}
			    	else {
				    	this.addBiomes = new Biome[list.length];
				    	for(int z = 0; z < this.addBiomes.length; z++) {
				    		this.addBiomes[z] = Biome.findByName(list[z]);
				    	}
			    	}
		    	}
		    	else {
		    		this.addBiomes = null;
		    	}
		    	if(tag.hasStringArray("FrostBiomes")) {
		    		String[] list = tag.getStringArray("FrostBiomes");
			    	if(list.length == 0) {
			    		this.frostBiomes = null;
			    	}
			    	else {
				    	this.frostBiomes = new Biome[list.length];
				    	for(int z = 0; z < this.frostBiomes.length; z++) {
				    		this.frostBiomes[z] = Biome.findByName(list[z]);
				    	}
			    	}
		    	}
		    	else {
		    		this.frostBiomes = null;
		    	}
		    	if(tag.hasStringArray("ColdBiomes")) {
		    		String[] list = tag.getStringArray("ColdBiomes");
			    	if(list.length == 0) {
			    		this.coldBiomes = null;
			    	}
			    	else {
				    	this.coldBiomes = new Biome[list.length];
				    	for(int z = 0; z < this.coldBiomes.length; z++) {
				    		this.coldBiomes[z] = Biome.findByName(list[z]);
				    	}
			    	}
		    	}
		    	else {
		    		this.coldBiomes = null;
		    	}
		    	if(tag.hasStringArray("MediumBiomes")) {
		    		String[] list = tag.getStringArray("MediumBiomes");
			    	if(list.length == 0) {
			    		this.mediumBiomes = null;
			    	}
			    	else {
				    	this.mediumBiomes = new Biome[list.length];
				    	for(int z = 0; z < this.mediumBiomes.length; z++) {
				    		this.mediumBiomes[z] = Biome.findByName(list[z]);
				    	}
			    	}
		    	}
		    	else {
		    		this.mediumBiomes = null;
		    	}
		    	if(tag.hasStringArray("HotBiomes")) {
		    		String[] list = tag.getStringArray("HotBiomes");
			    	if(list.length == 0) {
			    		this.hotBiomes = null;
			    	}
			    	else {
				    	this.hotBiomes = new Biome[list.length];
				    	for(int z = 0; z < this.hotBiomes.length; z++) {
				    		this.hotBiomes[z] = Biome.findByName(list[z]);
				    	}
			    	}
		    	}
		    	else {
		    		this.hotBiomes = null;
		    	}
		    	this.ores.clear();
		    	if(tag.hasList("Ores")) {
		    		List<TagObject> list = tag.getList("Ores");
			    	for(int z = 0; z < list.size(); z++) {
			    		TagObject gen = list.get(z);
			    		this.ores.add(new Ore(readState(gen, Blocks.iron_ore.getState()),
			    				gen.getInt("Count"), gen.getInt("Add"), gen.getInt("Size"), 
			    				gen.getInt("MinC"), gen.getInt("MaxS"), gen.getBool("Distrib")));
			    	}
		    	}
		    	this.lakes.clear();
		    	if(tag.hasList("Lakes")) {
		    		List<TagObject> list = tag.getList("Lakes");
			    	for(int z = 0; z < list.size(); z++) {
			    		TagObject gen = list.get(z);
			    		this.lakes.add(new Lake(
			    				readState(gen, Blocks.water.getState()),
			    				readState(gen, "Filler", null), readState(gen, "Top", null),
			    				gen.getInt("Chance"), gen.getInt("Min"), gen.getInt("Max"), gen.getBool("Ratiod")));
			    	}
		    	}
		    	this.liquids.clear();
		    	if(tag.hasList("Liquids")) {
		    		List<TagObject> list = tag.getList("Liquids");
			    	for(int z = 0; z < list.size(); z++) {
			    		TagObject gen = list.get(z);
			    		this.liquids.add(new Liquid(
			    				readState(gen, Blocks.flowing_water.getState()),
			    				gen.getInt("Chance"), gen.getInt("Min"), gen.getInt("Max"), gen.getBool("Lower")));
			    	}
		    	}
		    	this.populated = !tag.hasBool("NoPopulation") || !tag.getBool("NoPopulation");
    		}
    	}
    	else {
    		this.fullName = tag.getString("FullName");
        	this.readTags(tag);
    	}
//    	this.customName = tag.hasString("CustomName") ? tag.getString("CustomName") : null;
		if(all || !generator || this.id >= UniverseRegistry.MORE_DIM_ID) {
	    	this.denseFog = tag.getBool("DenseFog");
	    	this.timeQualifier = tag.getInt("ImperialTime");
	    	this.brightness = tag.getInt("Brightness");
	    	this.skyColor = tag.getInt("SkyColor");
	    	this.fogColor = tag.getInt("FogColor");
	    	this.cloudColor = tag.getInt("CloudColor");
	    	this.gravity = tag.getFloat("Gravity");
	    	this.temperature = tag.getFloat("Temperature");
	    	this.orbitOffset = tag.getFloat("OrbitOffset");
	    	this.cloudHeight = tag.getFloat("CloudHeight");
	    	this.starBrightness = tag.getFloat("StarBrighness");
	    	this.deepstarBrightness = tag.getFloat("DStarBrightness");
	    	this.orbitalPeriod = tag.getLong("OrbitalPeriod");
	    	this.rotationPeriod = tag.getLong("RotationPeriod");
	    	this.cloudTexture = CloudType.getByName(tag.getString("CloudTexture"));
	    	this.skyboxTexture = tag.hasString("SkyBoxTexture") ? 
	    			SkyboxType.getByName(tag.getString("SkyBoxTexture")) : null;
	    	if(tag.hasInt("StarColor")) {
		    	this.setStarColor(tag.getInt("StarColor"));
	    	}
	    	else if(tag.hasObject("StarColorFnc")) {
	    		TagObject fnc = tag.getObject("StarColorFnc");
	    		this.setStarColorSin(fnc.getFloat("Period"), fnc.getFloat("Det"), fnc.getFloat("Dist"), 
	    				fnc.getInt("Color"), fnc.getByte("DetChn"), fnc.getByte("DistChn"));
	    	}
	    	else {
	    		this.starColorFunc = null;
	    	}
	    	if(tag.hasInt("DStarColor")) {
		    	this.setDeepStarColor(tag.getInt("DStarColor"));
	    	}
	    	else if(tag.hasObject("DStarColorFnc")) {
	    		TagObject fnc = tag.getObject("DStarColorFnc");
	    		this.setDeepStarColorSin(fnc.getFloat("Period"), fnc.getFloat("Det"), fnc.getFloat("Dist"), 
	    				fnc.getInt("Color"), fnc.getByte("DetChn"), fnc.getByte("DistChn"));
	    	}
	    	else {
	    		this.deepstarColorFunc = null;
	    	}
		}
    }
    
    public final TagObject dumpTags() {
    	return this.toTags(true, false, true);
    }
    
    public final TagObject toTags(boolean generator) {
    	return this.toTags(generator, !generator, false);
    }
    
    private final TagObject toTags(boolean generator, boolean partialGen, boolean all) {
    	TagObject tag = (all || !generator || this.id >= UniverseRegistry.MORE_DIM_ID) ? this.toTags() : new TagObject();
    	if(this == Space.INSTANCE) {
    		if(generator || partialGen)
    			tag.setLong("Seed", this.seed);
    		return tag;
    	}
    	if(generator || partialGen) {
			tag.setLong("Seed", this.seed);
			if(partialGen || all || this.id >= UniverseRegistry.MORE_DIM_ID) {
		    	tag.setInt("SeaLevel", this.seaLevel);
				writeState(tag, "FillerBlock", this.filler);
				writeState(tag, "LiquidBlock", this.liquid);
			}
    	}
    	if(generator) {
			if(all || this.id >= UniverseRegistry.MORE_DIM_ID) {
	    		tag.setFloat("CoordScale", this.noiseGen.coordinateScale);
		    	tag.setFloat("HeightScale", this.noiseGen.heightScale);
		    	tag.setFloat("UpperLmtScale", this.noiseGen.upperLimitScale);
		    	tag.setFloat("LowerLmtScale", this.noiseGen.lowerLimitScale);
		    	tag.setFloat("DepthScaleX", this.noiseGen.depthNoiseScaleX);
		    	tag.setFloat("DepthScaleZ", this.noiseGen.depthNoiseScaleZ);
		    	tag.setFloat("Amplification", this.noiseGen.amplification);
		    	tag.setFloat("ScaleX", this.noiseGen.mainNoiseScaleX);
		    	tag.setFloat("ScaleY", this.noiseGen.mainNoiseScaleY);
		    	tag.setFloat("ScaleZ", this.noiseGen.mainNoiseScaleZ);
		    	tag.setFloat("BaseSize", this.noiseGen.baseSize);
		    	tag.setFloat("Stretch", this.noiseGen.stretchY);
		    	tag.setFloat("BDepthWeight", this.noiseGen.biomeDepthWeight);
		    	tag.setFloat("BDepthOffset", this.noiseGen.biomeDepthOffset);
		    	tag.setFloat("BScaleWeight", this.noiseGen.biomeScaleWeight);
		    	tag.setFloat("BScaleOffset", this.noiseGen.biomeScaleOffset);
		    	tag.setString("Generator", this.generatorType.getName());
		    	tag.setString("Replacer", this.replacerType.getName());
		    	tag.setBool("MobGen", this.mobs);
		    	tag.setBool("SnowGen", this.snow);
				tag.setBool("Ceiling", this.ceiling);
		    	tag.setBool("Caves", this.caves);
		    	tag.setBool("Ravines", this.ravines);
		    	tag.setBool("AltCaves", this.strideCaves);
		    	tag.setBool("Strongholds", this.useStrongholds);
		    	tag.setBool("Villages", this.useVillages);
		    	tag.setBool("Mineshafts", this.useMineshafts);
		    	tag.setBool("Scattered", this.useScattered);
		    	tag.setBool("Fortresses", this.useFortresses);
		    	tag.setInt("Dungeons", this.dungeons);
		    	tag.setInt("BiomeSize", this.biomeSize);
		    	tag.setInt("RiverSize", this.riverSize);
		    	tag.setInt("SnowRarity", this.snowRarity);
		    	tag.setInt("SeaRarity", this.seaRarity);
		    	tag.setInt("AddRarity", this.addRarity);
	//	    	tag.setInteger("BiomeRarity", this.biomeRarity);
	//			if(this.defaultBiome != null)
				tag.setString("DefaultBiome", this.defaultBiome.name.toLowerCase());
	//			if(this.mainBiome != null)
				tag.setBool("SemiFixed", this.semiFixed);
				tag.setString("DefaultWeather", this.defaultWeather.getName());
				tag.setString("DefaultLeaves", this.defaultLeaves.getName());
				writeState(tag, "TopBlock", this.top);
				writeState(tag, "SurfaceBlock", this.surface);
				writeState(tag, "AltBlock1", this.alt1);
				writeState(tag, "AltBlock2", this.alt2);
				writeState(tag, "CaveFillBlock", this.caveFiller);
	    		if(this.layers != null) {
	    			String[] list = new String[this.layers.length];
	    			for(int z = 0; z < this.layers.length; z++) {
	    				list[z] = this.layers[z].getId();
	    			}
	    			tag.setStringArray("Layers", list);
	    		}
	    		if(this.addBiomes != null) {
	    			String[] list = new String[this.addBiomes.length];
	    			for(int z = 0; z < this.addBiomes.length; z++) {
	    				list[z] = this.addBiomes[z].name.toLowerCase();
	    			}
	    			tag.setStringArray("AddBiomes", list);
	    		}
	    		if(this.frostBiomes != null) {
	    			String[] list = new String[this.frostBiomes.length];
	    			for(int z = 0; z < this.frostBiomes.length; z++) {
	    				list[z] = this.frostBiomes[z].name.toLowerCase();
	    			}
	    			tag.setStringArray("FrostBiomes", list);
	    		}
	    		if(this.coldBiomes != null) {
	    			String[] list = new String[this.coldBiomes.length];
	    			for(int z = 0; z < this.coldBiomes.length; z++) {
	    				list[z] = this.coldBiomes[z].name.toLowerCase();
	    			}
	    			tag.setStringArray("ColdBiomes", list);
	    		}
	    		if(this.mediumBiomes != null) {
	    			String[] list = new String[this.mediumBiomes.length];
	    			for(int z = 0; z < this.mediumBiomes.length; z++) {
	    				list[z] = this.mediumBiomes[z].name.toLowerCase();
	    			}
	    			tag.setStringArray("MediumBiomes", list);
	    		}
	    		if(this.hotBiomes != null) {
	    			String[] list = new String[this.hotBiomes.length];
	    			for(int z = 0; z < this.hotBiomes.length; z++) {
	    				list[z] = this.hotBiomes[z].name.toLowerCase();
	    			}
	    			tag.setStringArray("HotBiomes", list);
	    		}
	    		if(!this.ores.isEmpty()) {
	    			List<TagObject> list = Lists.newArrayList();
	    			for(Ore gen : this.ores) {
		    			TagObject ore = new TagObject();
		    			writeState(ore, gen.state());
		    			ore.setBool("Distrib", gen.dist());
		    			ore.setInt("Size", gen.size());
		    			ore.setInt("Count", gen.count());
		    			ore.setInt("Add", gen.more());
		    			ore.setInt("MinC", gen.min());
		    			ore.setInt("MaxS", gen.max());
		    			list.add(ore);
	    			}
	    			tag.setList("Ores", list);
	    		}
	    		if(!this.lakes.isEmpty()) {
	    			List<TagObject> list = Lists.newArrayList();
	    			for(Lake gen : this.lakes) {
		    			TagObject lake = new TagObject();
		    			writeState(lake, gen.state());
		    			writeState(lake, "Filler", gen.filler());
		    			writeState(lake, "Top", gen.top());
		    			lake.setBool("Ratiod", gen.ratiod());
		    			lake.setInt("Chance", gen.chance());
		    			lake.setInt("Min", gen.minHeight());
		    			lake.setInt("Max", gen.maxHeight());
		    			list.add(lake);
	    			}
	    			tag.setList("Lakes", list);
	    		}
	    		if(!this.liquids.isEmpty()) {
	    			List<TagObject> list = Lists.newArrayList();
	    			for(Liquid gen : this.liquids) {
		    			TagObject liquid = new TagObject();
		    			writeState(liquid, gen.state());
		    			liquid.setBool("Lower", gen.lower());
		    			liquid.setInt("Chance", gen.chance());
		    			liquid.setInt("Min", gen.minHeight());
		    			liquid.setInt("Max", gen.maxHeight());
		    			list.add(liquid);
	    			}
	    			tag.setList("Liquids", list);
	    		}
	    		if(!this.populated)
	    			tag.setBool("NoPopulation", true);
			}
    	}
    	else {
    		tag.setString("FullName", this.getFormattedName(true));
        	this.writeTags(tag);
    	}
//    	if(this.customName != null)
//    		tag.setString("CustomName", this.customName);
		if(all || !generator || this.id >= UniverseRegistry.MORE_DIM_ID) {
	    	tag.setBool("DenseFog", this.denseFog);
	    	tag.setInt("ImperialTime", this.timeQualifier);
	    	tag.setInt("Brightness", this.brightness);
	    	tag.setInt("SkyColor", this.skyColor);
	    	tag.setInt("FogColor", this.fogColor);
	    	tag.setInt("CloudColor", this.cloudColor);
	    	tag.setFloat("Gravity", this.gravity);
	    	tag.setFloat("Temperature", this.temperature);
	    	tag.setFloat("OrbitOffset", this.orbitOffset);
	    	tag.setFloat("CloudHeight", this.cloudHeight);
	    	tag.setFloat("StarBrighness", this.starBrightness);
	    	tag.setFloat("DStarBrightness", this.deepstarBrightness);
	    	tag.setLong("OrbitalPeriod", this.orbitalPeriod);
	    	tag.setLong("RotationPeriod", this.rotationPeriod);
			tag.setString("CloudTexture", this.cloudTexture.toString());
	    	if(this.skyboxTexture != null)
	    		tag.setString("SkyBoxTexture", this.skyboxTexture.toString());
	    	if(this.starColorFunc instanceof SingleColorGen) {
	    		tag.setInt("StarColor", ((SingleColorGen)this.starColorFunc).color);
	    	}
	    	else if(this.starColorFunc instanceof SinusColorGen) {
	    		TagObject fnc = new TagObject();
	    		fnc.setFloat("Period", ((SinusColorGen)this.starColorFunc).period);
	    		fnc.setFloat("Det", ((SinusColorGen)this.starColorFunc).det);
	    		fnc.setFloat("Dist", ((SinusColorGen)this.starColorFunc).dist); 
				fnc.setInt("Color", ((SinusColorGen)this.starColorFunc).color);
				fnc.setByte("DetChn", (byte)((SinusColorGen)this.starColorFunc).detChn);
				fnc.setByte("DistChn", (byte)((SinusColorGen)this.starColorFunc).distChn);
				tag.setObject("StarColorFnc", fnc);
	    	}
	    	if(this.deepstarColorFunc instanceof SingleColorGen) {
	    		tag.setInt("DStarColor", ((SingleColorGen)this.deepstarColorFunc).color);
	    	}
	    	else if(this.deepstarColorFunc instanceof SinusColorGen) {
	    		TagObject fnc = new TagObject();
	    		fnc.setFloat("Period", ((SinusColorGen)this.deepstarColorFunc).period);
	    		fnc.setFloat("Det", ((SinusColorGen)this.deepstarColorFunc).det);
	    		fnc.setFloat("Dist", ((SinusColorGen)this.deepstarColorFunc).dist); 
				fnc.setInt("Color", ((SinusColorGen)this.deepstarColorFunc).color);
				fnc.setByte("DetChn", (byte)((SinusColorGen)this.deepstarColorFunc).detChn);
				fnc.setByte("DistChn", (byte)((SinusColorGen)this.deepstarColorFunc).distChn);
				tag.setObject("DStarColorFnc", fnc);
	    	}
		}
    	return tag;
    }
    
    public final TagObject toTags() {
    	TagObject tag = new TagObject();
    	tag.setInt("ID", this.id);
    	tag.setString("Name", this.name);
    	tag.setString("Type", this.getType().getName());
    	return tag;
    }
    
	protected String getNameIdentifier() {
		return (this.id >= UniverseRegistry.MORE_DIM_ID && (this.customName == null || this.customName.isEmpty())) ? "%s" : 
			this.getType().format;
	}
	
	protected String getIdentifier() {
		return this.name;
	}

	public int getBiomeSize() {
		return this.biomeSize;
	}

	public Biome getDefaultBiome() {
		return this.defaultBiome;
	}

	public boolean isSemiFixed() {
		return this.semiFixed;
	}

	public int getRiverSize() {
		return this.riverSize;
	}

	public int getSnowRarity() {
		return this.snowRarity;
	}

	public int getSeaRarity() {
		return this.seaRarity;
	}

	public Biome[] getAddBiomes() {
		return this.addBiomes;
	}

	public int getAddRarity() {
		return this.addRarity;
	}

	public Biome[] getHotBiomes() {
		return this.hotBiomes;
	}

	public Biome[] getMediumBiomes() {
		return this.mediumBiomes;
	}

	public Biome[] getColdBiomes() {
		return this.coldBiomes;
	}

	public Biome[] getFrostBiomes() {
		return this.frostBiomes;
	}

	public GeneratorType getGeneratorType() {
		return this.generatorType;
	}

	public State[] getLayers() {
		return this.layers;
	}

	public GeneratorSettings getNoiseGen() {
		return this.noiseGen;
	}

	public ReplacerType getReplacerType() {
		return this.replacerType;
	}

	public State getAlt1() {
		return this.alt1;
	}

	public State getAlt2() {
		return this.alt2;
	}

	public State getSurface() {
		return this.surface;
	}

	public int getDungeons() {
		return this.dungeons;
	}

	public boolean hasCaves() {
		return this.caves;
	}

	public State getCaveFiller() {
		return this.caveFiller;
	}

	public boolean hasRavines() {
		return this.ravines;
	}

	public boolean hasStrideCaves() {
		return this.strideCaves;
	}

	public List<Ore> getOres() {
		return this.ores;
	}

	public List<Lake> getLakes() {
		return this.lakes;
	}

	public List<Liquid> getLiquids() {
		return this.liquids;
	}
}
