public Map GenerateMap()
{
Map map = new Map( null, args.MapWidth, args.MapLength, args.MapHeight, true );
// Match water coverage
float desiredWaterLevel = .5f;
if ( args.MatchWaterCoverage ) {
ReportProgress( 2, "Heightmap Processing: Matching water coverage" );
desiredWaterLevel = Noise.FindThreshold( heightmap, args.WaterCoverage );
}
// Calculate above/below water multipliers
float aboveWaterMultiplier = 0;
if ( desiredWaterLevel != 1 ) {
aboveWaterMultiplier = ( args.MaxHeight / ( 1 - desiredWaterLevel ) );
}
// Apply power functions to above/below water parts of the heightmap
if ( args.BelowFuncExponent != 1 || args.AboveFuncExponent != 1 ) {
ReportProgress( 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, args.BelowFuncExponent ) * desiredWaterLevel;
} else {
float normalizedHeight = ( heightmap[x, y] - desiredWaterLevel ) / ( 1 - desiredWaterLevel );
heightmap[x, y] = desiredWaterLevel + ( float )Math.Pow( normalizedHeight, args.AboveFuncExponent ) * ( 1 - desiredWaterLevel );
}
}
}
}
// Calculate the slope
if ( args.CliffSmoothing ) {
ReportProgress( 2, "Heightmap Processing: Smoothing" );
slopemap = Noise.CalculateSlope( Noise.GaussianBlur5X5( heightmap ) );
} else {
slopemap = Noise.CalculateSlope( heightmap );
}
float[,] altmap = null;
if ( args.MaxHeightVariation != 0 || args.MaxDepthVariation != 0 ) {
ReportProgress( 5, "Heightmap Processing: Randomizing" );
altmap = new float[map.Width, map.Length];
int blendmapDetailSize = ( int )Math.Log( Math.Max( args.MapWidth, args.MapLength ), 2 ) - 2;
new Noise( rand.Next(), NoiseInterpolationMode.Cosine ).PerlinNoise( altmap, 3, blendmapDetailSize, 0.5f, 0, 0 );
Noise.Normalize( altmap, -1, 1 );
}
int snowStartThreshold = args.SnowAltitude - args.SnowTransition;
int snowThreshold = args.SnowAltitude;
ReportProgress( 10, "Filling" );
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 ) {
float depth = args.MaxDepth;
if ( altmap != null ) {
depth += altmap[x, y] * args.MaxDepthVariation;
}
slope = slopemap[x, y] * depth;
level = args.WaterLevel - ( int )Math.Round( Math.Pow( 1 - heightmap[x, y] / desiredWaterLevel, args.BelowFuncExponent ) * depth );
if ( args.AddWater ) {
if ( args.WaterLevel - level > 3 ) {
map.SetBlock( x, y, args.WaterLevel, bDeepWaterSurface );
} else {
map.SetBlock( x, y, args.WaterLevel, bWaterSurface );
}
for ( int i = args.WaterLevel; i > level; i-- ) {
map.SetBlock( x, y, i, bWater );
}
for ( int i = level; i >= 0; i-- ) {
if ( level - i < SeaFloorThickness ) {
map.SetBlock( x, y, i, bSeaFloor );
} else {
map.SetBlock( x, y, i, bBedrock );
}
}
} else {
if ( blendmap != null && blendmap[x, y] > .25 && blendmap[x, y] < .75 ) {
map.SetBlock( x, y, level, bCliff );
} else {
if ( slope < args.CliffThreshold ) {
map.SetBlock( x, y, level, bGroundSurface );
} else {
map.SetBlock( x, y, level, bCliff );
}
}
for ( int i = level - 1; i >= 0; i-- ) {
if ( level - i < groundThickness ) {
if ( blendmap != null && blendmap[x, y] > CliffsideBlockThreshold && blendmap[x, y] < ( 1 - CliffsideBlockThreshold ) ) {
map.SetBlock( x, y, i, bCliff );
} else {
if ( slope < args.CliffThreshold ) {
map.SetBlock( x, y, i, bGround );
} else {
map.SetBlock( x, y, i, bCliff );
}
}
} else {
map.SetBlock( x, y, i, bBedrock );
}
}
}
} else {
float height;
if ( altmap != null ) {
height = args.MaxHeight + altmap[x, y] * args.MaxHeightVariation;
} else {
height = args.MaxHeight;
}
slope = slopemap[x, y] * height;
if ( height != 0 ) {
level = args.WaterLevel + ( int )Math.Round( Math.Pow( heightmap[x, y] - desiredWaterLevel, args.AboveFuncExponent ) * aboveWaterMultiplier / args.MaxHeight * height );
} else {
level = args.WaterLevel;
}
bool snow = args.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, bCliff );
} else {
if ( slope < args.CliffThreshold ) {
map.SetBlock( x, y, level, ( snow ? Block.White : bGroundSurface ) );
} else {
map.SetBlock( x, y, level, bCliff );
}
}
for ( int i = level - 1; i >= 0; i-- ) {
if ( level - i < groundThickness ) {
if ( blendmap != null && blendmap[x, y] > CliffsideBlockThreshold && blendmap[x, y] < ( 1 - CliffsideBlockThreshold ) ) {
map.SetBlock( x, y, i, bCliff );
} else {
if ( slope < args.CliffThreshold ) {
if ( snow ) {
map.SetBlock( x, y, i, Block.White );
} else {
map.SetBlock( x, y, i, bGround );
}
} else {
map.SetBlock( x, y, i, bCliff );
}
}
} else {
map.SetBlock( x, y, i, bBedrock );
}
}
}
}
}
if ( args.AddCaves || args.AddOre ) {
AddCaves( map );
}
if ( args.AddBeaches ) {
ReportProgress( 5, "Processing: Adding beaches" );
AddBeaches( map );
}
if ( args.AddIgloos ) {
//GenerateIgloos( map );
}
if ( args.AddTrees ) {
ReportProgress( 5, "Processing: Planting trees" );
if ( args.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 * ( args.TreeSpacingMax + args.TreeSpacingMin ) / 2 ) ),
Operation = Forester.ForesterOperation.Add,
PlantOn = bGroundSurface
};
foresterArgs.BlockPlacing += ( sender, e ) => outMap.SetBlock( e.Coordinate, e.Block );
Forester.Generate( foresterArgs );
map = outMap;
}
GenerateTrees( map );
}
ReportProgress( 0, "Generation complete" );
map.Metadata["_Origin", "GeneratorName"] = "fCraft";
map.Metadata["_Origin", "GeneratorVersion"] = Updater.CurrentRelease.VersionString;
map.Metadata["_Origin", "GeneratorParams"] = args.Serialize().ToString( SaveOptions.DisableFormatting );
return map;
}