using UnityEngine; /// /// Utility struct for chunk coordinate conversions. /// Handles conversions between world, grid, chunk, and local block coordinates. /// public struct ChunkCoord { public const int CHUNK_SIZE = 4; /// /// Chunk position in chunk coordinates (not world or grid) /// public Vector3Int chunkPos; public ChunkCoord(Vector3Int pos) { chunkPos = pos; } public ChunkCoord(int x, int y, int z) { chunkPos = new Vector3Int(x, y, z); } /// /// Get the grid position of the chunk's origin (corner with smallest coordinates) /// public Vector3Int GridOrigin => new Vector3Int( chunkPos.x * CHUNK_SIZE, chunkPos.y * CHUNK_SIZE, chunkPos.z * CHUNK_SIZE ); /// /// Get world position of chunk origin using BuildManager's grid system /// public Vector3 WorldOrigin { get { if (BuildManager.Instance != null) { return BuildManager.Instance.GridToWorld(GridOrigin); } // Fallback if BuildManager not available return new Vector3( GridOrigin.x + 0.5f, GridOrigin.y + 0.5f, GridOrigin.z + 0.5f ); } } /// /// Convert grid coordinates to chunk coordinates /// public static ChunkCoord FromGridPos(Vector3Int gridPos) { return new ChunkCoord( Mathf.FloorToInt((float)gridPos.x / CHUNK_SIZE), Mathf.FloorToInt((float)gridPos.y / CHUNK_SIZE), Mathf.FloorToInt((float)gridPos.z / CHUNK_SIZE) ); } /// /// Convert world position to chunk coordinates /// public static ChunkCoord FromWorldPos(Vector3 worldPos) { Vector3Int gridPos; if (BuildManager.Instance != null) { gridPos = BuildManager.Instance.WorldToGrid3D(worldPos); } else { // Fallback gridPos = new Vector3Int( Mathf.RoundToInt(worldPos.x - 0.5f), Mathf.RoundToInt(worldPos.y - 0.5f), Mathf.RoundToInt(worldPos.z - 0.5f) ); } return FromGridPos(gridPos); } /// /// Get local block coordinates within chunk from grid position /// public static Vector3Int GridToLocal(Vector3Int gridPos) { // Use modulo to get local position, handling negative coords int x = ((gridPos.x % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE; int y = ((gridPos.y % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE; int z = ((gridPos.z % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE; return new Vector3Int(x, y, z); } /// /// Convert local block coordinates to grid position /// public Vector3Int LocalToGrid(Vector3Int localPos) { return GridOrigin + localPos; } /// /// Convert local block coordinates to world position /// public Vector3 LocalToWorld(Vector3Int localPos) { Vector3Int gridPos = LocalToGrid(localPos); if (BuildManager.Instance != null) { return BuildManager.Instance.GridToWorld(gridPos); } return new Vector3(gridPos.x + 0.5f, gridPos.y + 0.5f, gridPos.z + 0.5f); } /// /// Convert local index to local 3D coordinates /// public static Vector3Int IndexToLocal(int index) { int x = index % CHUNK_SIZE; int y = (index / CHUNK_SIZE) % CHUNK_SIZE; int z = index / (CHUNK_SIZE * CHUNK_SIZE); return new Vector3Int(x, y, z); } /// /// Convert local 3D coordinates to index /// public static int LocalToIndex(Vector3Int localPos) { return localPos.x + localPos.y * CHUNK_SIZE + localPos.z * CHUNK_SIZE * CHUNK_SIZE; } /// /// Convert local coordinates (int) to index /// public static int LocalToIndex(int x, int y, int z) { return x + y * CHUNK_SIZE + z * CHUNK_SIZE * CHUNK_SIZE; } /// /// Check if local coordinates are within valid range /// public static bool IsValidLocal(int x, int y, int z) { return x >= 0 && x < CHUNK_SIZE && y >= 0 && y < CHUNK_SIZE && z >= 0 && z < CHUNK_SIZE; } /// /// Check if local position is within valid range /// public static bool IsValidLocal(Vector3Int local) { return IsValidLocal(local.x, local.y, local.z); } /// /// Convert world hit point to local block index within chunk /// public int WorldPointToLocalIndex(Vector3 worldPoint) { // Get chunk origin in world space Vector3 chunkWorldOrigin = WorldOrigin; // Calculate offset from chunk origin (in grid units, assuming 1 unit per block) float cellSize = BuildManager.Instance != null ? BuildManager.Instance.cellSize : 1f; Vector3 offset = (worldPoint - chunkWorldOrigin) / cellSize; // Convert to local coordinates (add small epsilon to handle edge cases) int lx = Mathf.Clamp(Mathf.FloorToInt(offset.x + 0.5f), 0, CHUNK_SIZE - 1); int ly = Mathf.Clamp(Mathf.FloorToInt(offset.y + 0.5f), 0, CHUNK_SIZE - 1); int lz = Mathf.Clamp(Mathf.FloorToInt(offset.z + 0.5f), 0, CHUNK_SIZE - 1); return LocalToIndex(lx, ly, lz); } public override bool Equals(object obj) { if (obj is ChunkCoord other) { return chunkPos == other.chunkPos; } return false; } public override int GetHashCode() { return chunkPos.GetHashCode(); } public static bool operator ==(ChunkCoord a, ChunkCoord b) { return a.chunkPos == b.chunkPos; } public static bool operator !=(ChunkCoord a, ChunkCoord b) { return a.chunkPos != b.chunkPos; } public override string ToString() { return $"ChunkCoord({chunkPos.x}, {chunkPos.y}, {chunkPos.z})"; } }