mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Overcomplicated chunk loading
Implemented an overly complicated mechanism into LoadChunk to be able to passively wait for chunks to be loaded by another thread.
This commit is contained in:
@@ -8,6 +8,8 @@ using System.Collections;
|
||||
using GlitchyEngine.ImGui;
|
||||
using ImGui;
|
||||
using System.IO;
|
||||
using GlitchyEngine;
|
||||
using GlitchyEngine.Threading;
|
||||
|
||||
namespace Sandbox.VoxelFun
|
||||
{
|
||||
@@ -30,6 +32,9 @@ namespace Sandbox.VoxelFun
|
||||
|
||||
Dictionary<Int32_3, Chunk> _chunks = new .() ~ DeleteDictionaryAndValues!(_);
|
||||
|
||||
private HashSet<Int32_3> _generatingChunks = new .() ~ delete _;
|
||||
private Monitor _generatingChunksLock = new .() ~ delete _;
|
||||
|
||||
public Texture2D Texture ~ _?.ReleaseRef();
|
||||
public Effect TextureEffect ~ _?.ReleaseRef();
|
||||
|
||||
@@ -48,6 +53,11 @@ namespace Sandbox.VoxelFun
|
||||
|
||||
public World World => _world;
|
||||
|
||||
public delegate void ChunkLoadedHandler(Int32_3 chunkCoordinate);
|
||||
|
||||
Event<ChunkLoadedHandler> _chunkLoaded ~ _.Dispose();
|
||||
Monitor _chunkLoadedLock = new Monitor() ~ delete _;
|
||||
|
||||
public this(GraphicsContext context, VertexLayout vertexLayout, World world)
|
||||
{
|
||||
_context = context..AddRef();
|
||||
@@ -101,12 +111,26 @@ namespace Sandbox.VoxelFun
|
||||
|
||||
/**
|
||||
* Loads and returns the chunk with the given coordinate. If the chunk doesn't exist it will be generated.
|
||||
* @param chunkCoordinate The coordinate of the chunk to load.
|
||||
* @param noBlocking If set to true this method will not wait if the chunk cannot be loaded right now (because it is currently being loaded by another thread);
|
||||
* otherwise the method will block until the chunk has been loaded.
|
||||
* @returns The loaded chunk. If noBlocking is set to true and the chunk cannot be obtained right now the return value will be null.
|
||||
*/
|
||||
public Chunk LoadChunk(Int32_3 chunkCoordinate)
|
||||
public Chunk LoadChunk(Int32_3 chunkCoordinate, bool noBlocking = false)
|
||||
{
|
||||
Chunk chunk = GetChunk(chunkCoordinate);
|
||||
|
||||
if(chunk == null)
|
||||
{
|
||||
// Add chunk coordinate to generating list
|
||||
// If it could be added, we have to generate it ourselves, otherwise we have to wait for the other thread to finish.
|
||||
bool alreadyInList = false;
|
||||
using(_generatingChunksLock.Enter())
|
||||
{
|
||||
alreadyInList = !_generatingChunks.Add(chunkCoordinate);
|
||||
}
|
||||
|
||||
if(!alreadyInList)
|
||||
{
|
||||
chunk = new Chunk();
|
||||
chunk.Position = chunkCoordinate * .(VoxelChunk.SizeX, VoxelChunk.SizeY, VoxelChunk.SizeZ);
|
||||
@@ -122,7 +146,56 @@ namespace Sandbox.VoxelFun
|
||||
|
||||
using(chunkListLock.Enter())
|
||||
{
|
||||
_chunks.Add(chunkCoordinate, chunk);
|
||||
if(!_chunks.TryAdd(chunkCoordinate, chunk))
|
||||
{
|
||||
chunk = LoadChunk(chunkCoordinate);
|
||||
}
|
||||
}
|
||||
|
||||
using(_generatingChunksLock.Enter())
|
||||
{
|
||||
_generatingChunks.Remove(chunkCoordinate);
|
||||
}
|
||||
|
||||
// Raise chunk loaded event (this will wake up all calls of LoadChunk waiting for our chunk)
|
||||
using(_chunkLoadedLock.Enter())
|
||||
{
|
||||
_chunkLoaded.Invoke(chunkCoordinate);
|
||||
}
|
||||
}
|
||||
else if(!noBlocking)
|
||||
{
|
||||
Semaphore semaphore = new Semaphore(0);
|
||||
defer delete semaphore;
|
||||
|
||||
// event handler will increase semaphore as soon as our requested chunk is loaded.
|
||||
ChunkLoadedHandler eventHandler = scope (coordinate) =>
|
||||
{
|
||||
if(coordinate == chunkCoordinate)
|
||||
{
|
||||
semaphore.Unlock();
|
||||
}
|
||||
};
|
||||
|
||||
// register event listener
|
||||
using(_chunkLoadedLock.Enter())
|
||||
{
|
||||
_chunkLoaded.Add(eventHandler);
|
||||
}
|
||||
|
||||
Log.ClientLogger.Trace($"Sleeping until chunk ({chunkCoordinate}) has been generated...");
|
||||
|
||||
// wait for semaphore to be released (in the event handler)
|
||||
semaphore.Lock();
|
||||
|
||||
// unregister event handler
|
||||
using(_chunkLoadedLock.Enter())
|
||||
{
|
||||
_chunkLoaded.Remove(eventHandler);
|
||||
}
|
||||
|
||||
// retry loading the chunk
|
||||
chunk = LoadChunk(chunkCoordinate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,46 +268,30 @@ namespace Sandbox.VoxelFun
|
||||
}
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
int z = 0;
|
||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos;
|
||||
int x = 0, z = 0;
|
||||
for(int r = 1; r < _viewDistance; r++)
|
||||
{
|
||||
for(; x < r; x++)
|
||||
for(; x < r; x++, chunkCoordinate.X++)
|
||||
{
|
||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos + .(x, 0, z);
|
||||
LoadChunk(chunkCoordinate);
|
||||
LoadChunk(chunkCoordinate, true);
|
||||
}
|
||||
|
||||
for(; z < r; z++)
|
||||
for(; z < r; z++, chunkCoordinate.Z++)
|
||||
{
|
||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos + .(x, 0, z);
|
||||
LoadChunk(chunkCoordinate);
|
||||
LoadChunk(chunkCoordinate, true);
|
||||
}
|
||||
|
||||
for(; x > -r; x--)
|
||||
for(; x > -r; x--, chunkCoordinate.X--)
|
||||
{
|
||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos + .(x, 0, z);
|
||||
LoadChunk(chunkCoordinate);
|
||||
LoadChunk(chunkCoordinate, true);
|
||||
}
|
||||
|
||||
for(; z > -r; z--)
|
||||
for(; z > -r; z--, chunkCoordinate.Z--)
|
||||
{
|
||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos + .(x, 0, z);
|
||||
LoadChunk(chunkCoordinate);
|
||||
LoadChunk(chunkCoordinate, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
for(int x = -_viewDistance; x < _viewDistance; x++)
|
||||
//for(int y = -_viewDistance; y < _viewDistance; y++)
|
||||
for(int z = -_viewDistance; z < _viewDistance; z++)
|
||||
{
|
||||
int y = 0;
|
||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos + .(x, y, z);
|
||||
|
||||
LoadChunk(chunkCoordinate);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
Result<void> LoadChunkFromFile(Int32_3 chunkCoordinate, Chunk outChunk)
|
||||
|
||||
Reference in New Issue
Block a user