public void ApplyDefaults()
        {
            Theme = new RealisticMapGenBlockTheme(MapGenTheme.Forest);
            Seed  = (new Random()).Next();

            // default map dimensions
            MapWidth  = 256;
            MapLength = 256;
            MapHeight = 96;

            // default terrain elevation / depth
            MaxHeight          = 20;
            MaxDepth           = 12;
            MaxHeightVariation = 4;
            MaxDepthVariation  = 0;

            // water defaults: 50% water level, approx 50% coverage
            AddWater           = true;
            CustomWaterLevel   = false;
            MatchWaterCoverage = false;
            WaterLevel         = 48;
            WaterCoverage      = .5f;

            // bias defaults (no bias at all)
            UseBias        = false;
            DelayBias      = false;
            Bias           = 0;
            RaisedCorners  = 0;
            LoweredCorners = 0;
            MidPoint       = 0;

            // default heightmap filtering options
            DetailScale       = 7;
            FeatureScale      = 1;
            Roughness         = .5f;
            LayeredHeightmap  = false;
            MarbledHeightmap  = false;
            InvertHeightmap   = false;
            AboveFuncExponent = 1;
            BelowFuncExponent = 1;

            // default tree params (small tress only)
            AddTrees       = true;
            AddGiantTrees  = false;
            TreeSpacingMin = 7;
            TreeSpacingMax = 11;
            TreeHeightMin  = 5;
            TreeHeightMax  = 7;

            // default cave/ore params (all off)
            AddCaves     = false;
            AddOre       = false;
            AddCaveWater = false;
            AddCaveLava  = false;
            CaveDensity  = 2;
            CaveSize     = 1;

            // default snow params (off)
            AddSnow        = false;
            SnowAltitude   = 70;
            SnowTransition = 7;

            // default cliff params (on)
            AddCliffs               = true;
            CliffSmoothing          = true;
            CliffThreshold          = 1;
            CliffsideBlockThreshold = 0.01f;

            // default beach params (off)
            AddBeaches  = false;
            BeachExtent = 6;
            BeachHeight = 2;
        }
        public RealisticMapGenParameters([NotNull] XElement root)
            : this()
        {
            if (root == null)
            {
                throw new ArgumentNullException("root");
            }

            XAttribute versionTag = root.Attribute("version");
            int        version    = 0;

            if (versionTag != null && !String.IsNullOrEmpty(versionTag.Value))
            {
                version = Int32.Parse(versionTag.Value);
            }

            XElement el = root.Element("theme");

            if (el != null)
            {
                string      themeVal = el.Value;
                MapGenTheme theme;
                if (EnumUtil.TryParse(themeVal, out theme, true))
                {
                    // for old versions of MapGen templates, use enum
                    Theme = new RealisticMapGenBlockTheme(theme);
                }
                else
                {
                    // for newer versions, use the whole custom thing
                    Theme = new RealisticMapGenBlockTheme(el);
                }
            }

            Seed      = Int32.Parse(root.Element("seed").Value);
            MapWidth  = Int32.Parse(root.Element("dimX").Value);
            MapLength = Int32.Parse(root.Element("dimY").Value);
            MapHeight = Int32.Parse(root.Element("dimH").Value);
            MaxHeight = Int32.Parse(root.Element("maxHeight").Value);
            MaxDepth  = Int32.Parse(root.Element("maxDepth").Value);

            AddWater = Boolean.Parse(root.Element("addWater").Value);
            if (root.Element("customWaterLevel") != null)
            {
                CustomWaterLevel = Boolean.Parse(root.Element("customWaterLevel").Value);
            }
            MatchWaterCoverage = Boolean.Parse(root.Element("matchWaterCoverage").Value);
            WaterLevel         = Int32.Parse(root.Element("waterLevel").Value);
            WaterCoverage      = float.Parse(root.Element("waterCoverage").Value);

            UseBias = Boolean.Parse(root.Element("useBias").Value);
            if (root.Element("delayBias") != null)
            {
                DelayBias = Boolean.Parse(root.Element("delayBias").Value);
            }
            Bias           = float.Parse(root.Element("bias").Value);
            RaisedCorners  = Int32.Parse(root.Element("raisedCorners").Value);
            LoweredCorners = Int32.Parse(root.Element("loweredCorners").Value);
            MidPoint       = Int32.Parse(root.Element("midPoint").Value);

            if (version == 0)
            {
                DetailScale  = Int32.Parse(root.Element("minDetailSize").Value);
                FeatureScale = Int32.Parse(root.Element("maxDetailSize").Value);
            }
            else
            {
                DetailScale  = Int32.Parse(root.Element("detailScale").Value);
                FeatureScale = Int32.Parse(root.Element("featureScale").Value);
            }
            Roughness        = float.Parse(root.Element("roughness").Value);
            LayeredHeightmap = Boolean.Parse(root.Element("layeredHeightmap").Value);
            MarbledHeightmap = Boolean.Parse(root.Element("marbledHeightmap").Value);
            InvertHeightmap  = Boolean.Parse(root.Element("invertHeightmap").Value);
            if (root.Element("aboveFuncExponent") != null)
            {
                AboveFuncExponent = float.Parse(root.Element("aboveFuncExponent").Value);
            }
            if (root.Element("belowFuncExponent") != null)
            {
                BelowFuncExponent = float.Parse(root.Element("belowFuncExponent").Value);
            }

            AddTrees       = Boolean.Parse(root.Element("addTrees").Value);
            TreeSpacingMin = Int32.Parse(root.Element("treeSpacingMin").Value);
            TreeSpacingMax = Int32.Parse(root.Element("treeSpacingMax").Value);
            TreeHeightMin  = Int32.Parse(root.Element("treeHeightMin").Value);
            TreeHeightMax  = Int32.Parse(root.Element("treeHeightMax").Value);

            if (root.Element("addCaves") != null)
            {
                AddCaves     = Boolean.Parse(root.Element("addCaves").Value);
                AddCaveLava  = Boolean.Parse(root.Element("addCaveLava").Value);
                AddCaveWater = Boolean.Parse(root.Element("addCaveWater").Value);
                AddOre       = Boolean.Parse(root.Element("addOre").Value);
                CaveDensity  = float.Parse(root.Element("caveDensity").Value);
                CaveSize     = float.Parse(root.Element("caveSize").Value);
            }

            if (root.Element("addSnow") != null)
            {
                AddSnow = Boolean.Parse(root.Element("addSnow").Value);
            }
            if (root.Element("snowAltitude") != null)
            {
                SnowAltitude = Int32.Parse(root.Element("snowAltitude").Value);
            }
            if (root.Element("snowTransition") != null)
            {
                SnowTransition = Int32.Parse(root.Element("snowTransition").Value);
            }

            if (root.Element("addCliffs") != null)
            {
                AddCliffs = Boolean.Parse(root.Element("addCliffs").Value);
            }
            if (root.Element("cliffSmoothing") != null)
            {
                CliffSmoothing = Boolean.Parse(root.Element("cliffSmoothing").Value);
            }
            if (root.Element("cliffThreshold") != null)
            {
                CliffThreshold = float.Parse(root.Element("cliffThreshold").Value);
            }

            if (root.Element("addBeaches") != null)
            {
                AddBeaches = Boolean.Parse(root.Element("addBeaches").Value);
            }
            if (root.Element("beachExtent") != null)
            {
                BeachExtent = Int32.Parse(root.Element("beachExtent").Value);
            }
            if (root.Element("beachHeight") != null)
            {
                BeachHeight = Int32.Parse(root.Element("beachHeight").Value);
            }

            if (root.Element("maxHeightVariation") != null)
            {
                MaxHeightVariation = Int32.Parse(root.Element("maxHeightVariation").Value);
            }
            if (root.Element("maxDepthVariation") != null)
            {
                MaxDepthVariation = Int32.Parse(root.Element("maxDepthVariation").Value);
            }

            if (root.Element("addGiantTrees") != null)
            {
                AddGiantTrees = Boolean.Parse(root.Element("addGiantTrees").Value);
            }

            Validate();
        }
