protected override void Init(MyObjectBuilder_DefinitionBase builder)
        {
            base.Init(builder);
            var ob = builder as MyObjectBuilder_PlanetGeneratorDefinition;

            if (ob.InheritFrom != null && ob.InheritFrom.Length > 0)
            {
                InheritFrom(ob.InheritFrom);
            }

            if (ob.PlanetMaps.HasValue)
                PlanetMaps = ob.PlanetMaps.Value;

            if (ob.HasAtmosphere.HasValue) HasAtmosphere = ob.HasAtmosphere.Value;

			if(ob.CloudLayers != null)
				CloudLayers = ob.CloudLayers;

            if (ob.SoundRules != null)
            {
                SoundRules = new MyPlanetEnvironmentalSoundRule[ob.SoundRules.Length];

                for (int ruleIndex = 0; ruleIndex < ob.SoundRules.Length; ++ruleIndex)
                {
                    MyPlanetEnvironmentalSoundRule sr;

                    sr = new MyPlanetEnvironmentalSoundRule()
                    {
                        Latitude = ob.SoundRules[ruleIndex].Latitude,
                        Height = ob.SoundRules[ruleIndex].Height,
                        SunAngleFromZenith = ob.SoundRules[ruleIndex].SunAngleFromZenith,
                        EnvironmentSound = MyStringHash.GetOrCompute(ob.SoundRules[ruleIndex].EnvironmentSound)
                    };

                    sr.Latitude.ConvertToSine();
                    sr.SunAngleFromZenith.ConvertToCosine();
                    SoundRules[ruleIndex] = sr;
                }
            }
            if (ob.MusicCategories != null)
                MusicCategories = ob.MusicCategories;

            if (ob.HillParams.HasValue)
                HillParams = ob.HillParams.Value;

            if (ob.Atmosphere != null)
                Atmosphere = ob.Atmosphere;

            if (ob.GravityFalloffPower.HasValue) GravityFalloffPower = ob.GravityFalloffPower.Value;

            if (ob.HostileAtmosphereColorShift != null)
                HostileAtmosphereColorShift = ob.HostileAtmosphereColorShift;

            if (ob.MaterialsMaxDepth.HasValue)
                MaterialsMaxDepth = ob.MaterialsMaxDepth.Value;
            if (ob.MaterialsMinDepth.HasValue)
                MaterialsMinDepth = ob.MaterialsMinDepth.Value;

            if (ob.CustomMaterialTable != null && ob.CustomMaterialTable.Length > 0)
            {
                SurfaceMaterialTable = new MyPlanetMaterialDefinition[ob.CustomMaterialTable.Length];
                for (int i = 0; i < SurfaceMaterialTable.Length; i++)
                {
                    SurfaceMaterialTable[i] = ob.CustomMaterialTable[i].Clone() as MyPlanetMaterialDefinition;
                    if (SurfaceMaterialTable[i].Material == null && !SurfaceMaterialTable[i].HasLayers)
                    {
                        MyLog.Default.WriteLine("Custom material does not contain any material ids.");
                    }
                    else if (SurfaceMaterialTable[i].HasLayers)
                    {
                        // Make the depth cumulative so we don't have to calculate it later.
                        // If we want we can even binary search it.
                        float depth = SurfaceMaterialTable[i].Layers[0].Depth;
                        for (int j = 1; j < SurfaceMaterialTable[i].Layers.Length; j++)
                        {
                            SurfaceMaterialTable[i].Layers[j].Depth += depth;
                            depth = SurfaceMaterialTable[i].Layers[j].Depth;
                        }
                    }
                }
            }

            if (ob.DistortionTable != null && ob.DistortionTable.Length > 0)
            {
                DistortionTable = ob.DistortionTable;
            }

            if (ob.DefaultSurfaceMaterial != null)
                DefaultSurfaceMaterial = ob.DefaultSurfaceMaterial;

            if (ob.DefaultSubSurfaceMaterial != null)
                DefaultSubSurfaceMaterial = ob.DefaultSubSurfaceMaterial;

            if (ob.SurfaceGravity.HasValue) SurfaceGravity = ob.SurfaceGravity.Value;

            if (ob.AtmosphereSettings != null)
                AtmosphereSettings = ob.AtmosphereSettings;

            // Folder name is not inherited to avoid weirdness.
            FolderName = ob.FolderName != null ? ob.FolderName : ob.Id.SubtypeName;

            if (ob.ComplexMaterials != null && ob.ComplexMaterials.Length > 0)
            {
                MaterialGroups = new MyPlanetMaterialGroup[ob.ComplexMaterials.Length];

                for (int k = 0; k < ob.ComplexMaterials.Length; k++)
                {
                    MaterialGroups[k] = ob.ComplexMaterials[k].Clone() as MyPlanetMaterialGroup;

                    var group = MaterialGroups[k];
                    var matRules = group.MaterialRules;
                    List<int> badMaterials = new List<int>();

                    for (int i = 0; i < matRules.Length; i++)
                    {
                        if (matRules[i].Material == null && (matRules[i].Layers == null || matRules[i].Layers.Length == 0))
                        {
                            MyLog.Default.WriteLine("Material rule does not contain any material ids.");
                            badMaterials.Add(i);
                            continue;
                        }
                        else if (matRules[i].Layers != null && matRules[i].Layers.Length != 0)
                        {
                            // Make the depth cumulative so we don't have to calculate it later.
                            // If we want we can even binary search it.
                            float depth = matRules[i].Layers[0].Depth;
                            for (int j = 1; j < matRules[i].Layers.Length; j++)
                            {
                                matRules[i].Layers[j].Depth += depth;
                                depth = matRules[i].Layers[j].Depth;
                            }
                        }

                        // We use the cosine later so we precompute it here.
                        matRules[i].Slope.ConvertToCosine();
                        matRules[i].Latitude.ConvertToSine();
                        matRules[i].Longitude.ConvertToCosineLongitude();
                    }

                    if (badMaterials.Count > 0)
                    {
                        matRules = matRules.RemoveIndices(badMaterials);
                    }

                    group.MaterialRules = matRules;
                }
            }

            if (ob.EnvironmentItems != null && ob.EnvironmentItems.Length > 0)
            {
                MaterialEnvironmentMappings = new Dictionary<int,Dictionary<string,List<MyPlanetEnvironmentMapping>>>();

                for (int i = 0; i < ob.EnvironmentItems.Length; i++)
                {
                    PlanetEnvironmentItemMapping map = ob.EnvironmentItems[i];
                    if (map.Rule != null)
                        map.Rule = map.Rule.Clone() as MyPlanetSurfaceRule;
                    else
                        map.Rule = new MyPlanetSurfaceRule();
                    map.Rule.Slope.ConvertToCosine();
                    map.Rule.Latitude.ConvertToSine();
                    map.Rule.Longitude.ConvertToCosineLongitude();
                    
                    // If the mapping does not assign a material it is ignored
                    if (map.Materials == null) break;

                    if (map.Biomes == null) map.Biomes = m_arrayOfZero;

                    foreach (var biome in map.Biomes)
                    {
                        Dictionary<string,List<MyPlanetEnvironmentMapping>> matmap;

                        if (MaterialEnvironmentMappings.ContainsKey(biome))
                        {
                            matmap = MaterialEnvironmentMappings[biome];
                        }
                        else
                        {
                            matmap = new Dictionary<string, List<MyPlanetEnvironmentMapping>>();
                            MaterialEnvironmentMappings.Add(biome, matmap);
                        }

                        foreach (var material in map.Materials)
                        {
                            if (!matmap.ContainsKey(material))
                                matmap.Add(material, new List<MyPlanetEnvironmentMapping>());

                            matmap[material].Add(new MyPlanetEnvironmentMapping(map));
                        }
                    }
                }
            }

            if (ob.OreMappings != null)
            {
                OreMappings = ob.OreMappings;
            }

            if (ob.MaterialBlending.HasValue)
            {
                MaterialBlending = ob.MaterialBlending.Value;
            }

            if (ob.SurfaceDetail != null)
            {
                Detail = ob.SurfaceDetail;
            }

            if (ob.AnimalSpawnInfo != null)
            {
                AnimalSpawnInfo = ob.AnimalSpawnInfo;
            }

            if (ob.NightAnimalSpawnInfo != null)
            {
                NightAnimalSpawnInfo = ob.NightAnimalSpawnInfo;
            }

            if (ob.SectorDensity.HasValue)
            {
                SectorDensity = ob.SectorDensity.Value;
            }
        }
        public void GetPlanetMaps(string folder, MyModContext context, MyPlanetMaps mapsToUse, out MyCubemap[] maps)
        {
            if (m_planetMaps.ContainsKey(folder))
            {
                maps = m_planetMaps[folder];
                return;
            }

            maps = new MyCubemap[4];
            
            MyCubemapData<byte>[] tmpMaps = new MyCubemapData<byte>[4 * 6];

            byte[][] streams = new byte[4][];

            string fullPath;

            ProfilerShort.Begin("MyHeightmapLoadingSystem::GetPlanetMaps()");

            ProfilerShort.Begin("Load _mat");
            // Round one: material, ore, biome
            if (mapsToUse.Material || mapsToUse.Biome || mapsToUse.Ores)
                for (int i = 0; i < 6; ++i)
                {
                    string name = Path.Combine(folder, MyCubemapHelpers.GetNameForFace(i));

                    using (var texture = TryGetPlanetTexture(name, context, "_mat", out fullPath))
                    {
                        if (texture == null)
                        {
                            ClearMatValues(tmpMaps);
                            break;
                        }

                        PixelBuffer buffer = texture.GetPixelBuffer(0, 0, 0);

                        if (buffer.Format != Format.B8G8R8A8_UNorm &&
                            buffer.Format != Format.R8G8B8A8_UNorm)
                        {
                            MyDebug.FailRelease("While loading maps from {1}: Unsupported planet map format: {0}.", buffer.Format, fullPath);
                            break;
                        }

                        if (buffer.Width != buffer.Height)
                        {
                            MyDebug.FailRelease("While loading maps from {0}: Width and height must be the same.", fullPath);
                            break;
                        }

                        if (mapsToUse.Material)
                        {
                            tmpMaps[i * 4] = new MyCubemapData<byte>(buffer.Width);
                            streams[0] = tmpMaps[i * 4].Data;
                        }

                        if (mapsToUse.Biome)
                        {
                            tmpMaps[i * 4 + 1] = new MyCubemapData<byte>(buffer.Width);
                            streams[1] = tmpMaps[i * 4 + 1].Data;
                        }

                        if (mapsToUse.Ores)
                        {
                            tmpMaps[i * 4 + 2] = new MyCubemapData<byte>(buffer.Width);
                            streams[2] = tmpMaps[i * 4 + 2].Data;
                        }

                        // Invert channels for BGRA
                        if (buffer.Format == Format.B8G8R8A8_UNorm)
                        {
                            var tmp = streams[2];
                            streams[2] = streams[0];
                            streams[0] = tmp;
                        }
                        ReadChannelsFromImage(streams, buffer);
                        texture.Dispose();
                    }
                }

            ProfilerShort.BeginNextBlock("Load _add");
            // round two: add map
            if (mapsToUse.Occlusion)
                for (int i = 0; i < 6; ++i)
                {
                    string name = Path.Combine(folder, MyCubemapHelpers.GetNameForFace(i));

                    using (var texture = TryGetPlanetTexture(name, context,"_add", out fullPath))
                    {
                        if (texture == null)
                        {
                            ClearAddValues(tmpMaps);
                            break;
                        }

                        PixelBuffer buffer = texture.GetPixelBuffer(0, 0, 0);

                        if (buffer.Format != Format.B8G8R8A8_UNorm &&
                            buffer.Format != Format.R8G8B8A8_UNorm)
                        {
                            MyDebug.FailRelease("While loading maps from {1}: Unsupported planet map format: {0}.", buffer.Format, fullPath);
                            break;
                        }

                        if (buffer.Width != buffer.Height)
                        {
                            MyDebug.FailRelease("While loading maps from {0}: Width and height must be the same.", fullPath);
                            break;
                        }

                        if (mapsToUse.Occlusion)
                        {
                            tmpMaps[i * 4 + 3] = new MyCubemapData<byte>(buffer.Width);
                            streams[0] = tmpMaps[i * 4 + 3].Data;
                        }

                        streams[1] = streams[2] = null;

                        // Invert channels for BGRA
                        if (buffer.Format == Format.B8G8R8A8_UNorm)
                        {
                            var tmp = streams[2];
                            streams[2] = streams[0];
                            streams[0] = tmp;
                        }

                        ReadChannelsFromImage(streams, buffer);
                        texture.Dispose();
                    }
                }

            ProfilerShort.BeginNextBlock("Finish");

            for (int i = 0; i < 4; ++i)
            {
                if (tmpMaps[i] != null)
                {
                    var cmaps = new MyCubemapData<byte>[6];
                    for (int j = 0; j < 6; j++)
                    {
                        cmaps[j] = tmpMaps[i + j * 4];
                    }
                    maps[i] = new MyCubemap(cmaps);
                }
            }

            m_planetMaps[folder] = maps;

            ProfilerShort.End();
            ProfilerShort.End();
        }
        private void InheritFrom(string generator)
        {
            MyPlanetGeneratorDefinition parent = MyDefinitionManager.Static.GetDefinition<MyPlanetGeneratorDefinition>(MyStringHash.GetOrCompute(generator));

            if (parent == null)
            {
                MyDefinitionManager.Static.LoadingSet.m_planetGeneratorDefinitions.TryGetValue(new MyDefinitionId(typeof(MyObjectBuilder_PlanetGeneratorDefinition), generator), out parent);
            }

            if (parent == null)
            {
                MyLog.Default.WriteLine(String.Format("Could not find planet generator definition for '{0}'.", generator));
                return;
            }

            PlanetMaps = parent.PlanetMaps;
            HasAtmosphere = parent.HasAtmosphere;
            Atmosphere = parent.Atmosphere;
			CloudLayers = parent.CloudLayers;
            SoundRules = parent.SoundRules;
            MusicCategories = parent.MusicCategories;
            HillParams = parent.HillParams;
            MaterialsMaxDepth = parent.MaterialsMaxDepth;
            MaterialsMinDepth = parent.MaterialsMinDepth;
            GravityFalloffPower = parent.GravityFalloffPower;
            HostileAtmosphereColorShift = parent.HostileAtmosphereColorShift;
            SurfaceMaterialTable = parent.SurfaceMaterialTable;
            DistortionTable = parent.DistortionTable;
            DefaultSurfaceMaterial = parent.DefaultSurfaceMaterial;
            DefaultSubSurfaceMaterial = parent.DefaultSubSurfaceMaterial;
            MaterialGroups = parent.MaterialGroups;
            MaterialEnvironmentMappings = parent.MaterialEnvironmentMappings;
            SurfaceGravity = parent.SurfaceGravity;
            AtmosphereSettings = parent.AtmosphereSettings;
            FolderName = parent.FolderName;
            MaterialBlending = parent.MaterialBlending;
            OreMappings = parent.OreMappings;
            AnimalSpawnInfo = parent.AnimalSpawnInfo;
            NightAnimalSpawnInfo = parent.NightAnimalSpawnInfo;
            Detail = parent.Detail;
            SectorDensity = parent.SectorDensity;
        }