using OpenTK.Mathematics; using System.Collections.Generic; namespace Voxel { public class World { private Dictionary<(int, int), Chunk> _chunks; public World() { _chunks = new Dictionary<(int, int), Chunk>(); } public Chunk GetChunk(int chunkX, int chunkZ) { _chunks.TryGetValue((chunkX, chunkZ), out Chunk chunk); return chunk; } public void AddChunk(Chunk chunk) { _chunks[(chunk.X, chunk.Y)] = chunk; } public void RemoveChunk(int chunkX, int chunkZ) { _chunks.Remove((chunkX, chunkZ)); } public IEnumerable GetAllChunks() { return _chunks.Values; } public Blocks GetBlock(int worldX, int worldY, int worldZ) { int chunkX = worldX / Chunk.Size; int chunkZ = worldZ / Chunk.Size; Chunk chunk = GetChunk(chunkX, chunkZ); if (chunk == null) return 0; // air if chunk not loaded int localX = worldX % Chunk.Size; int localZ = worldZ % Chunk.Size; return chunk.GetBlock(localX, worldY, localZ); } public void SetBlock(int worldX, int worldY, int worldZ, Blocks block) { int chunkX = worldX / Chunk.Size; int chunkZ = worldZ / Chunk.Size; Chunk chunk = GetChunk(chunkX, chunkZ); if (chunk == null) return; int localX = worldX % Chunk.Size; int localZ = worldZ % Chunk.Size; chunk.SetBlock(localX, worldY, localZ, block); } public (bool success, Blocks block, int x, int y, int z, Vector3i normal) Raycast(Vector3 origin, Vector3 direction, float maxDistance) { int x = (int)MathF.Floor(origin.X); int y = (int)MathF.Floor(origin.Y); int z = (int)MathF.Floor(origin.Z); int stepX = direction.X > 0 ? 1 : -1; int stepY = direction.Y > 0 ? 1 : -1; int stepZ = direction.Z > 0 ? 1 : -1; float tDeltaX = direction.X != 0 ? MathF.Abs(1 / direction.X) : float.MaxValue; float tDeltaY = direction.Y != 0 ? MathF.Abs(1 / direction.Y) : float.MaxValue; float tDeltaZ = direction.Z != 0 ? MathF.Abs(1 / direction.Z) : float.MaxValue; float tMaxX = direction.X > 0 ? (MathF.Floor(origin.X) + 1 - origin.X) * tDeltaX : (origin.X - MathF.Floor(origin.X)) * tDeltaX; float tMaxY = direction.Y > 0 ? (MathF.Floor(origin.Y) + 1 - origin.Y) * tDeltaY : (origin.Y - MathF.Floor(origin.Y)) * tDeltaY; float tMaxZ = direction.Z > 0 ? (MathF.Floor(origin.Z) + 1 - origin.Z) * tDeltaZ : (origin.Z - MathF.Floor(origin.Z)) * tDeltaZ; float distance = 0f; Vector3i normal = Vector3i.Zero; while (distance <= maxDistance) { Blocks block = GetBlock(x, y, z); if (block != Blocks.Air) return (true, block, x, y, z, normal); if (tMaxX < tMaxY && tMaxX < tMaxZ) { x += stepX; normal = new Vector3i(-stepX, 0, 0); distance = tMaxX; tMaxX += tDeltaX; } else if (tMaxY < tMaxZ) { y += stepY; normal = new Vector3i(0, -stepY, 0); distance = tMaxY; tMaxY += tDeltaY; } else { z += stepZ; normal = new Vector3i(0, 0, -stepZ); distance = tMaxZ; tMaxZ += tDeltaZ; } } return (false, Blocks.Air, 0, 0, 0, Vector3i.Zero); } public void Update() { } } }