use fxhash::FxHashMap; use crate::{ config::CHUNK_SIZE, sim::{ cell::Cell, cell_manager::{chunk::Chunk, sim::sim_tick}, }, }; pub struct CellManager { pub seqno: u64, pub chunks: Vec, pub chunk_position_to_chunk_idx: FxHashMap<(i32, i32), usize>, } impl CellManager { #[inline] pub fn split_game_position(x: i32, y: i32) -> ((i32, i32), (u8, u8)) { ( (x.div_euclid(CHUNK_SIZE), y.div_euclid(CHUNK_SIZE)), ( x.rem_euclid(CHUNK_SIZE) as u8, y.rem_euclid(CHUNK_SIZE) as u8, ), ) } // VERY EXPENSIVE pub fn get_cell_from_game_position(&self, x: i32, y: i32) -> Option { let ((cx, cy), (dx, dy)) = CellManager::split_game_position(x, y); self.chunk_position_to_chunk_idx .get(&(cx, cy)) .map(|&idx| self.chunks[idx].get_cell_at_local_position(dx, dy)) } // VERY EXPENSIVE pub fn set_cell_from_game_position(&mut self, x: i32, y: i32, cell: Cell, sleeping: bool) { let ((cx, cy), (dx, dy)) = CellManager::split_game_position(x, y); if let Some(&idx) = self.chunk_position_to_chunk_idx.get(&(cx, cy)) { self.chunks[idx].set_cell_at_local_position(dx, dy, cell); // this is a temporary hack if !sleeping { self.chunks[idx].sleeping = false; // remove this self.chunks[idx].mark_collider_dirty(0); } self.chunks[idx].needs_texture_update = true; } } pub fn upsert(&mut self, x: i32, y: i32, chunk: Chunk) { if let Some(&idx) = self.chunk_position_to_chunk_idx.get(&(x, y)) { self.chunks[idx] = chunk; } else { self.chunk_position_to_chunk_idx .insert((x, y), self.chunks.len()); self.chunks.push(chunk); } } pub fn tick(&mut self, use_threading: bool) { let seqno = self.seqno; sim_tick(self, seqno, use_threading); self.seqno += 1; } pub fn from_default_size() -> Self { let mut world = CellManager { seqno: 0, chunks: Vec::new(), chunk_position_to_chunk_idx: FxHashMap::default(), }; for y in -10..1 { for x in -100..100 { if y == 0 { world.upsert(x, y, Chunk::floor()); } else { world.upsert(x, y, Chunk::void()); } } } world } }