diff options
Diffstat (limited to 'ecs')
-rw-r--r-- | ecs/Cargo.toml | 4 | ||||
-rw-r--r-- | ecs/src/component/storage.rs | 203 | ||||
-rw-r--r-- | ecs/src/component/storage/archetype.rs | 94 | ||||
-rw-r--r-- | ecs/src/component/storage/graph.rs | 12 | ||||
-rw-r--r-- | ecs/src/entity.rs | 38 | ||||
-rw-r--r-- | ecs/src/lib.rs | 95 | ||||
-rw-r--r-- | ecs/src/query.rs | 29 | ||||
-rw-r--r-- | ecs/src/query/flexible.rs | 34 | ||||
-rw-r--r-- | ecs/src/relationship.rs | 8 |
9 files changed, 408 insertions, 109 deletions
diff --git a/ecs/Cargo.toml b/ecs/Cargo.toml index 4945171..cf35a74 100644 --- a/ecs/Cargo.toml +++ b/ecs/Cargo.toml @@ -3,6 +3,9 @@ name = "ecs" version = "0.1.0" edition = "2021" +[features] +vizoxide = ["dep:vizoxide"] + [dependencies] seq-macro = "0.3.5" paste = "1.0.14" @@ -13,6 +16,7 @@ hashbrown = "0.15.2" parking_lot = "0.12.3" ecs-macros = { path = "../ecs-macros" } util-macros = { path = "../util-macros" } +vizoxide = { version = "1.0.5", optional = true } [dev-dependencies.criterion] version = "0.5.1" diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs index 4b2b6d8..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) @@ -421,6 +408,176 @@ impl TypeName for Storage } } +#[cfg(feature = "vizoxide")] +impl Storage +{ + pub fn create_vizoxide_archetype_graph( + &self, + graph_name: impl AsRef<str>, + params: VizoxideArchetypeGraphParams, + ) -> Result<vizoxide::Graph, vizoxide::GraphvizError> + { + let viz_graph = vizoxide::Graph::builder(graph_name.as_ref()) + .strict(true) + .directed(true) + .build()?; + + let mut viz_node_lookup = HashMap::new(); + + for node in self.graph.iter_nodes() { + let id = node.archetype().id(); + + if !viz_node_lookup.contains_key(&id) { + let node = self.graph.get_node_by_id(id).unwrap(); + + let viz_node = (params.create_node_cb)( + node.archetype(), + ArchetypeMetadata { is_imaginary: false }, + viz_graph.create_node(&(params.create_node_name)( + node.archetype(), + ArchetypeMetadata { is_imaginary: false }, + )), + ) + .build()?; + + viz_node_lookup.insert(id, viz_node); + } + + for (edge_comp_id, edges) in node.iter_edges() { + if let Some(add_edge) = edges.add { + if !viz_node_lookup.contains_key(&add_edge) { + let viz_node = self.create_vizoxide_archetype_graph_edge_node( + &viz_graph, + node, + add_edge, + *edge_comp_id, + ¶ms, + )?; + + viz_node_lookup.insert(add_edge, viz_node); + } + + (params.create_edge_cb)( + node.archetype(), + *edge_comp_id, + VizoxideArchetypeGraphEdgeKind::Add, + viz_graph.create_edge( + viz_node_lookup.get(&id).unwrap(), + viz_node_lookup.get(&add_edge).unwrap(), + Some(&format!("Add {}", edge_comp_id.id())), + ), + ) + .build()?; + } + + if let Some(remove_edge) = edges.remove { + if !viz_node_lookup.contains_key(&remove_edge) { + let viz_node = self.create_vizoxide_archetype_graph_edge_node( + &viz_graph, + node, + remove_edge, + *edge_comp_id, + ¶ms, + )?; + + viz_node_lookup.insert(remove_edge, viz_node); + } + + (params.create_edge_cb)( + node.archetype(), + *edge_comp_id, + VizoxideArchetypeGraphEdgeKind::Remove, + viz_graph.create_edge( + viz_node_lookup.get(&id).unwrap(), + viz_node_lookup.get(&remove_edge).unwrap(), + Some(&format!("Remove {}", edge_comp_id.id())), + ), + ) + .build()?; + } + } + } + + drop(viz_node_lookup); + + Ok(viz_graph) + } + + fn create_vizoxide_archetype_graph_edge_node<'vizoxide_graph>( + &self, + viz_graph: &'vizoxide_graph vizoxide::Graph, + node: &graph::ArchetypeNode, + edge_id: ArchetypeId, + edge_comp_id: Uid, + params: &VizoxideArchetypeGraphParams, + ) -> Result<vizoxide::Node<'vizoxide_graph>, vizoxide::GraphvizError> + { + match self.graph.get_node_by_id(edge_id) { + Some(edge_node) => (params.create_node_cb)( + edge_node.archetype(), + ArchetypeMetadata { is_imaginary: false }, + viz_graph.create_node(&(params.create_node_name)( + edge_node.archetype(), + ArchetypeMetadata { is_imaginary: false }, + )), + ) + .build(), + None => { + let mut comp_ids = + node.archetype().component_ids_sorted().collect::<Vec<_>>(); + + let insert_index = comp_ids.partition_point(|cid| *cid <= edge_comp_id); + + comp_ids.insert(insert_index, edge_comp_id); + + let imaginary_edge_archetype = Archetype::new(edge_id, comp_ids); + + (params.create_node_cb)( + &imaginary_edge_archetype, + ArchetypeMetadata { is_imaginary: true }, + viz_graph.create_node(&(params.create_node_name)( + &imaginary_edge_archetype, + ArchetypeMetadata { is_imaginary: true }, + )), + ) + .build() + } + } + } +} + +#[cfg(feature = "vizoxide")] +pub struct VizoxideArchetypeGraphParams +{ + pub create_node_name: fn(&Archetype, ArchetypeMetadata) -> std::borrow::Cow<'_, str>, + pub create_node_cb: for<'storage, 'graph> fn( + &'storage Archetype, + ArchetypeMetadata, + vizoxide::NodeBuilder<'graph>, + ) -> vizoxide::NodeBuilder<'graph>, + pub create_edge_cb: for<'storage, 'graph> fn( + &'storage Archetype, + Uid, + VizoxideArchetypeGraphEdgeKind, + vizoxide::EdgeBuilder<'graph>, + ) -> vizoxide::EdgeBuilder<'graph>, +} + +#[cfg(feature = "vizoxide")] +#[derive(Debug, Clone)] +pub struct ArchetypeMetadata +{ + pub is_imaginary: bool, +} + +#[cfg(feature = "vizoxide")] +#[derive(Debug, Clone, Copy)] +pub enum VizoxideArchetypeGraphEdgeKind +{ + Add, + Remove, +} + #[derive(Debug)] pub struct ArchetypeRefIter<'storage, 'search_terms> { 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/component/storage/graph.rs b/ecs/src/component/storage/graph.rs index a221877..11160e7 100644 --- a/ecs/src/component/storage/graph.rs +++ b/ecs/src/component/storage/graph.rs @@ -71,6 +71,12 @@ impl Graph })) } + #[cfg(feature = "vizoxide")] + pub fn iter_nodes(&self) -> impl Iterator<Item = &ArchetypeNode> + { + self.nodes.iter() + } + pub fn dfs_archetype_add_edges( &self, archetype_id: ArchetypeId, @@ -233,6 +239,12 @@ impl ArchetypeNode self.edges.entry(component_id).or_insert_with(insert_fn) } + #[cfg(feature = "vizoxide")] + pub fn iter_edges(&self) -> impl Iterator<Item = (&Uid, &ArchetypeEdges)> + { + self.edges.iter() + } + pub fn get_edges_mut(&mut self, component_id: Uid) -> Option<&mut ArchetypeEdges> { debug_assert_eq!(component_id.kind(), UidKind::Component); diff --git a/ecs/src/entity.rs b/ecs/src/entity.rs index 3de9cd5..a43f9ce 100644 --- a/ecs/src/entity.rs +++ b/ecs/src/entity.rs @@ -1,6 +1,42 @@ use linkme::distributed_slice; -use crate::World; +use crate::component::storage::archetype::{Archetype, Entity as ArchetypeEntity}; +use crate::uid::Uid; +use crate::{EntityComponentRef, World}; + +/// A handle to a entity. +pub struct Handle<'a> +{ + archetype: &'a Archetype, + entity: &'a ArchetypeEntity, +} + +impl<'a> Handle<'a> +{ + /// Returns the [`Uid`] of this entity. + #[inline] + #[must_use] + pub fn uid(&self) -> Uid + { + self.entity.uid() + } + + #[inline] + #[must_use] + pub fn get_component(&self, component_uid: Uid) -> Option<EntityComponentRef<'a>> + { + let index = self.archetype.get_index_for_component(component_uid)?; + + Some(EntityComponentRef::new( + self.entity.components().get(index).unwrap(), + )) + } + + pub(crate) fn new(archetype: &'a Archetype, entity: &'a ArchetypeEntity) -> Self + { + Self { archetype, entity } + } +} #[allow(clippy::module_name_repetitions)] #[macro_export] diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 9b787a2..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, @@ -246,6 +247,59 @@ impl World while let StepResult::Continue = self.step() {} } + #[cfg(feature = "vizoxide")] + pub fn create_vizoxide_archetype_graph( + &self, + name: impl AsRef<str>, + ) -> Result<vizoxide::Graph, vizoxide::GraphvizError> + { + use std::borrow::Cow; + + use crate::component::storage::{ + VizoxideArchetypeGraphEdgeKind, + VizoxideArchetypeGraphParams, + }; + + let component_storage_lock = self + .data + .component_storage + .read_nonblock() + .expect("Failed to acquire read-only component storage lock"); + + component_storage_lock.create_vizoxide_archetype_graph( + name, + VizoxideArchetypeGraphParams { + create_node_name: |archetype, _| { + Cow::Owned(format!( + "[{}]", + archetype + .component_ids_sorted() + .into_iter() + .map(|comp_id| comp_id.id().to_string()) + .collect::<Vec<_>>() + .join(", ") + )) + }, + create_node_cb: |_archetype, archetype_metadata, node_builder| { + if archetype_metadata.is_imaginary { + return node_builder.attribute("shape", "ellipse"); + } + + node_builder.attribute("shape", "box") + }, + create_edge_cb: |_, _, edge_kind, edge_builder| { + edge_builder.attribute( + "color", + match edge_kind { + VizoxideArchetypeGraphEdgeKind::Add => "green", + VizoxideArchetypeGraphEdgeKind::Remove => "red", + }, + ) + }, + }, + ) + } + fn query_and_run_systems(&self, phase_euid: Uid) { let system_comps_query = @@ -414,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}"); @@ -422,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) @@ -481,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( @@ -494,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); } @@ -550,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 1889e00..d7d2d1c 100644 --- a/ecs/src/query.rs +++ b/ecs/src/query.rs @@ -5,11 +5,8 @@ use std::marker::PhantomData; use seq_macro::seq; use crate::component::{Component, FromLockedOptional, Ref as ComponentRef}; -use crate::query::flexible::{ - EntityHandle, - Iter as FlexibleQueryIter, - Query as FlexibleQuery, -}; +use crate::entity::Handle as EntityHandle; +use crate::query::flexible::{Iter as FlexibleQueryIter, Query as FlexibleQuery}; use crate::system::{Param as SystemParam, System}; use crate::uid::Uid; use crate::util::VecExt; @@ -39,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, @@ -51,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, @@ -70,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, @@ -116,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 @@ -304,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| { @@ -333,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>>, @@ -344,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>>, @@ -363,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/query/flexible.rs b/ecs/src/query/flexible.rs index 7d24dc9..652b96f 100644 --- a/ecs/src/query/flexible.rs +++ b/ecs/src/query/flexible.rs @@ -1,16 +1,16 @@ //! Low-level querying. use std::iter::{repeat_n, FlatMap, RepeatN, Zip}; -use crate::component::storage::archetype::{Archetype, ArchetypeEntity, EntityIter}; +use crate::component::storage::archetype::{Archetype, EntityIter}; use crate::component::storage::{ ArchetypeRefIter, ArchetypeSearchTerms, Storage as ComponentStorage, }; +use crate::entity::Handle as EntityHandle; use crate::lock::ReadGuard; use crate::query::Terms; -use crate::uid::Uid; -use crate::{EntityComponent, World}; +use crate::World; /// Low-level entity query structure. #[derive(Debug)] @@ -68,33 +68,7 @@ impl<'query> Iterator for Iter<'query> { let (archetype, entity) = self.iter.next()?; - Some(EntityHandle { archetype, entity }) - } -} - -pub struct EntityHandle<'query> -{ - archetype: &'query Archetype, - entity: &'query ArchetypeEntity, -} - -impl<'query> EntityHandle<'query> -{ - /// Returns the [`Uid`] of this entity. - #[inline] - #[must_use] - pub fn uid(&self) -> Uid - { - self.entity.uid - } - - #[inline] - #[must_use] - pub fn get_component(&self, component_uid: Uid) -> Option<&'query EntityComponent> - { - let index = self.archetype.get_index_for_component(component_uid)?; - - Some(self.entity.components.get(index).unwrap()) + Some(EntityHandle::new(archetype, entity)) } } 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!( |