summaryrefslogtreecommitdiff
path: root/ecs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-06-06 12:50:05 +0200
committerHampusM <hampus@hampusmat.com>2024-06-06 12:50:20 +0200
commitcb1ff29c8c7fa77bbb4e532eaa7e45df717a58ef (patch)
tree44cbc9c821609dc117b26369c3872386ab533f55 /ecs
parent43079a8dc9e2b608f47c5919f45c1f1661f11a2e (diff)
refactor(ecs): move ComponentStorage to it's own module
Diffstat (limited to 'ecs')
-rw-r--r--ecs/src/component.rs2
-rw-r--r--ecs/src/component/storage.rs81
-rw-r--r--ecs/src/lib.rs117
-rw-r--r--ecs/src/query.rs4
4 files changed, 104 insertions, 100 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 63ef7c4..d3b00ef 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -10,6 +10,8 @@ use crate::EntityComponent;
pub mod local;
+pub(crate) mod storage;
+
pub trait Component: SystemInput + Any + TypeName
{
/// The component type in question. Will usually be `Self`
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs
new file mode 100644
index 0000000..cdff09e
--- /dev/null
+++ b/ecs/src/component/storage.rs
@@ -0,0 +1,81 @@
+use std::any::{type_name, TypeId};
+use std::collections::HashSet;
+
+use crate::component::{Component, IsOptional as ComponentIsOptional};
+use crate::lock::Lock;
+use crate::type_name::TypeName;
+use crate::EntityComponent;
+
+#[derive(Debug, Default)]
+pub struct ComponentStorage
+{
+ entities: Vec<Entity>,
+}
+
+impl ComponentStorage
+{
+ pub fn find_entity_with_components(
+ &self,
+ start_index: usize,
+ component_type_ids: &[(TypeId, ComponentIsOptional)],
+ ) -> Option<(usize, &[EntityComponent])>
+ {
+ // TODO: This is a really dumb and slow way to do this. Refactor the world
+ // to store components in archetypes
+ self.entities
+ .iter()
+ .enumerate()
+ .skip(start_index)
+ .find(move |(_index, entity)| {
+ let entity_components = entity
+ .components
+ .iter()
+ .map(|component| component.id)
+ .collect::<HashSet<_>>();
+
+ if component_type_ids
+ .iter()
+ .filter(|(_, is_optional)| *is_optional == ComponentIsOptional::No)
+ .all(|(component_type_id, _)| {
+ entity_components.contains(component_type_id)
+ })
+ {
+ return true;
+ }
+
+ false
+ })
+ .map(|(index, entity)| (index, &*entity.components))
+ }
+
+ pub fn push_entity(
+ &mut self,
+ components: impl IntoIterator<Item = Box<dyn Component>>,
+ )
+ {
+ self.entities.push(Entity {
+ components: components
+ .into_iter()
+ .map(|component| EntityComponent {
+ id: (*component).type_id(),
+ name: component.type_name(),
+ component: Lock::new(component),
+ })
+ .collect(),
+ });
+ }
+}
+
+impl TypeName for ComponentStorage
+{
+ fn type_name(&self) -> &'static str
+ {
+ type_name::<Self>()
+ }
+}
+
+#[derive(Debug, Default)]
+struct Entity
+{
+ components: Vec<EntityComponent>,
+}
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index f76d1ae..1983f66 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -1,7 +1,7 @@
#![deny(clippy::all, clippy::pedantic)]
use std::any::{type_name, TypeId};
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
use std::fmt::Debug;
use std::mem::ManuallyDrop;
use std::ops::RangeBounds;
@@ -10,11 +10,8 @@ use std::sync::Arc;
use std::vec::Drain;
use crate::actions::Action;
-use crate::component::{
- Component,
- IsOptional as ComponentIsOptional,
- Sequence as ComponentSequence,
-};
+use crate::component::storage::ComponentStorage;
+use crate::component::{Component, Sequence as ComponentSequence};
use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence};
use crate::extension::{Collector as ExtensionCollector, Extension};
use crate::lock::Lock;
@@ -38,21 +35,6 @@ pub use ecs_macros::{Component, Sole};
pub use crate::query::Query;
#[derive(Debug, Default)]
-struct Entity
-{
- components: Vec<EntityComponent>,
-}
-
-#[derive(Debug)]
-#[non_exhaustive]
-pub struct EntityComponent
-{
- pub id: TypeId,
- pub name: &'static str,
- pub component: Lock<Box<dyn Component>>,
-}
-
-#[derive(Debug, Default)]
pub struct World
{
systems: Vec<TypeErasedSystem>,
@@ -80,18 +62,7 @@ impl World
.component_storage
.write_nonblock()
.expect("Failed to acquire read-write component storage lock")
- .entities
- .push(Entity {
- components: components
- .into_vec()
- .into_iter()
- .map(|component| EntityComponent {
- id: (*component).type_id(),
- name: component.type_name(),
- component: Lock::new(component),
- })
- .collect(),
- });
+ .push_entity(components.into_vec())
}
/// Adds a globally shared singleton value.
@@ -169,23 +140,12 @@ impl World
.drain(..)
{
match action {
- Action::Spawn(components) => {
- self.data
- .component_storage
- .write_nonblock()
- .expect("Failed to acquire read-write component storage lock")
- .entities
- .push(Entity {
- components: components
- .into_iter()
- .map(|component| EntityComponent {
- id: (*component).type_id(),
- name: component.type_name(),
- component: Lock::new(component),
- })
- .collect(),
- });
- }
+ Action::Spawn(components) => self
+ .data
+ .component_storage
+ .write_nonblock()
+ .expect("Failed to acquire read-write component storage lock")
+ .push_entity(components),
Action::Stop => {
self.stop.store(true, Ordering::Relaxed);
}
@@ -240,6 +200,15 @@ pub struct WorldData
action_queue: Arc<Lock<ActionQueue>>,
}
+#[derive(Debug)]
+#[non_exhaustive]
+pub struct EntityComponent
+{
+ pub id: TypeId,
+ pub name: &'static str,
+ pub component: Lock<Box<dyn Component>>,
+}
+
#[derive(Debug, Default)]
struct ActionQueue
{
@@ -267,54 +236,6 @@ impl TypeName for ActionQueue
}
}
-#[derive(Debug, Default)]
-pub struct ComponentStorage
-{
- entities: Vec<Entity>,
-}
-
-impl ComponentStorage
-{
- fn find_entity_with_components(
- &self,
- start_index: usize,
- component_type_ids: &[(TypeId, ComponentIsOptional)],
- ) -> Option<(usize, &Entity)>
- {
- // TODO: This is a really dumb and slow way to do this. Refactor the world
- // to store components in archetypes
- self.entities.iter().enumerate().skip(start_index).find(
- move |(_index, entity)| {
- let entity_components = entity
- .components
- .iter()
- .map(|component| component.id)
- .collect::<HashSet<_>>();
-
- if component_type_ids
- .iter()
- .filter(|(_, is_optional)| *is_optional == ComponentIsOptional::No)
- .all(|(component_type_id, _)| {
- entity_components.contains(component_type_id)
- })
- {
- return true;
- }
-
- false
- },
- )
- }
-}
-
-impl TypeName for ComponentStorage
-{
- fn type_name(&self) -> &'static str
- {
- type_name::<Self>()
- }
-}
-
#[derive(Debug, thiserror::Error)]
#[error("Sole {0} already exists")]
pub struct SoleAlreadyExistsError(pub &'static str);
diff --git a/ecs/src/query.rs b/ecs/src/query.rs
index ffab105..90e6169 100644
--- a/ecs/src/query.rs
+++ b/ecs/src/query.rs
@@ -199,7 +199,7 @@ where
fn next(&mut self) -> Option<Self::Item>
{
- let (matching_entity_index, matching_entity) =
+ let (matching_entity_index, matching_entity_components) =
self.component_storage.find_entity_with_components(
self.current_entity_index,
&self.component_type_ids,
@@ -208,7 +208,7 @@ where
self.current_entity_index = matching_entity_index + 1;
Some(Comps::from_components(
- matching_entity.components.iter().map(|component| component),
+ matching_entity_components.iter().map(|component| component),
))
}
}