Add world manifests

These include the spawn point, seed, and terrain generator so that you
can load saved worlds with all the right details.
This commit is contained in:
Drew DeVault 2015-04-13 17:41:57 -06:00
parent 4d5509b734
commit 65deecd131
8 changed files with 79 additions and 56 deletions

View File

@ -10,6 +10,6 @@ namespace TrueCraft.API.World
{ {
IList<IChunkDecorator> ChunkDecorators { get; } IList<IChunkDecorator> ChunkDecorators { get; }
IChunk GenerateChunk(IWorld world, Coordinates2D coordinates); IChunk GenerateChunk(IWorld world, Coordinates2D coordinates);
Vector3 SpawnPoint { get; } Coordinates3D GetSpawn(IWorld world);
} }
} }

View File

@ -14,6 +14,7 @@ namespace TrueCraft.API.World
int Seed { get; set; } int Seed { get; set; }
IBiomeMap BiomeDiagram { get; set; } IBiomeMap BiomeDiagram { get; set; }
IChunkProvider ChunkProvider { get; set; } IChunkProvider ChunkProvider { get; set; }
Coordinates3D SpawnPoint { get; set; }
long Time { get; set; } long Time { get; set; }
event EventHandler<BlockChangeEventArgs> BlockChanged; event EventHandler<BlockChangeEventArgs> BlockChanged;

View File

