summaryrefslogtreecommitdiff
path: root/ecs/src/component/storage.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/component/storage.rs')
-rw-r--r--ecs/src/component/storage.rs224
1 files changed, 198 insertions, 26 deletions
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs
index 4b2b6d8..40909fb 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>
@@ -195,10 +192,24 @@ impl Storage
});
}
- let add_edge_archetype_id = archetype_node
+ let add_edge_archetype_id = match archetype_node
.get_or_insert_edges(component_id, ArchetypeEdges::default)
.add
- .unwrap_or_else(|| {
+ {
+ Some(add_edge_id) => {
+ 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
+ }
+ None => {
let archetype_node = self
.graph
.get_node_by_id_mut(archetype_id)
@@ -217,7 +228,8 @@ impl Storage
}
add_edge_id
- });
+ }
+ };
{
let add_edge_archetype_node = self
@@ -247,13 +259,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 +335,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 +423,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,
+ &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>
{