use std::sync::Arc;
use crate::{
archetype::Archetype,
entity::{EntityId, EntityMeta},
prelude::{ArchFilter, ArchQuery, Bundle, Component},
tag::{TagFactory, TagTracker},
};
pub mod data;
pub mod storage;
#[derive(Default)]
pub struct World {
pub(crate) components: crate::component::ComponentFactory,
pub(crate) entities: crate::entity::EntityFactory,
pub(crate) storages: storage::storages::StorageFactory,
}
impl World {
pub fn with_tags(tagf: TagFactory) -> Self {
Self {
storages: storage::storages::StorageFactory {
tag_storage: storage::tag_storage::TagStorage::new(Arc::new(tagf)),
..Default::default()
},
..Default::default()
}
}
}
impl World {
pub fn get_tag_tracker(&self, entity: EntityId) -> TagTracker {
self.storages.tag_storage.get_tag_tracker(entity)
}
}
impl World {}
impl World {
pub fn query<Q: ArchQuery>(&mut self) -> impl Iterator<Item = Q::Item<'_>> + '_ {
unsafe { Q::iter_query_matches(&mut self.storages.arch_storages, &self.components) }
}
pub fn query_filtered<'a, Q: ArchQuery + 'a, F: ArchFilter + 'a>(
&'a mut self,
) -> impl Iterator<Item = Q::Item<'a>> + 'a {
unsafe {
Q::iter_filtered_query_matches::<F>(&mut self.storages.arch_storages, &self.components)
}
}
}
impl World {
pub fn spawn<B: Bundle + Archetype>(&mut self, bundle: B) -> EntityId {
let (sid, storage) = self
.storages
.arch_storages
.get_mut_or_create_storage_with_exact_archetype::<B>(&mut self.components);
let index = storage.next_index();
let entity_id = self.entities.new_entity(EntityMeta {
archetype_storage_id: sid,
archetype_storage_index: index,
});
storage.store_entity(entity_id, bundle, &self.components);
self.storages.tag_storage.new_entity();
entity_id
}
pub fn get_component<C: Component>(&self, entity: EntityId) -> Option<&C> {
let entity_meta = self.entities.get_entity_meta(entity)?;
self.storages
.arch_storages
.get_storage(entity_meta.archetype_storage_id)
.map(|storage| {
self.components
.get_component_id::<C>()
.map(|comp_id| {
storage.get_component(entity_meta.archetype_storage_index, comp_id)
})
.flatten()
.map(|raw_comp| unsafe { raw_comp.deref::<C>() })
})
.flatten()
}
pub fn get_component_mut<C: Component>(&mut self, entity: EntityId) -> Option<&mut C> {
let entity_meta = self.entities.get_entity_meta(entity)?;
self.storages
.arch_storages
.get_storage_mut(entity_meta.archetype_storage_id)
.map(|storage| {
self.components
.get_component_id::<C>()
.map(|comp_id| {
storage.get_component_mut(entity_meta.archetype_storage_index, comp_id)
})
.flatten()
.map(|raw_comp| unsafe { raw_comp.deref_mut::<C>() })
})
.flatten()
}
pub fn despawn(&mut self, entity: EntityId) {
let entity_meta = self
.entities
.get_entity_meta(entity)
.expect("Can't despawn already despawned entity.");
if let Some(entity_to_update) = self
.storages
.arch_storages
.get_storage_mut(entity_meta.archetype_storage_id)
.unwrap()
.swap_remove(entity_meta.archetype_storage_index)
{
self.entities.set_entity_arch_storage_index(
entity_meta.archetype_storage_index,
entity_to_update,
);
}
self.storages.tag_storage.untag_all(entity);
self.entities.remove_entity(entity);
}
}
#[cfg(test)]
mod tests {
use crate::{entity::EntityId, prelude::*, world::storage::storages::ArchStorageId};
#[derive(Component)]
struct A(usize);
#[derive(Component)]
struct B(Box<[u8]>);
#[derive(Component)]
struct C(String);
#[test]
fn test_world_entities_1() {
let mut world = World::default();
let carter = world.spawn((A(1), B(Box::new([10, 20, 30, 40])), C("Carter".into())));
let alice = world.spawn((A(2), B(Box::new([133, 107])), C("Alice".into())));
let adam = world.spawn((A(3), B(Box::new([])), C("Adam".into())));
assert_eq!(world.get_component::<A>(carter).unwrap().0, 1);
assert_eq!(world.get_component::<A>(alice).unwrap().0, 2);
assert_eq!(world.get_component::<A>(adam).unwrap().0, 3);
world.get_component_mut::<A>(carter).unwrap().0 *= 10;
world.get_component_mut::<A>(alice).unwrap().0 *= 10;
world.get_component_mut::<A>(adam).unwrap().0 *= 10;
assert_eq!(world.get_component::<A>(carter).unwrap().0, 10);
assert_eq!(world.get_component::<A>(alice).unwrap().0, 20);
assert_eq!(world.get_component::<A>(adam).unwrap().0, 30);
assert_eq!(world.get_component::<B>(carter).unwrap().0.len(), 4);
assert_eq!(world.get_component::<B>(alice).unwrap().0.len(), 2);
assert_eq!(world.get_component::<B>(adam).unwrap().0.len(), 0);
assert_eq!(&world.get_component::<C>(carter).unwrap().0, "Carter");
assert_eq!(&world.get_component::<C>(alice).unwrap().0, "Alice");
assert_eq!(&world.get_component::<C>(adam).unwrap().0, "Adam");
}
#[test]
#[should_panic]
fn test_multiple_components_1() {
let mut world = World::default();
world.spawn((A(0), A(1)));
}
#[test]
#[should_panic]
fn test_multiple_components_2() {
let mut world = World::default();
world.spawn((A(0), A(1), B(Box::new([0, 1]))));
}
#[test]
fn test_despawning_entities_1() {
let mut world = World::default();
let a_cart = world.spawn((A(1), C(String::from("Cart"))));
let a_alice = world.spawn((A(2), C(String::from("Alice"))));
let a_james = world.spawn((A(3), C(String::from("James"))));
assert_eq!(
world
.storages
.arch_storages
.get_storage(ArchStorageId(0))
.unwrap()
.len(),
3
);
assert_eq!(world.query::<(&A, &C)>().into_iter().count(), 3);
world.despawn(a_cart);
assert_eq!(world.get_component::<A>(a_alice).unwrap().0, 2);
assert_eq!(world.get_component::<A>(a_james).unwrap().0, 3);
assert!(world.get_component::<A>(a_cart).is_none());
assert_eq!(
world
.storages
.arch_storages
.get_storage(ArchStorageId(0))
.unwrap()
.len(),
2
);
world
.query_filtered::<EntityId, Has<(A, C)>>()
.into_iter()
.for_each(|eid| assert_ne!(eid, a_cart));
assert_eq!(world.query::<(&A, &C)>().into_iter().count(), 2);
}
#[test]
fn test_despawning_entities_2() {
let mut world = World::default();
let mut entities = Vec::new();
(0..1000).for_each(|i| entities.push(world.spawn(A(i))));
(0..1000)
.filter(|i| i % 2 == 0)
.for_each(|i| world.despawn(entities[i]));
assert_eq!(world.query::<&A>().into_iter().count(), 500);
world.query::<&A>().for_each(|A(i)| assert!(i % 2 == 1));
}
}