182 lines
5.3 KiB
Rust
182 lines
5.3 KiB
Rust
|
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)
|
||
|
}
|
||
|
}
|