namespace Voxel { public class Chunk { public static int Size = 16; public static int Height = 256; public readonly int X; public readonly int Y; private ChunkMesh _chunkMesh; private Dictionary _blockData; private Blocks[] _blocks; public Dictionary Neighbors = new(); public Chunk(int x, int y) { X = x; Y = y; _blockData = new Dictionary(); _blocks = new Blocks[Size * Size * Height]; _chunkMesh = new ChunkMesh(X, Y); Initialize(); } public void SetBlock(int x, int y, int z, Blocks block, bool updateMesh = true) { int i = GetBlockIndex(x, y, z); if (i == -1) return; _blocks[i] = block; if (updateMesh) { UpdateChunkMesh(); Renderer.MarkBuffersDirty(); } } public void SetBlockIndex(int i, Blocks block) { _blocks[i] = block; } public Blocks GetBlock(int x, int y, int z) { int i = GetBlockIndex(x, y, z); if (i == -1) return Blocks.Air; return _blocks[i]; } public BlockData GetBlockData(int x, int y, int z) { return new BlockData(); } private void Initialize() { for (int x = 0; x < Size; x++) { for (int z = 0; z < Size; z++) { var position = GetWorldCoordinates(x, 0, z); int height = Worldgen.GetHeight(position.x, position.z); for (int y = 0; y < 256; y++) { Blocks block = Worldgen.GetBlock(y, height); SetBlock(x, y, z, block, false); } } } UpdateChunkMesh(); } // todo public (int x, int y, int z) IndexToPosition(int i) { int x = 0; int y = 0; int z = 0; return (x, y, z); } public (int x, int y, int z) GetWorldCoordinates(int x, int y, int z) { x += (Size * X); z += (Size * Y); return (x, y, z); } private int GetBlockIndex(int x, int y, int z) { if (x < 0 || x > 15 || y < 0 || y > 255 || z < 0 || z > 15) return -1; return x + z * Size + y * Size * Size; } private static readonly (int dx, int dy, int dz)[] Offsets = new (int, int, int)[6] { ( 1, 0, 0), // +X (-1, 0, 0), // -X ( 0, 1, 0), // +Y ( 0, -1, 0), // -Y ( 0, 0, 1), // +Z ( 0, 0, -1) // -Z }; public void UpdateChunkMesh() { List faces = new List(Size * Size * Height / 2); for (int x = 0; x < Size; x++) { for (int z = 0; z < Size; z++) { for (int y = 0; y < Height; y++) { for (byte face = 0; face < 6; face++) { int indexBase = y * Size * Size + z * Size + x; Blocks block = _blocks[indexBase]; void AddFace() { FaceData faceData = new FaceData(); faceData.Facing = (Orientation)face; faceData.Texture = BlockDefinitions.Blocks[block].FaceTextures[face]; faceData.X = (byte)x; faceData.Y = (byte)y; faceData.Z = (byte)z; faces.Add(faceData); } if (block == Blocks.Air) continue; // ignore if air int nx = x + Offsets[face].dx; int ny = y + Offsets[face].dy; int nz = z + Offsets[face].dz; // check neighbor, ignore if at chunk edge int ni = GetBlockIndex(nx, ny, nz); if (GetBlockIndex(nx, ny, nz) == -1) { if (Neighbors.TryGetValue((Orientation)face, out Chunk neighbor) && neighbor != null) { int localX = nx; int localZ = nz; if (nx < 0) localX = nx + Size; if (nx >= Size) localX = nx - Size; if (nz < 0) localZ = nz + Size; if (nz >= Size) localZ = nz - Size; Blocks neighborBlock = neighbor.GetBlock(localX, y, localZ); if (neighborBlock != Blocks.Air) continue; } AddFace(); continue; } if (_blocks[ni] == Blocks.Air) { AddFace(); continue; } } } } } _chunkMesh.SetFaces(faces); } public ChunkMesh GetChunkMesh() { return _chunkMesh; } } }