use std::collections::HashMap;
use crate::ecs::archetype::{Archetype, ArchetypeBuilder, ArchetypeId, ComponentBundle};
use crate::ecs::component::{Component, ComponentId, ComponentIdRegistry};
use crate::ecs::entity::{Entity, EntityAllocator};
use crate::ecs::storage::DEFAULT_BLOCK_SIZE;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ArchetypeHandle {
index: usize,
}
pub struct Universe {
block_size: usize,
registry: ComponentIdRegistry,
entities: EntityAllocator,
archetypes: Vec<Archetype>,
archetype_index: HashMap<ArchetypeId, usize>,
entity_index: HashMap<Entity, (usize, usize)>,
}
impl Universe {
pub fn new() -> Self {
Self::with_block_size(DEFAULT_BLOCK_SIZE)
}
pub fn with_block_size(block_size: usize) -> Self {
Self {
block_size,
registry: ComponentIdRegistry::new(),
entities: EntityAllocator::new(),
archetypes: Vec::new(),
archetype_index: HashMap::new(),
entity_index: HashMap::new(),
}
}
#[inline]
pub fn block_size(&self) -> usize { self.block_size }
#[inline]
pub fn registry(&self) -> &ComponentIdRegistry { &self.registry }
fn get_or_create_archetype_idx<B: ComponentBundle>(&mut self) -> usize {
let id = ArchetypeId::from_bundle::<B>(&self.registry);
if let Some(&idx) = self.archetype_index.get(&id) {
return idx;
}
let metas: Vec<_> = B::column_metas(&self.registry)
.into_iter()
.map(|cm| (cm.component_id, cm.meta))
.collect();
let arch = Archetype::new(id.clone(), &metas, self.block_size);
let idx = self.archetypes.len();
self.archetype_index.insert(id, idx);
self.archetypes.push(arch);
idx
}
pub fn spawn<B: ComponentBundle>(&mut self, bundle: B) -> Entity {
let entity = self.entities.alloc();
let arch_idx = self.get_or_create_archetype_idx::<B>();
let arch = &mut self.archetypes[arch_idx];
let row = arch.add_entity_with_bundle(entity, bundle, &self.registry);
self.entity_index.insert(entity, (arch_idx, row));
entity
}
pub fn spawn_empty(&mut self) -> Entity {
self.spawn(())
}
pub fn despawn(&mut self, entity: Entity) -> bool {
let (arch_idx, row) = match self.entity_index.remove(&entity) {
Some(x) => x,
None => return false,
};
if !self.entities.is_valid(entity) {
return false;
}
self.entities.free(entity);
let arch = &mut self.archetypes[arch_idx];
let last_index = arch.len() - 1;
let moved_entity = (row != last_index)
.then(|| arch.entity_at(last_index))
.flatten();
arch.remove_entity(row);
if let Some(moved) = moved_entity {
self.entity_index.insert(moved, (arch_idx, row));
}
true
}
pub fn get<T: Component>(&self, entity: Entity) -> Option<&T> {
let &(arch_idx, row) = self.entity_index.get(&entity)?;
let arch = self.archetypes.get(arch_idx)?;
arch.get_comp::<T>(row, &self.registry)
}
pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Option<&mut T> {
let &(arch_idx, row) = self.entity_index.get(&entity)?;
let arch = self.archetypes.get_mut(arch_idx)?;
arch.get_comp_mut::<T>(row, &self.registry)
}
pub fn contains_entity(&self, entity: Entity) -> bool {
self.entity_index.contains_key(&entity) && self.entities.is_valid(entity)
}
pub fn entity_count(&self) -> usize {
self.entity_index.len()
}
pub fn archetypes(&self) -> impl Iterator<Item = &Archetype> {
self.archetypes.iter()
}
pub fn archetypes_mut(&mut self) -> impl Iterator<Item = &mut Archetype> {
self.archetypes.iter_mut()
}
pub fn get_archetype(&self, id: &ArchetypeId) -> Option<&Archetype> {
let &idx = self.archetype_index.get(id)?;
self.archetypes.get(idx)
}
pub fn get_archetype_mut(&mut self, id: &ArchetypeId) -> Option<&mut Archetype> {
let &idx = self.archetype_index.get(id)?;
self.archetypes.get_mut(idx)
}
pub fn register_archetype<B: ComponentBundle>(&mut self) -> ArchetypeHandle {
let idx = self.get_or_create_archetype_idx::<B>();
ArchetypeHandle { index: idx }
}
pub fn register_archetype_dynamic(&mut self, builder: ArchetypeBuilder) -> ArchetypeHandle {
let id = builder.archetype_id();
if let Some(&idx) = self.archetype_index.get(&id) {
return ArchetypeHandle { index: idx };
}
let arch = builder.build(self.block_size);
let idx = self.archetypes.len();
self.archetype_index.insert(id, idx);
self.archetypes.push(arch);
ArchetypeHandle { index: idx }
}
pub fn spawn_at(&mut self, handle: ArchetypeHandle) -> EntityBuilder<'_> {
let entity = self.entities.alloc();
let arch = &mut self.archetypes[handle.index];
let row = arch.push_entity(entity);
self.entity_index.insert(entity, (handle.index, row));
EntityBuilder {
universe: self,
arch_idx: handle.index,
entity,
row,
}
}
pub fn handle_for(&self, id: &ArchetypeId) -> Option<ArchetypeHandle> {
self.archetype_index.get(id).map(|&index| ArchetypeHandle { index })
}
}
pub struct EntityBuilder<'u> {
universe: &'u mut Universe,
arch_idx: usize,
entity: Entity,
row: usize,
}
impl<'u> EntityBuilder<'u> {
pub fn set<T: Component>(self, value: T) -> Self {
let cid = self.universe.registry.id_for::<T>();
let arch = &mut self.universe.archetypes[self.arch_idx];
unsafe { arch.write_component(self.row, cid, value); }
self
}
pub unsafe fn set_by_id<T: Component>(self, component_id: ComponentId, value: T) -> Self {
let arch = &mut self.universe.archetypes[self.arch_idx];
arch.write_component(self.row, component_id, value);
self
}
pub fn finish(self) -> Entity {
self.entity
}
}
impl Default for Universe {
fn default() -> Self { Self::new() }
}
unsafe impl Send for Universe {}
unsafe impl Sync for Universe {}
#[cfg(test)]
mod tests {
use super::*;
use crate::ecs::component::Component;
#[derive(Debug, Clone, PartialEq)]
struct Pos(i32, i32);
impl Component for Pos {}
#[derive(Debug, Clone, PartialEq)]
struct Vel(i32, i32);
impl Component for Vel {}
#[derive(Debug, Clone, PartialEq)]
struct Hp(i32);
impl Component for Hp {}
#[test]
fn spawn_and_get() {
let mut u = Universe::new();
let e = u.spawn((Pos(1, 2), Vel(3, 4)));
assert_eq!(u.get::<Pos>(e), Some(&Pos(1, 2)));
assert_eq!(u.get::<Vel>(e), Some(&Vel(3, 4)));
u.despawn(e);
assert!(u.get::<Pos>(e).is_none());
}
#[test]
fn register_archetype_static() {
let mut u = Universe::new();
let h1 = u.register_archetype::<(Pos, Vel)>();
let h2 = u.register_archetype::<(Pos, Vel)>();
assert_eq!(h1, h2);
}
#[test]
fn spawn_at_handle() {
let mut u = Universe::new();
let handle = u.register_archetype::<(Pos, Vel, Hp)>();
let e = u.spawn_at(handle)
.set(Pos(1, 2))
.set(Vel(3, 4))
.set(Hp(100))
.finish();
assert_eq!(u.get::<Pos>(e), Some(&Pos(1, 2)));
assert_eq!(u.get::<Vel>(e), Some(&Vel(3, 4)));
assert_eq!(u.get::<Hp>(e), Some(&Hp(100)));
assert_eq!(u.entity_count(), 1);
}
#[test]
fn spawn_at_multiple() {
let mut u = Universe::new();
let handle = u.register_archetype::<(Pos, Vel)>();
let e1 = u.spawn_at(handle).set(Pos(1, 1)).set(Vel(0, 0)).finish();
let e2 = u.spawn_at(handle).set(Pos(2, 2)).set(Vel(1, 1)).finish();
assert_eq!(u.entity_count(), 2);
assert_eq!(u.get::<Pos>(e1), Some(&Pos(1, 1)));
assert_eq!(u.get::<Pos>(e2), Some(&Pos(2, 2)));
}
#[test]
fn register_archetype_dynamic_builder() {
let mut u = Universe::new();
let mut builder = ArchetypeBuilder::new();
builder.add_component::<Pos>(u.registry()).add_component::<Hp>(u.registry());
let handle = u.register_archetype_dynamic(builder);
let e = u.spawn_at(handle)
.set(Pos(10, 20))
.set(Hp(50))
.finish();
assert_eq!(u.get::<Pos>(e), Some(&Pos(10, 20)));
assert_eq!(u.get::<Hp>(e), Some(&Hp(50)));
}
#[test]
fn dynamic_and_static_same_archetype() {
let mut u = Universe::new();
let h_static = u.register_archetype::<(Pos, Vel)>();
let mut builder = ArchetypeBuilder::new();
builder.add_component::<Pos>(u.registry()).add_component::<Vel>(u.registry());
let h_dynamic = u.register_archetype_dynamic(builder);
assert_eq!(h_static, h_dynamic);
}
#[test]
fn despawn_after_spawn_at() {
let mut u = Universe::new();
let handle = u.register_archetype::<(Pos, Vel)>();
let e = u.spawn_at(handle).set(Pos(1, 2)).set(Vel(3, 4)).finish();
assert!(u.contains_entity(e));
u.despawn(e);
assert!(!u.contains_entity(e));
}
}