@ -19,7 +19,6 @@ namespace TrueCraft.Core.TerrainGen
public FlatlandGenerator() public FlatlandGenerator()
{ {
GeneratorOptions = DefaultGeneratorOptions; GeneratorOptions = DefaultGeneratorOptions;
SpawnPoint = new Vector3(0, 5, 0);
ChunkDecorators = new List<IChunkDecorator>(); ChunkDecorators = new List<IChunkDecorator>();
} }
@ -58,7 +57,6 @@ namespace TrueCraft.Core.TerrainGen
Layers.Add(generatorLayer); Layers.Add(generatorLayer);
} }
Biome = (Biome)byte.Parse(parts[2]); Biome = (Biome)byte.Parse(parts[2]);
SpawnPoint = new Vector3(0, y, 0);
} }
public IChunk GenerateChunk(IWorld world, Coordinates2D position) public IChunk GenerateChunk(IWorld world, Coordinates2D position)
@ -97,7 +95,10 @@ namespace TrueCraft.Core.TerrainGen
public IList<IChunkDecorator> ChunkDecorators { get; set; } public IList<IChunkDecorator> ChunkDecorators { get; set; }
public Vector3 SpawnPoint { get; set; } public Coordinates3D GetSpawn(IWorld world)
{
return Coordinates3D.Up * 5;
}
protected class GeneratorLayer protected class GeneratorLayer
{ {

View File

@ -16,7 +16,7 @@ namespace TrueCraft.Core.TerrainGen
/// <summary> /// <summary>
/// This terrain generator is still under heavy development. Use at your own risk. /// This terrain generator is still under heavy development. Use at your own risk.
/// </summary> /// </summary>
public class NewGenerator : IChunkProvider public class StandardGenerator : IChunkProvider
{ {
BiomeRepository Biomes = new BiomeRepository(); BiomeRepository Biomes = new BiomeRepository();
Perlin HighNoise = new Perlin(); Perlin HighNoise = new Perlin();
@ -27,7 +27,8 @@ namespace TrueCraft.Core.TerrainGen
ClampNoise BottomClamp; ClampNoise BottomClamp;
ModifyNoise Modified; ModifyNoise Modified;
private int GroundLevel = 50; private int GroundLevel = 50;
public NewGenerator(bool SingleBiome = false, byte GenerateBiome = (byte)Biome.Plains)
public StandardGenerator(bool SingleBiome = false, byte GenerateBiome = (byte)Biome.Plains)
{ {
this.SingleBiome = SingleBiome; this.SingleBiome = SingleBiome;
this.GenerationBiome = GenerateBiome; this.GenerationBiome = GenerateBiome;
@ -71,25 +72,26 @@ namespace TrueCraft.Core.TerrainGen
public Vector3 SpawnPoint { get; private set; } public Vector3 SpawnPoint { get; private set; }
public bool SingleBiome { get; private set; } public bool SingleBiome { get; private set; }
public byte GenerationBiome { get; private set; } public byte GenerationBiome { get; private set; }
public IChunk GenerateChunk(IWorld world, Coordinates2D coordinates) public IChunk GenerateChunk(IWorld world, Coordinates2D coordinates)
{ {
int FeaturePointDistance = 400; const int featurePointDistance = 400;
int Seed = world.Seed; int seed = world.Seed;
CellNoise Worley = new CellNoise(); var worley = new CellNoise();
Worley.Seed = Seed; worley.Seed = seed;
HighNoise.Seed = Seed; HighNoise.Seed = seed;
LowNoise.Seed = Seed; LowNoise.Seed = seed;
var chunk = new Chunk(coordinates); var chunk = new Chunk(coordinates);
for (int X = 0; X < 16; X++) for (int X = 0; X < 16; X++)
{ {
for (int Z = 0; Z < 16; Z++) for (int Z = 0; Z < 16; Z++)
{ {
var BlockX = MathHelper.ChunkToBlockX(X, coordinates.X); var blockX = MathHelper.ChunkToBlockX(X, coordinates.X);
var BlockZ = MathHelper.ChunkToBlockZ(Z, coordinates.Z); var blockZ = MathHelper.ChunkToBlockZ(Z, coordinates.Z);
double LowClampMid = LowClamp.MaxValue - ((LowClamp.MaxValue + LowClamp.MinValue) / 2); const double lowClampRange = 5;
double LowClampRange = 5; double lowClampMid = LowClamp.MaxValue - ((LowClamp.MaxValue + LowClamp.MinValue) / 2);
double LowClampValue = LowClamp.Value2D(BlockX, BlockZ); double lowClampValue = LowClamp.Value2D(blockX, blockZ);
if (LowClampValue > LowClampMid - LowClampRange && LowClampValue < LowClampMid + LowClampRange) if (lowClampValue > lowClampMid - lowClampRange && lowClampValue < lowClampMid + lowClampRange)
{ {
InvertNoise NewPrimary = new InvertNoise(HighClamp); InvertNoise NewPrimary = new InvertNoise(HighClamp);
Modified.PrimaryNoise = NewPrimary; Modified.PrimaryNoise = NewPrimary;
@ -100,23 +102,23 @@ namespace TrueCraft.Core.TerrainGen
Modified = new ModifyNoise(HighClamp, LowClamp, NoiseModifier.Add); Modified = new ModifyNoise(HighClamp, LowClamp, NoiseModifier.Add);
} }
Modified = new ModifyNoise(Modified, BottomClamp, NoiseModifier.Subtract); Modified = new ModifyNoise(Modified, BottomClamp, NoiseModifier.Subtract);
var CellValue = Worley.Value2D(BlockX, BlockZ); var cellValue = worley.Value2D(blockX, blockZ);
var Location = new Coordinates2D(BlockX, BlockZ); var location = new Coordinates2D(blockX, blockZ);
if (world.BiomeDiagram.BiomeCells.Count < 1 || CellValue.Equals(1) && world.BiomeDiagram.ClosestCellPoint(Location) >= FeaturePointDistance) if (world.BiomeDiagram.BiomeCells.Count < 1 || cellValue.Equals(1) && world.BiomeDiagram.ClosestCellPoint(location) >= featurePointDistance)
{ {
byte ID = (SingleBiome) ? GenerationBiome : world.BiomeDiagram.GenerateBiome(Seed, Biomes, Location); byte id = (SingleBiome) ? GenerationBiome : world.BiomeDiagram.GenerateBiome(seed, Biomes, location);
BiomeCell Cell = new BiomeCell(ID, Location); BiomeCell Cell = new BiomeCell(id, location);
world.BiomeDiagram.AddCell(Cell); world.BiomeDiagram.AddCell(Cell);
} }
var BiomeID = GetBiome(world, Location); var biomeId = GetBiome(world, location);
IBiomeProvider Biome = Biomes.GetBiome(BiomeID); IBiomeProvider Biome = Biomes.GetBiome(biomeId);
chunk.Biomes[X * Chunk.Width + Z] = BiomeID; chunk.Biomes[X * Chunk.Width + Z] = biomeId;
var Height = GetHeight(BlockX, BlockZ); var height = GetHeight(blockX, blockZ);
var SurfaceHeight = Height - Biome.SurfaceDepth; var surfaceHeight = height - Biome.SurfaceDepth;
chunk.HeightMap[X * Chunk.Width + Z] = Height; chunk.HeightMap[X * Chunk.Width + Z] = height;
for (int Y = 0; Y <= Height; Y++) for (int Y = 0; Y <= height; Y++)
{ {
if (Y == 0) if (Y == 0)
{ {
@ -124,13 +126,13 @@ namespace TrueCraft.Core.TerrainGen
} }
else else
{ {
if (Y.Equals(Height) || Y < Height && Y > SurfaceHeight) if (Y.Equals(height) || Y < height && Y > surfaceHeight)
{ {
chunk.SetBlockID(new Coordinates3D(X, Y, Z), Biome.SurfaceBlock); chunk.SetBlockID(new Coordinates3D(X, Y, Z), Biome.SurfaceBlock);
} }
else else
{ {
if (Y > SurfaceHeight - Biome.FillerDepth) if (Y > surfaceHeight - Biome.FillerDepth)
{ {
chunk.SetBlockID(new Coordinates3D(X, Y, Z), Biome.FillerBlock); chunk.SetBlockID(new Coordinates3D(X, Y, Z), Biome.FillerBlock);
} }
@ -144,29 +146,27 @@ namespace TrueCraft.Core.TerrainGen
} }
} }
foreach (IChunkDecorator ChunkDecorator in ChunkDecorators) foreach (IChunkDecorator ChunkDecorator in ChunkDecorators)
{
ChunkDecorator.Decorate(world, chunk, Biomes); ChunkDecorator.Decorate(world, chunk, Biomes);
}
var SpawnOffset = 2;
var SpawnPointHeight = GetHeight(0, 0);
if (SpawnPointHeight + SpawnOffset < Chunk.Height)
SpawnPointHeight += SpawnOffset;
SpawnPoint = new Vector3(0, SpawnPointHeight, 0);
return chunk; return chunk;
} }
byte GetBiome(IWorld world, Coordinates2D Location) public Coordinates3D GetSpawn(IWorld world)
{ {
if (SingleBiome) var chunk = GenerateChunk(world, Coordinates2D.Zero);
{ var spawnPointHeight = chunk.HeightMap[0];
return GenerationBiome; return new Coordinates3D(0, spawnPointHeight + 1, 0);
}
return world.BiomeDiagram.GetBiome(Location);
} }
int GetHeight(int X, int Z) byte GetBiome(IWorld world, Coordinates2D location)
{ {
var NoiseValue = Modified.Value2D(X, Z) + GroundLevel; if (SingleBiome)
return GenerationBiome;
return world.BiomeDiagram.GetBiome(location);
}
int GetHeight(int x, int z)
{
var NoiseValue = Modified.Value2D(x, z) + GroundLevel;
if (NoiseValue < 0) if (NoiseValue < 0)
NoiseValue = GroundLevel; NoiseValue = GroundLevel;
if (NoiseValue > Chunk.Height) if (NoiseValue > Chunk.Height)

View File

@ -206,7 +206,6 @@
<Compile Include="TerrainGen\Noise\Perlin.cs" /> <Compile Include="TerrainGen\Noise\Perlin.cs" />
<Compile Include="TerrainGen\Noise\ScaleNoise.cs" /> <Compile Include="TerrainGen\Noise\ScaleNoise.cs" />
<Compile Include="TerrainGen\Noise\CellNoise.cs" /> <Compile Include="TerrainGen\Noise\CellNoise.cs" />
<Compile Include="TerrainGen\NewGenerator.cs" />
<Compile Include="World\BiomeMap.cs" /> <Compile Include="World\BiomeMap.cs" />
<Compile Include="World\Chunk.cs" /> <Compile Include="World\Chunk.cs" />
<Compile Include="World\Region.cs" /> <Compile Include="World\Region.cs" />
@ -309,6 +308,7 @@
<Compile Include="Logic\Blocks\FluidBlock.cs" /> <Compile Include="Logic\Blocks\FluidBlock.cs" />
<Compile Include="Entities\FallingSandEntity.cs" /> <Compile Include="Entities\FallingSandEntity.cs" />
<Compile Include="Logic\Blocks\DoorBlock.cs" /> <Compile Include="Logic\Blocks\DoorBlock.cs" />
<Compile Include="TerrainGen\StandardGenerator.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>

View File

@ -6,6 +6,7 @@ using System.Threading;
using TrueCraft.API; using TrueCraft.API;
using TrueCraft.API.World; using TrueCraft.API.World;
using TrueCraft.API.Logic; using TrueCraft.API.Logic;
using fNbt;
namespace TrueCraft.Core.World namespace TrueCraft.Core.World
{ {
@ -15,12 +16,14 @@ namespace TrueCraft.Core.World
public string Name { get; set; } public string Name { get; set; }
public int Seed { get; set; } public int Seed { get; set; }
public Coordinates3D SpawnPoint { get; set; }
public string BaseDirectory { get; internal set; } public string BaseDirectory { get; internal set; }
public IDictionary<Coordinates2D, IRegion> Regions { get; set; } public IDictionary<Coordinates2D, IRegion> Regions { get; set; }
public IBiomeMap BiomeDiagram { get; set; } public IBiomeMap BiomeDiagram { get; set; }
public IChunkProvider ChunkProvider { get; set; } public IChunkProvider ChunkProvider { get; set; }
public IBlockRepository BlockRepository { get; set; } public IBlockRepository BlockRepository { get; set; }
public DateTime BaseTime { get; set; } public DateTime BaseTime { get; set; }
public long Time public long Time
{ {
get get
@ -47,6 +50,7 @@ namespace TrueCraft.Core.World
public World(string name, IChunkProvider chunkProvider) : this(name) public World(string name, IChunkProvider chunkProvider) : this(name)
{ {
ChunkProvider = chunkProvider; ChunkProvider = chunkProvider;
SpawnPoint = chunkProvider.GetSpawn(this);
} }
public static World LoadWorld(string baseDirectory) public static World LoadWorld(string baseDirectory)
@ -55,6 +59,17 @@ namespace TrueCraft.Core.World
throw new DirectoryNotFoundException(); throw new DirectoryNotFoundException();
var world = new World(Path.GetFileName(baseDirectory)); var world = new World(Path.GetFileName(baseDirectory));
world.BaseDirectory = baseDirectory; world.BaseDirectory = baseDirectory;
if (File.Exists(Path.Combine(baseDirectory, "manifest.nbt")))
{
var file = new NbtFile(Path.Combine(baseDirectory, "manifest.nbt"));
world.SpawnPoint = new Coordinates3D(file.RootTag["SpawnPoint"]["X"].IntValue,
file.RootTag["SpawnPoint"]["Y"].IntValue,
file.RootTag["SpawnPoint"]["Z"].IntValue);
world.Seed = file.RootTag["Seed"].IntValue;
var providerName = file.RootTag["ChunkProvider"].StringValue;
var provider = (IChunkProvider)Activator.CreateInstance(Type.GetType(providerName), world);
world.ChunkProvider = provider;
}
return world; return world;
} }
@ -223,6 +238,16 @@ namespace TrueCraft.Core.World
foreach (var region in Regions) foreach (var region in Regions)
region.Value.Save(Path.Combine(BaseDirectory, Region.GetRegionFileName(region.Key))); region.Value.Save(Path.Combine(BaseDirectory, Region.GetRegionFileName(region.Key)));
} }
var file = new NbtFile();
file.RootTag.Add(new NbtCompound("SpawnPoint", new[]
{
new NbtInt("X", this.SpawnPoint.X),
new NbtInt("Y", this.SpawnPoint.Y),
new NbtInt("Z", this.SpawnPoint.Z)
}));
file.RootTag.Add(new NbtInt("Seed", this.Seed));
file.RootTag.Add(new NbtString("ChunkProvider", this.ChunkProvider.GetType().FullName));
file.SaveToFile(Path.Combine(this.BaseDirectory, "manifest.nbt"), NbtCompression.ZLib);
} }
public void Save(string path) public void Save(string path)
@ -230,11 +255,7 @@ namespace TrueCraft.Core.World
if (!Directory.Exists(path)) if (!Directory.Exists(path))
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
BaseDirectory = path; BaseDirectory = path;
lock (Regions) Save();
{
foreach (var region in Regions)
region.Value.Save(Path.Combine(BaseDirectory, Region.GetRegionFileName(region.Key)));
}
} }
public Coordinates3D FindBlockPosition(Coordinates3D coordinates, out IChunk chunk) public Coordinates3D FindBlockPosition(Coordinates3D coordinates, out IChunk chunk)

View File

@ -39,7 +39,7 @@ namespace TrueCraft.Handlers
client.QueuePacket(new LoginResponsePacket(0, 0, Dimension.Overworld)); client.QueuePacket(new LoginResponsePacket(0, 0, Dimension.Overworld));
client.UpdateChunks(); client.UpdateChunks();
client.QueuePacket(new WindowItemsPacket(0, client.Inventory.GetSlots())); client.QueuePacket(new WindowItemsPacket(0, client.Inventory.GetSlots()));
client.Entity.Position = client.World.ChunkProvider.SpawnPoint; client.Entity.Position = client.World.SpawnPoint;
client.QueuePacket(new SpawnPositionPacket((int)client.Entity.Position.X, client.QueuePacket(new SpawnPositionPacket((int)client.Entity.Position.X,
(int)client.Entity.Position.Y, (int)client.Entity.Position.Z)); (int)client.Entity.Position.Y, (int)client.Entity.Position.Z));
client.QueuePacket(new SetPlayerPositionPacket(client.Entity.Position.X, client.Entity.Position.Y, client.QueuePacket(new SetPlayerPositionPacket(client.Entity.Position.X, client.Entity.Position.Y,

View File

@ -26,11 +26,11 @@ namespace TrueCraft
{ {
// TODO: Save and load levels, with seeds and everything // TODO: Save and load levels, with seeds and everything
world = World.LoadWorld("world"); world = World.LoadWorld("world");
world.ChunkProvider = new NewGenerator(); world.ChunkProvider = new StandardGenerator();
} }
catch catch
{ {
world = new World("default", new NewGenerator()); world = new World("default", new StandardGenerator());
world.Save("world"); world.Save("world");
} }
server.AddWorld(world); server.AddWorld(world);