#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.Threading;
using Shared;
#endregion
namespace Craft
{
public class SimpleTerrain
{
#region Fields
public static Random r = new Random(SEED);
public static int SEED = 1984;
public const byte SIZEX = BlockFunctions.SIZEX;
public const byte SIZEY = BlockFunctions.SIZEY;
public const byte SIZEZ = BlockFunctions.SIZEZ;
public const int WATERLEVEL = 48;
public const int SNOWLEVEL = 95;
public const int MINIMUMGROUNDHEIGHT = 32;
#endregion
Region region;
public Region Region
{
get { return region; }
set { region = value; }
}
public SimpleTerrain() { }
public SimpleTerrain(Region region)
{
this.region = region;
ThreadPool.QueueUserWorkItem(GenerateTerrain);
}
/// <summary>
/// Generate terrain from code
/// </summary>
public void GenerateTerrain()
{
int tX = ((int)region.Position.X / (BlockFunctions.SCALE * 16)) + SEED;
int tZ = ((int)region.Position.Z / (BlockFunctions.SCALE * 16));
//Console.WriteLine("Thread Started");
float temperature = PerlinSimplexNoise.noise(tX * 0.1f, tZ * 0.1f);
region.BlockTypes = new BlockType[SIZEX, SIZEY, SIZEZ];
for (byte x = 0; x < SIZEX; x++)
{
int worldX = ((int)region.Position.X / BlockFunctions.SCALE) + x + SEED;
for (byte z = 0; z < SIZEZ; z++)
{
int worldZ = ((int)region.Position.Z / BlockFunctions.SCALE) + z;
//Console.WriteLine((worldX - SEED) + " " + worldZ);
GenerateTerrain(x, z, worldX, worldZ, tX, tZ);
}
}
region.RegionState = Region.RegionStates.Partial;
Region.loading = false;
Region.loadTime = TimeSpan.Zero;
}
/// <summary>
/// Check if region is available on disk. Else generate new terrain from code.
/// </summary>
/// <param name="o"></param>
public void GenerateTerrain(object o)
{
//bool opened = Integrity.OpenRegion(region);
//if (opened)
//{
// GenerateBlocks();
// BlockFunctions.CreateFaces(region);
// region.BlockRenderer.UpdateVertexBuffers();
// region.RegionState = Region.RegionStates.Loaded;
//}
//else
//{
GenerateTerrain();
//}
}
/// <summary>
/// Multiplayer
/// </summary>
/// <param name="o"></param>
public void GenerateBlocks(object o)
{
//GenerateBlocks();
BlockFunctions.CreateFaces(region);
region.RegionState = Region.RegionStates.Loaded;
}
protected virtual void GenerateTerrain(byte x, byte z, int worldX, int worldZ, float tempX, float tempZ)
{
int minimumGroundDepth = 32;
float temp1 = PerlinSimplexNoise.noise(worldX * 0.01f, worldZ * 0.01f) * 0.5f;
float temp2 = PerlinSimplexNoise.noise(worldX * 0.0005f, worldZ * 0.0005f) * 0.25f;
float temp3 = PerlinSimplexNoise.noise(worldX * 0.005f, worldZ * 0.005f) * 0.12f;
float temp4 = PerlinSimplexNoise.noise(worldX * 0.01f, worldZ * 0.01f) * 0.09f;
float temp5 = PerlinSimplexNoise.noise(worldX * 0.03f, worldZ * 0.03f) * temp4;
float humidity1 = PerlinSimplexNoise.noise(tempX * 0.01f, tempZ * 0.01f) * 0.5f;
float humidity2 = PerlinSimplexNoise.noise(tempX * 0.0005f, tempZ * 0.0005f) * 0.25f;
float humidity3 = PerlinSimplexNoise.noise(tempX * 0.005f, tempZ * 0.005f) * 0.12f;
float humidity4 = PerlinSimplexNoise.noise(tempX * 0.01f, tempZ * 0.01f) * 0.09f;
float humidity5 = PerlinSimplexNoise.noise(worldX * 0.03f, worldZ * 0.03f) * humidity4;
float temp = temp1 + temp2 + temp3 + temp4 + temp5;
float humidity = humidity1 + humidity2 + humidity3 + humidity4 + humidity5;
//Console.WriteLine(temp * humidity);
Biome.Biomes biome = Biome.GetBiomeType(humidity, temp);
float octave1 = PerlinSimplexNoise.noise(worldX * 0.0001f, worldZ * 0.0001f) * 0.5f;
float octave2 = PerlinSimplexNoise.noise(worldX * 0.0005f, worldZ * 0.0005f) * 0.25f;
float octave3 = PerlinSimplexNoise.noise(worldX * 0.005f, worldZ * 0.005f) * 0.12f;
float octave4 = PerlinSimplexNoise.noise(worldX * 0.01f, worldZ * 0.01f) * 0.25f;
float octave5 = PerlinSimplexNoise.noise(worldX * 0.03f, worldZ * 0.03f) * octave4;
float lowerGroundHeight = octave1 + octave2 + octave3 + octave4 + octave5;
bool sunlit = true;
BlockType blockType2 = BlockType.Grass;
BlockType blockType = BlockType.Air;
switch (biome)
{
case Biome.Biomes.Plains:
blockType2 = BlockType.Sand;
lowerGroundHeight -= octave5;
break;
case Biome.Biomes.Tundra:
blockType2 = BlockType.Snow;
break;
case Biome.Biomes.Desert:
blockType2 = BlockType.Sand;
break;
case Biome.Biomes.Forest:
blockType2 = BlockType.Grass;
break;
case Biome.Biomes.Savanna:
blockType2 = BlockType.Sand;
break;
case Biome.Biomes.SeasonalForest:
blockType2 = BlockType.Grass;
break;
case Biome.Biomes.Shrubland:
blockType2 = BlockType.Grass;
break;
case Biome.Biomes.RainForest:
blockType2 = BlockType.Grass;
break;
case Biome.Biomes.Taiga:
blockType2 = BlockType.Snow;
break;
}
lowerGroundHeight *= minimumGroundDepth;
for (int y = SIZEY - 1; y >= 0; y--)
{
if (y <= lowerGroundHeight)
{
if (sunlit)
{
blockType = blockType2;
sunlit = false;
//if (r.Next(700) == 1)
{
//Trees.Tree(region, x, (byte)y, z);
//BuildTree(x, (byte)y, z);
}
}
else
{
blockType = BlockType.Dirt;
}
}
region.BlockTypes[x, y, z] = blockType;
}
}
#region BuildTree
public virtual void BuildTree(byte tx, byte ty, byte tz)
{
// Trunk
byte height = (byte)(4 + (byte)r.Next(3));
if ((ty + height) < SIZEY)
{
for (byte y = ty; y < ty + height; y++)
{
region.BlockTypes[tx, y, tz] = BlockType.Wood;
}
}
// Foliage
int radius = 3 + r.Next(2);
int ny = ty + height;
for (int i = 0; i < 80 + r.Next(2); i++)
{
int lx = tx + r.Next(radius) - r.Next(radius);
int ly = ny + r.Next(radius) - r.Next(radius);
int lz = tz + r.Next(radius) - r.Next(radius);
unchecked //TODO foliage out of bound => new chunk.blockat or needs a chunk.setat
{
if (WithinMapBounds(lx, ly, lz))
{
if (region.BlockTypes[lx, ly, lz] == BlockType.Air)
{
region.BlockTypes[lx, ly, lz] = BlockType.Leaves; //leaves
}
}
}
}
}
#endregion
#region MakeTreeTrunk
private void MakeTreeTrunk(byte tx, byte ty, byte tz, int height)
{
for (byte y = ty; y < ty + height; y++)
{
region.BlockTypes[tx, y, tz] = BlockType.Gravel;
}
}
#endregion
#region MakeTreeFoliage
private void MakeTreeFoliage(int tx, int ty, int tz, int height)
{
int start = ty + height - 4;
int end = ty + height + 3;
int rad;
int radiusEnd = 2;
int radiusMiddle = radiusEnd + 1;
for (int y = start; y < end; y++)
{
if ((y > start) && (y < end - 1))
{
rad = radiusMiddle;
}
else
{
rad = radiusEnd;
}
for (int xoff = -rad; xoff < rad + 1; xoff++)
{
for (int zoff = -rad; zoff < rad + 1; zoff++)
{
if (WithinMapBounds((byte)(tx + xoff), (byte)y, (byte)(tz + zoff)) == false)
{
region.BlockTypes[(byte)(tx + xoff), (byte)y, (byte)(tz + zoff)] = BlockType.Grass; //leaves
}
}
}
}
}
#endregion
public static bool WithinMapBounds(int x, int y, int z)
{
if (x < 0 || y < 0 || z < 0)
return false;
if (x > SIZEX - 1 || y > SIZEY - 1 || z > SIZEZ - 1)
return false;
return true;
}
}
}