diff options
-rw-r--r-- | ecs/src/component/storage.rs | 33 | ||||
-rw-r--r-- | ecs/src/component/storage/archetype.rs | 94 | ||||
-rw-r--r-- | ecs/src/entity.rs | 12 | ||||
-rw-r--r-- | ecs/src/lib.rs | 42 | ||||
-rw-r--r-- | ecs/src/query.rs | 22 | ||||
-rw-r--r-- | ecs/src/relationship.rs | 8 |
6 files changed, 133 insertions, 78 deletions
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs index c70e7e7..4a00510 100644 --- a/ecs/src/component/storage.rs +++ b/ecs/src/component/storage.rs @@ -7,7 +7,8 @@ use hashbrown::HashMap; use crate::component::storage::archetype::{ Archetype, - ArchetypeEntity, + Entity as ArchetypeEntity, + EntityComponent as ArchetypeEntityComponent, Id as ArchetypeId, }; use crate::component::storage::graph::{ @@ -20,7 +21,6 @@ use crate::component::Component; use crate::type_name::TypeName; use crate::uid::{Kind as UidKind, Uid}; use crate::util::{BorrowedOrOwned, Either, StreamingIterator, VecExt}; -use crate::EntityComponent; pub mod archetype; @@ -123,17 +123,14 @@ impl Storage archetype_node .archetype_mut() - .push_entity(ArchetypeEntity { uid, components: vec![] }); + .push_entity(ArchetypeEntity::new(uid, [])); self.entity_archetype_lookup.insert(uid, empty_archetype_id); Ok(()) } - pub fn remove_entity( - &mut self, - entity_uid: Uid, - ) -> Result<Vec<EntityComponent>, Error> + pub fn remove_entity(&mut self, entity_uid: Uid) -> Result<ArchetypeEntity, Error> { let Some(archetype_id) = self.entity_archetype_lookup.get(&entity_uid) else { return Err(Error::EntityDoesNotExist(entity_uid)); @@ -151,7 +148,7 @@ impl Storage self.entity_archetype_lookup.remove(&entity_uid); - Ok(entity.components) + Ok(entity) } pub fn get_entity_archetype(&self, entity_uid: Uid) -> Option<&Archetype> @@ -247,13 +244,10 @@ impl Storage .expect("Add edge archetype should exist") .archetype_mut(); - let component_index = add_edge_archetype - .get_index_for_component(component_id) - .expect("Archetype should have index for component"); - - entity.components.insert( - component_index, - EntityComponent::new(component_id, component), + entity.insert_component( + component_id, + ArchetypeEntityComponent::new(component), + add_edge_archetype, ); add_edge_archetype.push_entity(entity); @@ -326,14 +320,7 @@ impl Storage .remove_entity(entity_uid) .expect("Entity should exist in archetype"); - let (comp_to_remove_index, _) = entity - .components - .iter() - .enumerate() - .find(|(_, comp)| comp.id == component_id) - .expect("Entity should contain component"); - - entity.components.remove(comp_to_remove_index); + entity.remove_component(component_id, archetype_node.archetype()); self.graph .get_node_by_id_mut(remove_edge_id) diff --git a/ecs/src/component/storage/archetype.rs b/ecs/src/component/storage/archetype.rs index f6f8132..5306cf9 100644 --- a/ecs/src/component/storage/archetype.rs +++ b/ecs/src/component/storage/archetype.rs @@ -3,16 +3,16 @@ use std::slice::Iter as SliceIter; use hashbrown::HashMap; -use crate::component::Metadata as ComponentMetadata; +use crate::component::{Component, Metadata as ComponentMetadata}; +use crate::lock::Lock; use crate::uid::{Kind as UidKind, Uid}; use crate::util::HashMapExt; -use crate::EntityComponent; #[derive(Debug)] pub struct Archetype { id: Id, - entities: Vec<ArchetypeEntity>, + entities: Vec<Entity>, entity_index_lookup: HashMap<Uid, usize>, component_index_lookup: HashMap<Uid, usize>, component_ids: Vec<Uid>, @@ -53,7 +53,7 @@ impl Archetype .keys_is_subset(&other.component_index_lookup) } - pub fn get_entity_by_id(&self, entity_uid: Uid) -> Option<&ArchetypeEntity> + pub fn get_entity_by_id(&self, entity_uid: Uid) -> Option<&Entity> { let index = *self.entity_index_lookup.get(&entity_uid)?; @@ -64,7 +64,7 @@ impl Archetype })) } - pub fn push_entity(&mut self, entity: ArchetypeEntity) + pub fn push_entity(&mut self, entity: Entity) { self.entity_index_lookup .insert(entity.uid, self.entities.len()); @@ -72,7 +72,7 @@ impl Archetype self.entities.push(entity); } - pub fn remove_entity(&mut self, entity_uid: Uid) -> Option<ArchetypeEntity> + pub fn remove_entity(&mut self, entity_uid: Uid) -> Option<Entity> { //debug_assert_eq!(entity_uid.kind(), UidKind::Entity); @@ -142,12 +142,12 @@ impl Archetype #[derive(Debug)] pub struct EntityIter<'archetype> { - iter: SliceIter<'archetype, ArchetypeEntity>, + iter: SliceIter<'archetype, Entity>, } impl<'archetype> Iterator for EntityIter<'archetype> { - type Item = &'archetype ArchetypeEntity; + type Item = &'archetype Entity; fn next(&mut self) -> Option<Self::Item> { @@ -156,10 +156,82 @@ impl<'archetype> Iterator for EntityIter<'archetype> } #[derive(Debug)] -pub struct ArchetypeEntity +pub struct Entity { - pub uid: Uid, - pub components: Vec<EntityComponent>, + uid: Uid, + components: Vec<EntityComponent>, +} + +impl Entity +{ + pub fn new(uid: Uid, components: impl IntoIterator<Item = EntityComponent>) -> Self + { + Self { + uid, + components: components.into_iter().collect(), + } + } + + pub fn uid(&self) -> Uid + { + self.uid + } + + pub fn components(&self) -> &[EntityComponent] + { + &self.components + } + + pub fn remove_component(&mut self, component_id: Uid, archetype: &Archetype) + { + let index = archetype + .get_index_for_component(component_id) + .expect("Archetype should contain component"); + + self.components.remove(index); + } + + pub fn insert_component( + &mut self, + component_id: Uid, + component: EntityComponent, + archetype: &Archetype, + ) + { + let index = archetype + .get_index_for_component(component_id) + .expect("Archetype should contain component"); + + self.components.insert(index, component); + } +} + +#[derive(Debug)] +pub struct EntityComponent +{ + name: &'static str, + component: Lock<Box<dyn Component>>, +} + +impl EntityComponent +{ + pub fn new(component: Box<dyn Component>) -> Self + { + Self { + name: component.type_name(), + component: Lock::new(component), + } + } + + pub fn name(&self) -> &str + { + self.name + } + + pub fn component(&self) -> &Lock<Box<dyn Component>> + { + &self.component + } } /// Archetype ID. diff --git a/ecs/src/entity.rs b/ecs/src/entity.rs index 85e7461..a43f9ce 100644 --- a/ecs/src/entity.rs +++ b/ecs/src/entity.rs @@ -1,8 +1,8 @@ use linkme::distributed_slice; -use crate::component::storage::archetype::{Archetype, ArchetypeEntity}; +use crate::component::storage::archetype::{Archetype, Entity as ArchetypeEntity}; use crate::uid::Uid; -use crate::{EntityComponent, World}; +use crate::{EntityComponentRef, World}; /// A handle to a entity. pub struct Handle<'a> @@ -18,16 +18,18 @@ impl<'a> Handle<'a> #[must_use] pub fn uid(&self) -> Uid { - self.entity.uid + self.entity.uid() } #[inline] #[must_use] - pub fn get_component(&self, component_uid: Uid) -> Option<&'a EntityComponent> + pub fn get_component(&self, component_uid: Uid) -> Option<EntityComponentRef<'a>> { let index = self.archetype.get_index_for_component(component_uid)?; - Some(self.entity.components.get(index).unwrap()) + Some(EntityComponentRef::new( + self.entity.components().get(index).unwrap(), + )) } pub(crate) fn new(archetype: &'a Archetype, entity: &'a ArchetypeEntity) -> Self diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 3adc415..3caaa6b 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -10,6 +10,7 @@ use std::sync::Arc; use hashbrown::HashMap; use crate::actions::Action; +use crate::component::storage::archetype::EntityComponent as ArchetypeEntityComponent; use crate::component::storage::Storage as ComponentStorage; use crate::component::{Component, Sequence as ComponentSequence}; use crate::entity::CREATE_STATIC_ENTITIES; @@ -20,7 +21,7 @@ use crate::phase::{Phase, START as START_PHASE}; use crate::query::flexible::Query as FlexibleQuery; use crate::query::term::Without; use crate::query::{ - ComponentIter, + Iter as QueryIter, TermWithFieldTuple as QueryTermWithFieldTuple, TermWithoutFieldTuple as QueryTermWithoutFieldTuple, Terms as QueryTerms, @@ -467,7 +468,7 @@ impl World { let mut component_storage_lock = self.lock_component_storage_rw(); - let components = match component_storage_lock.remove_entity(entity_uid) { + let removed_entity = match component_storage_lock.remove_entity(entity_uid) { Ok(components) => components, Err(err) => { tracing::error!("Failed to despawn entity: {err}"); @@ -475,16 +476,17 @@ impl World } }; - let component_removed_event_uids = components + let component_removed_event_uids = removed_entity + .components() .iter() .map(|component| { component - .component + .component() .read_nonblock() .unwrap_or_else(|_| { panic!( "Failed to acquire read-only {} component lock", - component.name + component.name() ) }) .get_event_uid(ComponentEventKind::Removed) @@ -534,11 +536,6 @@ impl World fn emit_event_by_id(&self, event_id: Uid) { - //let query = self.flexible_query([ - // ComponentMetadata::of::<SystemComponent>(), - // ComponentMetadata { id: event_id, is_optional: false }, - //]); - let mut query_required_ids = [SystemComponent::id(), event_id]; let query = self.flexible_query( @@ -547,8 +544,7 @@ impl World .build(), ); - for (system,) in ComponentIter::<(&SystemComponent,), _>::new(self, query.iter()) - { + for (system,) in QueryIter::<(&SystemComponent,), _>::new(self, query.iter()) { unsafe { system.system.run(self); } @@ -603,23 +599,21 @@ pub struct WorldData } #[derive(Debug)] -#[non_exhaustive] -pub struct EntityComponent +pub struct EntityComponentRef<'a> { - pub id: Uid, - pub name: &'static str, - pub component: Lock<Box<dyn Component>>, + comp: &'a ArchetypeEntityComponent, } -impl EntityComponent +impl<'a> EntityComponentRef<'a> { - pub fn new(id: Uid, component: Box<dyn Component>) -> Self + pub fn component(&self) -> &'a Lock<Box<dyn Component>> { - Self { - id, - name: component.type_name(), - component: Lock::new(component), - } + self.comp.component() + } + + fn new(comp: &'a ArchetypeEntityComponent) -> Self + { + Self { comp } } } diff --git a/ecs/src/query.rs b/ecs/src/query.rs index 668c573..d7d2d1c 100644 --- a/ecs/src/query.rs +++ b/ecs/src/query.rs @@ -36,11 +36,11 @@ where #[must_use] pub fn iter<'query>( &'query self, - ) -> ComponentIter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>> + ) -> Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>> { tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>()); - ComponentIter { + Iter { world: self.world, iter: self.inner.iter(), comps_pd: PhantomData, @@ -48,7 +48,7 @@ where } /// Iterates over the entities matching this query, the iterator item being the entity - /// [`Uid`] and the entity components. + /// [`Uid`] and the matching entity components. #[must_use] pub fn iter_with_euids<'query>( &'query self, @@ -67,18 +67,18 @@ where /// `func`. /// /// This function exists so that a custom [`EntityHandle`] iterator can be given to - /// [`ComponentIter`] without giving the user access to a reference to the [`World`]. + /// [`Iter`] without giving the user access to a reference to the [`World`]. #[must_use] pub fn iter_with<'query, OutIter>( &'query self, func: impl FnOnce(FlexibleQueryIter<'query>) -> OutIter, - ) -> ComponentIter<'query, 'world, FieldTerms, OutIter> + ) -> Iter<'query, 'world, FieldTerms, OutIter> where OutIter: Iterator<Item = EntityHandle<'query>>, { tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>()); - ComponentIter { + Iter { world: self.world, iter: func(self.inner.iter()), comps_pd: PhantomData, @@ -113,7 +113,7 @@ where FieldTerms: TermWithFieldTuple + 'world, FieldlessTerms: TermWithoutFieldTuple, { - type IntoIter = ComponentIter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>; + type IntoIter = Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>; type Item = FieldTerms::Fields<'query>; fn into_iter(self) -> Self::IntoIter @@ -301,7 +301,7 @@ impl<ComponentRefT: ComponentRef> TermWithField for ComponentRefT Self::Field::from_locked_optional_component( entity_handle .get_component(ComponentRefT::Component::id()) - .map(|component| &component.component), + .map(|component| component.component()), world, ) .unwrap_or_else(|err| { @@ -330,7 +330,7 @@ pub trait TermWithFieldTuple ) -> Self::Fields<'component>; } -pub struct ComponentIter<'query, 'world, FieldTerms, EntityHandleIter> +pub struct Iter<'query, 'world, FieldTerms, EntityHandleIter> where FieldTerms: TermWithFieldTuple + 'world, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, @@ -341,7 +341,7 @@ where } impl<'query, 'world, FieldTerms, EntityHandleIter> - ComponentIter<'query, 'world, FieldTerms, EntityHandleIter> + Iter<'query, 'world, FieldTerms, EntityHandleIter> where FieldTerms: TermWithFieldTuple + 'world, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, @@ -360,7 +360,7 @@ where } impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator - for ComponentIter<'query, 'world, FieldTerms, EntityHandleIter> + for Iter<'query, 'world, FieldTerms, EntityHandleIter> where FieldTerms: TermWithFieldTuple + 'world, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, diff --git a/ecs/src/relationship.rs b/ecs/src/relationship.rs index a0ccf4d..e5442c2 100644 --- a/ecs/src/relationship.rs +++ b/ecs/src/relationship.rs @@ -179,9 +179,9 @@ where let component = ComponentRefMut::new( entity - .components + .components() .get(component_index)? - .component + .component() .write_nonblock() .unwrap_or_else(|_| { panic!( @@ -434,9 +434,9 @@ where let component = ComponentRef::new( entity - .components + .components() .get(component_index)? - .component + .component() .read_nonblock() .unwrap_or_else(|_| { panic!( |