use bevy::prelude::*; use crate::hex_utils::*; use super::{chunk::Chunk, mesh_chunk::MeshChunkData}; #[derive(Resource, Clone)] pub struct Map { pub chunks: Vec, pub height: usize, pub width: usize, pub sea_level: f32, } impl Map { pub fn get_chunk_mesh_data(&self, chunk_index: usize) -> MeshChunkData { #[cfg(feature = "tracing")] let _spawn_span = info_span!("Chunk Mesh Data").entered(); let chunk = &self.chunks[chunk_index]; return MeshChunkData { heights: chunk.heights.clone(), textures: chunk.textures.clone(), }; } pub fn get_neighbors(&self, pos: &HexCoord) -> [Option; 6] { let mut results: [Option; 6] = [None; 6]; let w = self.width * Chunk::SIZE; let h = self.height * Chunk::SIZE; let n_tiles = pos.get_neighbors(); for i in 0..6 { let n_tile = n_tiles[i]; if !n_tile.is_in_bounds(h, w) { continue; } let c_idx = n_tile.to_chunk_index(self.width); let chunk = &self.chunks[c_idx]; let local = n_tile.to_chunk_local_index(); results[i] = Some(chunk.heights[local]); } return results; } pub fn sample_height(&self, pos: &HexCoord) -> f32 { let chunk = &self.chunks[pos.to_chunk_index(self.width)]; return chunk.heights[pos.to_chunk_local_index()]; } pub fn sample_height_mut(&mut self, pos: &HexCoord) -> &mut f32 { let chunk = &mut self.chunks[pos.to_chunk_index(self.width)]; return &mut chunk.heights[pos.to_chunk_local_index()]; } pub fn is_in_bounds(&self, pos: &HexCoord) -> bool { return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE); } pub fn get_moisture(&self, pos: &HexCoord) -> f32 { let chunk = &self.chunks[pos.to_chunk_index(self.width)]; return chunk.moisture[pos.to_chunk_local_index()]; } pub fn get_tempurature(&self, pos: &HexCoord) -> f32 { let chunk = &self.chunks[pos.to_chunk_index(self.width)]; return chunk.temperature[pos.to_chunk_local_index()]; } pub fn get_center(&self) -> Vec3 { let w = self.get_world_width(); let h = self.get_world_height(); return Vec3::new(w / 2., self.sea_level, h / 2.); } pub fn get_world_width(&self) -> f32 { return (self.width * Chunk::SIZE) as f32 * SHORT_DIAGONAL; } pub fn get_world_height(&self) -> f32 { return (self.height * Chunk::SIZE) as f32 * 1.5; } pub fn get_world_size(&self) -> Vec2 { return Vec2::new(self.get_world_width(), self.get_world_height()); } pub fn set_height(&mut self, pos: &HexCoord, height: f32) { self.chunks[pos.to_chunk_index(self.width)].heights[pos.to_chunk_local_index()] = height; } pub fn create_crater(&mut self, pos: &HexCoord, radius: usize, depth: f32) -> Vec { assert!(radius != 0, "Radius cannot be zero"); let width = self.width; let mut chunks = self.hex_select_mut(pos, radius, true, |p, h, r| { let d = (r as f32) / (radius as f32); let cur = *h; let h2 = cur - depth; *h = h2.lerp(cur, d * d); return p.to_chunk_index(width); }); chunks.dedup(); return chunks; } pub fn hex_select(&self, center: &HexCoord, radius: usize, include_center: bool, op: OP) -> Vec where OP: (Fn(&HexCoord, f32, usize) -> Ret) + Sync + Send, { assert!(radius != 0, "Radius cannot be zero"); if include_center { let h = self.sample_height(¢er); (op)(¢er, h, 0); } let mut result = Vec::with_capacity(get_tile_count(radius)); for k in 0..(radius + 1) { let mut p = center.scale(4, k); for i in 0..6 { for _j in 0..k { p = p.get_neighbor(i); let h = self.sample_height(&p); result.push((op)(&p, h, k)); } } } return result; } pub fn hex_select_mut( &mut self, center: &HexCoord, radius: usize, include_center: bool, op: OP, ) -> Vec where OP: (Fn(&HexCoord, &mut f32, usize) -> Ret) + Sync + Send, { assert!(radius != 0, "Radius cannot be zero"); if include_center { let h = self.sample_height_mut(¢er); (op)(¢er, h, 0); } let mut result = Vec::with_capacity(get_tile_count(radius)); for k in 0..(radius + 1) { let mut p = center.scale(4, k); for i in 0..6 { for _j in 0..k { p = p.get_neighbor(i); let h = self.sample_height_mut(&p); result.push((op)(&p, h, k)); } } } return result; } }