mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 21: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 GlitchyEngine.ImGui;
|
||||||
using ImGui;
|
using ImGui;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.Threading;
|
||||||
|
|
||||||
namespace Sandbox.VoxelFun
|
namespace Sandbox.VoxelFun
|
||||||
{
|
{
|
||||||
@@ -30,6 +32,9 @@ namespace Sandbox.VoxelFun
|
|||||||
|
|
||||||
Dictionary<Int32_3, Chunk> _chunks = new .() ~ DeleteDictionaryAndValues!(_);
|
Dictionary<Int32_3, Chunk> _chunks = new .() ~ DeleteDictionaryAndValues!(_);
|
||||||
|
|
||||||
|
private HashSet<Int32_3> _generatingChunks = new .() ~ delete _;
|
||||||
|
private Monitor _generatingChunksLock = new .() ~ delete _;
|
||||||
|
|
||||||
public Texture2D Texture ~ _?.ReleaseRef();
|
public Texture2D Texture ~ _?.ReleaseRef();
|
||||||
public Effect TextureEffect ~ _?.ReleaseRef();
|
public Effect TextureEffect ~ _?.ReleaseRef();
|
||||||
|
|
||||||
@@ -48,6 +53,11 @@ namespace Sandbox.VoxelFun
|
|||||||
|
|
||||||
public World World => _world;
|
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)
|
public this(GraphicsContext context, VertexLayout vertexLayout, World world)
|
||||||
{
|
{
|
||||||
_context = context..AddRef();
|
_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.
|
* 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);
|
Chunk chunk = GetChunk(chunkCoordinate);
|
||||||
|
|
||||||
if(chunk == null)
|
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 = new Chunk();
|
||||||
chunk.Position = chunkCoordinate * .(VoxelChunk.SizeX, VoxelChunk.SizeY, VoxelChunk.SizeZ);
|
chunk.Position = chunkCoordinate * .(VoxelChunk.SizeX, VoxelChunk.SizeY, VoxelChunk.SizeZ);
|
||||||
@@ -122,7 +146,56 @@ namespace Sandbox.VoxelFun
|
|||||||
|
|
||||||
using(chunkListLock.Enter())
|
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;
|
Int32_3 chunkCoordinate = (Int32_3)chunkPos;
|
||||||
int z = 0;
|
int x = 0, z = 0;
|
||||||
for(int r = 1; r < _viewDistance; r++)
|
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, true);
|
||||||
LoadChunk(chunkCoordinate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(; z < r; z++)
|
for(; z < r; z++, chunkCoordinate.Z++)
|
||||||
{
|
{
|
||||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos + .(x, 0, z);
|
LoadChunk(chunkCoordinate, true);
|
||||||
LoadChunk(chunkCoordinate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(; x > -r; x--)
|
for(; x > -r; x--, chunkCoordinate.X--)
|
||||||
{
|
{
|
||||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos + .(x, 0, z);
|
LoadChunk(chunkCoordinate, true);
|
||||||
LoadChunk(chunkCoordinate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(; z > -r; z--)
|
for(; z > -r; z--, chunkCoordinate.Z--)
|
||||||
{
|
{
|
||||||
Int32_3 chunkCoordinate = (Int32_3)chunkPos + .(x, 0, z);
|
LoadChunk(chunkCoordinate, true);
|
||||||
LoadChunk(chunkCoordinate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
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)
|
Result<void> LoadChunkFromFile(Int32_3 chunkCoordinate, Chunk outChunk)
|
||||||
|
|||||||
Reference in New Issue
Block a user