summaryrefslogtreecommitdiff
path: root/ecs/src/component
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/component')
-rw-r--r--ecs/src/component/local.rs104
-rw-r--r--ecs/src/component/storage.rs795
-rw-r--r--ecs/src/component/storage/archetype.rs385
-rw-r--r--ecs/src/component/storage/graph.rs432
4 files changed, 0 insertions, 1716 deletions
diff --git a/ecs/src/component/local.rs b/ecs/src/component/local.rs
deleted file mode 100644
index b19a30b..0000000
--- a/ecs/src/component/local.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-use std::any::type_name;
-use std::ops::{Deref, DerefMut};
-
-use ecs_macros::Component;
-
-use crate::component::{
- Component,
- HandleMut as ComponentHandleMut,
- IntoParts as _,
- Parts as ComponentParts,
-};
-use crate::pair::Pair;
-use crate::system::initializable::Param as InitializableParam;
-use crate::system::{Metadata as SystemMetadata, Param as SystemParam};
-use crate::World;
-
-/// Holds a component which is local to a single system.
-#[derive(Debug)]
-pub struct Local<'world, LocalComponent: Component>
-{
- local_component: ComponentHandleMut<'world, LocalComponent>,
-}
-
-impl<'world, LocalComponent> SystemParam<'world> for Local<'world, LocalComponent>
-where
- LocalComponent: Component,
-{
- type Input = LocalComponent;
-
- fn new(world: &'world World, system_metadata: &SystemMetadata) -> Self
- {
- let Some(system_ent) = world.get_entity(system_metadata.ent_id) else {
- panic!(
- "System entity with ID {} does not exist",
- system_metadata.ent_id
- );
- };
-
- let Some(local_component) = system_ent.get_with_id_mut::<LocalComponent>(
- Pair::builder()
- .relation::<IsLocalComponent>()
- .target::<LocalComponent>()
- .build()
- .id(),
- ) else {
- panic!(
- "Local component {} of system with ID {} is uninitialized",
- type_name::<LocalComponent>(),
- system_metadata.ent_id
- );
- };
-
- Self { local_component }
- }
-}
-
-impl<'world, LocalComponent, SystemT> InitializableParam<'world, SystemT>
- for Local<'world, LocalComponent>
-where
- LocalComponent: Component,
- SystemT: SystemWithLocalComponents,
- Self: SystemParam<'world, Input = LocalComponent>,
-{
- fn initialize(system: &mut SystemT, input: Self::Input)
- {
- system.add_local_component(
- Pair::builder()
- .relation::<IsLocalComponent>()
- .target_as_data(input)
- .build()
- .into_parts(),
- );
- }
-}
-
-impl<LocalComponent> Deref for Local<'_, LocalComponent>
-where
- LocalComponent: Component,
-{
- type Target = LocalComponent;
-
- fn deref(&self) -> &Self::Target
- {
- &self.local_component
- }
-}
-
-impl<LocalComponent> DerefMut for Local<'_, LocalComponent>
-where
- LocalComponent: Component,
-{
- fn deref_mut(&mut self) -> &mut Self::Target
- {
- &mut self.local_component
- }
-}
-
-pub trait SystemWithLocalComponents
-{
- fn add_local_component(&mut self, component_parts: ComponentParts);
-}
-
-#[derive(Component)]
-struct IsLocalComponent;
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs
deleted file mode 100644
index dc38b6a..0000000
--- a/ecs/src/component/storage.rs
+++ /dev/null
@@ -1,795 +0,0 @@
-use std::any::Any;
-use std::array::IntoIter as ArrayIter;
-use std::cell::RefCell;
-use std::vec::IntoIter as VecIntoIter;
-
-use hashbrown::HashMap;
-
-use crate::component::storage::archetype::{
- Archetype,
- Entity as ArchetypeEntity,
- EntityComponent as ArchetypeEntityComponent,
- Id as ArchetypeId,
-};
-use crate::component::storage::graph::{
- ArchetypeAddEdgeDfsIter,
- ArchetypeAddEdgeDfsIterResult,
- ArchetypeEdges,
- Graph,
-};
-use crate::uid::{Kind as UidKind, Uid};
-use crate::util::{BorrowedOrOwned, Either, StreamingIterator, VecExt};
-
-pub mod archetype;
-
-mod graph;
-
-#[derive(Debug)]
-pub struct ArchetypeSearchTerms<'a>
-{
- pub required_components: &'a [Uid],
- pub excluded_components: &'a [Uid],
-}
-
-impl ArchetypeSearchTerms<'_>
-{
- fn excluded_contains(&self, comp_id: Uid) -> bool
- {
- let comp_id_kind = comp_id.kind();
-
- debug_assert!(
- comp_id_kind == UidKind::Component
- || (comp_id_kind == UidKind::Pair
- && comp_id.target_component() != Uid::wildcard())
- );
-
- let is_found = self.excluded_components.binary_search(&comp_id).is_ok();
-
- if !is_found && comp_id_kind == UidKind::Pair {
- return self.excluded_components.iter().any(|excluded_comp_id| {
- excluded_comp_id.kind() == UidKind::Pair
- && excluded_comp_id.has_same_relation_as(comp_id)
- && excluded_comp_id.target_component() == Uid::wildcard()
- });
- }
-
- is_found
- }
-
- fn contains_conflicting(&self) -> bool
- {
- self.excluded_components.iter().any(|excluded_comp_id| {
- self.required_components
- .binary_search(excluded_comp_id)
- .is_ok()
- })
- }
-
- fn archetype_contains_all_required(&self, archetype: &Archetype) -> bool
- {
- self.required_components
- .iter()
- .all(|comp_id| archetype.contains_matching_component(*comp_id))
- }
-}
-
-#[derive(Debug, Default)]
-pub struct Storage
-{
- graph: Graph,
- entity_archetype_lookup: HashMap<Uid, ArchetypeId>,
- imaginary_archetypes: RefCell<Vec<ImaginaryArchetype>>,
-}
-
-impl Storage
-{
- pub fn search_archetypes<'search_terms>(
- &self,
- search_terms: ArchetypeSearchTerms<'search_terms>,
- ) -> ArchetypeRefIter<'_, 'search_terms>
- {
- let archetype_id = ArchetypeId::new(search_terms.required_components);
-
- if search_terms.contains_conflicting() {
- return ArchetypeRefIter {
- storage: self,
- pre_iter: Either::B(Vec::new().into_iter()),
- dfs_iter: ArchetypeAddEdgeDfsIter::new(&self.graph, &[]),
- search_terms,
- };
- }
-
- let Some(add_edge_recursive_iter) =
- self.graph.dfs_archetype_add_edges(archetype_id)
- else {
- self.imaginary_archetypes
- .borrow_mut()
- .push(ImaginaryArchetype {
- id: ArchetypeId::new(search_terms.required_components.iter().filter(
- |required_comp_id| {
- required_comp_id.kind() != UidKind::Pair
- || required_comp_id.target_component() != Uid::wildcard()
- },
- )),
- component_ids: search_terms
- .required_components
- .iter()
- .copied()
- .filter(|required_comp_id| {
- required_comp_id.kind() != UidKind::Pair
- || required_comp_id.target_component() != Uid::wildcard()
- })
- .collect(),
- });
-
- let found_archetypes = self.find_all_archetype_with_comps(&search_terms);
-
- return ArchetypeRefIter {
- storage: self,
- pre_iter: Either::B(found_archetypes.clone().into_iter()),
- dfs_iter: ArchetypeAddEdgeDfsIter::new(&self.graph, &found_archetypes),
- search_terms,
- };
- };
-
- ArchetypeRefIter {
- storage: self,
- pre_iter: Either::A([archetype_id].into_iter()),
- dfs_iter: add_edge_recursive_iter,
- search_terms,
- }
- }
-
- pub fn get_archetype_by_id(&self, id: ArchetypeId) -> Option<&Archetype>
- {
- Some(self.graph.get_node_by_id(id)?.archetype())
- }
-
- pub fn create_entity(&mut self, uid: Uid) -> Result<(), EntityAlreadyExistsError>
- {
- debug_assert_eq!(uid.kind(), UidKind::Entity);
-
- if self.entity_archetype_lookup.contains_key(&uid) {
- return Err(EntityAlreadyExistsError);
- }
-
- let empty_archetype_id = ArchetypeId::new_empty();
-
- let archetype_node = self.graph.get_or_create_node(empty_archetype_id, &[]);
-
- archetype_node
- .archetype_mut()
- .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<ArchetypeEntity, Error>
- {
- let Some(archetype_id) = self.entity_archetype_lookup.get(&entity_uid) else {
- return Err(Error::EntityDoesNotExist(entity_uid));
- };
-
- let archetype_node = self
- .graph
- .get_node_by_id_mut(*archetype_id)
- .expect("Archetype should exist");
-
- let entity = archetype_node
- .archetype_mut()
- .remove_entity(entity_uid)
- .expect("Entity should exist in archetype");
-
- self.entity_archetype_lookup.remove(&entity_uid);
-
- Ok(entity)
- }
-
- pub fn get_entity_archetype(&self, entity_uid: Uid) -> Option<&Archetype>
- {
- let archetype_id = self.entity_archetype_lookup.get(&entity_uid)?;
-
- self.get_archetype_by_id(*archetype_id)
- }
-
- pub fn add_entity_component(
- &mut self,
- entity_uid: Uid,
- (component_id, component_name, component): (Uid, &'static str, Box<dyn Any>),
- ) -> Result<(), Error>
- {
- let Some(archetype_id) = self.entity_archetype_lookup.get(&entity_uid) else {
- return Err(Error::EntityDoesNotExist(entity_uid));
- };
-
- let archetype_id = *archetype_id;
-
- let archetype_node = self
- .graph
- .get_node_by_id_mut(archetype_id)
- .expect("Archetype should exist");
-
- if archetype_node
- .archetype()
- .contains_component_with_exact_id(component_id)
- {
- return Err(Error::ComponentAlreadyInEntity {
- entity: entity_uid,
- component: component_id,
- });
- }
-
- let add_edge_archetype_id = if let Some(add_edge_id) = archetype_node
- .get_or_insert_edges(component_id, ArchetypeEdges::default)
- .add
- {
- if !self.graph.contains_archetype(add_edge_id) {
- let (_, add_edge_comp_ids) = self
- .graph
- .get_node_by_id(archetype_id)
- .expect("Archetype should exist")
- .make_add_edge(component_id);
-
- self.graph.create_node(add_edge_id, &add_edge_comp_ids);
- }
-
- add_edge_id
- } else {
- let archetype_node = self
- .graph
- .get_node_by_id(archetype_id)
- .expect("Archetype should exist");
-
- let (add_edge_id, add_edge_comp_ids) =
- archetype_node.make_add_edge(component_id);
-
- if !self.graph.contains_archetype(add_edge_id) {
- self.graph.create_node(add_edge_id, &add_edge_comp_ids);
- }
-
- add_edge_id
- };
-
- let archetype_node = self
- .graph
- .get_node_by_id_mut(archetype_id)
- .expect("Archetype should exist");
-
- let mut entity = archetype_node
- .archetype_mut()
- .remove_entity(entity_uid)
- .expect("Entity should exist in archetype");
-
- let add_edge_archetype = self
- .graph
- .get_node_by_id_mut(add_edge_archetype_id)
- .expect("Add edge archetype should exist")
- .archetype_mut();
-
- entity.insert_component(
- component_id,
- ArchetypeEntityComponent::new(component, component_name),
- add_edge_archetype,
- );
-
- add_edge_archetype.push_entity(entity);
-
- self.entity_archetype_lookup
- .insert(entity_uid, add_edge_archetype_id);
-
- Ok(())
- }
-
- pub fn remove_entity_component(
- &mut self,
- entity_uid: Uid,
- component_id: Uid,
- ) -> Result<(), Error>
- {
- let Some(archetype_id) = self.entity_archetype_lookup.get(&entity_uid) else {
- return Err(Error::EntityDoesNotExist(entity_uid));
- };
-
- let archetype_id = *archetype_id;
-
- let archetype_node = self
- .graph
- .get_node_by_id_mut(archetype_id)
- .expect("Archetype should exist");
-
- if !archetype_node
- .archetype()
- .contains_component_with_exact_id(component_id)
- {
- return Err(Error::ComponentNotFoundInEntity {
- entity: entity_uid,
- component: component_id,
- });
- }
-
- let remove_edge_id = archetype_node
- .get_or_insert_edges(component_id, ArchetypeEdges::default)
- .remove
- .unwrap_or_else(|| {
- let archetype_node = self
- .graph
- .get_node_by_id_mut(archetype_id)
- .expect("Archetype should exist");
-
- let (remove_edge_id, remove_edge_comp_ids) =
- archetype_node.make_remove_edge(component_id);
-
- if !self.graph.contains_archetype(remove_edge_id) {
- self.graph
- .create_node(remove_edge_id, &remove_edge_comp_ids);
- }
-
- remove_edge_id
- });
-
- let archetype_node = self
- .graph
- .get_node_by_id_mut(archetype_id)
- .expect("Archetype should exist");
-
- let mut entity = archetype_node
- .archetype_mut()
- .remove_entity(entity_uid)
- .expect("Entity should exist in archetype");
-
- let removed_component =
- entity.remove_component(component_id, archetype_node.archetype());
-
- self.graph
- .get_node_by_id_mut(remove_edge_id)
- .expect("Remove edge archetype should exist")
- .archetype_mut()
- .push_entity(entity);
-
- self.entity_archetype_lookup
- .insert(entity_uid, remove_edge_id);
-
- tracing::debug!(
- entity_id = %entity_uid,
- component_id = %component_id,
- component_name = removed_component.name(),
- "Removed component from entity"
- );
-
- Ok(())
- }
-
- pub fn create_imaginary_archetypes(&mut self)
- {
- for imaginary_archetype in self.imaginary_archetypes.get_mut().drain(..) {
- if self.graph.contains_archetype(imaginary_archetype.id) {
- continue;
- }
-
- self.graph
- .create_node(imaginary_archetype.id, &imaginary_archetype.component_ids);
- }
- }
-
- fn find_all_archetype_with_comps(
- &self,
- search_terms: &ArchetypeSearchTerms<'_>,
- ) -> Vec<ArchetypeId>
- {
- let Some(mut search_iter) =
- self.graph.dfs_archetype_add_edges(ArchetypeId::new_empty())
- else {
- // If the root archetype doesn't exist, no other archetype can exist either
- //
- // TODO: The above comment is not true. Cases where imaginary archetypes have
- // been created should be handled as well
- return Vec::new();
- };
-
- let mut found = Vec::<ArchetypeId>::new();
-
- while let Some(node_id) = search_iter.streaming_next() {
- let ArchetypeAddEdgeDfsIterResult::AddEdge {
- add_edge_archetype_id: node_id,
- add_edge_component_id,
- } = node_id
- else {
- continue;
- };
-
- if search_terms.excluded_contains(add_edge_component_id) {
- search_iter.pop();
- continue;
- }
-
- let node = self
- .graph
- .get_node_by_id(node_id)
- .expect("Graph node found through DFS doesn't exist");
-
- if node.archetype().component_cnt() < search_terms.required_components.len() {
- continue;
- }
-
- if !search_terms.archetype_contains_all_required(node.archetype()) {
- continue;
- }
-
- found.push(node.archetype().id());
-
- search_iter.pop();
- }
-
- found
- }
-}
-
-#[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,
- &params,
- )?;
-
- 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,
- &params,
- )?;
-
- 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>
-{
- storage: &'storage Storage,
- pre_iter: Either<ArrayIter<ArchetypeId, 1>, VecIntoIter<ArchetypeId>>,
- dfs_iter: ArchetypeAddEdgeDfsIter<'storage>,
- search_terms: ArchetypeSearchTerms<'search_terms>,
-}
-
-impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage, '_>
-{
- type Item = &'component_storage Archetype;
-
- fn next(&mut self) -> Option<Self::Item>
- {
- if let Some(pre_iter_archetype_id) = self.pre_iter.next() {
- return Some(
- self.storage
- .get_archetype_by_id(pre_iter_archetype_id)
- .expect("Archetype should exist"),
- );
- }
-
- let archetype_id = loop {
- match self.dfs_iter.streaming_find(|res| {
- matches!(
- res,
- ArchetypeAddEdgeDfsIterResult::AddEdge { .. }
- | ArchetypeAddEdgeDfsIterResult::AddEdgeArchetypeNotFound { .. }
- )
- })? {
- ArchetypeAddEdgeDfsIterResult::AddEdge {
- add_edge_archetype_id,
- add_edge_component_id,
- } => {
- if self.search_terms.excluded_contains(add_edge_component_id) {
- self.dfs_iter.pop();
- continue;
- }
-
- break add_edge_archetype_id;
- }
- ArchetypeAddEdgeDfsIterResult::AddEdgeArchetypeNotFound {
- archetype,
- add_edge_archetype_id,
- add_edge_component_id,
- } => {
- if self.search_terms.excluded_contains(add_edge_component_id) {
- continue;
- }
-
- let mut add_edge_archetype_comps =
- archetype.component_ids_sorted().collect::<Vec<_>>();
-
- add_edge_archetype_comps
- .insert_at_part_pt_by_key(add_edge_component_id, |comp_id| {
- comp_id
- });
-
- self.storage.imaginary_archetypes.borrow_mut().push(
- ImaginaryArchetype {
- id: add_edge_archetype_id,
- component_ids: add_edge_archetype_comps.clone(),
- },
- );
-
- let found =
- self.find_edges_of_imaginary_archetype(&add_edge_archetype_comps);
-
- self.dfs_iter.push((
- BorrowedOrOwned::Owned(Archetype::new(
- add_edge_archetype_id,
- add_edge_archetype_comps.clone(),
- )),
- found.into_iter(),
- ));
- }
- _ => {
- unreachable!();
- }
- }
- };
-
- Some(
- self.storage
- .get_archetype_by_id(archetype_id)
- .expect("Archetype should exist"),
- )
- }
-}
-
-impl ArchetypeRefIter<'_, '_>
-{
- fn find_edges_of_imaginary_archetype(
- &self,
- imaginary_archetype_comps: &[Uid],
- ) -> Vec<(Uid, ArchetypeEdges)>
- {
- self.storage
- .find_all_archetype_with_comps(&ArchetypeSearchTerms {
- required_components: imaginary_archetype_comps,
- excluded_components: &[],
- })
- .into_iter()
- .filter_map(|found_id| {
- let found_archetype = self.storage.get_archetype_by_id(found_id).unwrap();
-
- if found_archetype.component_cnt() < imaginary_archetype_comps.len() + 1 {
- return None;
- }
-
- let unique_comp_id = found_archetype
- .component_ids_sorted()
- .find(|found_archetype_comp_id| {
- !imaginary_archetype_comps.iter().any(
- |imaginary_archetype_comp_id| {
- *imaginary_archetype_comp_id == *found_archetype_comp_id
- },
- )
- })
- .expect("Oh noooo");
-
- let mut add_edge_comp_ids = imaginary_archetype_comps.to_vec();
-
- add_edge_comp_ids.insert_at_part_pt_by_key(unique_comp_id, |id| id);
-
- let add_edge = ArchetypeId::new(&add_edge_comp_ids);
-
- Some((
- unique_comp_id,
- ArchetypeEdges { add: Some(add_edge), remove: None },
- ))
- })
- .collect::<Vec<_>>()
- }
-}
-
-#[derive(Debug, thiserror::Error)]
-pub enum Error
-{
- #[error("Entity with ID {0:?} does not exist")]
- EntityDoesNotExist(Uid),
-
- #[error("Entity with ID {entity:?} already has component with ID {component:?}")]
- ComponentAlreadyInEntity
- {
- entity: Uid, component: Uid
- },
-
- #[error("Entity with ID {entity:?} does not have component with ID {component:?}")]
- ComponentNotFoundInEntity
- {
- entity: Uid, component: Uid
- },
-}
-
-#[derive(Debug, thiserror::Error)]
-#[error("Entity with already exists")]
-pub struct EntityAlreadyExistsError;
-
-#[derive(Debug)]
-struct ImaginaryArchetype
-{
- id: ArchetypeId,
- component_ids: Vec<Uid>,
-}
-
-#[cfg(test)]
-mod tests
-{
- use crate::component::storage::Storage;
- use crate::component::storage::archetype::Id as ArchetypeId;
- use crate::uid::{Kind as UidKind, Uid};
-
- #[test]
- fn create_entity_works()
- {
- let mut new_storage = Storage::default();
-
- let uid = Uid::new_unique(UidKind::Entity);
-
- new_storage.create_entity(uid).expect("Expected Ok");
-
- let archetype_node = new_storage
- .graph
- .get_node_by_id(ArchetypeId::new_empty())
- .expect("Archetype for entities with no component doesn't exist");
-
- assert_eq!(archetype_node.archetype().component_cnt(), 0);
- assert_eq!(archetype_node.archetype().entity_cnt(), 1);
-
- assert_eq!(
- new_storage.entity_archetype_lookup.get(&uid).copied(),
- Some(ArchetypeId::new_empty())
- );
- }
-}
diff --git a/ecs/src/component/storage/archetype.rs b/ecs/src/component/storage/archetype.rs
deleted file mode 100644
index a7fe7ed..0000000
--- a/ecs/src/component/storage/archetype.rs
+++ /dev/null
@@ -1,385 +0,0 @@
-use std::any::Any;
-use std::array::IntoIter as ArrayIntoIter;
-use std::hash::{DefaultHasher, Hash, Hasher};
-use std::iter::{Enumerate, Filter, Map, RepeatN, Zip};
-use std::option::IntoIter as OptionIntoIter;
-use std::slice::Iter as SliceIter;
-
-use hashbrown::HashMap;
-
-use crate::lock::Lock;
-use crate::uid::{Kind as UidKind, Uid};
-use crate::util::{Either, HashMapExt};
-
-#[derive(Debug)]
-pub struct Archetype
-{
- id: Id,
- entities: Vec<Entity>,
- entity_index_lookup: HashMap<Uid, usize>,
- component_index_lookup: HashMap<Uid, usize>,
- component_ids: Vec<Uid>,
-}
-
-impl Archetype
-{
- pub fn new(id: Id, component_ids: impl AsRef<[Uid]>) -> Self
- {
- Self {
- id,
- entities: Vec::new(),
- entity_index_lookup: HashMap::new(),
- component_index_lookup: component_ids
- .as_ref()
- .iter()
- .enumerate()
- .map(|(index, id)| (*id, index))
- .collect(),
- component_ids: component_ids.as_ref().to_vec(),
- }
- }
-
- pub fn id(&self) -> Id
- {
- self.id
- }
-
- pub fn is_superset(&self, other: &Self) -> bool
- {
- self.component_index_lookup
- .keys_is_superset(&other.component_index_lookup)
- }
-
- pub fn is_subset(&self, other: &Self) -> bool
- {
- self.component_index_lookup
- .keys_is_subset(&other.component_index_lookup)
- }
-
- pub fn get_entity_by_id(&self, entity_uid: Uid) -> Option<&Entity>
- {
- let index = *self.entity_index_lookup.get(&entity_uid)?;
-
- Some(self.entities.get(index).unwrap_or_else(|| {
- panic!(
- "In invalid state! Index of entity with ID {entity_uid:?} is out of bounds"
- );
- }))
- }
-
- pub fn push_entity(&mut self, entity: Entity)
- {
- self.entity_index_lookup
- .insert(entity.uid, self.entities.len());
-
- self.entities.push(entity);
- }
-
- pub fn remove_entity(&mut self, entity_uid: Uid) -> Option<Entity>
- {
- //debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
-
- let entity_index = self.entity_index_lookup.remove(&entity_uid)?;
-
- if self.entities.len() == 1 {
- return Some(self.entities.remove(entity_index));
- }
-
- let last_entity_uid = self
- .entities
- .last()
- .expect(concat!(
- "Invalid state. No entities in archetype but entry was ",
- "removed successfully from entity index lookup"
- ))
- .uid;
-
- // By using swap_remove, no memory reallocation occurs and only one index in the
- // entity lookup needs to be updated
- let removed_entity = self.entities.swap_remove(entity_index);
-
- self.entity_index_lookup
- .insert(last_entity_uid, entity_index);
-
- Some(removed_entity)
- }
-
- pub fn entities(&self) -> EntityIter<'_>
- {
- EntityIter { iter: self.entities.iter() }
- }
-
- pub fn entity_cnt(&self) -> usize
- {
- self.entities.len()
- }
-
- pub fn component_cnt(&self) -> usize
- {
- self.component_index_lookup.len()
- }
-
- pub fn get_matching_component_indices(
- &self,
- component_id: Uid,
- ) -> MatchingComponentIter<'_>
- {
- assert!(
- component_id.kind() == UidKind::Component
- || component_id.kind() == UidKind::Pair
- );
-
- if component_id.kind() == UidKind::Pair
- && component_id.target_component() == Uid::wildcard()
- {
- return MatchingComponentIter {
- inner: Either::A(
- self.component_ids
- .iter()
- .enumerate()
- .zip(std::iter::repeat_n(component_id, self.component_ids.len()))
- .filter(
- (|((_, other_comp_id), component_id)| {
- other_comp_id.kind() == UidKind::Pair
- && other_comp_id.has_same_relation_as(*component_id)
- })
- as MatchingComponentIterFilterFn,
- )
- .map(|((index, other_comp_id), _)| (*other_comp_id, index)),
- ),
- };
- }
-
- MatchingComponentIter {
- inner: Either::B(
- [component_id]
- .into_iter()
- .zip(self.get_index_for_component(component_id)),
- ),
- }
- }
-
- pub fn get_index_for_component(&self, component_id: Uid) -> Option<usize>
- {
- assert!(
- component_id.kind() == UidKind::Component
- || (component_id.kind() == UidKind::Pair
- && component_id.target_component() != Uid::wildcard())
- );
-
- self.component_index_lookup.get(&component_id).copied()
- }
-
- pub fn component_ids_unsorted(&self) -> impl Iterator<Item = Uid> + '_
- {
- self.component_index_lookup.keys().copied()
- }
-
- pub fn component_ids_sorted(&self) -> impl Iterator<Item = Uid> + '_
- {
- self.component_ids.iter().copied()
- }
-
- pub fn contains_matching_component(&self, component_id: Uid) -> bool
- {
- let component_id_kind = component_id.kind();
-
- debug_assert!(
- component_id_kind == UidKind::Component || component_id_kind == UidKind::Pair
- );
-
- if component_id.kind() == UidKind::Pair
- && component_id.target_component() == Uid::wildcard()
- {
- return self.component_ids.iter().any(|other_comp_id| {
- other_comp_id.kind() == UidKind::Pair
- && other_comp_id.has_same_relation_as(component_id)
- });
- }
-
- self.contains_component_with_exact_id(component_id)
- }
-
- pub fn contains_component_with_exact_id(&self, component_id: Uid) -> bool
- {
- let component_id_kind = component_id.kind();
-
- debug_assert!(
- component_id_kind == UidKind::Component
- || (component_id_kind == UidKind::Pair
- && component_id.target_component() != Uid::wildcard())
- );
-
- self.component_index_lookup.contains_key(&component_id)
- }
-}
-
-type MatchingComponentIterFilterFn = fn(&((usize, &Uid), Uid)) -> bool;
-
-type MatchingComponentIterMapFn = fn(((usize, &Uid), Uid)) -> (Uid, usize);
-
-type InnerMatchingComponentIterA<'archetype> = Map<
- Filter<
- Zip<Enumerate<SliceIter<'archetype, Uid>>, RepeatN<Uid>>,
- MatchingComponentIterFilterFn,
- >,
- MatchingComponentIterMapFn,
->;
-
-type InnerMatchingComponentIterB = Zip<ArrayIntoIter<Uid, 1>, OptionIntoIter<usize>>;
-
-#[derive(Debug)]
-pub struct MatchingComponentIter<'archetype>
-{
- inner: Either<InnerMatchingComponentIterA<'archetype>, InnerMatchingComponentIterB>,
-}
-
-impl Iterator for MatchingComponentIter<'_>
-{
- type Item = (Uid, usize);
-
- fn next(&mut self) -> Option<Self::Item>
- {
- self.inner.next()
- }
-}
-
-#[derive(Debug)]
-pub struct EntityIter<'archetype>
-{
- iter: SliceIter<'archetype, Entity>,
-}
-
-impl<'archetype> Iterator for EntityIter<'archetype>
-{
- type Item = &'archetype Entity;
-
- fn next(&mut self) -> Option<Self::Item>
- {
- self.iter.next()
- }
-}
-
-#[derive(Debug)]
-pub struct Entity
-{
- 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,
- ) -> EntityComponent
- {
- 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
-{
- component: Lock<Box<dyn Any>>,
- name: &'static str,
-}
-
-impl EntityComponent
-{
- pub fn new(component: Box<dyn Any>, component_name: &'static str) -> Self
- {
- Self {
- component: Lock::new(component, component_name),
- name: component_name,
- }
- }
-
- pub fn component(&self) -> &Lock<Box<dyn Any>>
- {
- &self.component
- }
-
- pub fn name(&self) -> &str
- {
- self.name
- }
-}
-
-/// Archetype ID.
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Id
-{
- hash: u64,
-}
-
-impl Id
-{
- pub fn new_empty() -> Self
- {
- Self { hash: 0 }
- }
-
- pub fn new<'a>(component_ids: impl IntoIterator<Item = &'a Uid>) -> Self
- {
- let mut hasher = DefaultHasher::new();
-
- let mut prev_component_id: Option<Uid> = None;
-
- let mut component_id_iter = component_ids.into_iter().peekable();
-
- if component_id_iter.peek().is_none() {
- return Self::new_empty();
- }
-
- for comp_id in component_id_iter {
- assert!(
- prev_component_id.is_none_or(|prev_comp_id| *comp_id >= prev_comp_id),
- "Cannot create archetype ID from a unsorted component metadata list"
- );
-
- prev_component_id = Some(*comp_id);
-
- comp_id.hash(&mut hasher);
- }
-
- Self { hash: hasher.finish() }
- }
-}
diff --git a/ecs/src/component/storage/graph.rs b/ecs/src/component/storage/graph.rs
deleted file mode 100644
index 76200f9..0000000
--- a/ecs/src/component/storage/graph.rs
+++ /dev/null
@@ -1,432 +0,0 @@
-use std::vec::IntoIter as VecIntoIter;
-
-use hashbrown::{HashMap, HashSet};
-
-use crate::component::storage::archetype::{Archetype, Id as ArchetypeId};
-use crate::uid::{Kind as UidKind, Uid};
-use crate::util::{BorrowedOrOwned, StreamingIterator};
-
-#[derive(Debug, Default)]
-pub struct Graph
-{
- nodes: Vec<ArchetypeNode>,
- archetype_index_lookup: HashMap<ArchetypeId, usize>,
-}
-
-impl Graph
-{
- pub fn create_node(&mut self, id: ArchetypeId, component_ids: &impl AsRef<[Uid]>)
- {
- debug_assert!(!self.contains_archetype(id));
-
- let _ = self.get_or_create_node(id, component_ids);
- }
-
- pub fn get_or_create_node(
- &mut self,
- id: ArchetypeId,
- component_ids: &impl AsRef<[Uid]>,
- ) -> &mut ArchetypeNode
- {
- let exists_before = self.archetype_index_lookup.contains_key(&id);
-
- let index = *self.archetype_index_lookup.entry(id).or_insert_with(|| {
- self.nodes.push(ArchetypeNode {
- archetype: Archetype::new(id, component_ids.as_ref()),
- edges: HashMap::new(),
- });
-
- self.nodes.len() - 1
- });
-
- if !exists_before {
- self.create_missing_edges(id);
- }
-
- self.nodes
- .get_mut(index)
- .expect("Archetype index from lookup is out of bounds")
- }
-
- pub fn contains_archetype(&self, id: ArchetypeId) -> bool
- {
- self.archetype_index_lookup.contains_key(&id)
- }
-
- pub fn get_node_by_id(&self, id: ArchetypeId) -> Option<&ArchetypeNode>
- {
- let index = self.archetype_index_lookup.get(&id)?;
-
- Some(self.nodes.get(*index).unwrap_or_else(|| {
- panic!("In invalid state! Index of archetype with ID {id:?} is out of bounds")
- }))
- }
-
- pub fn get_node_by_id_mut(&mut self, id: ArchetypeId) -> Option<&mut ArchetypeNode>
- {
- let index = self.archetype_index_lookup.get(&id)?;
-
- Some(self.nodes.get_mut(*index).unwrap_or_else(|| {
- panic!("In invalid state! Index of archetype with ID {id:?} is out of bounds")
- }))
- }
-
- #[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,
- ) -> Option<ArchetypeAddEdgeDfsIter<'_>>
- {
- let node = self.get_node_by_id(archetype_id)?;
-
- Some(ArchetypeAddEdgeDfsIter {
- graph: self,
- stack: vec![(
- BorrowedOrOwned::Borrowned(node.archetype()),
- node.edges
- .iter()
- .map(|(comp_id, edges)| (*comp_id, edges.clone()))
- .collect::<Vec<_>>()
- .into_iter(),
- )],
- visited: HashSet::new(),
- })
- }
-
- fn create_missing_edges(&mut self, archetype_id: ArchetypeId)
- {
- let archetype_node_index = *self
- .archetype_index_lookup
- .get(&archetype_id)
- .expect("Archetype should exist");
-
- let (nodes_before, nodes_rest) = self.nodes.split_at_mut(archetype_node_index);
-
- let ([archetype_node], nodes_after) = nodes_rest.split_at_mut(1) else {
- unreachable!();
- };
-
- for other_archetype_node in nodes_before.iter_mut().chain(nodes_after.iter_mut())
- {
- if archetype_node.archetype().component_cnt()
- > other_archetype_node.archetype().component_cnt()
- && other_archetype_node
- .archetype()
- .is_subset(archetype_node.archetype())
- {
- Self::create_missing_subset_node_edges(
- archetype_node,
- other_archetype_node,
- );
-
- continue;
- }
-
- if other_archetype_node
- .archetype()
- .is_superset(archetype_node.archetype())
- {
- Self::create_missing_superset_node_edges(
- archetype_node,
- other_archetype_node,
- );
- }
- }
- }
-
- fn create_missing_subset_node_edges(
- target_node: &mut ArchetypeNode,
- subset_node: &mut ArchetypeNode,
- )
- {
- let uniq_comp_id = target_node
- .archetype()
- .component_ids_sorted()
- .find(|id| {
- !subset_node
- .archetype()
- .contains_component_with_exact_id(*id)
- })
- .unwrap();
-
- subset_node
- .get_or_insert_edges(uniq_comp_id, ArchetypeEdges::default)
- .add = Some(subset_node.make_add_edge(uniq_comp_id).0);
-
- if target_node.archetype().component_cnt()
- == subset_node.archetype().component_cnt() + 1
- {
- target_node
- .get_or_insert_edges(uniq_comp_id, ArchetypeEdges::default)
- .remove = Some(subset_node.archetype().id());
- }
- }
-
- fn create_missing_superset_node_edges(
- target_node: &mut ArchetypeNode,
- superset_node: &mut ArchetypeNode,
- )
- {
- if superset_node.archetype().component_cnt()
- > target_node.archetype().component_cnt() + 1
- {
- let first_unique_comp_id = superset_node
- .archetype()
- .component_ids_sorted()
- .find(|other_archetype_comp_id| {
- !target_node
- .archetype()
- .contains_component_with_exact_id(*other_archetype_comp_id)
- })
- .or_else(|| {
- if target_node.archetype().component_cnt() != 0 {
- return None;
- }
-
- superset_node.archetype().component_ids_sorted().next()
- })
- .expect("Not possible");
-
- target_node
- .get_or_insert_edges(first_unique_comp_id, ArchetypeEdges::default)
- .add = Some(target_node.make_add_edge(first_unique_comp_id).0);
-
- return;
- }
-
- if superset_node.archetype().component_cnt()
- != target_node.archetype().component_cnt() + 1
- {
- return;
- }
-
- let extra_comp_id = superset_node
- .archetype()
- .component_ids_unsorted()
- .find(|comp_id| {
- !target_node
- .archetype()
- .contains_component_with_exact_id(*comp_id)
- })
- .expect("Archetype should contain one extra component ID");
-
- superset_node
- .get_or_insert_edges(extra_comp_id, ArchetypeEdges::default)
- .remove = Some(target_node.archetype().id());
-
- target_node
- .get_or_insert_edges(extra_comp_id, ArchetypeEdges::default)
- .add = Some(superset_node.archetype().id());
- }
-}
-
-#[derive(Debug)]
-pub struct ArchetypeNode
-{
- archetype: Archetype,
- edges: HashMap<Uid, ArchetypeEdges>,
-}
-
-impl ArchetypeNode
-{
- pub fn archetype(&self) -> &Archetype
- {
- &self.archetype
- }
-
- pub fn archetype_mut(&mut self) -> &mut Archetype
- {
- &mut self.archetype
- }
-
- pub fn get_or_insert_edges(
- &mut self,
- component_id: Uid,
- insert_fn: impl FnOnce() -> ArchetypeEdges,
- ) -> &mut ArchetypeEdges
- {
- debug_assert!(matches!(
- component_id.kind(),
- UidKind::Component | UidKind::Pair
- ));
-
- 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 make_add_edge(&self, component_id: Uid) -> (ArchetypeId, Vec<Uid>)
- {
- let mut edge_comp_ids = self
- .archetype()
- .component_ids_unsorted()
- .chain([component_id])
- .collect::<Vec<_>>();
-
- edge_comp_ids.sort();
-
- let add_edge_id = ArchetypeId::new(&edge_comp_ids);
-
- (add_edge_id, edge_comp_ids)
- }
-
- pub fn make_remove_edge(&self, component_id: Uid) -> (ArchetypeId, Vec<Uid>)
- {
- let mut edge_comp_ids = self
- .archetype()
- .component_ids_unsorted()
- .filter(|id| *id != component_id)
- .collect::<Vec<_>>();
-
- edge_comp_ids.sort();
-
- let remove_edge_id = ArchetypeId::new(&edge_comp_ids);
-
- (remove_edge_id, edge_comp_ids)
- }
-}
-
-#[derive(Debug, Default, Clone)]
-pub struct ArchetypeEdges
-{
- pub add: Option<ArchetypeId>,
- pub remove: Option<ArchetypeId>,
-}
-
-type ArchetypeAddEdgeDfsIterStackElem<'graph> = (
- BorrowedOrOwned<'graph, Archetype>,
- VecIntoIter<(Uid, ArchetypeEdges)>,
-);
-
-#[derive(Debug)]
-pub struct ArchetypeAddEdgeDfsIter<'graph>
-{
- graph: &'graph Graph,
- stack: Vec<ArchetypeAddEdgeDfsIterStackElem<'graph>>,
- visited: HashSet<ArchetypeId>,
-}
-
-impl<'graph> ArchetypeAddEdgeDfsIter<'graph>
-{
- pub fn new(graph: &'graph Graph, start_nodes: &[ArchetypeId]) -> Self
- {
- Self {
- graph,
- stack: start_nodes
- .iter()
- .map(|start_node_id| {
- let start_node = graph
- .get_node_by_id(*start_node_id)
- .expect("Start node does not exist");
-
- (
- BorrowedOrOwned::Borrowned(start_node.archetype()),
- start_node
- .edges
- .iter()
- .map(|(comp_id, edges)| (*comp_id, edges.clone()))
- .collect::<Vec<_>>()
- .into_iter(),
- )
- })
- .collect(),
- visited: start_nodes.iter().copied().collect::<HashSet<_>>(),
- }
- }
-
- pub fn push(
- &mut self,
- item: (
- BorrowedOrOwned<'graph, Archetype>,
- VecIntoIter<(Uid, ArchetypeEdges)>,
- ),
- )
- {
- self.stack.push(item);
- }
-
- pub fn pop(&mut self)
- {
- self.stack.pop();
- }
-}
-
-impl<'graph> StreamingIterator for ArchetypeAddEdgeDfsIter<'graph>
-{
- type Item<'a>
- = ArchetypeAddEdgeDfsIterResult<'graph, 'a>
- where
- Self: 'a;
-
- fn streaming_next(&mut self) -> Option<Self::Item<'_>>
- {
- let (_, edges_iter) = self.stack.last_mut()?;
-
- let Some((component_id, edges)) = edges_iter.next() else {
- self.stack.pop();
-
- return Some(ArchetypeAddEdgeDfsIterResult::NoEdgesLeftForArchetype);
- };
-
- let Some(add_edge) = edges.add else {
- return Some(ArchetypeAddEdgeDfsIterResult::NoAddEdge);
- };
-
- if self.visited.contains(&add_edge) {
- return Some(ArchetypeAddEdgeDfsIterResult::AddEdgeAlreadyVisited);
- }
-
- self.visited.insert(add_edge);
-
- let Some(add_edge_archetype) = self.graph.get_node_by_id(add_edge) else {
- return Some(ArchetypeAddEdgeDfsIterResult::AddEdgeArchetypeNotFound {
- archetype: &self.stack.last().unwrap().0,
- add_edge_archetype_id: add_edge,
- add_edge_component_id: component_id,
- });
- };
-
- self.stack.push((
- BorrowedOrOwned::Borrowned(add_edge_archetype.archetype()),
- add_edge_archetype
- .edges
- .iter()
- .map(|(comp_id, edges)| (*comp_id, edges.clone()))
- .collect::<Vec<_>>()
- .into_iter(),
- ));
-
- Some(ArchetypeAddEdgeDfsIterResult::AddEdge {
- add_edge_archetype_id: add_edge,
- add_edge_component_id: component_id,
- })
- }
-}
-
-#[derive(Debug)]
-pub enum ArchetypeAddEdgeDfsIterResult<'graph, 'iter>
-{
- AddEdge
- {
- add_edge_archetype_id: ArchetypeId,
- add_edge_component_id: Uid,
- },
- NoEdgesLeftForArchetype,
- NoAddEdge,
- AddEdgeAlreadyVisited,
- AddEdgeArchetypeNotFound
- {
- archetype: &'iter BorrowedOrOwned<'graph, Archetype>,
- add_edge_archetype_id: ArchetypeId,
- add_edge_component_id: Uid,
- },
-}