using System.Collections; using OpenTK.Mathematics; using VoxelEngine.Core; using VoxelEngine.World.Blocks; using VoxelEngine.World.Persistence; namespace VoxelEngine.World; public sealed class World(BlockRegistry registry, IChunkModificationStore modStore) : IWorld, IEnumerable> { private readonly Dictionary _chunks = new(); public IChunkModificationStore ModificationStore { get; } = modStore; 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( ChunkMath.FloorDiv(worldX, Chunk.Chunk.Size), ChunkMath.FloorDiv(worldY, Chunk.Chunk.Size), ChunkMath.FloorDiv(worldZ, Chunk.Chunk.Size)); Chunk.Chunk? chunk = this.GetChunk(chunkPos); if (chunk == null) return 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 registry.Get(chunk[localX, localY, localZ]); } public bool SetBlock(int worldX, int worldY, int worldZ, ushort blockId) { Vector3i chunkPos = new( ChunkMath.FloorDiv(worldX, Chunk.Chunk.Size), ChunkMath.FloorDiv(worldY, Chunk.Chunk.Size), ChunkMath.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; } public IEnumerator> GetEnumerator() => this._chunks.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); }