use bevy::prelude::*;
use crate::math::Region;
const CACHE_DEPTH: u8 = 5;
const CACHE_SIZE: usize = usize::pow(1 << CACHE_DEPTH as usize, 3);
struct Sector {
chunks: Box<[Option<Entity>; CACHE_SIZE]>,
sector_coords: IVec3,
active_chunks: usize,
}
impl Sector {
fn new(sector_coords: IVec3) -> Self {
Self {
sector_coords,
chunks: Box::new([None; CACHE_SIZE]),
active_chunks: 0,
}
}
fn region(&self) -> Region {
Region::from_size(self.sector_coords << CACHE_DEPTH, IVec3::ONE << CACHE_DEPTH).unwrap()
}
fn get_chunk_entity(&self, chunk_coords: IVec3) -> Option<Entity> {
let index = self.region().point_to_index(chunk_coords).unwrap();
self.chunks[index]
}
fn set_chunk_entity(&mut self, chunk_coords: IVec3, entity: Option<Entity>) {
let index = self.region().point_to_index(chunk_coords).unwrap();
match (self.chunks[index], entity) {
(Some(_), None) => self.active_chunks -= 1,
(None, Some(_)) => self.active_chunks += 1,
_ => {},
}
self.chunks[index] = entity;
}
fn is_empty(&self) -> bool {
self.active_chunks == 0
}
}
#[derive(Component, Reflect, Default)]
pub struct ChunkEntityPointers {
#[reflect(ignore)]
sectors: Vec<Sector>,
}
impl ChunkEntityPointers {
pub fn get_chunk_entity(&self, chunk_coords: IVec3) -> Option<Entity> {
let sector_coords = chunk_coords >> CACHE_DEPTH;
self.sectors
.iter()
.find(|c| c.sector_coords == sector_coords)?
.get_chunk_entity(chunk_coords)
}
pub fn set_chunk_entity(&mut self, chunk_coords: IVec3, entity: Option<Entity>) {
let sector_coords = chunk_coords >> CACHE_DEPTH;
let sector = match self
.sectors
.iter_mut()
.find(|c| c.sector_coords == sector_coords)
{
Some(s) => s,
None => {
let sector = Sector::new(sector_coords);
self.sectors.push(sector);
self.sectors.last_mut().unwrap()
},
};
sector.set_chunk_entity(chunk_coords, entity);
if sector.is_empty() {
let index = self
.sectors
.iter()
.position(|s| s.sector_coords == sector_coords)
.unwrap();
self.sectors.remove(index);
}
}
}