package common.dimension;

import java.util.List;
import java.util.Map;
import java.util.Set;

import common.biome.BaseBiome;
import common.biome.IBiome;
import common.block.LeavesType;
import common.collect.Lists;
import common.collect.Maps;
import common.collect.Sets;
import common.init.BlockRegistry;
import common.init.Blocks;
import common.init.MetalType;
import common.init.UniverseRegistry;
import common.nbt.NBTTagCompound;
import common.nbt.NBTTagList;
import common.nbt.NBTTagString;
import common.util.ExtMath;
import common.util.Vec3;
import common.world.State;
import common.world.Weather;
import common.worldgen.FeatureLake;
import common.worldgen.FeatureLiquid;
import common.worldgen.FeatureOre;

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 class FlatSettings {
//		public IBlockState state;
//	    public int height;
//		
//		public FlatSettings(IBlockState block) {
//			this.state = block;
//		}
//	}
	
//	public static class OreSettings {
//		public IBlockState state;
//	    public boolean distrib;
//	    public int size;
//	    public int count;
//	    public int addCount;
//	    public int minHeight;
//	    public int maxHeight;
//		
//		public OreSettings(IBlockState block, boolean distrib, int size, int count, int addCount, int minCenter, int maxSpread) {
//			this.state = block;
//			this.distrib = distrib;
//			this.size = size;
//			this.count = count;
//			this.addCount = addCount;
//			this.minHeight = minCenter;
//			this.maxHeight = maxSpread;
//		}
//		
//		public OreSettings(IBlockState block, boolean distrib, int size, int count, int minCenter, int maxSpread) {
//			this(block, distrib, size, count, 0, minCenter, maxSpread);
//		}
//		
//		public OreSettings(IBlockState block, int size, int count, int divAdd, int min, int max) {
//			this(block, false, size, count, divAdd, min, max);
//		}
//		
//		public OreSettings(IBlockState block, int size, int count, int min, int max) {
//			this(block, false, size, count, min, max);
//		}
//		
////		public OreSettings(IBlockState block) {
////			this(block, 9, 20, 0, 64);
////		}
//		
//		public FeatureOres createGenerator() {
//			return new FeatureOres(this.state, this.count, this.addCount, this.size, this.minHeight, this.maxHeight, this.distrib);
//		}
//		
////		public OreSettings clone() {
////			return new OreSettings(this.state, this.distrib, this.size, this.count, this.addCount, this.minHeight, this.maxHeight);
////		}
//	}
	
	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_HEIGHTS = new int[] {64, 56, 48, 38, 32, 28, 16, 14, 12, 10};
	private static final Set<Character> SAFE_CHARS = Sets.newHashSet();
	
//	private static final FeatureOres[] DEFAULT_ORES;
//	
//	static {
//		List<OreSettings> ores = Lists.<OreSettings>newArrayList();
//		OreRegistry.populateDefault(ores);
//		DEFAULT_ORES = new FeatureOres[ores.size()];
//		for(int z = 0; z < DEFAULT_ORES.length; z++) {
//			DEFAULT_ORES[z] = ores.get(z).createGenerator();
//		}
//	}
	
	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 String cloudTexture = "clouds";
	private String 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;
//	private String customName = null;
	
	// 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 BaseBiome defaultBiome = BaseBiome.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 State floor = null; // chunk
	private State ceiling = null; // chunk
	private State caveFiller = Blocks.air.getState(); // cavebase, ravine
	private State[] layers = null; // g.flat
	private BaseBiome[] frostBiomes = null; // b.layered
	private BaseBiome[] coldBiomes = null; // b.layered
	private BaseBiome[] mediumBiomes = null; // b.layered
	private BaseBiome[] hotBiomes = null; // b.layered
	private BaseBiome[] addBiomes = null; // b.layered
	
	private final List<FeatureOre> ores = Lists.newArrayList();
	private final List<FeatureLake> lakes = Lists.newArrayList();
	private final List<FeatureLiquid> liquids = Lists.newArrayList();
	
	private long seed = 0L;
	
	static {
		final String safe = "0123456789abcdefghijklmnopqrstuvwxyz_";
		for(int z = 0; z < safe.length(); z++) {
			SAFE_CHARS.add(safe.charAt(z));
		}
	}

	private static String getSafeFilename(String name, String fallback) {
		if(name.length() < 1 || name.length() > 32)
			return fallback;
		for(int z = 0; z < name.length(); z++) {
			if(!SAFE_CHARS.contains(name.charAt(z))) {
				return fallback;
			}
		}
		return name;
	}
	
	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 setCustomName(String name) {
//		this.customName = 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(BaseBiome 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(BaseBiome mainBiome, boolean semiFixed, int biomeSize, int riverSize, int snowRarity, int seaRarity, 
			int addRarity, BaseBiome ... 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(BaseBiome ... biomes) {
		this.frostBiomes = biomes;
		return this;
	}

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

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

	public final Dimension setHotBiomes(BaseBiome ... biomes) {
		this.hotBiomes = biomes;
		return this;
	}
	
	public final Dimension setBiome(BaseBiome 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 setWorldFloor(State value) {
		this.floor = value;
		return this;
	}

	public final Dimension setWorldCeiling(State value) {
		this.ceiling = value;
		return this;
	}

	public final Dimension setWorldFloorCeiling(State value) {
		this.floor = this.ceiling = value;
		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 FeatureLake(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 FeatureLiquid(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 FeatureOre(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 FeatureOre(BlockRegistry.getRegisteredBlock(metal.name + "_ore").getState(), 
					count < 0 ? 0 : count, count < 0 ? (-count) : 0, METAL_SIZES[metal.rarity], 0, 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(String value) {
		this.cloudTexture = value;
		return this;
	}

	public final Dimension setSkyBoxTexture(String 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 + ".png";
	}
	
	public final String getSkyBoxTexture() {
		return this.skyboxTexture == null ? null : ("textures/world/" + this.skyboxTexture + ".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 State getWorldFloor() {
		return this.floor;
	}

	public final State getWorldCeiling() {
		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 getByNbt(NBTTagCompound tag) {
    	return getByNbt(tag, true, false, false);
    }
    
    public static Dimension getByNbt(NBTTagCompound tag, boolean generator) {
    	return getByNbt(tag, false, generator, false);
    }
    
    private static Dimension getByNbt(NBTTagCompound tag, boolean mapOnly, boolean generator, boolean all) {
    	Dimension dim;
    	DimType type = DimType.getByName(tag.getString("Type"));
    	int id = tag.getInteger("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.fromNbt(tag, generator, all);
    	return dim;
    }
    
    public final Dimension copy() {
    	Dimension dim = getByNbt(this.toNbt(true, true), false, true, true);
    	dim.setCustomName(this.getCustomName());
    	return dim;
    }
    
    public final Dimension copy(int id, String name) {
    	NBTTagCompound tag = this.toNbt(true, true);
    	tag.setInteger("ID", id);
    	tag.setString("Name", name);
    	return getByNbt(tag, false, true, true);
    }
    
    public final void fromNbt(NBTTagCompound tag) {
    	this.fromNbt(tag, true, false);
    }
    
    private final void fromNbt(NBTTagCompound tag, boolean generator, boolean all) {
    	if(this == Space.INSTANCE) {
    		if(generator)
    			this.seed = tag.getLong("Seed");
    		return;
    	}
    	if(generator) {
	    	this.seed = tag.getLong("Seed");
    		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.getBoolean("MobGen");
		    	this.snow = tag.getBoolean("SnowGen");
		    	this.caves = tag.getBoolean("Caves");
		    	this.ravines = tag.getBoolean("Ravines");
		    	this.strideCaves = tag.getBoolean("AltCaves");
		    	this.useStrongholds = tag.getBoolean("Strongholds");
		    	this.useVillages = tag.getBoolean("Villages");
		    	this.useMineshafts = tag.getBoolean("Mineshafts");
		    	this.useScattered = tag.getBoolean("Scattered");
		    	this.useFortresses = tag.getBoolean("Fortresses");
		    	this.dungeons = tag.getInteger("Dungeons");
		    	this.biomeSize = tag.getInteger("BiomeSize");
		    	this.riverSize = tag.getInteger("RiverSize");
		    	this.snowRarity = tag.getInteger("SnowRarity");
		    	this.seaRarity = tag.getInteger("SeaRarity");
		    	this.addRarity = tag.getInteger("AddRarity");
	//	    	this.biomeRarity = tag.getInteger("BiomeRarity");
		    	this.seaLevel = tag.getInteger("SeaLevel");
		    	this.defaultBiome = BaseBiome.findByName(tag.getString("DefaultBiome"));
		    	this.semiFixed = tag.getBoolean("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.filler = BlockRegistry.getFromIdName(tag.getString("FillerBlock"), Blocks.stone.getState());
		    	this.top = BlockRegistry.getFromIdName(tag.getString("TopBlock"), Blocks.dirt.getState());
		    	this.surface = BlockRegistry.getFromIdName(tag.getString("SurfaceBlock"), Blocks.grass.getState());
		    	this.alt1 = BlockRegistry.getFromIdName(tag.getString("AltBlock1"), Blocks.gravel.getState());
		    	this.alt2 = BlockRegistry.getFromIdName(tag.getString("AltBlock2"), Blocks.sand.getState());
		    	this.liquid = BlockRegistry.getFromIdName(tag.getString("LiquidBlock"), Blocks.water.getState());
		    	this.floor = tag.hasKey("FloorBlock", 8) ? 
		    			BlockRegistry.getFromIdName(tag.getString("FloorBlock"), Blocks.bedrock.getState()) : null;
		    	this.ceiling = tag.hasKey("CeilingBlock", 8) ? 
		    			BlockRegistry.getFromIdName(tag.getString("CeilingBlock"), null) : null;
		    	this.caveFiller = BlockRegistry.getFromIdName(tag.getString("CaveFillBlock"), Blocks.lava.getState());
		    	if(tag.hasKey("Layers", 9)) {
			    	NBTTagList list = tag.getTagList("Layers", 8);
			    	this.layers = new State[list.tagCount()];
			    	for(int z = 0; z < this.layers.length; z++) {
			    		this.layers[z] = BlockRegistry.getFromIdName(list.getStringTagAt(z), Blocks.stone.getState());
			    	}
		    	}
		    	else {
		    		this.layers = null;
		    	}
		    	if(tag.hasKey("AddBiomes", 9)) {
			    	NBTTagList list = tag.getTagList("AddBiomes", 8);
			    	if(list.hasNoTags()) {
			    		this.addBiomes = null;
			    	}
			    	else {
				    	this.addBiomes = new BaseBiome[list.tagCount()];
				    	for(int z = 0; z < this.addBiomes.length; z++) {
				    		this.addBiomes[z] = BaseBiome.findByName(list.getStringTagAt(z));
				    	}
			    	}
		    	}
		    	else {
		    		this.addBiomes = null;
		    	}
		    	if(tag.hasKey("FrostBiomes", 9)) {
			    	NBTTagList list = tag.getTagList("FrostBiomes", 8);
			    	if(list.hasNoTags()) {
			    		this.frostBiomes = null;
			    	}
			    	else {
				    	this.frostBiomes = new BaseBiome[list.tagCount()];
				    	for(int z = 0; z < this.frostBiomes.length; z++) {
				    		this.frostBiomes[z] = BaseBiome.findByName(list.getStringTagAt(z));
				    	}
			    	}
		    	}
		    	else {
		    		this.frostBiomes = null;
		    	}
		    	if(tag.hasKey("ColdBiomes", 9)) {
			    	NBTTagList list = tag.getTagList("ColdBiomes", 8);
			    	if(list.hasNoTags()) {
			    		this.coldBiomes = null;
			    	}
			    	else {
				    	this.coldBiomes = new BaseBiome[list.tagCount()];
				    	for(int z = 0; z < this.coldBiomes.length; z++) {
				    		this.coldBiomes[z] = BaseBiome.findByName(list.getStringTagAt(z));
				    	}
			    	}
		    	}
		    	else {
		    		this.coldBiomes = null;
		    	}
		    	if(tag.hasKey("MediumBiomes", 9)) {
			    	NBTTagList list = tag.getTagList("MediumBiomes", 8);
			    	if(list.hasNoTags()) {
			    		this.mediumBiomes = null;
			    	}
			    	else {
				    	this.mediumBiomes = new BaseBiome[list.tagCount()];
				    	for(int z = 0; z < this.mediumBiomes.length; z++) {
				    		this.mediumBiomes[z] = BaseBiome.findByName(list.getStringTagAt(z));
				    	}
			    	}
		    	}
		    	else {
		    		this.mediumBiomes = null;
		    	}
		    	if(tag.hasKey("HotBiomes", 9)) {
			    	NBTTagList list = tag.getTagList("HotBiomes", 8);
			    	if(list.hasNoTags()) {
			    		this.hotBiomes = null;
			    	}
			    	else {
				    	this.hotBiomes = new BaseBiome[list.tagCount()];
				    	for(int z = 0; z < this.hotBiomes.length; z++) {
				    		this.hotBiomes[z] = BaseBiome.findByName(list.getStringTagAt(z));
				    	}
			    	}
		    	}
		    	else {
		    		this.hotBiomes = null;
		    	}
		    	this.ores.clear();
		    	if(tag.hasKey("Ores", 9)) {
			    	NBTTagList list = tag.getTagList("Ores", 10);
			    	for(int z = 0; z < list.tagCount(); z++) {
			    		NBTTagCompound gen = list.getCompoundTagAt(z);
			    		this.ores.add(new FeatureOre(BlockRegistry.getFromIdName(gen.getString("Block"), Blocks.iron_ore.getState()),
			    				gen.getInteger("Count"), gen.getInteger("Add"), gen.getInteger("Size"), 
			    				gen.getInteger("MinC"), gen.getInteger("MaxS"), gen.getBoolean("Distrib")));
			    	}
		    	}
		    	this.lakes.clear();
		    	if(tag.hasKey("Lakes", 9)) {
			    	NBTTagList list = tag.getTagList("Lakes", 10);
			    	for(int z = 0; z < list.tagCount(); z++) {
			    		NBTTagCompound gen = list.getCompoundTagAt(z);
			    		this.lakes.add(new FeatureLake(
			    				BlockRegistry.getFromIdName(gen.getString("Block"), Blocks.iron_ore.getState()),
			    				gen.hasKey("Filler", 8) ? BlockRegistry.getFromIdName(gen.getString("Filler"), null) : null,
					    		gen.hasKey("Top", 8) ? BlockRegistry.getFromIdName(gen.getString("Top"), null) : null,
			    				gen.getInteger("Chance"), gen.getInteger("Min"), gen.getInteger("Max"), gen.getBoolean("Ratiod")));
			    	}
		    	}
		    	this.liquids.clear();
		    	if(tag.hasKey("Liquids", 9)) {
			    	NBTTagList list = tag.getTagList("Liquids", 10);
			    	for(int z = 0; z < list.tagCount(); z++) {
			    		NBTTagCompound gen = list.getCompoundTagAt(z);
			    		this.liquids.add(new FeatureLiquid(
			    				BlockRegistry.getFromIdName(gen.getString("Block"), Blocks.iron_ore.getState()),
			    				gen.getInteger("Chance"), gen.getInteger("Min"), gen.getInteger("Max"), gen.getBoolean("Lower")));
			    	}
		    	}
		    	this.populated = !tag.hasKey("NoPopulation", 1) || !tag.getBoolean("NoPopulation");
    		}
    	}
    	else {
    		this.fullName = tag.getString("FullName");
        	this.readNbt(tag);
    	}
//    	this.readNbt(tag);
//    	this.customName = tag.hasKey("CustomName", 8) ? tag.getString("CustomName") : null;
		if(all || !generator || this.id >= UniverseRegistry.MORE_DIM_ID) {
	    	this.denseFog = tag.getBoolean("DenseFog");
	    	this.timeQualifier = tag.getInteger("ImperialTime");
	    	this.brightness = tag.getInteger("Brightness");
	    	this.skyColor = tag.getInteger("SkyColor");
	    	this.fogColor = tag.getInteger("FogColor");
	    	this.cloudColor = tag.getInteger("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 = getSafeFilename(tag.getString("CloudTexture"), "clouds");
	    	this.skyboxTexture = tag.hasKey("SkyBoxTexture", 8) ? 
	    			getSafeFilename(tag.getString("SkyBoxTexture"), null) : null;
	    	if(tag.hasKey("StarColor", 3)) {
		    	this.setStarColor(tag.getInteger("StarColor"));
	    	}
	    	else if(tag.hasKey("StarColorFnc", 10)) {
	    		NBTTagCompound fnc = tag.getCompoundTag("StarColorFnc");
	    		this.setStarColorSin(fnc.getFloat("Period"), fnc.getFloat("Det"), fnc.getFloat("Dist"), 
	    				fnc.getInteger("Color"), fnc.getByte("DetChn"), fnc.getByte("DistChn"));
	    	}
	    	else {
	    		this.starColorFunc = null;
	    	}
	    	if(tag.hasKey("DStarColor", 3)) {
		    	this.setDeepStarColor(tag.getInteger("DStarColor"));
	    	}
	    	else if(tag.hasKey("DStarColorFnc", 10)) {
	    		NBTTagCompound fnc = tag.getCompoundTag("DStarColorFnc");
	    		this.setDeepStarColorSin(fnc.getFloat("Period"), fnc.getFloat("Det"), fnc.getFloat("Dist"), 
	    				fnc.getInteger("Color"), fnc.getByte("DetChn"), fnc.getByte("DistChn"));
	    	}
	    	else {
	    		this.deepstarColorFunc = null;
	    	}
		}
    }
    
    public final NBTTagCompound toNbt(boolean generator) {
    	return this.toNbt(generator, false);
    }
    
    private final NBTTagCompound toNbt(boolean generator, boolean all) {
    	NBTTagCompound tag = (all || !generator || this.id >= UniverseRegistry.MORE_DIM_ID) ? this.toNbt() : new NBTTagCompound();
    	if(this == Space.INSTANCE) {
    		if(generator)
    			tag.setLong("Seed", this.seed);
    		return tag;
    	}
    	if(generator) {
			tag.setLong("Seed", this.seed);
			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.setBoolean("MobGen", this.mobs);
		    	tag.setBoolean("SnowGen", this.snow);
		    	tag.setBoolean("Caves", this.caves);
		    	tag.setBoolean("Ravines", this.ravines);
		    	tag.setBoolean("AltCaves", this.strideCaves);
		    	tag.setBoolean("Strongholds", this.useStrongholds);
		    	tag.setBoolean("Villages", this.useVillages);
		    	tag.setBoolean("Mineshafts", this.useMineshafts);
		    	tag.setBoolean("Scattered", this.useScattered);
		    	tag.setBoolean("Fortresses", this.useFortresses);
		    	tag.setInteger("Dungeons", this.dungeons);
		    	tag.setInteger("BiomeSize", this.biomeSize);
		    	tag.setInteger("RiverSize", this.riverSize);
		    	tag.setInteger("SnowRarity", this.snowRarity);
		    	tag.setInteger("SeaRarity", this.seaRarity);
		    	tag.setInteger("AddRarity", this.addRarity);
	//	    	tag.setInteger("BiomeRarity", this.biomeRarity);
		    	tag.setInteger("SeaLevel", this.seaLevel);
	//			if(this.defaultBiome != null)
				tag.setString("DefaultBiome", this.defaultBiome.name.toLowerCase());
	//			if(this.mainBiome != null)
				tag.setBoolean("SemiFixed", this.semiFixed);
				tag.setString("DefaultWeather", this.defaultWeather.getName());
				tag.setString("DefaultLeaves", this.defaultLeaves.getName());
				tag.setString("FillerBlock", BlockRegistry.toIdName(this.filler));
				tag.setString("TopBlock", BlockRegistry.toIdName(this.top));
				tag.setString("SurfaceBlock", BlockRegistry.toIdName(this.surface));
				tag.setString("AltBlock1", BlockRegistry.toIdName(this.alt1));
				tag.setString("AltBlock2", BlockRegistry.toIdName(this.alt2));
				tag.setString("LiquidBlock", BlockRegistry.toIdName(this.liquid));
				if(this.floor != null)
					tag.setString("FloorBlock", BlockRegistry.toIdName(this.floor));
				if(this.ceiling != null)
					tag.setString("CeilingBlock", BlockRegistry.toIdName(this.ceiling));
				tag.setString("CaveFillBlock", BlockRegistry.toIdName(this.caveFiller));
	    		if(this.layers != null) {
	    			NBTTagList list = new NBTTagList();
	    			for(State gen : this.layers) {
	    				list.appendTag(new NBTTagString(BlockRegistry.toIdName(gen)));
	    			}
	    			tag.setTag("Layers", list);
	    		}
	    		if(this.addBiomes != null) {
	    			NBTTagList list = new NBTTagList();
	    			for(BaseBiome biome : this.addBiomes) {
	    				list.appendTag(new NBTTagString(biome.name.toLowerCase()));
	    			}
	    			tag.setTag("AddBiomes", list);
	    		}
	    		if(this.frostBiomes != null) {
	    			NBTTagList list = new NBTTagList();
	    			for(BaseBiome biome : this.frostBiomes) {
	    				list.appendTag(new NBTTagString(biome.name.toLowerCase()));
	    			}
	    			tag.setTag("FrostBiomes", list);
	    		}
	    		if(this.coldBiomes != null) {
	    			NBTTagList list = new NBTTagList();
	    			for(BaseBiome biome : this.coldBiomes) {
	    				list.appendTag(new NBTTagString(biome.name.toLowerCase()));
	    			}
	    			tag.setTag("ColdBiomes", list);
	    		}
	    		if(this.mediumBiomes != null) {
	    			NBTTagList list = new NBTTagList();
	    			for(BaseBiome biome : this.mediumBiomes) {
	    				list.appendTag(new NBTTagString(biome.name.toLowerCase()));
	    			}
	    			tag.setTag("MediumBiomes", list);
	    		}
	    		if(this.hotBiomes != null) {
	    			NBTTagList list = new NBTTagList();
	    			for(BaseBiome biome : this.hotBiomes) {
	    				list.appendTag(new NBTTagString(biome.name.toLowerCase()));
	    			}
	    			tag.setTag("HotBiomes", list);
	    		}
	    		if(!this.ores.isEmpty()) {
	    			NBTTagList list = new NBTTagList();
	    			for(FeatureOre gen : this.ores) {
		    			NBTTagCompound ore = new NBTTagCompound();
		    			ore.setString("Block", BlockRegistry.toIdName(gen.state));
		    			ore.setBoolean("Distrib", gen.dist);
		    			ore.setInteger("Size", gen.size);
		    			ore.setInteger("Count", gen.count);
		    			ore.setInteger("Add", gen.more);
		    			ore.setInteger("MinC", gen.min);
		    			ore.setInteger("MaxS", gen.max);
		    			list.appendTag(ore);
	    			}
	    			tag.setTag("Ores", list);
	    		}
	    		if(!this.lakes.isEmpty()) {
	    			NBTTagList list = new NBTTagList();
	    			for(FeatureLake gen : this.lakes) {
		    			NBTTagCompound lake = new NBTTagCompound();
		    			lake.setString("Block", BlockRegistry.toIdName(gen.state));
		    			if(gen.filler != null)
		    				lake.setString("Filler", BlockRegistry.toIdName(gen.filler));
		    			if(gen.top != null)
		    				lake.setString("Top", BlockRegistry.toIdName(gen.top));
		    			lake.setBoolean("Ratiod", gen.ratiod);
		    			lake.setInteger("Chance", gen.chance);
		    			lake.setInteger("Min", gen.minHeight);
		    			lake.setInteger("Max", gen.maxHeight);
		    			list.appendTag(lake);
	    			}
	    			tag.setTag("Lakes", list);
	    		}
	    		if(!this.liquids.isEmpty()) {
	    			NBTTagList list = new NBTTagList();
	    			for(FeatureLiquid gen : this.liquids) {
		    			NBTTagCompound liquid = new NBTTagCompound();
		    			liquid.setString("Block", BlockRegistry.toIdName(gen.state));
		    			liquid.setBoolean("Lower", gen.lower);
		    			liquid.setInteger("Chance", gen.chance);
		    			liquid.setInteger("Min", gen.minHeight);
		    			liquid.setInteger("Max", gen.maxHeight);
		    			list.appendTag(liquid);
	    			}
	    			tag.setTag("Liquids", list);
	    		}
	    		if(!this.populated)
	    			tag.setBoolean("NoPopulation", true);
			}
    	}
    	else {
    		tag.setString("FullName", this.getFormattedName(true));
        	this.writeNbt(tag);
    	}
//    	this.writeNbt(tag);
//    	if(this.customName != null)
//    		tag.setString("CustomName", this.customName);
		if(all || !generator || this.id >= UniverseRegistry.MORE_DIM_ID) {
	    	tag.setBoolean("DenseFog", this.denseFog);
	    	tag.setInteger("ImperialTime", this.timeQualifier);
	    	tag.setInteger("Brightness", this.brightness);
	    	tag.setInteger("SkyColor", this.skyColor);
	    	tag.setInteger("FogColor", this.fogColor);
	    	tag.setInteger("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);
	    	if(this.skyboxTexture != null)
	    		tag.setString("SkyBoxTexture", this.skyboxTexture);
	    	if(this.starColorFunc instanceof SingleColorGen) {
	    		tag.setInteger("StarColor", ((SingleColorGen)this.starColorFunc).color);
	    	}
	    	else if(this.starColorFunc instanceof SinusColorGen) {
	    		NBTTagCompound fnc = new NBTTagCompound();
	    		fnc.setFloat("Period", ((SinusColorGen)this.starColorFunc).period);
	    		fnc.setFloat("Det", ((SinusColorGen)this.starColorFunc).det);
	    		fnc.setFloat("Dist", ((SinusColorGen)this.starColorFunc).dist); 
				fnc.setInteger("Color", ((SinusColorGen)this.starColorFunc).color);
				fnc.setByte("DetChn", (byte)((SinusColorGen)this.starColorFunc).detChn);
				fnc.setByte("DistChn", (byte)((SinusColorGen)this.starColorFunc).distChn);
				tag.setTag("StarColorFnc", fnc);
	    	}
	    	if(this.deepstarColorFunc instanceof SingleColorGen) {
	    		tag.setInteger("DStarColor", ((SingleColorGen)this.deepstarColorFunc).color);
	    	}
	    	else if(this.deepstarColorFunc instanceof SinusColorGen) {
	    		NBTTagCompound fnc = new NBTTagCompound();
	    		fnc.setFloat("Period", ((SinusColorGen)this.deepstarColorFunc).period);
	    		fnc.setFloat("Det", ((SinusColorGen)this.deepstarColorFunc).det);
	    		fnc.setFloat("Dist", ((SinusColorGen)this.deepstarColorFunc).dist); 
				fnc.setInteger("Color", ((SinusColorGen)this.deepstarColorFunc).color);
				fnc.setByte("DetChn", (byte)((SinusColorGen)this.deepstarColorFunc).detChn);
				fnc.setByte("DistChn", (byte)((SinusColorGen)this.deepstarColorFunc).distChn);
				tag.setTag("DStarColorFnc", fnc);
	    	}
		}
    	return tag;
    }
    
    public final NBTTagCompound toNbt() {
    	NBTTagCompound tag = new NBTTagCompound();
    	tag.setInteger("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 BaseBiome 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 BaseBiome[] getAddBiomes() {
		return this.addBiomes;
	}

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

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

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

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

	public BaseBiome[] 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<FeatureOre> getOres() {
		return this.ores;
	}

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

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