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.CalculateSlope( Noise.GaussianBlur5X5( heightmap ) ); } else { slopemap = Noise.CalculateSlope( 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; }
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; }