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(); }
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); }