Added chunk editing

This commit is contained in:
Simon Lübeß
2021-03-04 13:05:57 +01:00
parent 4e377bb117
commit 623ada4b2f
3 changed files with 148 additions and 23 deletions
+85 -15
View File
@@ -15,10 +15,48 @@ namespace Sandbox.VoxelFun
{ {
public class Chunk public class Chunk
{ {
public ChunkManager ChunkManager;
public GeometryBinding Geometry ~ _?.ReleaseRef(); public GeometryBinding Geometry ~ _?.ReleaseRef();
public VoxelChunk Data; public VoxelChunk Data;
public Matrix Transform; public Matrix Transform;
public Int32_3 Position; public Int32_3 Position;
public Int32_3 Coordinate;
private bool _isDirty;
private bool _isGeometryDirty;
public bool IsDirty => _isDirty;
public bool IsGeometryDirty
{
get => _isGeometryDirty;
set => _isGeometryDirty = value;
}
public void SetBlock(Int32_3 coordinate, uint8 blockId)
{
Log.EngineLogger.AssertDebug(coordinate.X >= 0 && coordinate.Y >= 0 && coordinate.Z >= 0 && coordinate.X < VoxelChunk.Size.X && coordinate.Y < VoxelChunk.Size.Y && coordinate.Z < VoxelChunk.Size.Z, "Specified coordinate is out of range.");
Data.Data[coordinate.X][coordinate.Y][coordinate.Z] = blockId;
_isDirty = true;
_isGeometryDirty = true;
ChunkManager.[Friend]chunkPosLock.Exit();
}
public uint8 GetBlock(Int32_3 coordinate)
{
Log.EngineLogger.AssertDebug(coordinate.X >= 0 && coordinate.Y >= 0 && coordinate.Z >= 0 && coordinate.X < VoxelChunk.Size.X && coordinate.Y < VoxelChunk.Size.Y && coordinate.Z < VoxelChunk.Size.Z, "Specified coordinate is out of range.");
return Data.Data[coordinate.X][coordinate.Y][coordinate.Z];
}
public void Serialize(Stream stream)
{
stream.Write(Data);
_isDirty = false;
}
} }
public class ChunkManager public class ChunkManager
@@ -30,7 +68,7 @@ namespace Sandbox.VoxelFun
private String _chunkBasePath ~ delete _; private String _chunkBasePath ~ delete _;
Dictionary<Int32_3, Chunk> _chunks = new .() ~ DeleteDictionaryAndValues!(_); Dictionary<Int32_3, Chunk> _chunks = new .() ~ delete _;
private HashSet<Int32_3> _generatingChunks = new .() ~ delete _; private HashSet<Int32_3> _generatingChunks = new .() ~ delete _;
private Monitor _generatingChunksLock = new .() ~ delete _; private Monitor _generatingChunksLock = new .() ~ delete _;
@@ -83,6 +121,12 @@ namespace Sandbox.VoxelFun
stopChunkLoader = true; stopChunkLoader = true;
chunkLoader.Join(); chunkLoader.Join();
// Unload (and save) all chunks
for(var pair in _chunks)
{
UnloadChunk(pair.value);
}
} }
/** /**
@@ -133,13 +177,15 @@ namespace Sandbox.VoxelFun
if(!alreadyInList) if(!alreadyInList)
{ {
chunk = new Chunk(); chunk = new Chunk();
chunk.ChunkManager = this;
chunk.Coordinate = chunkCoordinate;
chunk.Position = chunkCoordinate * .(VoxelChunk.SizeX, VoxelChunk.SizeY, VoxelChunk.SizeZ); chunk.Position = chunkCoordinate * .(VoxelChunk.SizeX, VoxelChunk.SizeY, VoxelChunk.SizeZ);
chunk.Transform = .Translation(chunk.Position.X, chunk.Position.Y, chunk.Position.Z); chunk.Transform = .Translation(chunk.Position.X, chunk.Position.Y, chunk.Position.Z);
if(LoadChunkFromFile(chunkCoordinate, chunk) case .Err) if(LoadChunkFromFile(chunkCoordinate, chunk) case .Err)
{ {
GenTestChunk(chunk); GenTestChunk(chunk);
SaveChunkToFile(chunkCoordinate, chunk); SaveChunkToFile(chunk);
} }
GenChunkGeo(chunk); GenChunkGeo(chunk);
@@ -243,8 +289,8 @@ namespace Sandbox.VoxelFun
} }
// Position didn't change -> skip // Position didn't change -> skip
if(curChunkPosition == oldChunkPosition) //if(curChunkPosition == oldChunkPosition)
continue; // continue;
ChunkLoaderThread_GenerateChunks(curChunkPosition); ChunkLoaderThread_GenerateChunks(curChunkPosition);
@@ -252,6 +298,20 @@ namespace Sandbox.VoxelFun
} }
} }
private void UnloadChunk(Chunk chunk)
{
if(chunk.IsDirty)
{
SaveChunkToFile(chunk);
}
using(chunkListLock.Enter())
{
_chunks.Remove(chunk.Coordinate);
delete chunk;
}
}
public void ChunkLoaderThread_GenerateChunks(Int32_3 chunkPos) public void ChunkLoaderThread_GenerateChunks(Int32_3 chunkPos)
{ {
for(var chunk in _chunks) for(var chunk in _chunks)
@@ -260,11 +320,11 @@ namespace Sandbox.VoxelFun
if(dist.X > _viewDistance || dist.Z > _viewDistance) if(dist.X > _viewDistance || dist.Z > _viewDistance)
{ {
using(chunkListLock.Enter()) UnloadChunk(chunk.value);
{ }
delete chunk.value; else if(chunk.value.IsGeometryDirty)
_chunks.Remove(chunk.key); {
} GenChunkGeo(chunk.value);
} }
} }
@@ -313,16 +373,16 @@ namespace Sandbox.VoxelFun
return .Ok; return .Ok;
} }
Result<void> SaveChunkToFile(Int32_3 chunkCoordinate, Chunk outChunk) Result<void> SaveChunkToFile(Chunk chunk)
{ {
String chunkFileName = scope String(_chunkBasePath); String chunkFileName = scope String(_chunkBasePath);
chunkFileName.AppendF($"{chunkCoordinate.X}_{chunkCoordinate.Y}_{chunkCoordinate.Z}.cdata"); chunkFileName.AppendF($"{chunk.Coordinate.X}_{chunk.Coordinate.Y}_{chunk.Coordinate.Z}.cdata");
FileStream fs = scope FileStream(); FileStream fs = scope FileStream();
fs.Open(chunkFileName, FileMode.Create, .Write); fs.Open(chunkFileName, FileMode.Create, .Write);
fs.Write(outChunk.Data); chunk.Serialize(fs);
fs.Close(); fs.Close();
@@ -463,8 +523,14 @@ namespace Sandbox.VoxelFun
void GenChunkGeo(Chunk chunk) void GenChunkGeo(Chunk chunk)
{ {
chunk.Geometry?.ReleaseRef(); var oldGeometry = chunk.Geometry;
chunk.Geometry = voxelGeoGen.GenerateGeometry(chunk.Data);
var newGeometry = voxelGeoGen.GenerateGeometry(chunk.Data);
Interlocked.Store(ref chunk.Geometry, newGeometry);
chunk.IsGeometryDirty = false;
oldGeometry?.ReleaseRef();
} }
public void Draw() public void Draw()
@@ -474,12 +540,16 @@ namespace Sandbox.VoxelFun
{ {
Chunk chunk = pair.value; Chunk chunk = pair.value;
if(chunk?.Geometry == null) GeometryBinding chunkGeo = Interlocked.Load(ref chunk.Geometry);
chunkGeo.AddRef();
if(chunkGeo == null)
continue; continue;
Texture.Bind(); Texture.Bind();
Renderer.Submit(chunk.Geometry, TextureEffect, chunk.Transform); Renderer.Submit(chunk.Geometry, TextureEffect, chunk.Transform);
chunkGeo.ReleaseRef();
} }
chunkListLock.Exit(); chunkListLock.Exit();
} }
+32
View File
@@ -398,6 +398,38 @@ namespace Sandbox.VoxelFun
Renderer.Submit(_cubeGeo, _textureEffect, .Translation(intersectInfo.Location) * .Scaling(0.1f) * .Translation(-0.5f.XXX)); Renderer.Submit(_cubeGeo, _textureEffect, .Translation(intersectInfo.Location) * .Scaling(0.1f) * .Translation(-0.5f.XXX));
if(intersectInfo.Face != .None)
{
if(Input.IsMouseButtonPressing(.LeftButton))
{
_world.SetBlock(intersectInfo.Coordinate, 0);
}
else if(Input.IsMouseButtonPressing(.RightButton))
{
var newBlockCoord = intersectInfo.Coordinate;
switch(intersectInfo.Face)
{
case .Front:
newBlockCoord.Z--;
case .Back:
newBlockCoord.Z++;
case .Left:
newBlockCoord.X--;
case .Right:
newBlockCoord.X++;
case .Bottom:
newBlockCoord.Y--;
case .Top:
newBlockCoord.Y++;
default:
Log.ClientLogger.Error("Unknown block face.");
}
_world.SetBlock(newBlockCoord, 1);
}
}
_world.ChunkManager.Draw(); _world.ChunkManager.Draw();
Renderer.EndScene(); Renderer.EndScene();
+31 -8
View File
@@ -280,13 +280,7 @@ namespace Sandbox.VoxelFun
} }
} }
Int32_3 chunkCoordinate = ChunkCoordFromBlockCoord(walker); uint8 blockData = [Inline]GetBlock(walker);
Chunk chunk = _chunkManager.LoadChunk(chunkCoordinate);
Int32_3 coordInChunk = BlockCoordInChunk(walker);
uint8 blockData = chunk.Data.Data[coordInChunk.X][coordInChunk.Y][coordInChunk.Z];
if(blockData != 0) if(blockData != 0)
{ {
@@ -294,12 +288,41 @@ namespace Sandbox.VoxelFun
return walker; return walker;
} }
} }
intersectionFace = .None; intersectionFace = .None;
intersectionPosition = .(float.NaN); intersectionPosition = .(float.NaN);
return .(int32.MaxValue, int32.MaxValue, int32.MaxValue); return .(int32.MaxValue, int32.MaxValue, int32.MaxValue);
} }
/**
* Gets the block at the specified coordinate.
* @remarks If the blocks chunk is not loaded it will be loaded from the disk.
*/
public void SetBlock(Int32_3 blockCoordinate, uint8 blockId)
{
Int32_3 chunkCoordinate = ChunkCoordFromBlockCoord(blockCoordinate);
Chunk chunk = _chunkManager.LoadChunk(chunkCoordinate);
Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate);
chunk.SetBlock(coordInChunk, blockId);
}
/**
* Gets the block at the specified coordinate.
* @remarks If the blocks chunk is not loaded it will be loaded from the disk.
*/
public uint8 GetBlock(Int32_3 blockCoordinate)
{
Int32_3 chunkCoordinate = ChunkCoordFromBlockCoord(blockCoordinate);
Chunk chunk = _chunkManager.LoadChunk(chunkCoordinate);
Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate);
return chunk.GetBlock(coordInChunk);
}
} }
} }