feat: World.SetBlock writes through to IChunkModificationStore

This commit is contained in:
2026-06-01 10:29:01 +02:00
parent 7c310ebc6a
commit 6a68953c9a
4 changed files with 149 additions and 40 deletions

View File

@@ -1,11 +1,16 @@
using OpenTK.Mathematics;
using OpenTK.Mathematics;
using VoxelEngine.World.Blocks;
using VoxelEngine.World.Persistence;
namespace VoxelEngine.World;
public interface IWorld
{
public void SetChunk(Vector3i chunkPos, Chunk.Chunk chunk);
public Chunk.Chunk? GetChunk(Vector3i chunkPos);
public IBlock GetBlock(int worldX, int worldY, int worldZ);
}
IChunkModificationStore ModificationStore { get; }
void SetChunk(Vector3i chunkPos, Chunk.Chunk chunk);
void RemoveChunk(Vector3i chunkPos);
Chunk.Chunk? GetChunk(Vector3i chunkPos);
IBlock GetBlock(int worldX, int worldY, int worldZ);
bool SetBlock(int worldX, int worldY, int worldZ, ushort blockId);
}

View File

@@ -1,6 +1,7 @@
using System.Collections;
using System.Collections;
using OpenTK.Mathematics;
using VoxelEngine.World.Blocks;
using VoxelEngine.World.Persistence;
namespace VoxelEngine.World;
@@ -9,55 +10,69 @@ public sealed class World : IWorld, IEnumerable<KeyValuePair<Vector3i, Chunk.Chu
private readonly Dictionary<Vector3i, Chunk.Chunk> _chunks = new();
private readonly BlockRegistry _registry;
public World(BlockRegistry registry)
public IChunkModificationStore ModificationStore { get; }
public World(BlockRegistry registry, IChunkModificationStore modStore)
{
this._registry = registry;
}
public void SetChunk(Vector3i chunkPos, Chunk.Chunk chunk)
{
this._chunks[chunkPos] = chunk;
this.ModificationStore = modStore;
}
public Chunk.Chunk? GetChunk(Vector3i chunkPos)
{
return this._chunks.GetValueOrDefault(chunkPos);
}
public void SetChunk(Vector3i chunkPos, Chunk.Chunk chunk) => this._chunks[chunkPos] = chunk;
public void RemoveChunk(Vector3i chunkPos) => this._chunks.Remove(chunkPos);
public Chunk.Chunk? GetChunk(Vector3i chunkPos) => this._chunks.GetValueOrDefault(chunkPos);
public IBlock GetBlock(int worldX, int worldY, int worldZ)
{
Vector3i chunkPos = new(
World.FloorDiv(worldX, Chunk.Chunk.Size),
World.FloorDiv(worldY, Chunk.Chunk.Size),
World.FloorDiv(worldZ, Chunk.Chunk.Size)
);
World.FloorDiv(worldZ, Chunk.Chunk.Size));
Chunk.Chunk? chunk = this.GetChunk(chunkPos);
if (chunk == null)
{
return this._registry.Air;
}
int localX = worldX - chunkPos.X * Chunk.Chunk.Size;
int localY = worldY - chunkPos.Y * Chunk.Chunk.Size;
int localZ = worldZ - chunkPos.Z * Chunk.Chunk.Size;
if (chunk == null) return this._registry.Air;
int localX = worldX - chunkPos.X * Chunk.Chunk.Size;
int localY = worldY - chunkPos.Y * Chunk.Chunk.Size;
int localZ = worldZ - chunkPos.Z * Chunk.Chunk.Size;
return this._registry.Get(chunk[localX, localY, localZ]);
}
public bool SetBlock(int worldX, int worldY, int worldZ, ushort blockId)
{
Vector3i chunkPos = new(
World.FloorDiv(worldX, Chunk.Chunk.Size),
World.FloorDiv(worldY, Chunk.Chunk.Size),
World.FloorDiv(worldZ, Chunk.Chunk.Size));
Chunk.Chunk? chunk = this.GetChunk(chunkPos);
int localX = worldX - chunkPos.X * Chunk.Chunk.Size;
int localY = worldY - chunkPos.Y * Chunk.Chunk.Size;
int localZ = worldZ - chunkPos.Z * Chunk.Chunk.Size;
int localIndex = (localX * Chunk.Chunk.Size + localY) * Chunk.Chunk.Size + localZ;
// For a loaded chunk, no-op writes shouldn't pollute the diff store.
if (chunk != null && chunk[localX, localY, localZ] == blockId) return true;
this.ModificationStore.RecordEdit(chunkPos, localIndex, blockId);
if (chunk == null) return false;
chunk[localX, localY, localZ] = blockId;
return true;
}
private static int FloorDiv(int value, int size)
{
int quotient = value / size;
if (value % size != 0 && value < 0)
{
quotient--;
}
return quotient;
int q = value / size;
if (value % size != 0 && value < 0) q--;
return q;
}
public IEnumerator<KeyValuePair<Vector3i, Chunk.Chunk>> GetEnumerator()
=> this._chunks.GetEnumerator();
public IEnumerator<KeyValuePair<Vector3i, Chunk.Chunk>> GetEnumerator() => this._chunks.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}
}