diff --git a/Cargo.toml b/Cargo.toml index 546759e..84d588d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ log = "0.4" env_logger = "0.10" strum = { version = "0.24", features = ["derive"] } glam = { version = "0.22", features = ["debug-glam-assert", "mint", "fast-math"] } +hashbrown = "0.13" diff --git a/src/game/world.rs b/src/game/world.rs index 8e5b4d8..47c2daa 100644 --- a/src/game/world.rs +++ b/src/game/world.rs @@ -1,6 +1,6 @@ use glam::{Vec2, IVec2}; use glium::Display; -use std::collections::HashMap; +use hashbrown::HashMap; use crate::game::options::GameOptions; mod chunk; @@ -50,16 +50,20 @@ impl World { if !self.chunks.contains_key(&position) { self.chunks.insert(position, Chunk::new(position)); } - let chunk = self.chunks.get_mut(&position).unwrap(); - if x == 0 || z == 0 || x == render_dist || z == render_dist { - chunk.desired = ChunkState::Loaded; - } else { - chunk.desired = ChunkState::Rendered; + { + //we only need mutable reference here: + let chunk = self.chunks.get_mut(&position).unwrap(); + if x == 0 || z == 0 || x == render_dist || z == render_dist { + chunk.desired = ChunkState::Loaded; + } else { + chunk.desired = ChunkState::Rendered; + } } - if matches!(chunk.state, ChunkState::Nothing) { + //borrow chunk immutably + let chunk = self.chunks.get(&position).unwrap(); + if matches!(chunk.state, ChunkState::Nothing) && matches!(chunk.desired, ChunkState::Loaded | ChunkState::Rendered) { self.thread.queue_load(position); - } - if matches!(chunk.state, ChunkState::Loaded) && matches!(chunk.desired, ChunkState::Rendered) { + } else if matches!(chunk.state, ChunkState::Loaded) && matches!(chunk.desired, ChunkState::Rendered) { fn all_some<'a>(x: [Option<&'a Chunk>; 4]) -> Option<[&'a Chunk; 4]> { Some([x[0]?, x[1]?, x[2]?, x[3]?]) } @@ -70,33 +74,43 @@ impl World { neighbors[2].block_data.is_some() && neighbors[3].block_data.is_some() } { - self.thread.queue_mesh(chunk, neighbors); + self.thread.queue_mesh( + position, + chunk.block_data.clone().unwrap(), + [ + neighbors[0].block_data.clone().unwrap(), + neighbors[1].block_data.clone().unwrap(), + neighbors[2].block_data.clone().unwrap(), + neighbors[3].block_data.clone().unwrap(), + ] + ); } } } } } - //Handle Unload - self.chunks.retain(|_, chunk| !matches!(chunk.desired, ChunkState::Unload)); - - //State downgrades - for (_, chunk) in &mut self.chunks { + //Unloads and state downgrades + self.chunks.retain(|_, chunk| { match chunk.desired { + // Chunk unload + ChunkState::Unload => false, // Any => Nothing downgrade ChunkState::Nothing => { chunk.block_data = None; chunk.mesh = None; chunk.state = ChunkState::Nothing; + true }, //Render => Loaded downgrade ChunkState::Loaded if matches!(chunk.state, ChunkState::Rendering | ChunkState::Rendered) => { chunk.mesh = None; chunk.state = ChunkState::Loaded; + true }, - _ => () + _ => true } - } + }); //Apply changes from threads self.thread.apply_tasks(&mut self.chunks, display); } diff --git a/src/game/world/chunk.rs b/src/game/world/chunk.rs index 0cb5f14..7b4f093 100644 --- a/src/game/world/chunk.rs +++ b/src/game/world/chunk.rs @@ -17,7 +17,7 @@ pub enum ChunkState { Rendered, } -pub type ChunkData = [[[Block; CHUNK_SIZE]; CHUNK_HEIGHT]; CHUNK_SIZE]; +pub type ChunkData = Box<[[[Block; CHUNK_SIZE]; CHUNK_HEIGHT]; CHUNK_SIZE]>; pub struct Chunk { pub position: IVec2, diff --git a/src/game/world/thread.rs b/src/game/world/thread.rs index 5465a05..02958a2 100644 --- a/src/game/world/thread.rs +++ b/src/game/world/thread.rs @@ -1,10 +1,7 @@ use glam::IVec2; use glium::{Display, VertexBuffer, IndexBuffer, index::PrimitiveType}; -use std::{ - thread::{self, JoinHandle}, - collections::HashMap, - mem -}; +use std::{mem, thread::{self, JoinHandle}}; +use hashbrown::HashMap; use super::chunk::{Chunk, ChunkData, ChunkState}; use crate::game::shaders::chunk::Vertex as ChunkVertex; @@ -38,20 +35,12 @@ impl WorldThreading { log::warn!("load: discarded {}, reason: new task started", position); } } - pub fn queue_mesh(&mut self, chunk: &Chunk, neighbors: [&Chunk; 4]) { - let position = chunk.position; - let data = chunk.block_data.expect("Chunk has no mesh!"); - let neighbor_data = [ - neighbors[0].block_data.expect("Chunk has no mesh!"), - neighbors[1].block_data.expect("Chunk has no mesh!"), - neighbors[2].block_data.expect("Chunk has no mesh!"), - neighbors[3].block_data.expect("Chunk has no mesh!"), - ]; + pub fn queue_mesh(&mut self, position: IVec2, chunk: ChunkData, neighbor_data: [ChunkData; 4]) { let handle = thread::spawn(move || { - mesh_gen::generate_mesh(position, data, neighbor_data) + mesh_gen::generate_mesh(position, chunk, neighbor_data) }); - if self.mesh_tasks.insert(chunk.position, Some(handle)).is_some() { - log::warn!("mesh: discarded {}, reason: new task started", chunk.position); + if self.mesh_tasks.insert(position, Some(handle)).is_some() { + log::warn!("mesh: discarded {}, reason: new task started", position); } } pub fn apply_tasks(&mut self, chunks: &mut HashMap, display: &Display) { diff --git a/src/game/world/thread/world_gen.rs b/src/game/world/thread/world_gen.rs index fd76af0..dc47b2d 100644 --- a/src/game/world/thread/world_gen.rs +++ b/src/game/world/thread/world_gen.rs @@ -4,5 +4,5 @@ use crate::game::{ }; pub fn generate_chunk() -> ChunkData { - [[[Block::Stone; CHUNK_SIZE]; CHUNK_HEIGHT]; CHUNK_SIZE] + Box::new([[[Block::Stone; CHUNK_SIZE]; CHUNK_HEIGHT]; CHUNK_SIZE]) }