public NoiseClimateRealistic(long seed, double mapsizeZ) : base(seed + 1)
        {
            // We want the full range (from min temp to max temp) to pass every 50.000 blocks
            double climateBandWaveLength = 50000;

            // range must be divided by the climate map scaling
            halfRange = climateBandWaveLength / TerraGenConfig.climateMapScale / TerraGenConfig.climateMapSubScale;

            // We want the player to spawn in an area of temperature from 6 to 15 degrees
            float minTemp = 6;
            float maxTemp = 14;

            // Our temperature values are stored in a range from 0..255, so lets descale them
            int minTempDescaled = TerraGenConfig.DescaleTemperature(minTemp);
            int maxTempDescaled = TerraGenConfig.DescaleTemperature(maxTemp);

            // Chose one random value between min and max temp
            double rndTemp = minTempDescaled + NextInt(maxTempDescaled - minTempDescaled + 1);

            // A change of one degree
            double zPerDegDescaled = halfRange / 255;

            // We need to shift over z by this much to achieve 6-15 degrees
            zOffset = rndTemp * zPerDegDescaled;

            this.mapsizeZ = mapsizeZ;
        }
        internal void LoadTrees()
        {
            treeGenProps = api.Assets.Get("worldgen/treengenproperties.json").ToObject <TreeGenProperties>();
            treeGenProps.descVineMinTempRel = TerraGenConfig.DescaleTemperature(treeGenProps.vinesMinTemp) / 255f;

            treeGenerators.LoadTreeGenerators();

            random = new Random(api.WorldManager.Seed);

            worldheight = api.WorldManager.MapSizeY;
        }
        public NoiseClimateRealistic(long seed, double mapsizeZ, int polarEquatorDistance, int spawnMinTemp, int spawnMaxTemp) : base(seed + 1)
        {
            // range must be divided by the climate map scaling
            halfRange = polarEquatorDistance / TerraGenConfig.climateMapScale / TerraGenConfig.climateMapSubScale;

            // Our temperature values are stored in a range from 0..255, so lets descale them
            int minTempDescaled = TerraGenConfig.DescaleTemperature(spawnMinTemp);
            int maxTempDescaled = TerraGenConfig.DescaleTemperature(spawnMaxTemp);

            // Chose one random value between min and max temp
            double rndTemp = minTempDescaled + NextInt(maxTempDescaled - minTempDescaled + 1);

            // A change of one degree
            double zPerDegDescaled = halfRange / 255;

            // We need to shift over z by this much to achieve 6-15 degrees
            ZOffset = rndTemp * zPerDegDescaled - mapsizeZ / 2;
        }
        public TreeGenForClimate GetRandomGenForClimate(TreeVariant[] gens, int climate, int forest, int y)
        {
            int   rain      = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, y);
            int   temp      = TerraGenConfig.GetScaledAdjustedTemperature((climate >> 16) & 0xff, y - TerraGenConfig.seaLevel);
            float heightRel = ((float)y - TerraGenConfig.seaLevel) / ((float)api.WorldManager.MapSizeY - TerraGenConfig.seaLevel);
            int   fertility = TerraGenConfig.GetFertility(rain, temp, heightRel);

            float total = 0;
            float fertDist, rainDist, tempDist, forestDist, heightDist;

            distances.Clear();

            for (int i = 0; i < gens.Length; i++)
            {
                TreeVariant variant = gens[i];

                fertDist   = Math.Abs(fertility - variant.FertMid) / variant.FertRange;
                rainDist   = Math.Abs(rain - variant.RainMid) / variant.RainRange;
                tempDist   = Math.Abs(temp - variant.TempMid) / variant.TempRange;
                forestDist = Math.Abs(forest - variant.ForestMid) / variant.ForestRange;
                heightDist = Math.Abs((y / worldheight) - variant.HeightMid) / variant.HeightRange;


                double distSq =
                    Math.Max(0, fertDist * fertDist - 1) +
                    Math.Max(0, rainDist * rainDist - 1) +
                    Math.Max(0, tempDist * tempDist - 1) +
                    Math.Max(0, forestDist * forestDist - 1) +
                    Math.Max(0, heightDist * heightDist - 1)
                ;

                if (random.NextDouble() < distSq)
                {
                    continue;
                }

                float distance = (fertDist + rainDist + tempDist + forestDist + heightDist) * variant.Weight / 100f;

                distances.Add(variant, distance);

                total += distance;
            }

            distances = distances.Shuffle(random);

            double rnd = random.NextDouble();

            foreach (var val in distances)
            {
                rnd -= val.Value / total;
                if (rnd <= 0.001)
                {
                    float suitabilityBonus = GameMath.Clamp(0.7f - val.Value, 0f, 0.7f) * 1 / 0.7f * val.Key.SuitabilitySizeBonus;

                    float size = val.Key.MinSize + (float)random.NextDouble() * (val.Key.MaxSize - val.Key.MinSize) + suitabilityBonus;

                    float rainVal = Math.Max(0, (rain / 255f - treeGenProps.vinesMinRain) / (1 - treeGenProps.vinesMinRain));
                    float tempVal = Math.Max(0, (TerraGenConfig.DescaleTemperature(temp) / 255f - treeGenProps.descVineMinTempRel) / (1 - treeGenProps.descVineMinTempRel));

                    float vinesGrowthChance = 2f * rainVal * tempVal;

                    ITreeGenerator treegen = treeGenerators.GetGenerator(val.Key.Generator);

                    if (treegen == null)
                    {
                        api.World.Logger.Error("treengenproperties.json references tree generator {0}, but no such generator exists!", val.Key.Generator);
                        return(null);
                    }


                    return(new TreeGenForClimate(treegen, size, vinesGrowthChance));
                }
            }

            return(null);
        }