use crate::{
system::{Borrow, SystemRunState},
SystemParameter,
};
use std::{any::TypeId, collections::HashSet, num::NonZeroUsize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Entity {
pub(crate) id: usize,
pub(crate) generation: NonZeroUsize,
}
pub struct EntityMap {
entities: Vec<(NonZeroUsize, HashSet<TypeId>)>,
next_free_entity: usize,
}
impl EntityMap {
pub(crate) fn new() -> Self {
Self {
entities: Vec::new(),
next_free_entity: 0,
}
}
pub(crate) fn create_entity(&mut self) -> Entity {
let id = self.next_free_entity;
if id < self.entities.len() {
let (generation, _) = self.entities[id];
let generation = NonZeroUsize::new(generation.get() + 1).unwrap();
self.entities[id].0 = generation;
while let Some(&(generation, _)) = self.entities.get(self.next_free_entity) {
self.next_free_entity += 1;
if generation.get() & 1 != 0 {
break;
}
}
Entity { id, generation }
} else {
const NEW_GENERATION: NonZeroUsize = match NonZeroUsize::new(2) {
Some(generation) => generation,
None => unreachable!(),
};
self.entities.push((NEW_GENERATION, HashSet::new()));
self.next_free_entity = self.entities.len();
Entity {
id,
generation: NEW_GENERATION,
}
}
}
pub(crate) fn destroy_entity(&mut self, entity: Entity) -> Option<HashSet<TypeId>> {
if self.entity_exists(entity) {
self.entities[entity.id].0 |= NonZeroUsize::MIN;
if entity.id < self.next_free_entity {
self.next_free_entity = entity.id;
}
Some(std::mem::take(&mut self.entities[entity.id].1))
} else {
None
}
}
pub(crate) fn entity_exists(&self, entity: Entity) -> bool {
self.entities
.get(entity.id)
.map_or(false, |&(generation, _)| generation == entity.generation)
}
pub(crate) fn add_component(&mut self, entity: Entity, component_type: TypeId) {
debug_assert_eq!(self.entities[entity.id].0, entity.generation);
self.entities[entity.id].1.insert(component_type);
}
pub(crate) fn remove_component(&mut self, entity: Entity, component_type: TypeId) {
debug_assert_eq!(self.entities[entity.id].0, entity.generation);
self.entities[entity.id].1.remove(&component_type);
}
pub(crate) fn iter(&self) -> impl Iterator<Item = Option<Entity>> + '_ {
self.entities
.iter()
.enumerate()
.map(|(id, &(generation, _))| {
(generation.get() & 1 == 0).then_some(Entity { id, generation })
})
}
}
impl Default for EntityMap {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy)]
pub struct Entities<'a> {
entities: &'a EntityMap,
}
impl<'a> Entities<'a> {
pub fn entity_exists(&self, entity: Entity) -> bool {
self.entities.entity_exists(entity)
}
pub fn iter(&self) -> impl Iterator<Item = Entity> + 'a {
self.entities.iter().flatten()
}
}
impl<'a> SystemParameter for Entities<'a> {
type This<'this> = Entities<'this>;
type Lock<'state> = &'state EntityMap;
fn lock<'state>(state: &SystemRunState<'state>) -> Self::Lock<'state> {
state.entities
}
fn construct<'this>(state: &'this mut Self::Lock<'_>, last_run_tick: u64) -> Self::This<'this> {
_ = last_run_tick;
Entities { entities: state }
}
fn get_resource_types() -> impl Iterator<Item = Borrow> {
std::iter::empty()
}
fn get_component_types() -> impl Iterator<Item = Borrow> {
std::iter::empty()
}
}