diff --git a/TrueCraft.API/World/IChunkProvider.cs b/TrueCraft.API/World/IChunkProvider.cs index 9734c7f..965bd2a 100644 --- a/TrueCraft.API/World/IChunkProvider.cs +++ b/TrueCraft.API/World/IChunkProvider.cs @@ -10,6 +10,6 @@ namespace TrueCraft.API.World { IList ChunkDecorators { get; } IChunk GenerateChunk(IWorld world, Coordinates2D coordinates); - Vector3 SpawnPoint { get; } + Coordinates3D GetSpawn(IWorld world); } } \ No newline at end of file diff --git a/TrueCraft.API/World/IWorld.cs b/TrueCraft.API/World/IWorld.cs index a6915d6..37e887f 100644 --- a/TrueCraft.API/World/IWorld.cs +++ b/TrueCraft.API/World/IWorld.cs @@ -14,6 +14,7 @@ namespace TrueCraft.API.World int Seed { get; set; } IBiomeMap BiomeDiagram { get; set; } IChunkProvider ChunkProvider { get; set; } + Coordinates3D SpawnPoint { get; set; } long Time { get; set; } event EventHandler BlockChanged; diff --git a/TrueCraft.Core/TerrainGen/FlatlandGenerator.cs b/TrueCraft.Core/TerrainGen/FlatlandGenerator.cs index f50a7f2..8ce55c1 100644 --- a/TrueCraft.Core/TerrainGen/FlatlandGenerator.cs +++ b/TrueCraft.Core/TerrainGen/FlatlandGenerator.cs @@ -19,7 +19,6 @@ namespace TrueCraft.Core.TerrainGen public FlatlandGenerator() { GeneratorOptions = DefaultGeneratorOptions; - SpawnPoint = new Vector3(0, 5, 0); ChunkDecorators = new List(); } @@ -58,7 +57,6 @@ namespace TrueCraft.Core.TerrainGen Layers.Add(generatorLayer); } Biome = (Biome)byte.Parse(parts[2]); - SpawnPoint = new Vector3(0, y, 0); } public IChunk GenerateChunk(IWorld world, Coordinates2D position) @@ -97,7 +95,10 @@ namespace TrueCraft.Core.TerrainGen public IList ChunkDecorators { get; set; } - public Vector3 SpawnPoint { get; set; } + public Coordinates3D GetSpawn(IWorld world) + { + return Coordinates3D.Up * 5; + } protected class GeneratorLayer { diff --git a/TrueCraft.Core/TerrainGen/NewGenerator.cs b/TrueCraft.Core/TerrainGen/StandardGenerator.cs similarity index 69% rename from TrueCraft.Core/TerrainGen/NewGenerator.cs rename to TrueCraft.Core/TerrainGen/StandardGenerator.cs index df3f7ea..551a335 100644 --- a/TrueCraft.Core/TerrainGen/NewGenerator.cs +++ b/TrueCraft.Core/TerrainGen/StandardGenerator.cs @@ -16,7 +16,7 @@ namespace TrueCraft.Core.TerrainGen /// /// This terrain generator is still under heavy development. Use at your own risk. /// - public class NewGenerator : IChunkProvider + public class StandardGenerator : IChunkProvider { BiomeRepository Biomes = new BiomeRepository(); Perlin HighNoise = new Perlin(); @@ -27,7 +27,8 @@ namespace TrueCraft.Core.TerrainGen ClampNoise BottomClamp; ModifyNoise Modified; 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.GenerationBiome = GenerateBiome; @@ -71,25 +72,26 @@ namespace TrueCraft.Core.TerrainGen public Vector3 SpawnPoint { get; private set; } public bool SingleBiome { get; private set; } public byte GenerationBiome { get; private set; } + public IChunk GenerateChunk(IWorld world, Coordinates2D coordinates) { - int FeaturePointDistance = 400; - int Seed = world.Seed; - CellNoise Worley = new CellNoise(); - Worley.Seed = Seed; - HighNoise.Seed = Seed; - LowNoise.Seed = Seed; + const int featurePointDistance = 400; + int seed = world.Seed; + var worley = new CellNoise(); + worley.Seed = seed; + HighNoise.Seed = seed; + LowNoise.Seed = seed; var chunk = new Chunk(coordinates); for (int X = 0; X < 16; X++) { for (int Z = 0; Z < 16; Z++) { - var BlockX = MathHelper.ChunkToBlockX(X, coordinates.X); - var BlockZ = MathHelper.ChunkToBlockZ(Z, coordinates.Z); - double LowClampMid = LowClamp.MaxValue - ((LowClamp.MaxValue + LowClamp.MinValue) / 2); - double LowClampRange = 5; - double LowClampValue = LowClamp.Value2D(BlockX, BlockZ); - if (LowClampValue > LowClampMid - LowClampRange && LowClampValue < LowClampMid + LowClampRange) + var blockX = MathHelper.ChunkToBlockX(X, coordinates.X); + var blockZ = MathHelper.ChunkToBlockZ(Z, coordinates.Z); + const double lowClampRange = 5; + double lowClampMid = LowClamp.MaxValue - ((LowClamp.MaxValue + LowClamp.MinValue) / 2); + double lowClampValue = LowClamp.Value2D(blockX, blockZ); + if (lowClampValue > lowClampMid - lowClampRange && lowClampValue < lowClampMid + lowClampRange) { InvertNoise NewPrimary = new InvertNoise(HighClamp); Modified.PrimaryNoise = NewPrimary; @@ -100,23 +102,23 @@ namespace TrueCraft.Core.TerrainGen Modified = new ModifyNoise(HighClamp, LowClamp, NoiseModifier.Add); } Modified = new ModifyNoise(Modified, BottomClamp, NoiseModifier.Subtract); - var CellValue = Worley.Value2D(BlockX, BlockZ); - var Location = new Coordinates2D(BlockX, BlockZ); - if (world.BiomeDiagram.BiomeCells.Count < 1 || CellValue.Equals(1) && world.BiomeDiagram.ClosestCellPoint(Location) >= FeaturePointDistance) + var cellValue = worley.Value2D(blockX, blockZ); + var location = new Coordinates2D(blockX, blockZ); + if (world.BiomeDiagram.BiomeCells.Count < 1 || cellValue.Equals(1) && world.BiomeDiagram.ClosestCellPoint(location) >= featurePointDistance) { - byte ID = (SingleBiome) ? GenerationBiome : world.BiomeDiagram.GenerateBiome(Seed, Biomes, Location); - BiomeCell Cell = new BiomeCell(ID, Location); + byte id = (SingleBiome) ? GenerationBiome : world.BiomeDiagram.GenerateBiome(seed, Biomes, location); + BiomeCell Cell = new BiomeCell(id, location); world.BiomeDiagram.AddCell(Cell); } - var BiomeID = GetBiome(world, Location); - IBiomeProvider Biome = Biomes.GetBiome(BiomeID); - chunk.Biomes[X * Chunk.Width + Z] = BiomeID; + var biomeId = GetBiome(world, location); + IBiomeProvider Biome = Biomes.GetBiome(biomeId); + chunk.Biomes[X * Chunk.Width + Z] = biomeId; - var Height = GetHeight(BlockX, BlockZ); - var SurfaceHeight = Height - Biome.SurfaceDepth; - chunk.HeightMap[X * Chunk.Width + Z] = Height; - for (int Y = 0; Y <= Height; Y++) + var height = GetHeight(blockX, blockZ); + var surfaceHeight = height - Biome.SurfaceDepth; + chunk.HeightMap[X * Chunk.Width + Z] = height; + for (int Y = 0; Y <= height; Y++) { if (Y == 0) { @@ -124,13 +126,13 @@ namespace TrueCraft.Core.TerrainGen } 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); } else { - if (Y > SurfaceHeight - Biome.FillerDepth) + if (Y > surfaceHeight - Biome.FillerDepth) { chunk.SetBlockID(new Coordinates3D(X, Y, Z), Biome.FillerBlock); } @@ -144,29 +146,27 @@ namespace TrueCraft.Core.TerrainGen } } foreach (IChunkDecorator ChunkDecorator in ChunkDecorators) - { 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; } - byte GetBiome(IWorld world, Coordinates2D Location) + public Coordinates3D GetSpawn(IWorld world) { - if (SingleBiome) - { - return GenerationBiome; - } - return world.BiomeDiagram.GetBiome(Location); + var chunk = GenerateChunk(world, Coordinates2D.Zero); + var spawnPointHeight = chunk.HeightMap[0]; + return new Coordinates3D(0, spawnPointHeight + 1, 0); } - 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) NoiseValue = GroundLevel; if (NoiseValue > Chunk.Height) diff --git a/TrueCraft.Core/TrueCraft.Core.csproj b/TrueCraft.Core/TrueCraft.Core.csproj index a6177fa..6d3e201 100644 --- a/TrueCraft.Core/TrueCraft.Core.csproj +++ b/TrueCraft.Core/TrueCraft.Core.csproj @@ -206,7 +206,6 @@ - @@ -309,6 +308,7 @@ + diff --git a/TrueCraft.Core/World/World.cs b/TrueCraft.Core/World/World.cs index 2d0356f..bf9464b 100644 --- a/TrueCraft.Core/World/World.cs +++ b/TrueCraft.Core/World/World.cs @@ -6,6 +6,7 @@ using System.Threading; using TrueCraft.API; using TrueCraft.API.World; using TrueCraft.API.Logic; +using fNbt; namespace TrueCraft.Core.World { @@ -15,12 +16,14 @@ namespace TrueCraft.Core.World public string Name { get; set; } public int Seed { get; set; } + public Coordinates3D SpawnPoint { get; set; } public string BaseDirectory { get; internal set; } public IDictionary Regions { get; set; } public IBiomeMap BiomeDiagram { get; set; } public IChunkProvider ChunkProvider { get; set; } public IBlockRepository BlockRepository { get; set; } public DateTime BaseTime { get; set; } + public long Time { get @@ -47,6 +50,7 @@ namespace TrueCraft.Core.World public World(string name, IChunkProvider chunkProvider) : this(name) { ChunkProvider = chunkProvider; + SpawnPoint = chunkProvider.GetSpawn(this); } public static World LoadWorld(string baseDirectory) @@ -55,6 +59,17 @@ namespace TrueCraft.Core.World throw new DirectoryNotFoundException(); var world = new World(Path.GetFileName(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; } @@ -223,6 +238,16 @@ namespace TrueCraft.Core.World foreach (var region in Regions) 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) @@ -230,11 +255,7 @@ namespace TrueCraft.Core.World if (!Directory.Exists(path)) Directory.CreateDirectory(path); BaseDirectory = path; - lock (Regions) - { - foreach (var region in Regions) - region.Value.Save(Path.Combine(BaseDirectory, Region.GetRegionFileName(region.Key))); - } + Save(); } public Coordinates3D FindBlockPosition(Coordinates3D coordinates, out IChunk chunk) diff --git a/TrueCraft/Handlers/LoginHandlers.cs b/TrueCraft/Handlers/LoginHandlers.cs index 3192b7a..ad995f4 100644 --- a/TrueCraft/Handlers/LoginHandlers.cs +++ b/TrueCraft/Handlers/LoginHandlers.cs @@ -39,7 +39,7 @@ namespace TrueCraft.Handlers client.QueuePacket(new LoginResponsePacket(0, 0, Dimension.Overworld)); client.UpdateChunks(); 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, (int)client.Entity.Position.Y, (int)client.Entity.Position.Z)); client.QueuePacket(new SetPlayerPositionPacket(client.Entity.Position.X, client.Entity.Position.Y, diff --git a/TrueCraft/Program.cs b/TrueCraft/Program.cs index 199597d..2400158 100644 --- a/TrueCraft/Program.cs +++ b/TrueCraft/Program.cs @@ -26,11 +26,11 @@ namespace TrueCraft { // TODO: Save and load levels, with seeds and everything world = World.LoadWorld("world"); - world.ChunkProvider = new NewGenerator(); + world.ChunkProvider = new StandardGenerator(); } catch { - world = new World("default", new NewGenerator()); + world = new World("default", new StandardGenerator()); world.Save("world"); } server.AddWorld(world);