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
+84 -14
View File
@@ -15,10 +15,48 @@ namespace Sandbox.VoxelFun
{
public class Chunk
{
public ChunkManager ChunkManager;
public GeometryBinding Geometry ~ _?.ReleaseRef();
public VoxelChunk Data;
public Matrix Transform;
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
@@ -30,7 +68,7 @@ namespace Sandbox.VoxelFun
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 Monitor _generatingChunksLock = new .() ~ delete _;
@@ -83,6 +121,12 @@ namespace Sandbox.VoxelFun
stopChunkLoader = true;
chunkLoader.Join();
// Unload (and save) all chunks
for(var pair in _chunks)
{
UnloadChunk(pair.value);
}
}
/**
@@ -133,13 +177,15 @@ namespace Sandbox.VoxelFun
if(!alreadyInList)
{
chunk = new Chunk();
chunk.ChunkManager = this;
chunk.Coordinate = chunkCoordinate;
chunk.Position = chunkCoordinate * .(VoxelChunk.SizeX, VoxelChunk.SizeY, VoxelChunk.SizeZ);
chunk.Transform = .Translation(chunk.Position.X, chunk.Position.Y, chunk.Position.Z);
if(LoadChunkFromFile(chunkCoordinate, chunk) case .Err)
{
GenTestChunk(chunk);
SaveChunkToFile(chunkCoordinate, chunk);
SaveChunkToFile(chunk);
}
GenChunkGeo(chunk);
@@ -243,8 +289,8 @@ namespace Sandbox.VoxelFun
}
// Position didn't change -> skip
if(curChunkPosition == oldChunkPosition)
continue;
//if(curChunkPosition == oldChunkPosition)
// continue;
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)
{
for(var chunk in _chunks)
@@ -260,11 +320,11 @@ namespace Sandbox.VoxelFun
if(dist.X > _viewDistance || dist.Z > _viewDistance)
{
using(chunkListLock.Enter())
{
delete chunk.value;
_chunks.Remove(chunk.key);
UnloadChunk(chunk.value);
}
else if(chunk.value.IsGeometryDirty)
{
GenChunkGeo(chunk.value);
}
}
@@ -313,16 +373,16 @@ namespace Sandbox.VoxelFun
return .Ok;
}
Result<void> SaveChunkToFile(Int32_3 chunkCoordinate, Chunk outChunk)
Result<void> SaveChunkToFile(Chunk chunk)
{
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();
fs.Open(chunkFileName, FileMode.Create, .Write);
fs.Write(outChunk.Data);
chunk.Serialize(fs);
fs.Close();
@@ -463,8 +523,14 @@ namespace Sandbox.VoxelFun
void GenChunkGeo(Chunk chunk)
{
chunk.Geometry?.ReleaseRef();
chunk.Geometry = voxelGeoGen.GenerateGeometry(chunk.Data);
var oldGeometry = chunk.Geometry;
var newGeometry = voxelGeoGen.GenerateGeometry(chunk.Data);
Interlocked.Store(ref chunk.Geometry, newGeometry);
chunk.IsGeometryDirty = false;
oldGeometry?.ReleaseRef();
}
public void Draw()
@@ -474,12 +540,16 @@ namespace Sandbox.VoxelFun
{
Chunk chunk = pair.value;
if(chunk?.Geometry == null)
GeometryBinding chunkGeo = Interlocked.Load(ref chunk.Geometry);
chunkGeo.AddRef();
if(chunkGeo == null)
continue;
Texture.Bind();
Renderer.Submit(chunk.Geometry, TextureEffect, chunk.Transform);
chunkGeo.ReleaseRef();
}
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));
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();
Renderer.EndScene();
+31 -8
View File
@@ -280,13 +280,7 @@ namespace Sandbox.VoxelFun
}
}
Int32_3 chunkCoordinate = ChunkCoordFromBlockCoord(walker);
Chunk chunk = _chunkManager.LoadChunk(chunkCoordinate);
Int32_3 coordInChunk = BlockCoordInChunk(walker);
uint8 blockData = chunk.Data.Data[coordInChunk.X][coordInChunk.Y][coordInChunk.Z];
uint8 blockData = [Inline]GetBlock(walker);
if(blockData != 0)
{
@@ -294,12 +288,41 @@ namespace Sandbox.VoxelFun
return walker;
}
}
intersectionFace = .None;
intersectionPosition = .(float.NaN);
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);
}
}
}