Example #3
0
        Map GenerateMap()
        {
            Map map = new Map(null, genParams.MapWidth, genParams.MapLength, genParams.MapHeight, true);

            theme = genParams.Theme;

            // scale features vertically based on map height
            double verticalScale = (genParams.MapHeight / 96.0) / 2 + 0.5;

            maxHeightScaled    = (int)Math.Round(genParams.MaxHeight * verticalScale);
            maxDepthScaled     = (int)Math.Round(genParams.MaxDepth * verticalScale);
            snowAltitudeScaled = (int)Math.Round(genParams.SnowAltitude * verticalScale);

            // Match water coverage
            float desiredWaterLevel = .5f;

            if (genParams.MatchWaterCoverage)
            {
                ReportRelativeProgress(2, "Heightmap Processing: Matching water coverage");
                // find a number between 0 and 1 ("desiredWaterLevel") for the heightmap such that
                // the fraction of heightmap coordinates ("blocks") that are below this threshold ("underwater")
                // match the specified WaterCoverage
                desiredWaterLevel = Noise.FindThreshold(heightMap, genParams.WaterCoverage);
            }

            // Calculate above/below water multipliers
            float aboveWaterMultiplier = 0;

            if (desiredWaterLevel < 1)
            {
                aboveWaterMultiplier = (maxHeightScaled / (1 - desiredWaterLevel));
            }

            // Apply power functions to above/below water parts of the heightmap
            if (Math.Abs(genParams.BelowFuncExponent - 1) > float.Epsilon ||
                Math.Abs(genParams.AboveFuncExponent - 1) > float.Epsilon)
            {
                ReportRelativeProgress(5, "Heightmap Processing: Adjusting slope");
                for (int x = heightMap.GetLength(0) - 1; x >= 0; x--)
                {
                    for (int y = heightMap.GetLength(1) - 1; y >= 0; y--)
                    {
                        if (heightMap[x, y] < desiredWaterLevel)
                        {
                            float normalizedDepth = 1 - heightMap[x, y] / desiredWaterLevel;
                            heightMap[x, y] = desiredWaterLevel -
                                              (float)Math.Pow(normalizedDepth, genParams.BelowFuncExponent) *
                                              desiredWaterLevel;
                        }
                        else
                        {
                            float normalizedHeight = (heightMap[x, y] - desiredWaterLevel) / (1 - desiredWaterLevel);
                            heightMap[x, y] = desiredWaterLevel +
                                              (float)Math.Pow(normalizedHeight, genParams.AboveFuncExponent) *
                                              (1 - desiredWaterLevel);
                        }
                    }
                }
            }

            // Calculate the slope
            if (genParams.CliffSmoothing)
            {
                ReportRelativeProgress(2, "Heightmap Processing: Smoothing");
                slopeMap = Noise.CalculateSteepness(Noise.GaussianBlur5X5(heightMap));
            }
            else
            {
                slopeMap = Noise.CalculateSteepness(heightMap);
            }

            // Randomize max height/depth
            float[,] altMap = null;
            if (genParams.MaxHeightVariation != 0 || genParams.MaxDepthVariation != 0)
            {
                ReportRelativeProgress(5, "Heightmap Processing: Randomizing");
                altMap = new float[map.Width, map.Length];
                int blendMapDetailSize = (int)Math.Log(Math.Max(genParams.MapWidth, genParams.MapLength), 2) - 2;
                new Noise(rand.Next(), NoiseInterpolationMode.Cosine)
                .PerlinNoise(altMap,
                             Math.Min(blendMapDetailSize, 3),
                             blendMapDetailSize,
                             0.5f,
                             0,
                             0);
                Noise.Normalize(altMap, -1, 1);
            }

            int snowStartThreshold = snowAltitudeScaled - genParams.SnowTransition;
            int snowThreshold      = snowAltitudeScaled;

            ReportRelativeProgress(10, "Filling");
            if (theme.AirBlock != Block.Air)
            {
                map.Blocks.MemSet((byte)theme.AirBlock);
            }
            for (int x = heightMap.GetLength(0) - 1; x >= 0; x--)
            {
                for (int y = heightMap.GetLength(1) - 1; y >= 0; y--)
                {
                    int   level;
                    float slope;
                    if (heightMap[x, y] < desiredWaterLevel)
                    {
                        // for blocks below "sea level"
                        float depth = maxDepthScaled;
                        if (altMap != null)
                        {
                            depth += altMap[x, y] * genParams.MaxDepthVariation;
                        }
                        slope = slopeMap[x, y] * depth;
                        level = genParams.WaterLevel -
                                (int)
                                Math.Round(
                            Math.Pow(1 - heightMap[x, y] / desiredWaterLevel, genParams.BelowFuncExponent) * depth);

                        if (genParams.AddWater)
                        {
                            if (genParams.WaterLevel - level > 3)
                            {
                                map.SetBlock(x, y, genParams.WaterLevel, theme.DeepWaterSurfaceBlock);
                            }
                            else
                            {
                                map.SetBlock(x, y, genParams.WaterLevel, theme.WaterSurfaceBlock);
                            }
                            for (int i = genParams.WaterLevel; i > level; i--)
                            {
                                map.SetBlock(x, y, i, theme.WaterBlock);
                            }
                            for (int i = level; i >= 0; i--)
                            {
                                if (level - i < theme.SeaFloorThickness)
                                {
                                    map.SetBlock(x, y, i, theme.SeaFloorBlock);
                                }
                                else
                                {
                                    map.SetBlock(x, y, i, theme.BedrockBlock);
                                }
                            }
                        }
                        else
                        {
                            if (blendMap != null && blendMap[x, y] > .25 && blendMap[x, y] < .75)
                            {
                                map.SetBlock(x, y, level, theme.CliffBlock);
                            }
                            else
                            {
                                if (slope < genParams.CliffThreshold)
                                {
                                    map.SetBlock(x, y, level, theme.GroundSurfaceBlock);
                                }
                                else
                                {
                                    map.SetBlock(x, y, level, theme.CliffBlock);
                                }
                            }

                            for (int i = level - 1; i >= 0; i--)
                            {
                                if (level - i < theme.GroundThickness)
                                {
                                    if (blendMap != null && blendMap[x, y] > CliffsideBlockThreshold &&
                                        blendMap[x, y] < (1 - CliffsideBlockThreshold))
                                    {
                                        map.SetBlock(x, y, i, theme.CliffBlock);
                                    }
                                    else
                                    {
                                        if (slope < genParams.CliffThreshold)
                                        {
                                            map.SetBlock(x, y, i, theme.GroundBlock);
                                        }
                                        else
                                        {
                                            map.SetBlock(x, y, i, theme.CliffBlock);
                                        }
                                    }
                                }
                                else
                                {
                                    map.SetBlock(x, y, i, theme.BedrockBlock);
                                }
                            }
                        }
                    }
                    else
                    {
                        // for blocks above "sea level"
                        float height;
                        if (altMap != null)
                        {
                            height = maxHeightScaled + altMap[x, y] * genParams.MaxHeightVariation;
                        }
                        else
                        {
                            height = maxHeightScaled;
                        }
                        slope = slopeMap[x, y] * height;
                        if (height != 0)
                        {
                            level = genParams.WaterLevel +
                                    (int)
                                    Math.Round(
                                Math.Pow(heightMap[x, y] - desiredWaterLevel, genParams.AboveFuncExponent) *
                                aboveWaterMultiplier / maxHeightScaled * height);
                        }
                        else
                        {
                            level = genParams.WaterLevel;
                        }

                        bool snow = genParams.AddSnow &&
                                    (level > snowThreshold ||
                                     (level > snowStartThreshold &&
                                      rand.NextDouble() <
                                      (level - snowStartThreshold) / (double)(snowThreshold - snowStartThreshold)));

                        if (blendMap != null && blendMap[x, y] > .25 && blendMap[x, y] < .75)
                        {
                            map.SetBlock(x, y, level, theme.CliffBlock);
                        }
                        else
                        {
                            if (slope < genParams.CliffThreshold)
                            {
                                map.SetBlock(x, y, level, (snow ? theme.SnowBlock : theme.GroundSurfaceBlock));
                            }
                            else
                            {
                                map.SetBlock(x, y, level, theme.CliffBlock);
                            }
                        }

                        for (int i = level - 1; i >= 0; i--)
                        {
                            if (level - i < theme.GroundThickness)
                            {
                                if (blendMap != null && blendMap[x, y] > CliffsideBlockThreshold &&
                                    blendMap[x, y] < (1 - CliffsideBlockThreshold))
                                {
                                    map.SetBlock(x, y, i, theme.CliffBlock);
                                }
                                else
                                {
                                    if (slope < genParams.CliffThreshold)
                                    {
                                        if (snow)
                                        {
                                            map.SetBlock(x, y, i, theme.SnowBlock);
                                        }
                                        else
                                        {
                                            map.SetBlock(x, y, i, theme.GroundBlock);
                                        }
                                    }
                                    else
                                    {
                                        map.SetBlock(x, y, i, theme.CliffBlock);
                                    }
                                }
                            }
                            else
                            {
                                map.SetBlock(x, y, i, theme.BedrockBlock);
                            }
                        }
                    }
                }
            }

            if (genParams.AddCaves || genParams.AddOre)
            {
                AddCaves(map);
            }

            if (genParams.AddBeaches)
            {
                ReportRelativeProgress(5, "Processing: Adding beaches");
                AddBeaches(map);
            }

            if (genParams.AddTrees)
            {
                ReportRelativeProgress(5, "Processing: Planting trees");
                if (genParams.AddGiantTrees)
                {
                    Map outMap = new Map(null, map.Width, map.Length, map.Height, false)
                    {
                        Blocks = (byte[])map.Blocks.Clone()
                    };
                    var foresterArgs = new ForesterArgs {
                        Map       = map,
                        Rand      = rand,
                        TreeCount =
                            (int)
                            (map.Width * map.Length * 4 / (1024f * (genParams.TreeSpacingMax + genParams.TreeSpacingMin) / 2)),
                        Operation = Forester.ForesterOperation.Add,
                        PlantOn   = theme.GroundSurfaceBlock
                    };
                    foresterArgs.BlockPlacing += (sender, e) => outMap.SetBlock(e.Coordinate, e.Block);
                    Forester.Generate(foresterArgs);
                    map = outMap;
                }
                GenerateTrees(map);
            }

            if (genParams.AddFloodBarrier)
            {
                MakeFloodBarrier(map);
            }
            return(map);
        }