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.Ceiling(origin.X) - origin.X) * tDeltaX : (origin.X - MathF.Floor(origin.X)) * tDeltaX; float tMaxY = direction.Y > 0 ? (MathF.Ceiling(origin.Y) + 1 - origin.Y) * tDeltaY : (origin.Y - MathF.Floor(origin.Y)) * tDeltaY; float tMaxZ = direction.Z > 0 ? (MathF.Ceiling(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); } // step to next voxel if (tMaxX < tMaxY && tMaxX < tMaxZ) { x += stepX; distance = tMaxX; tMaxX += tDeltaX; normal = new Vector3i(stepX > 0 ? -1 : 1, 0, 0); } else if (tMaxY < tMaxZ) { y += stepY; distance = tMaxY; tMaxY += tDeltaY; normal = new Vector3i(0, stepY > 0 ? -1 : 1, 0); } else { z += stepZ; distance = tMaxZ; tMaxZ += tDeltaZ; normal = new Vector3i(0, 0, stepZ > 0 ? -1 : 1); } } return (false, Blocks.Air, 0, 0, 0, normal); } public void Update() { } } }