lyra-engine/lyra-ecs/src/archetype.rs

182 lines
5.3 KiB
Rust
Raw Normal View History

2023-05-25 04:11:16 +00:00
use std::any::{Any, TypeId};
use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle};
pub trait ComponentColumn: Any {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn new_empty_column(&self) -> Box<dyn ComponentColumn>;
fn is_same_type(&self, column: &dyn ComponentColumn) -> bool;
fn len(&self) -> usize;
fn append(&mut self, column: &mut dyn ComponentColumn);
fn component_type_id(&self) -> TypeId;
// used for debugging
fn component_type_name(&self) -> String;
}
impl<T: Send + Sync + 'static> ComponentColumn for Vec<T> {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn new_empty_column(&self) -> Box<dyn ComponentColumn> {
Box::new(Vec::<T>::new())
}
fn is_same_type(&self, column: &dyn ComponentColumn) -> bool {
column.as_any().downcast_ref::<Self>().is_some()
}
fn len(&self) -> usize {
Vec::len(self)
}
fn append(&mut self, column: &mut dyn ComponentColumn) {
let column: &mut Self = column.as_any_mut().downcast_mut()
.expect("Attempt at appending an different column type!");
self.append(column);
}
fn component_type_id(&self) -> TypeId {
self.first().unwrap().type_id()
}
fn component_type_name(&self) -> String {
//self.first().unwrap().type_id()
std::any::type_name::<T>().to_string()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ArchetypeId(pub u64);
impl ArchetypeId {
/// Increments the id and returns a new id with the value it was before incrementing.
pub(crate) fn increment(&mut self) -> Self {
let v = self.0;
self.0 += 1;
ArchetypeId(v)
}
}
pub struct Archetype {
pub(crate) id: ArchetypeId,
entities: Vec<Entity>,
pub(crate) columns: Vec<Box<dyn ComponentColumn>>,
}
impl Archetype {
/// Create a new archetype from another archetype and add a column
pub fn new_archetype_add<T: Send + Sync + 'static>(new_id: ArchetypeId, archetype: &Archetype) -> Archetype {
let mut columns: Vec<_> = archetype
.columns
.iter()
.map(|c| c.new_empty_column())
.collect();
assert!(columns
.iter()
.find(|column| column.as_any().is::<Vec<T>>())
.is_none());
columns.push(Box::new(Vec::<T>::new()));
Archetype {
id: new_id,
entities: Vec::new(),
columns,
}
}
/// Create a new archetype from another archetype and remove a column
pub fn new_archetype_remove<T: Send + Sync + 'static>(new_id: ArchetypeId, archetype: &Archetype) -> Archetype {
let mut columns: Vec<_> = archetype
.columns
.iter()
.map(|c| c.new_empty_column())
.collect();
let idx = columns
.iter()
.position(|column| column.as_any().is::<Vec<T>>())
.unwrap();
columns.remove(idx);
Archetype {
id: new_id,
entities: Vec::new(),
columns,
}
}
pub fn from_columns(new_id: ArchetypeId, columns: Vec<Box<dyn ComponentColumn>>) -> Archetype {
Archetype {
id: new_id,
entities: Vec::new(),
columns,
}
}
pub fn get_component_mut<T: Send + Sync + 'static>(&mut self, entity: ArchetypeEntityId) -> Option<&mut T> {
for col in self.columns.iter_mut() {
if col.as_any().is::<Vec<T>>() {
let components: &mut Vec<T> = col.as_any_mut().downcast_mut().unwrap();
return components.get_mut(entity.0 as usize);
}
}
None
}
pub fn get_component<T: Send + Sync + 'static>(&self, entity: ArchetypeEntityId) -> Option<&T> {
for col in self.columns.iter() {
if col.as_ref().as_any().is::<Vec<T>>() {
let components: &Vec<T> = col.as_any().downcast_ref().unwrap();
return components.get(entity.0 as usize);
}
}
None
}
pub(crate) fn add_entity(&mut self, components: Vec<Box<dyn ComponentColumn>>) -> ArchetypeEntityId {
let mut created_entity: Option<ArchetypeEntityId> = None;
for mut component in components.into_iter() {
for col in self.columns.iter_mut() {
if col.is_same_type(component.as_ref()) {
match created_entity {
Some(e) => {
assert!(e.0 == col.len() as u64);
},
None => {
created_entity = Some(ArchetypeEntityId(col.len() as u64));
}
}
col.append(component.as_mut());
}
}
}
created_entity.expect("Failure to create entity!")
}
/// returns a boolean indicating whether this archetype can store the TypeIds given
pub(crate) fn is_archetype_for(&self, types: Vec<TypeId>) -> bool {
let types_iter = types.into_iter();
self.columns
.iter()
.map(|c| c.component_type_id())
.eq(types_iter)
}
}